diff --git a/CHANGELOG.md b/CHANGELOG.md index 864f793355..a7c12160bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # App Center SDK for Android Change Log +## Version 4.4.3 + +### App Center Crashes + +* **[Fix]** Add exception null check for `Crashes.trackError` API. + +### App Center Distribute + +* **[Fix]** Fix checking a new release if the application was already updated before. +* **[Fix]** Fix superfluous register/unregister receiver for installing new release. +* **[Fix]** Fix show custom in-app update dialog after opening release details. + +### App Center Distribute Play + +* **[Fix]** Add missing `Distribute.addStores` API. + +___ + ## Version 4.4.2 ### App Center @@ -10,6 +28,7 @@ ### App Center Distribute * **[Fix]** Fix missing required flag on Android 31 API for `PendingIntent` which is used for starting the process of installing a new release. +* **[Known issue]** After the first in-app update App Center doesn't indicate the next releases. Use a [workaround](https://github.com/microsoft/appcenter-sdk-android/issues/1594#issuecomment-1006313019) to avoid this issue. ___ diff --git a/apps/sasquatch/build.gradle b/apps/sasquatch/build.gradle index acfe363fd1..8af3fafb47 100644 --- a/apps/sasquatch/build.gradle +++ b/apps/sasquatch/build.gradle @@ -26,10 +26,20 @@ android { projectDependency { dimension "dependency" applicationIdSuffix ".project" + buildConfigField "String", "APP_SECRET", "\"${System.getenv("ANDROID_INT")}\"" + buildConfigField "String", "TARGET_TOKEN", "\"${System.getenv("ANDROID_TARGET_TOKEN_INT")}\"" + buildConfigField "String", "TARGET_TOKEN1", "\"${System.getenv("ANDROID_TARGET_TOKEN1_INT")}\"" + buildConfigField "String", "TARGET_TOKEN2", "\"${System.getenv("ANDROID_TARGET_TOKEN2_INT")}\"" + buildConfigField "String", "TARGET_TOKEN3", "\"${System.getenv("ANDROID_TARGET_TOKEN3_INT")}\"" } mavenCentralDependency { dimension "dependency" applicationIdSuffix ".mavenCentral" + buildConfigField "String", "APP_SECRET", "\"${System.getenv("ANDROID_PROD")}\"" + buildConfigField "String", "TARGET_TOKEN", "\"${System.getenv("ANDROID_TARGET_TOKEN_PROD")}\"" + buildConfigField "String", "TARGET_TOKEN1", "\"${System.getenv("ANDROID_TARGET_TOKEN1_PROD")}\"" + buildConfigField "String", "TARGET_TOKEN2", "\"${System.getenv("ANDROID_TARGET_TOKEN2_PROD")}\"" + buildConfigField "String", "TARGET_TOKEN3", "\"${System.getenv("ANDROID_TARGET_TOKEN3_PROD")}\"" } appCenter { dimension "distribute" diff --git a/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/MainActivity.java b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/MainActivity.java index 1cdac2e1d9..c6e5cc3406 100644 --- a/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/MainActivity.java +++ b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/MainActivity.java @@ -36,6 +36,7 @@ import com.microsoft.appcenter.crashes.CrashesListener; import com.microsoft.appcenter.crashes.model.ErrorReport; import com.microsoft.appcenter.distribute.Distribute; +import com.microsoft.appcenter.sasquatch.BuildConfig; import com.microsoft.appcenter.sasquatch.MSAAuthenticationProvider; import com.microsoft.appcenter.sasquatch.R; import com.microsoft.appcenter.sasquatch.features.TestFeatures; @@ -55,6 +56,12 @@ public class MainActivity extends AppCompatActivity { public static final String LOG_TAG = "AppCenterSasquatch"; + public static String[] mAppSecretsArray = {BuildConfig.APP_SECRET, "Custom"}; + + public static String mTargetToken = BuildConfig.TARGET_TOKEN; + + public static String[] mTargetTokenArray = {BuildConfig.TARGET_TOKEN1, BuildConfig.TARGET_TOKEN2, BuildConfig.TARGET_TOKEN3}; + static final String APP_SECRET_KEY = "appSecret"; static final String TARGET_KEY = "target"; @@ -153,7 +160,7 @@ static void startAppCenter(Application application, String startTypeString) { return; } String appId = sSharedPreferences.getString(APP_SECRET_KEY, getDefaultAppSecret(application.getResources())); - String targetId = sSharedPreferences.getString(TARGET_KEY, application.getString(R.string.target_id)); + String targetId = sSharedPreferences.getString(TARGET_KEY, MainActivity.mTargetToken); String appIdArg = ""; switch (startType) { case APP_SECRET: @@ -355,13 +362,11 @@ public void accept(ErrorReport data) { /* Get the default app secret from the app secret array. */ static String getDefaultAppSecret(Resources resources) { - final String[] secretValuesArray = resources.getStringArray(R.array.appcenter_secrets); - return secretValuesArray[0]; + return mAppSecretsArray[0]; } static String getCustomAppSecretString(Resources resources) { - final String[] secretValuesArray = resources.getStringArray(R.array.appcenter_secrets); - return secretValuesArray[secretValuesArray.length - 1]; + return mAppSecretsArray[mAppSecretsArray.length - 1]; } private void setDistributeEnabledForDebuggableBuild() { diff --git a/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/SettingsActivity.java b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/SettingsActivity.java index 8a4725d6d8..af50f4378b 100644 --- a/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/SettingsActivity.java +++ b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/activities/SettingsActivity.java @@ -16,6 +16,7 @@ import android.os.Bundle; import android.os.FileObserver; import android.preference.CheckBoxPreference; +import android.preference.ListPreference; import android.preference.Preference; import androidx.annotation.Nullable; import androidx.annotation.StringRes; @@ -479,6 +480,8 @@ public boolean onPreferenceChange(Preference preference, Object newValue) { }); final String defaultAppSecret = MainActivity.getDefaultAppSecret(getActivity().getResources()); final String appSecret = MainActivity.sSharedPreferences.getString(APP_SECRET_KEY, defaultAppSecret); + final ListPreference listOfAppSecrets = (ListPreference) findPreference(getString(R.string.app_secret_key)); + listOfAppSecrets.setEntryValues(MainActivity.mAppSecretsArray); initChangeableSetting(R.string.app_secret_key, appSecret, new Preference.OnPreferenceChangeListener() { @Override @@ -556,7 +559,7 @@ public boolean onPreferenceChange(Preference preference, Object newValue) { return true; } }); - initEditText(R.string.target_id_key, R.string.target_id_title, TARGET_KEY, getString(R.string.target_id), new EditTextListener() { + initEditText(R.string.target_id_key, R.string.target_id_title, TARGET_KEY, MainActivity.mTargetToken, new EditTextListener() { @Override public void onSave(String value) { @@ -570,7 +573,7 @@ public void onSave(String value) { @Override public void onReset() { - String defaultTargetId = getString(R.string.target_id); + String defaultTargetId = MainActivity.mTargetToken; setKeyValue(TARGET_KEY, defaultTargetId); Toast.makeText(getActivity(), String.format(getActivity().getString(R.string.target_id_changed_format), defaultTargetId), Toast.LENGTH_SHORT).show(); } diff --git a/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/listeners/SasquatchDistributeListener.java b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/listeners/SasquatchDistributeListener.java index d77f43a5d0..0bc862f937 100644 --- a/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/listeners/SasquatchDistributeListener.java +++ b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/listeners/SasquatchDistributeListener.java @@ -7,6 +7,7 @@ import android.app.Activity; import android.content.DialogInterface; +import android.content.Intent; import android.widget.Toast; import androidx.appcompat.app.AlertDialog; @@ -20,7 +21,7 @@ public class SasquatchDistributeListener implements DistributeListener { @Override - public boolean onReleaseAvailable(Activity activity, ReleaseDetails releaseDetails) { + public boolean onReleaseAvailable(final Activity activity, final ReleaseDetails releaseDetails) { final String releaseNotes = releaseDetails.getReleaseNotes(); boolean custom = releaseNotes != null && releaseNotes.toLowerCase().contains("custom"); if (custom) { @@ -44,6 +45,12 @@ public void onClick(DialogInterface dialog, int which) { } }); } + dialogBuilder.setNeutralButton(R.string.appcenter_distribute_update_dialog_view_release_notes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + activity.startActivity(new Intent(Intent.ACTION_VIEW, releaseDetails.getReleaseNotesUrl())); + } + }); dialogBuilder.create().show(); } return custom; diff --git a/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/util/EventActivityUtil.java b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/util/EventActivityUtil.java index 021513c32a..8dd9da2c23 100644 --- a/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/util/EventActivityUtil.java +++ b/apps/sasquatch/src/main/java/com/microsoft/appcenter/sasquatch/util/EventActivityUtil.java @@ -10,6 +10,7 @@ import com.microsoft.appcenter.analytics.Analytics; import com.microsoft.appcenter.analytics.AnalyticsTransmissionTarget; import com.microsoft.appcenter.sasquatch.R; +import com.microsoft.appcenter.sasquatch.activities.MainActivity; import java.util.ArrayList; import java.util.List; @@ -24,7 +25,7 @@ public static List getAnalyticTransmissionTargetLis * The second one is the parent transmission target, the third one is a child, * the forth is a grandchild, etc... */ - String[] targetTokens = activity.getResources().getStringArray(R.array.target_id_values); + String[] targetTokens = MainActivity.mTargetTokenArray; targets.add(null); targets.add(Analytics.getTransmissionTarget(targetTokens[1])); for (int i = 2; i < targetTokens.length; i++) { diff --git a/apps/sasquatch/src/main/res/values/env.xml b/apps/sasquatch/src/main/res/values/env.xml index c946e7b094..e216c026eb 100644 --- a/apps/sasquatch/src/main/res/values/env.xml +++ b/apps/sasquatch/src/main/res/values/env.xml @@ -8,9 +8,4 @@ - - - 45d1d9f6-2492-4e68-bd44-7190351eb5f3 - Custom - diff --git a/apps/sasquatch/src/main/res/values/targets.xml b/apps/sasquatch/src/main/res/values/targets.xml index a6d4feeec7..e7eda01494 100644 --- a/apps/sasquatch/src/main/res/values/targets.xml +++ b/apps/sasquatch/src/main/res/values/targets.xml @@ -5,13 +5,6 @@ --> - 89e889ccbe864ad6b924246d7045d55f-2d2d17d9-184c-4749-84a2-3fd0b3856ee1-7620 - - - c86c1b0383d149f6969b80462b250e62-e3c516ac-ae36-4776-b3eb-9c21116a756c-7045 - 739fadd014d642809473cdde9d1177d1-4477e206-0087-4d70-b810-229652426c89-7219 - 518cb8157cb743be9f7a921a46fda15d-5c9111b6-2c0f-417e-95f9-2241235db0b6-6776 - Default transmission Sasquatch Android 2 diff --git a/apps/sasquatch/src/main/res/xml/settings.xml b/apps/sasquatch/src/main/res/xml/settings.xml index a68dde6345..6ff261e1de 100644 --- a/apps/sasquatch/src/main/res/xml/settings.xml +++ b/apps/sasquatch/src/main/res/xml/settings.xml @@ -107,7 +107,6 @@ android:title="@string/install_id_title" /> diff --git a/apps/sasquatch/src/projectDependency/res/values/env.xml b/apps/sasquatch/src/projectDependency/res/values/env.xml index 9ae1082c7f..941e3f935b 100644 --- a/apps/sasquatch/src/projectDependency/res/values/env.xml +++ b/apps/sasquatch/src/projectDependency/res/values/env.xml @@ -9,9 +9,4 @@ https://mobile.events.data.microsoft.com/OneCollector/1.0 https://install.portal-server-core-integration.dev.avalanch.es https://api-gateway-core-integration.dev.avalanch.es/v0.1 - - - 9e0d97c1-7838-46d0-9dab-1a0ef66aec6e - Custom - diff --git a/apps/sasquatch/src/projectDependency/res/values/targets.xml b/apps/sasquatch/src/projectDependency/res/values/targets.xml deleted file mode 100644 index e393421da3..0000000000 --- a/apps/sasquatch/src/projectDependency/res/values/targets.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - efebdbed73974ef881b81d43d1398e6b-d0b1aa53-61de-4320-af56-14aa7cd6e801-7197 - - - 0eac643c981e48e8afeb29d9df5593e1-cb0ac72d-a4c4-41a3-b032-9f5ae7b64460-7166 - 4ee5ab442b354e6abebd166820bd8fef-88dbb064-f5f9-4dec-a428-d34062307511-8016 - 3f883319a54e45c19cb9befa7540f7b5-495ff77a-be58-4d0c-b8a4-fabd04b9feac-7111 - - diff --git a/sdk/appcenter-crashes/src/main/java/com/microsoft/appcenter/crashes/Crashes.java b/sdk/appcenter-crashes/src/main/java/com/microsoft/appcenter/crashes/Crashes.java index 4e56f478e7..4ae6e38646 100644 --- a/sdk/appcenter-crashes/src/main/java/com/microsoft/appcenter/crashes/Crashes.java +++ b/sdk/appcenter-crashes/src/main/java/com/microsoft/appcenter/crashes/Crashes.java @@ -266,7 +266,7 @@ public static AppCenterFuture setEnabled(boolean enabled) { * @param throwable The throwable describing the handled error. */ @SuppressWarnings({"SameParameterValue", "WeakerAccess"}) - public static void trackError(Throwable throwable) { + public static void trackError(@NonNull Throwable throwable) { trackError(throwable, null, null); } @@ -282,7 +282,7 @@ public static void trackError(Throwable throwable) { * @param properties Optional properties. * @param attachments Optional attachments. */ - public static void trackError(Throwable throwable, Map properties, Iterable attachments) { + public static void trackError(@NonNull Throwable throwable, Map properties, Iterable attachments) { getInstance().queueException(throwable, properties, attachments); } diff --git a/sdk/appcenter-distribute-play/src/main/java/com/microsoft/appcenter/distribute/Distribute.java b/sdk/appcenter-distribute-play/src/main/java/com/microsoft/appcenter/distribute/Distribute.java index b91f22723b..8ee318c036 100644 --- a/sdk/appcenter-distribute-play/src/main/java/com/microsoft/appcenter/distribute/Distribute.java +++ b/sdk/appcenter-distribute-play/src/main/java/com/microsoft/appcenter/distribute/Distribute.java @@ -18,6 +18,7 @@ import com.microsoft.appcenter.utils.async.DefaultAppCenterFuture; import java.util.HashMap; import java.util.Map; +import java.util.Set; import static com.microsoft.appcenter.distribute.DistributeConstants.LOG_TAG; import static com.microsoft.appcenter.distribute.DistributeConstants.SERVICE_NAME; @@ -146,6 +147,14 @@ public static void checkForUpdate() { public static void disableAutomaticCheckForUpdate() { } + /** + * Add stores allowed to perform in-app updates. + * + * @param stores list of stores allowed to perform in-app updates. + */ + public static void addStores(Set stores) { + } + @Override protected String getGroupName() { return DISTRIBUTE_GROUP; diff --git a/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/AppCenterPackageInstallerReceiver.java b/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/AppCenterPackageInstallerReceiver.java index 7da03a000a..4fbcabb070 100644 --- a/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/AppCenterPackageInstallerReceiver.java +++ b/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/AppCenterPackageInstallerReceiver.java @@ -7,13 +7,17 @@ import static com.microsoft.appcenter.distribute.DistributeConstants.LOG_TAG; +import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageInstaller; import android.os.Bundle; import android.widget.Toast; +import androidx.annotation.NonNull; + import com.microsoft.appcenter.utils.AppCenterLog; import java.util.Locale; @@ -25,6 +29,7 @@ public class AppCenterPackageInstallerReceiver extends BroadcastReceiver { public static final String START_ACTION = "com.microsoft.appcenter.action.START"; public static final String MY_PACKAGE_REPLACED_ACTION = "android.intent.action.MY_PACKAGE_REPLACED"; + private boolean isReceiverRegistered; @Override public void onReceive(Context context, Intent intent) { @@ -65,4 +70,22 @@ public void onReceive(Context context, Intent intent) { AppCenterLog.debug(LOG_TAG, String.format(Locale.ENGLISH, "Unrecognized action %s - do nothing.", intent.getAction())); } } + + public void tryRegisterReceiver(@NonNull Context context, @NonNull IntentFilter intentFilter) { + if (isReceiverRegistered) { + return; + } + isReceiverRegistered = true; + context.registerReceiver(this, intentFilter); + AppCenterLog.debug(LOG_TAG, "The receiver for installing a new release was registered."); + } + + public void tryUnregisterReceiver(@NonNull Context context) { + if (!isReceiverRegistered) { + return; + } + isReceiverRegistered = false; + context.unregisterReceiver(this); + AppCenterLog.debug(LOG_TAG, "The receiver for installing a new release was unregistered."); + } } diff --git a/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/Distribute.java b/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/Distribute.java index 4bbe0a984e..4c6a3e7f96 100644 --- a/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/Distribute.java +++ b/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/Distribute.java @@ -539,6 +539,12 @@ private boolean tryResetWorkflow() { return false; } + @Override + public void onActivityStarted(Activity activity) { + super.onActivityStarted(activity); + registerReceiver(activity); + } + @Override public synchronized void onActivityResumed(Activity activity) { mForegroundActivity = activity; @@ -547,7 +553,6 @@ public synchronized void onActivityResumed(Activity activity) { if (mChannel != null) { resumeDistributeWorkflow(); } - registerReceiver(); } @Override @@ -582,7 +587,7 @@ protected synchronized void applyEnabledState(boolean enabled) { resumeWorkflowIfForeground(); /* Register package installer receiver. */ - registerReceiver(); + registerReceiver(mForegroundActivity); } else { /* Clean all state on disabling, cancel everything. Keep only redirection parameters. */ @@ -601,25 +606,20 @@ protected synchronized void applyEnabledState(boolean enabled) { mDistributeInfoTracker = null; /* Unregister package installer receiver. */ - unregisterReceiver(); + unregisterReceiver(mForegroundActivity); } } /** * Register package installer receiver. */ - private synchronized void registerReceiver() { + private synchronized void registerReceiver(Activity activity) { if (!isInstanceEnabled()) { AppCenterLog.warn(LOG_TAG, "Couldn't register receiver due to Distribute module is disabled."); return; } - if (mForegroundActivity != null) { - try { - mForegroundActivity.registerReceiver(mAppCenterPackageInstallerReceiver, mPackageInstallerReceiverFilter); - AppCenterLog.debug(LOG_TAG, "The receiver for installing a new release was registered."); - } catch (IllegalArgumentException e) { - AppCenterLog.error(LOG_TAG, "The receiver wasn't registered.", e); - } + if (activity != null) { + mAppCenterPackageInstallerReceiver.tryRegisterReceiver(activity.getApplicationContext(), mPackageInstallerReceiverFilter); } else { AppCenterLog.warn(LOG_TAG, "Couldn't register receiver due to activity is null."); } @@ -628,14 +628,9 @@ private synchronized void registerReceiver() { /** * Unregister package installer receiver. */ - private synchronized void unregisterReceiver() { - if (mForegroundActivity != null) { - try { - mForegroundActivity.unregisterReceiver(mAppCenterPackageInstallerReceiver); - AppCenterLog.debug(LOG_TAG, "The receiver for installing a new release was unregistered."); - } catch (IllegalArgumentException e) { - AppCenterLog.error(LOG_TAG, "The receiver wasn't unregistered.", e); - } + private synchronized void unregisterReceiver(Activity activity) { + if (activity != null) { + mAppCenterPackageInstallerReceiver.tryUnregisterReceiver(activity.getApplicationContext()); } else { AppCenterLog.warn(LOG_TAG, "Couldn't unregister due to activity is null."); } @@ -1532,7 +1527,7 @@ private synchronized void showUpdateDialog() { if (mListener == null && mUsingDefaultUpdateDialog == null) { mUsingDefaultUpdateDialog = true; } - if (mListener != null && mForegroundActivity != mLastActivityWithDialog.get()) { + if (mListener != null) { AppCenterLog.debug(LOG_TAG, "Calling listener.onReleaseAvailable."); boolean customized = mListener.onReleaseAvailable(mForegroundActivity, mReleaseDetails); if (customized) { @@ -1540,7 +1535,7 @@ private synchronized void showUpdateDialog() { } mUsingDefaultUpdateDialog = !customized; } - if (mUsingDefaultUpdateDialog != null && mUsingDefaultUpdateDialog) { + if (mUsingDefaultUpdateDialog) { if (!shouldRefreshDialog(mUpdateDialog)) { return; } diff --git a/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/InstallerUtils.java b/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/InstallerUtils.java index 7bb3c59f4a..0669f0cf87 100644 --- a/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/InstallerUtils.java +++ b/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/InstallerUtils.java @@ -88,7 +88,7 @@ static synchronized boolean isInstalledFromAppStore(@NonNull String logTag, @Non if (sInstalledFromAppStore == null) { String installer = context.getPackageManager().getInstallerPackageName(context.getPackageName()); AppCenterLog.debug(logTag, "InstallerPackageName=" + installer); - sInstalledFromAppStore = installer != null && !LOCAL_STORES.contains(installer); + sInstalledFromAppStore = installer != null && !LOCAL_STORES.contains(installer) && !installer.equals(context.getPackageName()); } return sInstalledFromAppStore; } diff --git a/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/AbstractDistributeTest.java b/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/AbstractDistributeTest.java index 2be795ae2e..fdbdc8327a 100644 --- a/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/AbstractDistributeTest.java +++ b/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/AbstractDistributeTest.java @@ -209,6 +209,7 @@ public Void answer(InvocationOnMock invocation) { when(mContext.getApplicationContext()).thenReturn(mContext); when(mContext.getPackageName()).thenReturn("com.contoso"); when(mActivity.getPackageName()).thenReturn("com.contoso"); + when(mActivity.getApplicationContext()).thenReturn(mContext); when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo); when(mActivity.getApplicationInfo()).thenReturn(mApplicationInfo); when(mContext.getPackageManager()).thenReturn(mPackageManager); diff --git a/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/AppCenterPackageInstallerReceiverTest.java b/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/AppCenterPackageInstallerReceiverTest.java index d93c8d31bc..fc5f464178 100644 --- a/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/AppCenterPackageInstallerReceiverTest.java +++ b/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/AppCenterPackageInstallerReceiverTest.java @@ -14,14 +14,18 @@ import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.powermock.api.mockito.PowerMockito.mockStatic; import static org.powermock.api.mockito.PowerMockito.verifyStatic; +import android.app.Activity; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.os.Bundle; @@ -38,8 +42,6 @@ import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.rule.PowerMockRule; -import java.util.Locale; - @PrepareForTest({ AppCenterLog.class, Toast.class, @@ -53,9 +55,15 @@ public class AppCenterPackageInstallerReceiverTest { @Mock private Context mContext; + @Mock + private Activity mActivity; + @Mock private Intent mIntent; + @Mock + private IntentFilter mIntentFilter; + @Mock private PackageManager mPackageManager; @@ -80,6 +88,7 @@ public void setUp() { /* Mock methods. */ when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mContext.getPackageName()).thenReturn("com.mock.package"); + when(mActivity.getApplicationContext()).thenReturn(mContext); /* Mock toast. */ when(Toast.makeText(any(Context.class), anyString(), anyInt())).thenReturn(mToast); @@ -213,5 +222,61 @@ public void onReceiverWithUnknownAction() { verifyStatic(); AppCenterLog.debug(eq(LOG_TAG), eq("Unrecognized action UnknownAction - do nothing.")); } + + @Test + public void tryRegisterAndUnregisterReceiver() { + + /* Register receiver. */ + mAppCenterPackageInstallerReceiver.tryRegisterReceiver(mActivity, mIntentFilter); + verify(mActivity).registerReceiver(eq(mAppCenterPackageInstallerReceiver), eq(mIntentFilter)); + + /* Unregister receiver again. */ + mAppCenterPackageInstallerReceiver.tryUnregisterReceiver(mActivity); + verify(mActivity).unregisterReceiver(eq(mAppCenterPackageInstallerReceiver)); + + /* Register receiver again. */ + mAppCenterPackageInstallerReceiver.tryRegisterReceiver(mActivity, mIntentFilter); + verify(mActivity, times(2)).registerReceiver(eq(mAppCenterPackageInstallerReceiver), eq(mIntentFilter)); + + /* Unregister receiver again. */ + mAppCenterPackageInstallerReceiver.tryUnregisterReceiver(mActivity); + verify(mActivity, times(2)).unregisterReceiver(eq(mAppCenterPackageInstallerReceiver)); + } + + @Test + public void tryDoubleUnregisterReceiver() { + + /* Unregister receiver and verify that nothing is happened. */ + mAppCenterPackageInstallerReceiver.tryUnregisterReceiver(mActivity); + verify(mActivity, never()).unregisterReceiver(eq(mAppCenterPackageInstallerReceiver)); + + /* Register receiver. */ + mAppCenterPackageInstallerReceiver.tryRegisterReceiver(mActivity, mIntentFilter); + verify(mActivity).registerReceiver(eq(mAppCenterPackageInstallerReceiver), eq(mIntentFilter)); + + /* Unregister receiver again. */ + mAppCenterPackageInstallerReceiver.tryUnregisterReceiver(mActivity); + verify(mActivity).unregisterReceiver(eq(mAppCenterPackageInstallerReceiver)); + + /* Unregister receiver again and verify that it wasn't re-unregister. */ + mAppCenterPackageInstallerReceiver.tryUnregisterReceiver(mActivity); + verify(mActivity).unregisterReceiver(eq(mAppCenterPackageInstallerReceiver)); + } + + @Test + public void tryDoubleRegisterReceiver() { + + /* Register receiver. */ + mAppCenterPackageInstallerReceiver.tryRegisterReceiver(mActivity, mIntentFilter); + verify(mActivity).registerReceiver(eq(mAppCenterPackageInstallerReceiver), eq(mIntentFilter)); + + /* Register receiver again and verify that it wasn't re-register. */ + mAppCenterPackageInstallerReceiver.tryRegisterReceiver(mActivity, mIntentFilter); + verify(mActivity).registerReceiver(eq(mAppCenterPackageInstallerReceiver), eq(mIntentFilter)); + + /* Unregister receiver. */ + mAppCenterPackageInstallerReceiver.tryUnregisterReceiver(mActivity); + verify(mActivity).unregisterReceiver(eq(mAppCenterPackageInstallerReceiver)); + } } diff --git a/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/AppStoreDetectionTest.java b/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/AppStoreDetectionTest.java index eb00f715dc..578ac3b0a3 100644 --- a/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/AppStoreDetectionTest.java +++ b/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/AppStoreDetectionTest.java @@ -20,6 +20,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -85,6 +86,23 @@ public void adbIsNotStore() { verifyNotFromAppStore(); } + @Test + public void applicationInstallerIsNotStore() { + String mockPackage = "mock.package.name"; + + /* Mock context. */ + Context mockContext = mock(Context.class); + when(mockContext.getPackageName()).thenReturn(mockPackage); + when(mockContext.getPackageManager()).thenReturn(mPackageManager); + mContext = mockContext; + + /* Mock installer package name. */ + setInstallerPackageName(mockPackage); + + /* Check cache. */ + verifyNotFromAppStore(); + } + @Test public void localInstallerIsNotStore() { setInstallerPackageName("com.google.android.packageinstaller"); diff --git a/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeBeforeApiSuccessTest.java b/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeBeforeApiSuccessTest.java index 817ff233d0..07c43177ad 100644 --- a/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeBeforeApiSuccessTest.java +++ b/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeBeforeApiSuccessTest.java @@ -104,7 +104,7 @@ private void testDistributeInactiveOnPrivateTrack() throws PackageManager.NameNo when(mPackageManager.getPackageInfo(DistributeUtils.TESTER_APP_PACKAGE_NAME, 0)).thenThrow(new PackageManager.NameNotFoundException()); Distribute.setUpdateTrack(UpdateTrack.PRIVATE); start(); - Distribute.getInstance().onActivityResumed(mock(Activity.class)); + Distribute.getInstance().onActivityResumed(mActivity); verifyStatic(never()); BrowserUtils.openBrowser(anyString(), any(Activity.class)); @@ -118,7 +118,7 @@ private void testDistributeInactiveOnPrivateTrack() throws PackageManager.NameNo Distribute.unsetInstance(); Distribute.setUpdateTrack(UpdateTrack.PRIVATE); start(); - Distribute.getInstance().onActivityResumed(mock(Activity.class)); + Distribute.getInstance().onActivityResumed(mActivity); verify(mHttpClient, never()).callAsync(anyString(), anyString(), anyMapOf(String.class, String.class), any(HttpClient.CallTemplate.class), any(ServiceCallback.class)); } @@ -129,7 +129,7 @@ private void showUpdateSetupFailedDialog() { /* Trigger call. */ start(); - Distribute.getInstance().onActivityResumed(mock(Activity.class)); + Distribute.getInstance().onActivityResumed(mActivity); /* Verify dialog. */ verify(mDialogBuilder).setCancelable(false); @@ -1060,7 +1060,7 @@ public void disableWhileCheckingRelease() { /* The call is only triggered when app is resumed. */ start(); verify(mHttpClient, never()).callAsync(anyString(), anyString(), eq(Collections.emptyMap()), any(HttpClient.CallTemplate.class), any(ServiceCallback.class)); - Distribute.getInstance().onActivityResumed(mock(Activity.class)); + Distribute.getInstance().onActivityResumed(mActivity); verify(mHttpClient).callAsync(anyString(), anyString(), eq(Collections.emptyMap()), any(HttpClient.CallTemplate.class), any(ServiceCallback.class)); /* Verify cancel on disabling. */ @@ -1285,7 +1285,7 @@ public void disableBeforeCheckReleaseFails() { /* Trigger call. */ start(); - Distribute.getInstance().onActivityResumed(mock(Activity.class)); + Distribute.getInstance().onActivityResumed(mActivity); /* Disable before it fails. */ Distribute.setEnabled(false); @@ -1299,8 +1299,8 @@ public void disableBeforeCheckReleaseFails() { SharedPreferencesManager.remove(PREFERENCE_KEY_DOWNLOAD_STATE); /* After that if we resume app nothing happens. */ - Distribute.getInstance().onActivityPaused(mock(Activity.class)); - Distribute.getInstance().onActivityResumed(mock(Activity.class)); + Distribute.getInstance().onActivityPaused(mActivity); + Distribute.getInstance().onActivityResumed(mActivity); } @Test @@ -1311,7 +1311,7 @@ public void disableBeforeCheckReleaseSucceed() { /* Trigger call. */ start(); - Distribute.getInstance().onActivityResumed(mock(Activity.class)); + Distribute.getInstance().onActivityResumed(mActivity); /* Disable before it succeeds. */ Distribute.setEnabled(false); @@ -1325,8 +1325,8 @@ public void disableBeforeCheckReleaseSucceed() { SharedPreferencesManager.remove(PREFERENCE_KEY_DOWNLOAD_STATE); /* After that if we resume app nothing happens. */ - Distribute.getInstance().onActivityPaused(mock(Activity.class)); - Distribute.getInstance().onActivityResumed(mock(Activity.class)); + Distribute.getInstance().onActivityPaused(mActivity); + Distribute.getInstance().onActivityResumed(mActivity); } @Test diff --git a/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeBeforeDownloadTest.java b/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeBeforeDownloadTest.java index d9ddd60b43..1165d1bbe3 100644 --- a/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeBeforeDownloadTest.java +++ b/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeBeforeDownloadTest.java @@ -468,7 +468,7 @@ public ServiceCall answer(InvocationOnMock invocation) { /* Trigger call. */ start(); - Distribute.getInstance().onActivityResumed(mock(Activity.class)); + Distribute.getInstance().onActivityResumed(mActivity); /* Verify dialog. */ ArgumentCaptor clickListener = ArgumentCaptor.forClass(DialogInterface.OnClickListener.class); @@ -494,8 +494,8 @@ public ServiceCall answer(InvocationOnMock invocation) { verify(mToast).show(); /* Verify no more calls, e.g. happened only once. */ - Distribute.getInstance().onActivityPaused(mock(Activity.class)); - Distribute.getInstance().onActivityResumed(mock(Activity.class)); + Distribute.getInstance().onActivityPaused(mActivity); + Distribute.getInstance().onActivityResumed(mActivity); verify(mDialog).show(); verify(mHttpClient).callAsync(anyString(), anyString(), anyMapOf(String.class, String.class), any(HttpClient.CallTemplate.class), any(ServiceCallback.class)); verifyStatic(); @@ -528,7 +528,7 @@ public ServiceCall answer(InvocationOnMock invocation) { /* Trigger call. */ start(); - Distribute.getInstance().onActivityResumed(mock(Activity.class)); + Distribute.getInstance().onActivityResumed(mActivity); /* Verify dialog. */ ArgumentCaptor clickListener = ArgumentCaptor.forClass(DialogInterface.OnClickListener.class); @@ -548,8 +548,8 @@ public ServiceCall answer(InvocationOnMock invocation) { verify(mToast).show(); /* Verify no more calls, e.g. happened only once. */ - Distribute.getInstance().onActivityPaused(mock(Activity.class)); - Distribute.getInstance().onActivityResumed(mock(Activity.class)); + Distribute.getInstance().onActivityPaused(mActivity); + Distribute.getInstance().onActivityResumed(mActivity); verify(mDialog).show(); verify(mHttpClient).callAsync(anyString(), anyString(), anyMapOf(String.class, String.class), any(HttpClient.CallTemplate.class), any(ServiceCallback.class)); verifyStatic(); diff --git a/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeCustomizationTest.java b/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeCustomizationTest.java index 8a2ad9d23f..e0f107e25a 100644 --- a/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeCustomizationTest.java +++ b/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeCustomizationTest.java @@ -331,8 +331,8 @@ public void distributeListener() throws Exception { /* Resume activity again to invoke update request. */ Distribute.getInstance().onActivityResumed(mActivity); - /* Verify the listener gets called. */ - verify(listener).onReleaseAvailable(mActivity, details); + /* Verify the listener gets called twice. */ + verify(listener, times(2)).onReleaseAvailable(mActivity, details); /* Verify the default update dialog is NOT built. The count includes previous call. */ verify(mDialogBuilder, times(2)).setPositiveButton(eq(R.string.appcenter_distribute_update_dialog_download), any(DialogInterface.OnClickListener.class)); diff --git a/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeTest.java b/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeTest.java index c50a1fb23b..3d74754792 100644 --- a/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeTest.java +++ b/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeTest.java @@ -862,59 +862,35 @@ public void checkRegisterAndUnregisterReceiver() { when(SharedPreferencesManager.getBoolean(DISTRIBUTE_ENABLED_KEY, true)).thenReturn(false).thenReturn(true); /* Verify that when distribute disabled no receivers was registered. */ + Distribute.getInstance().onActivityStarted(mActivity); Distribute.getInstance().onActivityResumed(mActivity); - verify(mActivity, never()).registerReceiver(Matchers.any(), Matchers.any()); + verify(mContext, never()).registerReceiver(Matchers.any(), Matchers.any()); /* Start distribute. */ start(); /* Check that receiver was registered. */ - verify(mActivity).registerReceiver(Matchers.any(), Matchers.any()); + verify(mContext).registerReceiver(Matchers.any(), Matchers.any()); /* Stop activity. */ Distribute.getInstance().onActivityPaused(mActivity); Distribute.getInstance().onActivityStopped(mActivity); /* Check that receiver was not unregistered on activity pause and stop. */ - verify(mActivity, never()).unregisterReceiver(Matchers.any()); + verify(mContext, never()).unregisterReceiver(Matchers.any()); /* Resume activity */ + Distribute.getInstance().onActivityStarted(mActivity); Distribute.getInstance().onActivityResumed(mActivity); /* Verify that register receiver was called again after activity is resumed. */ - verify(mActivity, times(2)).registerReceiver(Matchers.any(), Matchers.any()); + verify(mContext).registerReceiver(Matchers.any(), Matchers.any()); /* Disable Distribute. */ Distribute.setEnabled(false); /* Check that receiver was unregistered. */ - verify(mActivity).unregisterReceiver(Matchers.any()); - } - - @Test - public void checkRegisterReceiverWhenActivityRegisterReceiverThrowsException() { - - /* Mock throwing exception. */ - when(mActivity.registerReceiver(Matchers.any(), Matchers.any())).thenThrow(new IllegalArgumentException()); - willThrow(new IllegalArgumentException()).given(mActivity).unregisterReceiver(Matchers.any()); - - /* Start Distribute. */ - start(); - - /* Resume and set activity */ - Distribute.getInstance().onActivityResumed(mActivity); - - /* Verify that register receiver throw exception. */ - verify(mActivity).registerReceiver(Matchers.any(), Matchers.any()); - verifyStatic(); - AppCenterLog.error(eq(LOG_TAG), eq("The receiver wasn't registered."), Matchers.any()); - - /* Disable Distribute. */ - Distribute.setEnabled(false); - - /* Verify that unregister receiver throw exception. */ - verifyStatic(); - AppCenterLog.error(eq(LOG_TAG), eq("The receiver wasn't unregistered."), Matchers.any()); + verify(mContext).unregisterReceiver(Matchers.any()); } @Test @@ -1051,8 +1027,8 @@ public void showUpdateDialogAfterShowingInstallReleaseDialogTest() { Distribute.getInstance().onActivityStopped(mActivity); resumeWorkflow(mActivity); - /* Verify that SDK wasn't crash with NPE and don't show dialog. */ - verifyStatic(never()); + /* Verify that SDK wasn't crashed with NPE and showed dialog. */ + verifyStatic(); AppCenterLog.debug(eq(LOG_TAG), eq("Show default update dialog.")); } diff --git a/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeWarnAlertSystemWindowsTest.java b/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeWarnAlertSystemWindowsTest.java index b6c6790369..42e0dc92c6 100644 --- a/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeWarnAlertSystemWindowsTest.java +++ b/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeWarnAlertSystemWindowsTest.java @@ -96,6 +96,7 @@ public void setUpDialog() throws Exception { start(); /* Resume distribute. */ + when(mFirstActivity.getApplicationContext()).thenReturn(mContext); Distribute.getInstance().onActivityResumed(mFirstActivity); /* Mock system alert windows dialog. */ diff --git a/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeWarnUnknownSourcesTest.java b/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeWarnUnknownSourcesTest.java index bb889f43e5..4d72d2335e 100644 --- a/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeWarnUnknownSourcesTest.java +++ b/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeWarnUnknownSourcesTest.java @@ -93,6 +93,7 @@ public ServiceCall answer(InvocationOnMock invocation) { when(releaseDetails.getVersion()).thenReturn(7); when(releaseDetails.isMandatoryUpdate()).thenReturn(mMandatoryUpdate); when(ReleaseDetails.parse(anyString())).thenReturn(releaseDetails); + when(mFirstActivity.getApplicationContext()).thenReturn(mContext); /* Trigger call. */ start(); diff --git a/versions.gradle b/versions.gradle index a94dea3bb6..344c2db86d 100644 --- a/versions.gradle +++ b/versions.gradle @@ -6,8 +6,8 @@ // Version constants ext { - versionCode = 66 - versionName = '4.4.2' + versionCode = 67 + versionName = '4.4.3' minSdkVersion = 21 compileSdkVersion = 31 targetSdkVersion = 31