• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019, 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.managedprovisioning.finalization;
18 
19 import static android.app.admin.DevicePolicyManager.ACTION_ADMIN_POLICY_COMPLIANCE;
20 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
21 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
22 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE;
23 
24 import static com.android.managedprovisioning.TestUtils.createTestAdminExtras;
25 
26 import static com.google.common.truth.Truth.assertThat;
27 
28 import static org.mockito.ArgumentMatchers.anyString;
29 import static org.mockito.Matchers.any;
30 import static org.mockito.Matchers.anyInt;
31 import static org.mockito.Matchers.eq;
32 import static org.mockito.Mockito.mock;
33 import static org.mockito.Mockito.never;
34 import static org.mockito.Mockito.times;
35 import static org.mockito.Mockito.verify;
36 import static org.mockito.Mockito.verifyNoMoreInteractions;
37 import static org.mockito.Mockito.verifyZeroInteractions;
38 import static org.mockito.Mockito.when;
39 
40 import android.accounts.Account;
41 import android.app.Activity;
42 import android.app.admin.DevicePolicyManager;
43 import android.content.ComponentName;
44 import android.content.Context;
45 import android.content.Intent;
46 import android.content.ServiceConnection;
47 import android.content.SharedPreferences;
48 import android.content.pm.PackageManager;
49 import android.os.Bundle;
50 import android.os.PersistableBundle;
51 import android.os.UserHandle;
52 import android.os.UserManager;
53 import android.test.AndroidTestCase;
54 import android.test.suitebuilder.annotation.SmallTest;
55 
56 import androidx.test.InstrumentationRegistry;
57 
58 import com.android.managedprovisioning.TestUtils;
59 import com.android.managedprovisioning.analytics.DeferredMetricsReader;
60 import com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker;
61 import com.android.managedprovisioning.common.NotificationHelper;
62 import com.android.managedprovisioning.common.PolicyComplianceUtils;
63 import com.android.managedprovisioning.common.SettingsFacade;
64 import com.android.managedprovisioning.common.TransitionHelper;
65 import com.android.managedprovisioning.common.Utils;
66 import com.android.managedprovisioning.model.ProvisioningParams;
67 
68 import org.mockito.ArgumentCaptor;
69 import org.mockito.Mock;
70 import org.mockito.MockitoAnnotations;
71 
72 /**
73  * Unit tests for {@link FinalizationInsideSuwControllerLogic}.
74  */
75 public class FinalizationInsideSuwControllerTest extends AndroidTestCase {
76     private static final UserHandle MANAGED_PROFILE_USER_HANDLE = UserHandle.of(123);
77     private static final String TEST_MDM_PACKAGE_NAME = "mdm.package.name";
78     private static final String TEST_MDM_ADMIN_RECEIVER = TEST_MDM_PACKAGE_NAME + ".AdminReceiver";
79     private static final ComponentName TEST_MDM_ADMIN = new ComponentName(TEST_MDM_PACKAGE_NAME,
80             TEST_MDM_ADMIN_RECEIVER);
81     private static final PersistableBundle TEST_MDM_EXTRA_BUNDLE = createTestAdminExtras();
82     private static final Account TEST_ACCOUNT = new Account("test@account.com", "account.type");
83     private static final Intent ACTIVITY_INTENT =
84             new Intent("android.app.action.PROVISION_FINALIZATION_INSIDE_SUW");
85 
86     @Mock private Activity mActivity;
87     @Mock private Utils mUtils;
88     @Mock private SettingsFacade mSettingsFacade;
89     @Mock private UserProvisioningStateHelper mHelper;
90     @Mock private NotificationHelper mNotificationHelper;
91     @Mock private DeferredMetricsReader mDeferredMetricsReader;
92     @Mock private ProvisioningAnalyticsTracker mProvisioningAnalyticsTracker;
93     @Mock private UserManager mUserManager;
94     @Mock private SharedPreferences mSharedPreferences;
95 
96     private PreFinalizationController mPreFinalizationController;
97     private FinalizationController mFinalizationController;
98     private final Context mTargetContext = InstrumentationRegistry.getTargetContext();
99     @Mock private TransitionHelper mTransitionHelper;
100 
101     @Override
setUp()102     public void setUp() throws Exception {
103         // this is necessary for mockito to work
104         System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
105         MockitoAnnotations.initMocks(this);
106         when(mUtils.canResolveIntentAsUser(any(Context.class), any(Intent.class), anyInt()))
107                 .thenReturn(true);
108         when(mActivity.getFilesDir()).thenReturn(getContext().getFilesDir());
109         when(mActivity.getIntent()).thenReturn(ACTIVITY_INTENT);
110         when(mActivity.bindService(any(Intent.class), any(ServiceConnection.class), anyInt()))
111                 .thenReturn(false);
112         when(mActivity.getSystemServiceName(UserManager.class))
113                 .thenReturn(Context.USER_SERVICE);
114         when(mActivity.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
115         when(mActivity.getSharedPreferences(anyString(), anyInt())).thenReturn(mSharedPreferences);
116         when(mActivity.getResources()).thenReturn(mTargetContext.getResources());
117         when(mUserManager.isUserUnlocked(anyInt())).thenReturn(true);
118         when(mUserManager.isUserUnlocked(any(UserHandle.class))).thenReturn(true);
119 
120         final ProvisioningParamsUtils provisioningParamsUtils = new ProvisioningParamsUtils();
121         mPreFinalizationController = new PreFinalizationController(
122                 mActivity, mUtils, mSettingsFacade, mHelper,
123                 provisioningParamsUtils, new SendDpcBroadcastServiceUtils());
124         mFinalizationController = new FinalizationController(
125                 mActivity,
126                 new FinalizationInsideSuwControllerLogic(
127                         mActivity,
128                         mUtils,
129                         new PolicyComplianceUtils(),
130                         mProvisioningAnalyticsTracker,
131                         mTransitionHelper),
132                 mUtils, mSettingsFacade, mHelper, mNotificationHelper, mDeferredMetricsReader,
133                 provisioningParamsUtils);
134     }
135 
136     @Override
tearDown()137     public void tearDown() throws Exception {
138         mFinalizationController.clearParamsFile();
139     }
140 
141     @SmallTest
testFinalized_alreadyCalled()142     public void testFinalized_alreadyCalled() {
143         // GIVEN that deviceManagementEstablished has already been called
144         when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(true);
145         final ProvisioningParams params = createProvisioningParams(
146                 ACTION_PROVISION_MANAGED_PROFILE, false);
147 
148         // WHEN calling provisioningFinalized and commitFinalizedState
149         mFinalizationController.provisioningFinalized();
150         mFinalizationController.commitFinalizedState();
151 
152         // THEN nothing should happen
153         verify(mHelper, never()).markUserProvisioningStateInitiallyDone(params);
154         verify(mHelper, never()).markUserProvisioningStateFinalized(params);
155         verifyZeroInteractions(mDeferredMetricsReader);
156     }
157 
158     @SmallTest
testFinalized_noParamsStored()159     public void testFinalized_noParamsStored() {
160         // GIVEN that the user provisioning state is correct
161         when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(false);
162 
163         // WHEN calling provisioningFinalized and commitFinalizedState
164         mFinalizationController.provisioningFinalized();
165         mFinalizationController.commitFinalizedState();
166 
167         // THEN nothing should happen
168         verify(mHelper, never())
169                 .markUserProvisioningStateInitiallyDone(any(ProvisioningParams.class));
170         verify(mHelper, never()).markUserProvisioningStateFinalized(any(ProvisioningParams.class));
171         verifyZeroInteractions(mDeferredMetricsReader);
172     }
173 
174     @SmallTest
testManagedProfileFinalizationDuringSuw()175     public void testManagedProfileFinalizationDuringSuw() {
176         // GIVEN that deviceManagementEstablished has never been called
177         when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(true);
178         // GIVEN that we've provisioned a managed profile after SUW
179         final ProvisioningParams params = createProvisioningParams(
180                 ACTION_PROVISION_MANAGED_PROFILE, true);
181         when(mSettingsFacade.isUserSetupCompleted(mActivity)).thenReturn(false);
182         when(mSettingsFacade.isDuringSetupWizard(mActivity)).thenReturn(true);
183         when(mUtils.getManagedProfile(mActivity)).thenReturn(MANAGED_PROFILE_USER_HANDLE);
184 
185         // WHEN calling deviceManagementEstablished
186         mPreFinalizationController.deviceManagementEstablished(params);
187 
188         // THEN the user provisioning state should be marked as initially done
189         verify(mHelper).markUserProvisioningStateInitiallyDone(params);
190         // THEN the provisioning params have been stored and will be read in provisioningFinalized
191 
192         // GIVEN that the provisioning state is now incomplete
193         when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(false);
194 
195         // WHEN we save and restore controller state
196         saveAndRestoreControllerState();
197 
198         // THEN the user provisioning state is not yet finalized
199         verify(mHelper, never()).markUserProvisioningStateFinalized(params);
200 
201         // THEN no intent should be sent to the dpc.
202         verify(mTransitionHelper, never()).startActivityForResultAsUserWithTransition(
203                 eq(mActivity), any(Intent.class), anyInt(), eq(MANAGED_PROFILE_USER_HANDLE));
204 
205         // WHEN calling provisioningFinalized
206         mFinalizationController.provisioningFinalized();
207 
208         // THEN the user provisioning state is not yet finalized
209         verify(mHelper, never()).markUserProvisioningStateFinalized(params);
210 
211         // THEN intent should be sent to the dpc.
212         verifyDpcLaunchedForUser(MANAGED_PROFILE_USER_HANDLE, 1);
213 
214         // WHEN calling provisioningFinalized again
215         mFinalizationController.provisioningFinalized();
216 
217         // THEN the user provisioning state is not yet finalized
218         verify(mHelper, never()).markUserProvisioningStateFinalized(params);
219 
220          // THEN intent should not be sent to the dpc again
221         verifyDpcLaunchedForUser(MANAGED_PROFILE_USER_HANDLE, 1);
222 
223         // WHEN simulating a DPC cancel by calling activityDestroyed(true), and then
224         // provisioningFinalized again
225         mFinalizationController.activityDestroyed(true);
226         mFinalizationController.provisioningFinalized();
227 
228         // THEN the user provisioning state is not yet finalized
229         verify(mHelper, never()).markUserProvisioningStateFinalized(params);
230 
231         // THEN intent should be sent to the dpc again
232         verifyDpcLaunchedForUser(MANAGED_PROFILE_USER_HANDLE, 2);
233 
234         // WHEN we save and restore controller state, and then call provisioningFinalized again
235         saveAndRestoreControllerState();
236         mFinalizationController.provisioningFinalized();
237 
238         // THEN the user provisioning state is not yet finalized
239         verify(mHelper, never()).markUserProvisioningStateFinalized(params);
240 
241         // THEN intent is not sent to the dpc again
242         verifyDpcLaunchedForUser(MANAGED_PROFILE_USER_HANDLE, 2);
243 
244         // WHEN the provisioning state changes are now committed
245         mFinalizationController.commitFinalizedState();
246 
247         // THEN deferred metrics have been written exactly once
248         verify(mDeferredMetricsReader).scheduleDumpMetrics(any(Context.class));
249         verifyNoMoreInteractions(mDeferredMetricsReader);
250 
251         // THEN the user provisioning state is finalized
252         verify(mHelper).markUserProvisioningStateFinalized(params);
253 
254         // THEN the service which starts the DPC, has never been started.
255         verifySendDpcServiceNotStarted();
256     }
257 
258     @SmallTest
testDeviceOwnerFinalizationDuringSuw()259     public void testDeviceOwnerFinalizationDuringSuw() {
260         // GIVEN that deviceManagementEstablished has never been called
261         when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(true);
262         // GIVEN that we've provisioned a device owner during SUW
263         final ProvisioningParams params = createProvisioningParams(
264                 ACTION_PROVISION_MANAGED_DEVICE, false);
265         when(mSettingsFacade.isUserSetupCompleted(mActivity)).thenReturn(false);
266         when(mSettingsFacade.isDuringSetupWizard(mActivity)).thenReturn(true);
267 
268         // WHEN calling deviceManagementEstablished
269         mPreFinalizationController.deviceManagementEstablished(params);
270 
271         // THEN the user provisioning state should be marked as initially done
272         verify(mHelper).markUserProvisioningStateInitiallyDone(params);
273         // THEN the provisioning params have been stored and will be read in provisioningFinalized
274 
275         // GIVEN that the provisioning state is now incomplete
276         when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(false);
277 
278         // WHEN we save and restore controller state
279         saveAndRestoreControllerState();
280 
281         // THEN the user provisioning state is not yet finalized
282         verify(mHelper, never()).markUserProvisioningStateFinalized(params);
283 
284         // THEN no intent should be sent to the dpc.
285         verify(mTransitionHelper, never()).startActivityForResultAsUserWithTransition(
286                 eq(mActivity), any(Intent.class), anyInt(),
287                         eq(UserHandle.of(UserHandle.myUserId())));
288 
289         // WHEN calling provisioningFinalized
290         mFinalizationController.provisioningFinalized();
291 
292         // THEN the user provisioning state is not yet finalized
293         verify(mHelper, never()).markUserProvisioningStateFinalized(params);
294 
295         // THEN intent should be sent to the dpc.
296         verifyDpcLaunchedForUser(UserHandle.of(UserHandle.myUserId()), 1);
297 
298         // WHEN calling provisioningFinalized again
299         mFinalizationController.provisioningFinalized();
300 
301         // THEN the user provisioning state is not yet finalized
302         verify(mHelper, never()).markUserProvisioningStateFinalized(params);
303 
304         // THEN intent should not be sent to the dpc again
305         verifyDpcLaunchedForUser(UserHandle.of(UserHandle.myUserId()), 1);
306 
307         // WHEN simulating a DPC cancel by calling activityDestroyed(true), and then
308         // provisioningFinalized again
309         mFinalizationController.activityDestroyed(true);
310         mFinalizationController.provisioningFinalized();
311 
312         // THEN the user provisioning state is not yet finalized
313         verify(mHelper, never()).markUserProvisioningStateFinalized(params);
314 
315         // THEN intent should be sent to the dpc again
316         verifyDpcLaunchedForUser(UserHandle.of(UserHandle.myUserId()), 2);
317 
318         // WHEN we save and restore controller state, and then call provisioningFinalized again
319         saveAndRestoreControllerState();
320         mFinalizationController.provisioningFinalized();
321 
322         // THEN the user provisioning state is not yet finalized
323         verify(mHelper, never()).markUserProvisioningStateFinalized(params);
324 
325         // THEN intent should not be sent to the dpc again
326         verifyDpcLaunchedForUser(UserHandle.of(UserHandle.myUserId()), 2);
327 
328         // WHEN the provisioning state changes are now committed
329         mFinalizationController.commitFinalizedState();
330 
331         // THEN deferred metrics have been written exactly once
332         verify(mDeferredMetricsReader).scheduleDumpMetrics(any(Context.class));
333         verifyNoMoreInteractions(mDeferredMetricsReader);
334 
335         // THEN the user provisioning state is finalized
336         verify(mHelper).markUserProvisioningStateFinalized(params);
337 
338         // THEN a privacy reminder is shown to the user exactly once
339         verify(mNotificationHelper).showPrivacyReminderNotification(eq(mActivity), anyInt());
340 
341         // THEN no broadcast was ever sent to the primary user
342         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
343         verify(mActivity, never()).sendBroadcast(intentCaptor.capture());
344     }
345 
346     @SmallTest
testCorpOwnedManagedProfileDuringSuw()347     public void testCorpOwnedManagedProfileDuringSuw() throws PackageManager.NameNotFoundException {
348         // GIVEN that deviceManagementEstablished has never been called
349         when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(true);
350         // GIVEN that we're provisioning a corp-owned managed profile DURING SUW
351         final ProvisioningParams params =
352                 createProvisioningParamsBuilder(ACTION_PROVISION_MANAGED_PROFILE, true)
353                         .setIsOrganizationOwnedProvisioning(true)
354                         .setFlowType(ProvisioningParams.FLOW_TYPE_ADMIN_INTEGRATED)
355                         .build();
356 
357         when(mSettingsFacade.isUserSetupCompleted(mActivity)).thenReturn(false);
358         when(mSettingsFacade.isDuringSetupWizard(mActivity)).thenReturn(true);
359         when(mUtils.getManagedProfile(mActivity))
360                 .thenReturn(MANAGED_PROFILE_USER_HANDLE);
361 
362         // Mock DPM for testing access to device IDs is granted.
363         final DevicePolicyManager mockDpm = mock(DevicePolicyManager.class);
364         when(mActivity.getSystemServiceName(DevicePolicyManager.class))
365                 .thenReturn(Context.DEVICE_POLICY_SERVICE);
366         when(mActivity.getSystemService(DevicePolicyManager.class)).thenReturn(mockDpm);
367         final int managedProfileUserId = MANAGED_PROFILE_USER_HANDLE.getIdentifier();
368         when(mockDpm.getProfileOwnerAsUser(managedProfileUserId)).thenReturn(TEST_MDM_ADMIN);
369 
370         // Actual Device IDs access is  granted to the DPM of the managed profile, in the context
371         // of the managed profile.
372         final Context profileContext = mock(Context.class);
373         when(mActivity.createPackageContextAsUser(mActivity.getPackageName(), /*flags=*/ 0,
374                 MANAGED_PROFILE_USER_HANDLE)).thenReturn(profileContext);
375         when(profileContext.getSystemServiceName(DevicePolicyManager.class))
376                 .thenReturn(Context.DEVICE_POLICY_SERVICE);
377         final DevicePolicyManager mockProfileDpm = mock(DevicePolicyManager.class);
378         when(profileContext.getSystemService(DevicePolicyManager.class)).thenReturn(mockProfileDpm);
379 
380         // WHEN calling deviceManagementEstablished
381         mPreFinalizationController.deviceManagementEstablished(params);
382 
383         // THEN the user provisioning state should be marked as initially done
384         verify(mHelper).markUserProvisioningStateInitiallyDone(params);
385 
386         // GIVEN that the provisioning state is now incomplete
387         when(mHelper.isStateUnmanagedOrFinalized()).thenReturn(false);
388 
389         // WHEN calling provisioningFinalized
390         mFinalizationController.provisioningFinalized();
391 
392         // THEN the user provisioning state is not yet finalized
393         verify(mHelper, never()).markUserProvisioningStateFinalized(params);
394 
395         // THEN the DPC policy compliance screen should be shown on the work profile.
396         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
397         verify(mTransitionHelper).startActivityForResultAsUserWithTransition(
398                 eq(mActivity), intentCaptor.capture(), anyInt(), eq(MANAGED_PROFILE_USER_HANDLE));
399         assertThat(intentCaptor.getValue().getAction())
400                 .isEqualTo(DevicePolicyManager.ACTION_ADMIN_POLICY_COMPLIANCE);
401 
402         // WHEN calling provisioningFinalized again
403         mFinalizationController.provisioningFinalized();
404 
405         // THEN the user provisioning state is not yet finalized
406         verify(mHelper, never()).markUserProvisioningStateFinalized(params);
407 
408         // THEN the DPC policy compliance screen should be shown on the work profile.
409         intentCaptor = ArgumentCaptor.forClass(Intent.class);
410         verify(mTransitionHelper).startActivityForResultAsUserWithTransition(
411                 eq(mActivity), intentCaptor.capture(), anyInt(), eq(MANAGED_PROFILE_USER_HANDLE));
412         assertThat(intentCaptor.getValue().getAction())
413                 .isEqualTo(DevicePolicyManager.ACTION_ADMIN_POLICY_COMPLIANCE);
414 
415         // WHEN the provisioning state changes are now committed
416         mFinalizationController.commitFinalizedState();
417 
418         // THEN deferred metrics are written exactly once
419         verify(mDeferredMetricsReader).scheduleDumpMetrics(any(Context.class));
420         verifyNoMoreInteractions(mDeferredMetricsReader);
421 
422         // THEN the user provisioning state is finalized
423         verify(mHelper).markUserProvisioningStateFinalized(params);
424     }
425 
verifyDpcLaunchedForUser(UserHandle userHandle, int numTimes)426     private void verifyDpcLaunchedForUser(UserHandle userHandle, int numTimes) {
427         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
428         verify(mTransitionHelper, times(numTimes)).startActivityForResultAsUserWithTransition(
429                 eq(mActivity), intentCaptor.capture(), anyInt(), eq(userHandle));
430         final String intentAction = intentCaptor.getValue().getAction();
431         // THEN the intent should be ACTION_PROVISIONING_SUCCESSFUL
432         assertEquals(ACTION_ADMIN_POLICY_COMPLIANCE, intentAction);
433         // THEN the intent should only be sent to the dpc
434         assertEquals(TEST_MDM_PACKAGE_NAME, intentCaptor.getValue().getPackage());
435         // THEN the admin extras bundle should contain mdm extras
436         assertExtras(intentCaptor.getValue());
437         // THEN a metric should be logged
438         verify(mProvisioningAnalyticsTracker, times(numTimes)).logDpcSetupStarted(
439                 eq(mActivity), eq(intentAction));
440     }
441 
verifySendDpcServiceNotStarted()442     private void verifySendDpcServiceNotStarted() {
443         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
444         verify(mActivity, never()).startService(intentCaptor.capture());
445     }
446 
assertExtras(Intent intent)447     private void assertExtras(Intent intent) {
448         assertTrue(TestUtils.bundleEquals(TEST_MDM_EXTRA_BUNDLE,
449                 (PersistableBundle) intent.getExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE)));
450     }
451 
createProvisioningParams(String action, boolean migrateAccount)452     private ProvisioningParams createProvisioningParams(String action, boolean migrateAccount) {
453         return createProvisioningParamsBuilder(action, migrateAccount).build();
454     }
455 
createProvisioningParamsBuilder(String action, boolean migrateAccount)456     private ProvisioningParams.Builder createProvisioningParamsBuilder(String action,
457             boolean migrateAccount) {
458         ProvisioningParams.Builder builder = new ProvisioningParams.Builder()
459                 .setDeviceAdminComponentName(TEST_MDM_ADMIN)
460                 .setProvisioningAction(action)
461                 .setAdminExtrasBundle(TEST_MDM_EXTRA_BUNDLE)
462                 .setReturnBeforePolicyCompliance(true);
463 
464         if (migrateAccount) {
465             builder.setAccountToMigrate(TEST_ACCOUNT);
466             builder.setKeepAccountMigrated(false);
467         }
468 
469         return builder;
470     }
471 
saveAndRestoreControllerState()472     private void saveAndRestoreControllerState() {
473         final Bundle savedInstanceState = new Bundle();
474         mFinalizationController.saveInstanceState(savedInstanceState);
475         mFinalizationController.activityDestroyed(false);
476         mFinalizationController.restoreInstanceState(savedInstanceState);
477     }
478 }
479