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