• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.healthconnect.migration;
18 
19 import static android.health.connect.migration.HealthConnectMigrationUiState.MIGRATION_UI_STATE_ALLOWED_ERROR;
20 import static android.health.connect.migration.HealthConnectMigrationUiState.MIGRATION_UI_STATE_ALLOWED_MIGRATOR_DISABLED;
21 import static android.health.connect.migration.HealthConnectMigrationUiState.MIGRATION_UI_STATE_ALLOWED_NOT_STARTED;
22 import static android.health.connect.migration.HealthConnectMigrationUiState.MIGRATION_UI_STATE_ALLOWED_PAUSED;
23 import static android.health.connect.migration.HealthConnectMigrationUiState.MIGRATION_UI_STATE_APP_UPGRADE_REQUIRED;
24 import static android.health.connect.migration.HealthConnectMigrationUiState.MIGRATION_UI_STATE_COMPLETE;
25 import static android.health.connect.migration.HealthConnectMigrationUiState.MIGRATION_UI_STATE_COMPLETE_IDLE;
26 import static android.health.connect.migration.HealthConnectMigrationUiState.MIGRATION_UI_STATE_IDLE;
27 import static android.health.connect.migration.HealthConnectMigrationUiState.MIGRATION_UI_STATE_IN_PROGRESS;
28 import static android.health.connect.migration.HealthConnectMigrationUiState.MIGRATION_UI_STATE_MODULE_UPGRADE_REQUIRED;
29 
30 import android.content.Context;
31 import android.health.connect.HealthConnectDataState;
32 import android.health.connect.migration.HealthConnectMigrationUiState;
33 import android.os.UserHandle;
34 
35 import com.android.server.healthconnect.migration.notification.MigrationNotificationSender;
36 
37 /**
38  * Sends the appropriate notification based on the migration state, and returns the UI state to the
39  * caller.
40  *
41  * @hide
42  */
43 public class MigrationUiStateManager {
44 
45     private final Context mContext;
46     private volatile UserHandle mUserHandle;
47     private final MigrationNotificationSender mMigrationNotificationSender;
48     private final MigrationStateManager mMigrationStateManager;
49     private static final String TAG = "MigrationUiStateManager";
50 
MigrationUiStateManager( Context context, UserHandle userHandle, MigrationStateManager migrationStateManager, MigrationNotificationSender migrationNotificationSender)51     public MigrationUiStateManager(
52             Context context,
53             UserHandle userHandle,
54             MigrationStateManager migrationStateManager,
55             MigrationNotificationSender migrationNotificationSender) {
56         this.mContext = context;
57         this.mUserHandle = userHandle;
58         this.mMigrationNotificationSender = migrationNotificationSender;
59         this.mMigrationStateManager = migrationStateManager;
60     }
61 
62     /** Assigns a new user handle to this object. */
setupForUser(UserHandle userHandle)63     public void setupForUser(UserHandle userHandle) {
64         this.mUserHandle = userHandle;
65     }
66 
67     /** Attaches this MigrationUiStateManager to the provided {@link MigrationStateManager}. */
attachTo(MigrationStateManager migrationStateManager)68     public void attachTo(MigrationStateManager migrationStateManager) {
69         migrationStateManager.addStateChangedListener(this::onMigrationStateChanged);
70     }
71 
72     /** Returns the current Migration UI state. */
73     @HealthConnectMigrationUiState.Type
getHealthConnectMigrationUiState()74     public int getHealthConnectMigrationUiState() {
75         // get current migration state
76         @HealthConnectDataState.DataMigrationState
77         int migrationState = mMigrationStateManager.getMigrationState();
78 
79         switch (migrationState) {
80             case HealthConnectDataState.MIGRATION_STATE_IDLE:
81                 return MIGRATION_UI_STATE_IDLE;
82 
83             case HealthConnectDataState.MIGRATION_STATE_APP_UPGRADE_REQUIRED:
84                 return MIGRATION_UI_STATE_APP_UPGRADE_REQUIRED;
85 
86             case HealthConnectDataState.MIGRATION_STATE_MODULE_UPGRADE_REQUIRED:
87                 return MIGRATION_UI_STATE_MODULE_UPGRADE_REQUIRED;
88 
89             case HealthConnectDataState.MIGRATION_STATE_ALLOWED:
90                 if (isUiStateAllowedPaused()) {
91                     return MIGRATION_UI_STATE_ALLOWED_NOT_STARTED;
92                 } else if (isMigratorDisabled()) {
93                     return MIGRATION_UI_STATE_ALLOWED_ERROR;
94                 } else if (isUiStateInProgressPaused()) {
95                     return MIGRATION_UI_STATE_ALLOWED_PAUSED;
96                 } else {
97                     return MIGRATION_UI_STATE_ALLOWED_MIGRATOR_DISABLED;
98                 }
99 
100             case HealthConnectDataState.MIGRATION_STATE_IN_PROGRESS:
101                 return MIGRATION_UI_STATE_IN_PROGRESS;
102 
103             case HealthConnectDataState.MIGRATION_STATE_COMPLETE:
104                 if (isUiStateCompleteFromIdle()) {
105                     return MIGRATION_UI_STATE_COMPLETE_IDLE;
106                 } else {
107                     return MIGRATION_UI_STATE_COMPLETE;
108                 }
109 
110             default:
111                 throw new IllegalArgumentException(
112                         "Cannot compute migration UI state. Unknown migration state: "
113                                 + migrationState);
114         }
115     }
116 
onMigrationStateChanged(@ealthConnectDataState.DataMigrationState int newState)117     private void onMigrationStateChanged(@HealthConnectDataState.DataMigrationState int newState) {
118 
119         @HealthConnectMigrationUiState.Type
120         int migrationUiState = getHealthConnectMigrationUiState();
121 
122         switch (migrationUiState) {
123             case MIGRATION_UI_STATE_ALLOWED_PAUSED:
124                 mMigrationNotificationSender.sendNotification(
125                         MigrationNotificationSender.NOTIFICATION_TYPE_MIGRATION_PAUSED,
126                         mUserHandle);
127                 break;
128 
129             case MIGRATION_UI_STATE_MODULE_UPGRADE_REQUIRED:
130                 mMigrationNotificationSender.sendNotification(
131                         MigrationNotificationSender
132                                 .NOTIFICATION_TYPE_MIGRATION_MODULE_UPDATE_NEEDED,
133                         mUserHandle);
134                 break;
135             default:
136                 mMigrationNotificationSender.clearNotifications(mUserHandle);
137                 break;
138         }
139     }
140 
isUiStateCompleteFromIdle()141     private boolean isUiStateCompleteFromIdle() {
142         return mMigrationStateManager.hasIdleStateTimedOut();
143     }
144 
isUiStateAllowedPaused()145     private boolean isUiStateAllowedPaused() {
146         // Migrator not responding to broadcast before migration started
147         int migrationStartsCount = mMigrationStateManager.getMigrationStartsCount();
148         boolean isApkInstalled =
149                 mMigrationStateManager.existsMigrationAwarePackage(mContext)
150                         && mMigrationStateManager.existsMigratorPackage(mContext);
151         boolean doesMigratorHandleInfoIntent =
152                 mMigrationStateManager.doesMigratorHandleInfoIntent(mContext);
153 
154         return migrationStartsCount == 0 && isApkInstalled && doesMigratorHandleInfoIntent;
155     }
156 
isMigratorDisabled()157     private boolean isMigratorDisabled() {
158         int migrationStartsCount = mMigrationStateManager.getMigrationStartsCount();
159         boolean doesMigratorHandleInfoIntent =
160                 mMigrationStateManager.doesMigratorHandleInfoIntent(mContext);
161 
162         return migrationStartsCount > 0 && !doesMigratorHandleInfoIntent;
163     }
164 
isUiStateInProgressPaused()165     private boolean isUiStateInProgressPaused() {
166         int migrationStartsCount = mMigrationStateManager.getMigrationStartsCount();
167         boolean doesMigratorHandleInfoIntent =
168                 mMigrationStateManager.doesMigratorHandleInfoIntent(mContext);
169         boolean hasInProgressStateTimedOut = mMigrationStateManager.hasInProgressStateTimedOut();
170 
171         return migrationStartsCount > 0
172                 && doesMigratorHandleInfoIntent
173                 && hasInProgressStateTimedOut;
174     }
175 }
176