1 /*
2  * Copyright (C) 2010 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.settings.password;
18 
19 import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
20 
21 import android.annotation.Nullable;
22 import android.app.Activity;
23 import android.app.KeyguardManager;
24 import android.app.admin.DevicePolicyManager;
25 import android.content.Intent;
26 import android.content.IntentSender;
27 import android.os.Bundle;
28 import android.os.UserManager;
29 
30 import androidx.annotation.VisibleForTesting;
31 import androidx.fragment.app.Fragment;
32 
33 import com.android.internal.widget.LockPatternUtils;
34 import com.android.settings.SetupWizardUtils;
35 import com.android.settings.Utils;
36 import com.android.settings.core.SubSettingLauncher;
37 
38 import com.google.android.setupcompat.util.WizardManagerHelper;
39 
40 public final class ChooseLockSettingsHelper {
41 
42     public static final String EXTRA_KEY_TYPE = "type";
43     public static final String EXTRA_KEY_PASSWORD = "password";
44     public static final String EXTRA_KEY_RETURN_CREDENTIALS = "return_credentials";
45     public static final String EXTRA_KEY_HAS_CHALLENGE = "has_challenge";
46     public static final String EXTRA_KEY_CHALLENGE = "challenge";
47     public static final String EXTRA_KEY_CHALLENGE_TOKEN = "hw_auth_token";
48     public static final String EXTRA_KEY_FOR_FINGERPRINT = "for_fingerprint";
49     public static final String EXTRA_KEY_FOR_FACE = "for_face";
50     public static final String EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT = "for_cred_req_boot";
51     public static final String EXTRA_KEY_FOREGROUND_ONLY = "foreground_only";
52 
53     /**
54      * When EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL and EXTRA_KEY_UNIFICATION_PROFILE_ID are
55      * provided to ChooseLockGeneric as fragment arguments {@link SubSettingLauncher#setArguments},
56      * at the end of the password change flow, the supplied profile user
57      * (EXTRA_KEY_UNIFICATION_PROFILE_ID) will be unified to its parent. The current profile
58      * password is supplied by EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL.
59      */
60     public static final String EXTRA_KEY_UNIFICATION_PROFILE_ID = "unification_profile_id";
61     public static final String EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL =
62             "unification_profile_credential";
63 
64     /**
65      * Intent extra for passing the requested min password complexity to later steps in the set new
66      * screen lock flow.
67      */
68     public static final String EXTRA_KEY_REQUESTED_MIN_COMPLEXITY = "requested_min_complexity";
69 
70     /**
71      * Intent extra for passing the label of the calling app to later steps in the set new screen
72      * lock flow.
73      */
74     public static final String EXTRA_KEY_CALLER_APP_NAME = "caller_app_name";
75 
76     /**
77      * Intent extra indicating that the calling app is an admin, such as a Device Adimn, Device
78      * Owner, or Profile Owner.
79      */
80     public static final String EXTRA_KEY_IS_CALLING_APP_ADMIN = "is_calling_app_admin";
81 
82     /**
83      * When invoked via {@link ConfirmLockPassword.InternalActivity}, this flag
84      * controls if we relax the enforcement of
85      * {@link Utils#enforceSameOwner(android.content.Context, int)}.
86      */
87     public static final String EXTRA_ALLOW_ANY_USER = "allow_any_user";
88 
89     @VisibleForTesting LockPatternUtils mLockPatternUtils;
90     private Activity mActivity;
91     private Fragment mFragment;
92 
ChooseLockSettingsHelper(Activity activity)93     public ChooseLockSettingsHelper(Activity activity) {
94         mActivity = activity;
95         mLockPatternUtils = new LockPatternUtils(activity);
96     }
97 
ChooseLockSettingsHelper(Activity activity, Fragment fragment)98     public ChooseLockSettingsHelper(Activity activity, Fragment fragment) {
99         this(activity);
100         mFragment = fragment;
101     }
102 
utils()103     public LockPatternUtils utils() {
104         return mLockPatternUtils;
105     }
106 
107     /**
108      * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
109      *
110      * @param title title of the confirmation screen; shown in the action bar
111      * @return true if one exists and we launched an activity to confirm it
112      * @see Activity#onActivityResult(int, int, android.content.Intent)
113      */
launchConfirmationActivity(int request, CharSequence title)114     public boolean launchConfirmationActivity(int request, CharSequence title) {
115         return launchConfirmationActivity(
116                 request /* request */,
117                 title /* title */,
118                 null /* header */,
119                 null /* description */,
120                 false /* returnCredentials */,
121                 false /* external */,
122                 false /* foregroundOnly */);
123     }
124 
125     /**
126      * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
127      *
128      * @param title title of the confirmation screen; shown in the action bar
129      * @param returnCredentials if true, put credentials into intent. Note that if this is true,
130      *                          this can only be called internally.
131      * @return true if one exists and we launched an activity to confirm it
132      * @see Activity#onActivityResult(int, int, android.content.Intent)
133      */
launchConfirmationActivity(int request, CharSequence title, boolean returnCredentials)134     public boolean launchConfirmationActivity(int request, CharSequence title, boolean returnCredentials) {
135         return launchConfirmationActivity(
136                 request /* request */,
137                 title /* title */,
138                 null /* header */,
139                 null /* description */,
140                 returnCredentials /* returnCredentials */,
141                 false /* external */,
142                 false /* foregroundOnly */);
143     }
144 
145     /**
146      * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
147      *
148      * @param title title of the confirmation screen; shown in the action bar
149      * @param returnCredentials if true, put credentials into intent. Note that if this is true,
150      *                          this can only be called internally.
151      * @param userId The userId for whom the lock should be confirmed.
152      * @return true if one exists and we launched an activity to confirm it
153      * @see Activity#onActivityResult(int, int, android.content.Intent)
154      */
launchConfirmationActivity(int request, CharSequence title, boolean returnCredentials, int userId)155     public boolean launchConfirmationActivity(int request, CharSequence title,
156             boolean returnCredentials, int userId) {
157         return launchConfirmationActivity(
158                 request /* request */,
159                 title /* title */,
160                 null /* header */,
161                 null /* description */,
162                 returnCredentials /* returnCredentials */,
163                 false /* external */,
164                 false /* hasChallenge */,
165                 0 /* challenge */,
166                 Utils.enforceSameOwner(mActivity, userId) /* userId */,
167                 false /* foregroundOnly */);
168     }
169 
170     /**
171      * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
172      *
173      * @param title title of the confirmation screen; shown in the action bar
174      * @param header header of the confirmation screen; shown as large text
175      * @param description description of the confirmation screen
176      * @param returnCredentials if true, put credentials into intent. Note that if this is true,
177      *                          this can only be called internally.
178      * @param external specifies whether this activity is launched externally, meaning that it will
179      *                 get a dark theme, allow fingerprint authentication and it will forward
180      *                 activity result.
181      * @param foregroundOnly if the confirmation activity should be finished if it loses foreground.
182      * @return true if one exists and we launched an activity to confirm it
183      * @see Activity#onActivityResult(int, int, android.content.Intent)
184      */
launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, boolean returnCredentials, boolean external, boolean foregroundOnly)185     boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
186             @Nullable CharSequence header, @Nullable CharSequence description,
187             boolean returnCredentials, boolean external, boolean foregroundOnly) {
188         return launchConfirmationActivity(
189                 request /* request */,
190                 title /* title */,
191                 header /* header */,
192                 description /* description */,
193                 returnCredentials /* returnCredentials */,
194                 external /* external */,
195                 false /* hasChallenge */,
196                 0 /* challenge */,
197                 Utils.getCredentialOwnerUserId(mActivity) /* userId */,
198                 foregroundOnly /* foregroundOnly */);
199     }
200 
201     /**
202      * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
203      *
204      * @param title title of the confirmation screen; shown in the action bar
205      * @param header header of the confirmation screen; shown as large text
206      * @param description description of the confirmation screen
207      * @param returnCredentials if true, put credentials into intent. Note that if this is true,
208      *                          this can only be called internally.
209      * @param external specifies whether this activity is launched externally, meaning that it will
210      *                 get a dark theme, allow fingerprint authentication and it will forward
211      *                 activity result.
212      * @param userId The userId for whom the lock should be confirmed.
213      * @return true if one exists and we launched an activity to confirm it
214      * @see Activity#onActivityResult(int, int, android.content.Intent)
215      */
launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, boolean returnCredentials, boolean external, int userId)216     boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
217             @Nullable CharSequence header, @Nullable CharSequence description,
218             boolean returnCredentials, boolean external, int userId) {
219         return launchConfirmationActivity(
220                 request /* request */,
221                 title /* title */,
222                 header /* header */,
223                 description /* description */,
224                 returnCredentials /* returnCredentials */,
225                 external /* external */,
226                 false /* hasChallenge */,
227                 0 /* challenge */,
228                 Utils.enforceSameOwner(mActivity, userId) /* userId */,
229                 false /* foregroundOnly */);
230     }
231 
232     /**
233      * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
234      *
235      * @param title title of the confirmation screen; shown in the action bar
236      * @param header header of the confirmation screen; shown as large text
237      * @param description description of the confirmation screen
238      * @param challenge a challenge to be verified against the device credential.
239      * @param foregroundOnly if the confirmation activity should be finished if it loses foreground.
240      * @return true if one exists and we launched an activity to confirm it
241      * @see Activity#onActivityResult(int, int, android.content.Intent)
242      */
launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, long challenge, boolean foregroundOnly)243     public boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
244             @Nullable CharSequence header, @Nullable CharSequence description,
245             long challenge, boolean foregroundOnly) {
246         return launchConfirmationActivity(
247                 request /* request */,
248                 title /* title */,
249                 header /* header */,
250                 description /* description */,
251                 true /* returnCredentials */,
252                 false /* external */,
253                 true /* hasChallenge */,
254                 challenge /* challenge */,
255                 Utils.getCredentialOwnerUserId(mActivity) /* userId */,
256                 foregroundOnly /* foregroundOnly */);
257     }
258 
259     /**
260      * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
261      *
262      * @param title title of the confirmation screen; shown in the action bar
263      * @param header header of the confirmation screen; shown as large text
264      * @param description description of the confirmation screen
265      * @param challenge a challenge to be verified against the device credential.
266      * @param userId The userId for whom the lock should be confirmed.
267      * @param foregroundOnly if the confirmation activity should be finished if it loses foreground.
268      * @return true if one exists and we launched an activity to confirm it
269      * @see Activity#onActivityResult(int, int, android.content.Intent)
270      */
launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, long challenge, int userId, boolean foregroundOnly)271     public boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
272             @Nullable CharSequence header, @Nullable CharSequence description,
273             long challenge, int userId, boolean foregroundOnly) {
274         return launchConfirmationActivity(
275                 request /* request */,
276                 title /* title */,
277                 header /* header */,
278                 description /* description */,
279                 true /* returnCredentials */,
280                 false /* external */,
281                 true /* hasChallenge */,
282                 challenge /* challenge */,
283                 Utils.enforceSameOwner(mActivity, userId) /* userId */,
284                 foregroundOnly);
285     }
286 
287     /**
288      * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
289      *
290      * @param title title of the confirmation screen; shown in the action bar
291      * @param header header of the confirmation screen; shown as large text
292      * @param description description of the confirmation screen
293      * @param external specifies whether this activity is launched externally, meaning that it will
294      *                 get a dark theme, allow fingerprint authentication and it will forward
295      *                 activity result.
296      * @param challenge a challenge to be verified against the device credential.
297      * @param userId The userId for whom the lock should be confirmed.
298      * @return true if one exists and we launched an activity to confirm it
299      * @see Activity#onActivityResult(int, int, android.content.Intent)
300      */
launchConfirmationActivityWithExternalAndChallenge(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, boolean external, long challenge, int userId)301     public boolean launchConfirmationActivityWithExternalAndChallenge(int request,
302             @Nullable CharSequence title, @Nullable CharSequence header,
303             @Nullable CharSequence description, boolean external, long challenge, int userId) {
304         return launchConfirmationActivity(
305                 request /* request */,
306                 title /* title */,
307                 header /* header */,
308                 description /* description */,
309                 false /* returnCredentials */,
310                 external /* external */,
311                 true /* hasChallenge */,
312                 challenge /* challenge */,
313                 Utils.enforceSameOwner(mActivity, userId) /* userId */,
314                 false /* foregroundOnly */);
315     }
316 
317     /**
318      * Variant that allows you to prompt for credentials of any user, including
319      * those which aren't associated with the current user. As an example, this
320      * is useful when unlocking the storage for secondary users.
321      */
launchConfirmationActivityForAnyUser(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, int userId)322     public boolean launchConfirmationActivityForAnyUser(int request,
323             @Nullable CharSequence title, @Nullable CharSequence header,
324             @Nullable CharSequence description, int userId) {
325         final Bundle extras = new Bundle();
326         extras.putBoolean(EXTRA_ALLOW_ANY_USER, true);
327         return launchConfirmationActivity(
328                 request /* request */,
329                 title /* title */,
330                 header /* header */,
331                 description /* description */,
332                 false /* returnCredentials */,
333                 false /* external */,
334                 true /* hasChallenge */,
335                 0 /* challenge */,
336                 userId /* userId */,
337                 extras /* extras */);
338     }
339 
launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, boolean returnCredentials, boolean external, boolean hasChallenge, long challenge, int userId, boolean foregroundOnly)340     private boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
341             @Nullable CharSequence header, @Nullable CharSequence description,
342             boolean returnCredentials, boolean external, boolean hasChallenge,
343             long challenge, int userId, boolean foregroundOnly) {
344         return launchConfirmationActivity(
345                 request /* request */,
346                 title /* title */,
347                 header /* header */,
348                 description /* description */,
349                 returnCredentials /* returnCredentials */,
350                 external /* external */,
351                 hasChallenge /* hasChallenge */,
352                 challenge /* challenge */,
353                 userId /* userId */,
354                 null /* alternateButton */,
355                 null /* extras */,
356                 foregroundOnly /* foregroundOnly */);
357     }
358 
launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, boolean returnCredentials, boolean external, boolean hasChallenge, long challenge, int userId, Bundle extras)359     private boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
360             @Nullable CharSequence header, @Nullable CharSequence description,
361             boolean returnCredentials, boolean external, boolean hasChallenge,
362             long challenge, int userId, Bundle extras) {
363         return launchConfirmationActivity(
364                 request /* request */,
365                 title /* title */,
366                 header /* header */,
367                 description /* description */,
368                 returnCredentials /* returnCredentials */,
369                 external /* external */,
370                 hasChallenge /* hasChallenge */,
371                 challenge /* challenge */,
372                 userId /* userId */,
373                 null /* alternateButton */,
374                 extras /* extras */,
375                 false /* foregroundOnly */);
376     }
377 
launchFrpConfirmationActivity(int request, @Nullable CharSequence header, @Nullable CharSequence description, @Nullable CharSequence alternateButton)378     public boolean launchFrpConfirmationActivity(int request, @Nullable CharSequence header,
379             @Nullable CharSequence description, @Nullable CharSequence alternateButton) {
380         return launchConfirmationActivity(
381                 request /* request */,
382                 null /* title */,
383                 header /* header */,
384                 description /* description */,
385                 false /* returnCredentials */,
386                 true /* external */,
387                 false /* hasChallenge */,
388                 0 /* challenge */,
389                 LockPatternUtils.USER_FRP /* userId */,
390                 alternateButton /* alternateButton */,
391                 null /* extras */,
392                 false /* foregroundOnly */);
393     }
394 
launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, boolean returnCredentials, boolean external, boolean hasChallenge, long challenge, int userId, @Nullable CharSequence alternateButton, Bundle extras, boolean foregroundOnly)395     private boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
396             @Nullable CharSequence header, @Nullable CharSequence description,
397             boolean returnCredentials, boolean external, boolean hasChallenge,
398             long challenge, int userId, @Nullable CharSequence alternateButton, Bundle extras,
399             boolean foregroundOnly) {
400         final int effectiveUserId = UserManager.get(mActivity).getCredentialOwnerProfile(userId);
401         boolean launched = false;
402 
403         switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(effectiveUserId)) {
404             case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
405                 launched = launchConfirmationActivity(request, title, header, description,
406                         returnCredentials || hasChallenge
407                                 ? ConfirmLockPattern.InternalActivity.class
408                                 : ConfirmLockPattern.class, returnCredentials, external,
409                                 hasChallenge, challenge, userId, alternateButton, extras,
410                                 foregroundOnly);
411                 break;
412             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
413             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
414             case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
415             case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
416             case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
417             case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
418                 launched = launchConfirmationActivity(request, title, header, description,
419                         returnCredentials || hasChallenge
420                                 ? ConfirmLockPassword.InternalActivity.class
421                                 : ConfirmLockPassword.class, returnCredentials, external,
422                                 hasChallenge, challenge, userId, alternateButton, extras,
423                                 foregroundOnly);
424                 break;
425         }
426         return launched;
427     }
428 
launchConfirmationActivity(int request, CharSequence title, CharSequence header, CharSequence message, Class<?> activityClass, boolean returnCredentials, boolean external, boolean hasChallenge, long challenge, int userId, @Nullable CharSequence alternateButton, Bundle extras, boolean foregroundOnly)429     private boolean launchConfirmationActivity(int request, CharSequence title, CharSequence header,
430             CharSequence message, Class<?> activityClass, boolean returnCredentials,
431             boolean external, boolean hasChallenge, long challenge,
432             int userId, @Nullable CharSequence alternateButton, Bundle extras,
433             boolean foregroundOnly) {
434         final Intent intent = new Intent();
435         intent.putExtra(ConfirmDeviceCredentialBaseFragment.TITLE_TEXT, title);
436         intent.putExtra(ConfirmDeviceCredentialBaseFragment.HEADER_TEXT, header);
437         intent.putExtra(ConfirmDeviceCredentialBaseFragment.DETAILS_TEXT, message);
438         // TODO: Remove dark theme and show_cancel_button options since they are no longer used
439         intent.putExtra(ConfirmDeviceCredentialBaseFragment.DARK_THEME, false);
440         intent.putExtra(ConfirmDeviceCredentialBaseFragment.SHOW_CANCEL_BUTTON, false);
441         intent.putExtra(ConfirmDeviceCredentialBaseFragment.SHOW_WHEN_LOCKED, external);
442         intent.putExtra(ConfirmDeviceCredentialBaseFragment.USE_FADE_ANIMATION, external);
443         intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_RETURN_CREDENTIALS, returnCredentials);
444         intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, hasChallenge);
445         intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge);
446         intent.putExtra(Intent.EXTRA_USER_ID, userId);
447         intent.putExtra(KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL, alternateButton);
448         intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOREGROUND_ONLY, foregroundOnly);
449         if (extras != null) {
450             intent.putExtras(extras);
451         }
452         intent.setClassName(SETTINGS_PACKAGE_NAME, activityClass.getName());
453         if (external) {
454             intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
455             if (mFragment != null) {
456                 copyOptionalExtras(mFragment.getActivity().getIntent(), intent);
457                 mFragment.startActivity(intent);
458             } else {
459                 copyOptionalExtras(mActivity.getIntent(), intent);
460                 mActivity.startActivity(intent);
461             }
462         } else {
463             if (mFragment != null) {
464                 copyInternalExtras(mFragment.getActivity().getIntent(), intent);
465                 mFragment.startActivityForResult(intent, request);
466             } else {
467                 copyInternalExtras(mActivity.getIntent(), intent);
468                 mActivity.startActivityForResult(intent, request);
469             }
470         }
471         return true;
472     }
473 
copyOptionalExtras(Intent inIntent, Intent outIntent)474     private void copyOptionalExtras(Intent inIntent, Intent outIntent) {
475         IntentSender intentSender = inIntent.getParcelableExtra(Intent.EXTRA_INTENT);
476         if (intentSender != null) {
477             outIntent.putExtra(Intent.EXTRA_INTENT, intentSender);
478         }
479         int taskId = inIntent.getIntExtra(Intent.EXTRA_TASK_ID, -1);
480         if (taskId != -1) {
481             outIntent.putExtra(Intent.EXTRA_TASK_ID, taskId);
482         }
483         // If we will launch another activity once credentials are confirmed, exclude from recents.
484         // This is a workaround to a framework bug where affinity is incorrect for activities
485         // that are started from a no display activity, as is ConfirmDeviceCredentialActivity.
486         // TODO: Remove once that bug is fixed.
487         if (intentSender != null || taskId != -1) {
488             outIntent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
489             outIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
490         }
491     }
492 
copyInternalExtras(Intent inIntent, Intent outIntent)493     private void copyInternalExtras(Intent inIntent, Intent outIntent) {
494         SetupWizardUtils.copySetupExtras(inIntent, outIntent);
495         String theme = inIntent.getStringExtra(WizardManagerHelper.EXTRA_THEME);
496         if (theme != null) {
497             outIntent.putExtra(WizardManagerHelper.EXTRA_THEME, theme);
498         }
499     }
500 }
501