3030import android .widget .Toast ;
3131
3232import com .microsoft .appcenter .AbstractAppCenterService ;
33+ import com .microsoft .appcenter .AppCenter ;
3334import com .microsoft .appcenter .channel .Channel ;
35+ import com .microsoft .appcenter .distribute .channel .DistributeInfoTracker ;
3436import com .microsoft .appcenter .http .DefaultHttpClient ;
3537import com .microsoft .appcenter .http .HttpClient ;
3638import com .microsoft .appcenter .http .HttpClientNetworkStateHandler ;
7779import static com .microsoft .appcenter .distribute .DistributeConstants .LOG_TAG ;
7880import static com .microsoft .appcenter .distribute .DistributeConstants .MEBIBYTE_IN_BYTES ;
7981import static com .microsoft .appcenter .distribute .DistributeConstants .NOTIFICATION_CHANNEL_ID ;
82+ import static com .microsoft .appcenter .distribute .DistributeConstants .PARAMETER_DISTRIBUTION_GROUP_ID ;
83+ import static com .microsoft .appcenter .distribute .DistributeConstants .PARAMETER_INSTALL_ID ;
84+ import static com .microsoft .appcenter .distribute .DistributeConstants .PARAMETER_RELEASE_ID ;
8085import static com .microsoft .appcenter .distribute .DistributeConstants .PARAMETER_UPDATE_SETUP_FAILED ;
8186import static com .microsoft .appcenter .distribute .DistributeConstants .POSTPONE_TIME_THRESHOLD ;
8287import static com .microsoft .appcenter .distribute .DistributeConstants .PREFERENCES_NAME_MOBILE_CENTER ;
8388import static com .microsoft .appcenter .distribute .DistributeConstants .PREFERENCE_KEY_DISTRIBUTION_GROUP_ID ;
89+ import static com .microsoft .appcenter .distribute .DistributeConstants .PREFERENCE_KEY_DOWNLOADED_RELEASE_HASH ;
90+ import static com .microsoft .appcenter .distribute .DistributeConstants .PREFERENCE_KEY_DOWNLOADED_RELEASE_ID ;
8491import static com .microsoft .appcenter .distribute .DistributeConstants .PREFERENCE_KEY_DOWNLOAD_ID ;
8592import static com .microsoft .appcenter .distribute .DistributeConstants .PREFERENCE_KEY_DOWNLOAD_STATE ;
8693import static com .microsoft .appcenter .distribute .DistributeConstants .PREFERENCE_KEY_DOWNLOAD_TIME ;
8794import static com .microsoft .appcenter .distribute .DistributeConstants .PREFERENCE_KEY_POSTPONE_TIME ;
8895import static com .microsoft .appcenter .distribute .DistributeConstants .PREFERENCE_KEY_RELEASE_DETAILS ;
8996import static com .microsoft .appcenter .distribute .DistributeConstants .PREFERENCE_KEY_REQUEST_ID ;
97+ import static com .microsoft .appcenter .distribute .DistributeConstants .PREFERENCE_KEY_TESTER_APP_UPDATE_SETUP_FAILED_MESSAGE_KEY ;
9098import static com .microsoft .appcenter .distribute .DistributeConstants .PREFERENCE_KEY_UPDATE_SETUP_FAILED_MESSAGE_KEY ;
9199import static com .microsoft .appcenter .distribute .DistributeConstants .PREFERENCE_KEY_UPDATE_SETUP_FAILED_PACKAGE_HASH_KEY ;
92100import static com .microsoft .appcenter .distribute .DistributeConstants .PREFERENCE_KEY_UPDATE_TOKEN ;
@@ -137,6 +145,11 @@ public class Distribute extends AbstractAppCenterService {
137145 */
138146 private Activity mForegroundActivity ;
139147
148+ /**
149+ * Remember if we already tried to open the tester app to update setup.
150+ */
151+ private boolean mTesterAppOpenedOrAborted ;
152+
140153 /**
141154 * Remember if we already tried to open the browser to update setup.
142155 */
@@ -234,6 +247,11 @@ public class Distribute extends AbstractAppCenterService {
234247 */
235248 private String mLauncherActivityClassName ;
236249
250+ /**
251+ * Channel listener which adds extra fields to logs.
252+ */
253+ private DistributeInfoTracker mDistributeInfoTracker ;
254+
237255 /**
238256 * Custom listener if any.
239257 */
@@ -424,6 +442,11 @@ public synchronized void onActivityPaused(Activity activity) {
424442 @ Override
425443 protected synchronized void applyEnabledState (boolean enabled ) {
426444 if (enabled ) {
445+
446+ /* Enable the distribute info tracker. */
447+ String distributionGroupId = PreferencesStorage .getString (PREFERENCE_KEY_DISTRIBUTION_GROUP_ID );
448+ mDistributeInfoTracker = new DistributeInfoTracker (distributionGroupId );
449+ mChannel .addListener (mDistributeInfoTracker );
427450 HandlerUtils .runOnUiThread (new Runnable () {
428451
429452 @ Override
@@ -434,13 +457,19 @@ public void run() {
434457 } else {
435458
436459 /* Clean all state on disabling, cancel everything. Keep only redirection parameters. */
460+ mTesterAppOpenedOrAborted = false ;
437461 mBrowserOpenedOrAborted = false ;
438462 mWorkflowCompleted = false ;
439463 cancelPreviousTasks ();
440464 PreferencesStorage .remove (PREFERENCE_KEY_REQUEST_ID );
441465 PreferencesStorage .remove (PREFERENCE_KEY_POSTPONE_TIME );
442466 PreferencesStorage .remove (PREFERENCE_KEY_UPDATE_SETUP_FAILED_PACKAGE_HASH_KEY );
443467 PreferencesStorage .remove (PREFERENCE_KEY_UPDATE_SETUP_FAILED_MESSAGE_KEY );
468+ PreferencesStorage .remove (PREFERENCE_KEY_TESTER_APP_UPDATE_SETUP_FAILED_MESSAGE_KEY );
469+
470+ /* Disable the distribute info tracker. */
471+ mChannel .removeListener (mDistributeInfoTracker );
472+ mDistributeInfoTracker = null ;
444473 }
445474 }
446475
@@ -583,6 +612,7 @@ private synchronized void resumeDistributeWorkflow() {
583612 AppCenterLog .info (LOG_TAG , "Re-attempting in-app updates setup and cleaning up failure info from storage." );
584613 PreferencesStorage .remove (PREFERENCE_KEY_UPDATE_SETUP_FAILED_PACKAGE_HASH_KEY );
585614 PreferencesStorage .remove (PREFERENCE_KEY_UPDATE_SETUP_FAILED_MESSAGE_KEY );
615+ PreferencesStorage .remove (PREFERENCE_KEY_TESTER_APP_UPDATE_SETUP_FAILED_MESSAGE_KEY );
586616 }
587617 }
588618
@@ -728,14 +758,28 @@ else if (mUnknownSourcesDialog != null) {
728758 }
729759 }
730760
731- /* If not, open browser to update setup. */
732- if (!mBrowserOpenedOrAborted ) {
761+ /* If not, open native app (if installed) to update setup, unless it already failed. Otherwise, use the browser. */
762+ String testerAppUpdateSetupFailedMessage = PreferencesStorage .getString (PREFERENCE_KEY_TESTER_APP_UPDATE_SETUP_FAILED_MESSAGE_KEY );
763+ boolean shouldUseTesterAppForUpdateSetup = isAppCenterTesterAppInstalled () && TextUtils .isEmpty (testerAppUpdateSetupFailedMessage ) && !mContext .getPackageName ().equals (DistributeUtils .TESTER_APP_PACKAGE_NAME );
764+ if (shouldUseTesterAppForUpdateSetup && !mTesterAppOpenedOrAborted ) {
765+ DistributeUtils .updateSetupUsingTesterApp (mForegroundActivity , mPackageInfo );
766+ mTesterAppOpenedOrAborted = true ;
767+ } else if (!mBrowserOpenedOrAborted ) {
733768 DistributeUtils .updateSetupUsingBrowser (mForegroundActivity , mInstallUrl , mAppSecret , mPackageInfo );
734769 mBrowserOpenedOrAborted = true ;
735770 }
736771 }
737772 }
738773
774+ private boolean isAppCenterTesterAppInstalled () {
775+ try {
776+ mContext .getPackageManager ().getPackageInfo (DistributeUtils .TESTER_APP_PACKAGE_NAME , 0 );
777+ } catch (PackageManager .NameNotFoundException ignored ) {
778+ return false ;
779+ }
780+ return true ;
781+ }
782+
739783 private void decryptAndGetReleaseDetails (String updateToken , String distributionGroupId , boolean mobileCenterFailOver ) {
740784
741785 /* Decrypt token if any. */
@@ -759,6 +803,7 @@ private void decryptAndGetReleaseDetails(String updateToken, String distribution
759803 /* If the group was from Mobile Center storage, save it in the new storage. */
760804 if (mobileCenterFailOver ) {
761805 PreferencesStorage .putString (PREFERENCE_KEY_DISTRIBUTION_GROUP_ID , distributionGroupId );
806+ mDistributeInfoTracker .updateDistributionGroupId (distributionGroupId );
762807 }
763808
764809 /* Check latest release. */
@@ -816,6 +861,16 @@ synchronized void storeUpdateSetupFailedParameter(@NonNull String requestId, @No
816861 }
817862 }
818863
864+ /**
865+ * Store a flag for failure to enable updates from the tester apps, to later reattempt using the browser update setup.
866+ */
867+ synchronized void storeTesterAppUpdateSetupFailedParameter (@ NonNull String requestId , @ NonNull String updateSetupFailed ) {
868+ if (requestId .equals (PreferencesStorage .getString (PREFERENCE_KEY_REQUEST_ID ))) {
869+ AppCenterLog .debug (LOG_TAG , "Stored tester app update setup failed parameter." );
870+ PreferencesStorage .putString (PREFERENCE_KEY_TESTER_APP_UPDATE_SETUP_FAILED_MESSAGE_KEY , updateSetupFailed );
871+ }
872+ }
873+
819874 /**
820875 * Store update token and possibly trigger application update check.
821876 */
@@ -837,6 +892,7 @@ synchronized void storeRedirectionParameters(@NonNull String requestId, @NonNull
837892 PreferencesStorage .putString (PREFERENCE_KEY_DISTRIBUTION_GROUP_ID , distributionGroupId );
838893 AppCenterLog .debug (LOG_TAG , "Stored redirection parameters." );
839894 PreferencesStorage .remove (PREFERENCE_KEY_REQUEST_ID );
895+ mDistributeInfoTracker .updateDistributionGroupId (distributionGroupId );
840896 cancelPreviousTasks ();
841897 getLatestReleaseDetails (distributionGroupId , updateToken );
842898 } else {
@@ -859,9 +915,9 @@ synchronized void getLatestReleaseDetails(String distributionGroupId, String upd
859915 String releaseHash = computeReleaseHash (mPackageInfo );
860916 String url = mApiUrl ;
861917 if (updateToken == null ) {
862- url += String .format (GET_LATEST_PUBLIC_RELEASE_PATH_FORMAT , mAppSecret , distributionGroupId , releaseHash );
918+ url += String .format (GET_LATEST_PUBLIC_RELEASE_PATH_FORMAT , mAppSecret , distributionGroupId , releaseHash , getReportingParametersForUpdatedRelease ( true , "" ) );
863919 } else {
864- url += String .format (GET_LATEST_PRIVATE_RELEASE_PATH_FORMAT , mAppSecret , releaseHash );
920+ url += String .format (GET_LATEST_PRIVATE_RELEASE_PATH_FORMAT , mAppSecret , releaseHash , getReportingParametersForUpdatedRelease ( false , distributionGroupId ) );
865921 }
866922 Map <String , String > headers = new HashMap <>();
867923 if (updateToken != null ) {
@@ -956,6 +1012,7 @@ private synchronized void handleApiCallFailure(Object releaseCallId, Exception e
9561012 AppCenterLog .error (LOG_TAG , "Failed to check latest release:" , e );
9571013 PreferencesStorage .remove (PREFERENCE_KEY_DISTRIBUTION_GROUP_ID );
9581014 PreferencesStorage .remove (PREFERENCE_KEY_UPDATE_TOKEN );
1015+ mDistributeInfoTracker .removeDistributionGroupId ();
9591016 }
9601017 }
9611018 }
@@ -965,6 +1022,16 @@ private synchronized void handleApiCallFailure(Object releaseCallId, Exception e
9651022 * Handle API call success.
9661023 */
9671024 private synchronized void handleApiCallSuccess (Object releaseCallId , String rawReleaseDetails , ReleaseDetails releaseDetails ) {
1025+ String lastDownloadedReleaseHash = PreferencesStorage .getString (PREFERENCE_KEY_DOWNLOADED_RELEASE_HASH );
1026+ if (!TextUtils .isEmpty (lastDownloadedReleaseHash )) {
1027+ if (lastDownloadedReleaseHash .equals (DistributeUtils .computeReleaseHash (mPackageInfo ))) {
1028+ AppCenterLog .debug (LOG_TAG , "Successfully reported app update for downloaded release hash (" + lastDownloadedReleaseHash + "), removing from store.." );
1029+ PreferencesStorage .remove (PREFERENCE_KEY_DOWNLOADED_RELEASE_HASH );
1030+ PreferencesStorage .remove (PREFERENCE_KEY_DOWNLOADED_RELEASE_ID );
1031+ } else {
1032+ AppCenterLog .debug (LOG_TAG , "Stored release hash doesn't match current installation, probably downloaded but not installed yet, keep in store" );
1033+ }
1034+ }
9681035
9691036 /* Check if state did not change. */
9701037 if (mCheckReleaseCallId == releaseCallId ) {
@@ -1009,6 +1076,39 @@ private synchronized void handleApiCallSuccess(Object releaseCallId, String rawR
10091076 }
10101077 }
10111078
1079+ /**
1080+ * Get reporting parameters for updated release.
1081+ *
1082+ * @param isPublic are the parameters for public group or not.
1083+ * For public group we report install_id and release_id.
1084+ * For private group we report distribution_group_id and release_id.
1085+ * @param distributionGroupId distribution group id.
1086+ */
1087+ @ NonNull
1088+ private String getReportingParametersForUpdatedRelease (boolean isPublic , String distributionGroupId ) {
1089+ String reportingParameters = "" ;
1090+ AppCenterLog .debug (LOG_TAG , "Check if we need to report release installation.." );
1091+ String lastDownloadedReleaseHash = PreferencesStorage .getString (PREFERENCE_KEY_DOWNLOADED_RELEASE_HASH );
1092+ if (!TextUtils .isEmpty (lastDownloadedReleaseHash )) {
1093+ String currentInstalledReleaseHash = computeReleaseHash (mPackageInfo );
1094+ if (lastDownloadedReleaseHash .equals (currentInstalledReleaseHash )) {
1095+ AppCenterLog .debug (LOG_TAG , "Current release was updated but not reported yet, reporting.." );
1096+ if (isPublic ) {
1097+ reportingParameters += "&" + PARAMETER_INSTALL_ID + "=" + AppCenter .getInstallId ().get ();
1098+ } else {
1099+ reportingParameters += "&" + PARAMETER_DISTRIBUTION_GROUP_ID + "=" + distributionGroupId ;
1100+ }
1101+ int lastDownloadedReleaseId = PreferencesStorage .getInt (PREFERENCE_KEY_DOWNLOADED_RELEASE_ID );
1102+ reportingParameters += "&" + PARAMETER_RELEASE_ID + "=" + lastDownloadedReleaseId ;
1103+ } else {
1104+ AppCenterLog .debug (LOG_TAG , "New release was downloaded but not installed yet, skip reporting." );
1105+ }
1106+ } else {
1107+ AppCenterLog .debug (LOG_TAG , "Current release was already reported, skip reporting." );
1108+ }
1109+ return reportingParameters ;
1110+ }
1111+
10121112 /**
10131113 * Check if the fetched release information should be installed.
10141114 *
@@ -1190,6 +1290,7 @@ private synchronized void handleUpdateFailedDialogReinstallAction(DialogInterfac
11901290
11911291 /* Clear the update setup failure info from storage, to re-attempt setup on reinstall. */
11921292 PreferencesStorage .remove (PREFERENCE_KEY_UPDATE_SETUP_FAILED_PACKAGE_HASH_KEY );
1293+ PreferencesStorage .remove (PREFERENCE_KEY_TESTER_APP_UPDATE_SETUP_FAILED_MESSAGE_KEY );
11931294 } else {
11941295 showDisabledToast ();
11951296 }
0 commit comments