Only finish Setup Wizard Activity when fully done

Wait for the ACTION_FINISHED broadcast before finishing the Activity.
This prevents the Setup Wizard from being re-launched when it is still
set as the default home screen, which it continues to be until the
exit worker changes as part of its finishSetupWizard call.

Skip SetupWizardExitActivity during the normal finish process, moving
common exit operations to SetupWizardUtils.

Change-Id: I1c59553e7dcaf934fb81dce9bf901ec0f2bb7b59
This commit is contained in:
Tommy Webb
2023-12-20 11:59:48 -05:00
committed by Michael Bestas
parent f58c0f4b83
commit 63bbec0258
12 changed files with 92 additions and 126 deletions

View File

@@ -52,6 +52,9 @@
<protected-broadcast android:name="org.lineageos.setupwizard.LINEAGE_SETUP_COMPLETE"
android:permission="lineageos.permission.FINISH_SETUP"/>
<protected-broadcast android:name="org.lineageos.setupwizard.SETUP_FINISHED"
android:permission="lineageos.permission.FINISH_SETUP"/>
<application android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:theme="@style/Theme.Setup"
@@ -297,23 +300,11 @@
android:windowSoftInputMode="stateAlwaysHidden">
<intent-filter>
<action android:name="org.lineageos.setupwizard.LINEAGE_SETUP_COMPLETE" />
<action android:name="org.lineageos.setupwizard.SETUP_FINISHED"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name=".SetupWizardExitActivity"
android:configChanges="keyboard|keyboardHidden|mcc|mnc|orientation|screenSize"
android:excludeFromRecents="true"
android:immersive="true"
android:exported="false"
android:label="@@string/activity_label_empty"
android:theme="@style/NoDisplay">
<intent-filter>
<action android:name="org.lineageos.setupwizard.EXIT"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name=".SetupWizardTestActivity"
android:configChanges="keyboard|keyboardHidden|mcc|mnc|orientation|screenSize"
android:exported="false"

View File

@@ -3,7 +3,7 @@
adb root
wait ${!}
has_google_suw=$(adb shell pm list packages com.google.android.setupwizard)
adb shell pm enable org.lineageos.setupwizard/org.lineageos.setupwizard.SetupWizardExitActivity || true
adb shell pm enable org.lineageos.setupwizard/org.lineageos.setupwizard.FinishActivity || true
if [[ ! -z "$has_google_suw" ]]
then
wait ${!}
@@ -11,7 +11,7 @@ then
wait ${!}
fi
sleep 1
adb shell am start org.lineageos.setupwizard/org.lineageos.setupwizard.SetupWizardExitActivity || true
adb shell am start org.lineageos.setupwizard/org.lineageos.setupwizard.FinishActivity || true
if [[ ! -z "$has_google_suw" ]]
then
wait ${!}

View File

@@ -47,9 +47,6 @@
<result wizard:action="finish" />
</WizardAction>
<WizardAction wizard:uri="intent:#Intent;action=org.lineageos.setupwizard.LINEAGE_SETUP_COMPLETE;end" id="finish">
<result wizard:action="exit" />
</WizardAction>
<WizardAction wizard:uri="intent:#Intent;action=org.lineageos.setupwizard.EXIT;end" id="exit" />
<WizardAction wizard:uri="intent:#Intent;action=org.lineageos.setupwizard.LINEAGE_SETUP_COMPLETE;end" id="finish" />
</WizardScript>

View File

@@ -80,9 +80,6 @@
<result wizard:action="finish" />
</WizardAction>
<WizardAction wizard:uri="intent:#Intent;action=org.lineageos.setupwizard.LINEAGE_SETUP_COMPLETE;end" id="finish">
<result wizard:action="exit" />
</WizardAction>
<WizardAction wizard:uri="intent:#Intent;action=org.lineageos.setupwizard.EXIT;end" id="exit" />
<WizardAction wizard:uri="intent:#Intent;action=org.lineageos.setupwizard.LINEAGE_SETUP_COMPLETE;end" id="finish" />
</WizardScript>

View File

@@ -32,10 +32,6 @@
<result wizard:action="finish" />
</WizardAction>
<WizardAction wizard:uri="intent:#Intent;action=org.lineageos.setupwizard.LINEAGE_SETUP_COMPLETE;end" id="finish">
<result wizard:action="exit" />
</WizardAction>
<WizardAction wizard:uri="intent:#Intent;action=org.lineageos.setupwizard.EXIT;end" id="exit" />
<WizardAction wizard:uri="intent:#Intent;action=org.lineageos.setupwizard.LINEAGE_SETUP_COMPLETE;end" id="finish" />
</WizardScript>

View File

@@ -47,9 +47,6 @@
<result wizard:action="finish" />
</WizardAction>
<WizardAction wizard:uri="intent:#Intent;action=org.lineageos.setupwizard.LINEAGE_SETUP_COMPLETE;end" id="finish">
<result wizard:action="exit" />
</WizardAction>
<WizardAction wizard:uri="intent:#Intent;action=org.lineageos.setupwizard.EXIT;end" id="exit" />
<WizardAction wizard:uri="intent:#Intent;action=org.lineageos.setupwizard.LINEAGE_SETUP_COMPLETE;end" id="finish" />
</WizardScript>

View File

@@ -113,9 +113,6 @@ public abstract class BaseSetupWizardActivity extends AppCompatActivity implemen
logActivityState("onStart");
}
super.onStart();
if (!SetupWizardUtils.isManagedProfile(this)) {
exitIfSetupComplete();
}
}
@Override
@@ -263,15 +260,6 @@ public abstract class BaseSetupWizardActivity extends AppCompatActivity implemen
}
}
private void exitIfSetupComplete() {
if (WizardManagerHelper.isUserSetupComplete(this)) {
Log.i(TAG, "Starting activity with USER_SETUP_COMPLETE=true");
startSetupWizardExitActivity();
setResult(RESULT_CANCELED, null);
finishAllAppTasks();
}
}
protected final void finishAllAppTasks() {
List<ActivityManager.AppTask> appTasks =
getSystemService(ActivityManager.class).getAppTasks();
@@ -392,13 +380,6 @@ public abstract class BaseSetupWizardActivity extends AppCompatActivity implemen
return wifiManager.setWifiEnabled(true);
}
private void startSetupWizardExitActivity() {
if (LOGV) {
Log.v(TAG, "startSetupWizardExitActivity()");
}
startActivity(new Intent(this, SetupWizardExitActivity.class));
}
private boolean isFirstRun() {
return true;
}

View File

@@ -21,6 +21,7 @@ import static android.os.Binder.getCallingUserHandle;
import static android.os.UserHandle.USER_CURRENT;
import static org.lineageos.setupwizard.Manifest.permission.FINISH_SETUP;
import static org.lineageos.setupwizard.SetupWizardApp.ACTION_FINISHED;
import static org.lineageos.setupwizard.SetupWizardApp.ACTION_SETUP_COMPLETE;
import static org.lineageos.setupwizard.SetupWizardApp.DISABLE_NAV_KEYS;
import static org.lineageos.setupwizard.SetupWizardApp.ENABLE_RECOVERY_UPDATE;
@@ -32,8 +33,10 @@ import static org.lineageos.setupwizard.SetupWizardApp.UPDATE_RECOVERY_PROP;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.WallpaperManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.om.IOverlayManager;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
@@ -45,6 +48,7 @@ import android.os.Looper;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.util.Log;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.widget.ImageView;
@@ -63,7 +67,20 @@ public class FinishActivity extends BaseSetupWizardActivity {
private final Handler mHandler = new Handler(Looper.getMainLooper());
private volatile boolean mIsFinishing = false;
private boolean mIsFinishing;
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (LOGV) {
Log.v(TAG, "onReceive intent=" + intent);
}
if (intent != null && intent.getAction() == ACTION_FINISHED) {
unregisterReceiver(mIntentReceiver);
completeSetup();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -83,25 +100,29 @@ public class FinishActivity extends BaseSetupWizardActivity {
@Override
public void onNavigateNext() {
applyForwardTransition(TRANSITION_ID_NONE);
startFinishSequence();
}
private void finishSetup() {
if (!mIsFinishing) {
mIsFinishing = true;
setupRevealImage();
}
}
private void startFinishSequence() {
if (mIsFinishing) {
return;
}
mIsFinishing = true;
// Listen for completion from the exit service.
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_FINISHED);
registerReceiver(mIntentReceiver, filter, null, null);
Intent i = new Intent(ACTION_SETUP_COMPLETE);
i.setPackage(getPackageName());
sendBroadcastAsUser(i, getCallingUserHandle(), FINISH_SETUP);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
hideNextButton();
finishSetup();
// Begin outro animation.
setupRevealImage();
}
private void setupRevealImage() {
@@ -142,13 +163,20 @@ public class FinishActivity extends BaseSetupWizardActivity {
@Override
public void onAnimationEnd(Animator animation) {
mHandler.post(() -> completeSetup());
mHandler.post(() -> {
if (LOGV) {
Log.v(TAG, "Animation ended");
}
// Start exit procedures, including the exit service.
SetupWizardUtils.startSetupWizardExitProcedure(FinishActivity.this);
});
}
});
anim.start();
}
private void completeSetup() {
Log.i(TAG, "Setup complete!");
handleEnableMetrics(mSetupWizardApp);
handleNavKeys(mSetupWizardApp);
handleRecoveryUpdate(mSetupWizardApp);
@@ -158,7 +186,6 @@ public class FinishActivity extends BaseSetupWizardActivity {
wallpaperManager.forgetLoadedWallpaper();
finishAllAppTasks();
SetupWizardUtils.enableStatusBar();
finishAction(RESULT_OK);
}
private static void handleEnableMetrics(SetupWizardApp setupWizardApp) {

View File

@@ -54,7 +54,7 @@ public class SetupWizardActivity extends AppCompatActivity {
finish();
} else if (WizardManagerHelper.isUserSetupComplete(this)
&& !SetupWizardUtils.isManagedProfile(this)) {
SetupWizardUtils.finishSetupWizard(this);
SetupWizardUtils.startSetupWizardExitProcedure(this);
finish();
} else {
SetupWizardUtils.enableComponent(this, WizardManager.class);

View File

@@ -34,6 +34,7 @@ public class SetupWizardApp extends Application {
public static final String ACTION_ACCESSIBILITY_SETTINGS =
"android.settings.ACCESSIBILITY_SETTINGS_FOR_SUW";
public static final String ACTION_FINISHED = "org.lineageos.setupwizard.SETUP_FINISHED";
public static final String ACTION_SETUP_COMPLETE =
"org.lineageos.setupwizard.LINEAGE_SETUP_COMPLETE";
public static final String ACTION_SETUP_NETWORK = "android.settings.NETWORK_PROVIDER_SETUP";

View File

@@ -1,61 +0,0 @@
/*
* Copyright (C) 2017-2024 The LineageOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.lineageos.setupwizard;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static org.lineageos.setupwizard.SetupWizardApp.LOGV;
import android.annotation.Nullable;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import androidx.work.OneTimeWorkRequest;
import androidx.work.OutOfQuotaPolicy;
import androidx.work.WorkManager;
import org.lineageos.setupwizard.util.SetupWizardUtils;
public class SetupWizardExitActivity extends BaseSetupWizardActivity {
private static final String TAG = SetupWizardExitActivity.class.getSimpleName();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (LOGV) {
Log.v(TAG, "onCreate savedInstanceState=" + savedInstanceState);
}
if (!SetupWizardUtils.isManagedProfile(this)) {
launchHome();
}
finish();
applyForwardTransition(TRANSITION_ID_FADE);
WorkManager.getInstance(this).enqueue(new OneTimeWorkRequest.Builder(
SetupWizardExitWorker.class).setExpedited(
OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST).build());
}
private void launchHome() {
startActivity(new Intent("android.intent.action.MAIN")
.addCategory("android.intent.category.HOME")
.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK));
}
}

View File

@@ -47,6 +47,7 @@ import android.content.res.Resources;
import android.hardware.biometrics.BiometricManager;
import android.net.ConnectivityManager;
import android.net.NetworkCapabilities;
import android.os.Binder;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -58,12 +59,17 @@ import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;
import androidx.work.OneTimeWorkRequest;
import androidx.work.OutOfQuotaPolicy;
import androidx.work.WorkManager;
import org.lineageos.internal.util.PackageManagerUtils;
import org.lineageos.setupwizard.BiometricActivity;
import org.lineageos.setupwizard.BluetoothSetupActivity;
import org.lineageos.setupwizard.NetworkSetupActivity;
import org.lineageos.setupwizard.ScreenLockActivity;
import org.lineageos.setupwizard.SetupWizardApp;
import org.lineageos.setupwizard.SetupWizardExitWorker;
import org.lineageos.setupwizard.SimMissingActivity;
import org.lineageos.setupwizard.wizardmanager.WizardManager;
@@ -207,10 +213,33 @@ public class SetupWizardUtils {
}
}
public static void startSetupWizardExitProcedure(Context context) {
try {
WorkManager.getInstance(context).enqueue(new OneTimeWorkRequest.Builder(
SetupWizardExitWorker.class).setExpedited(
OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST).build());
} catch (IllegalArgumentException e) {
// finishSetupWizard -- called by the exit worker -- disables components at the end,
// including the WorkManager component required here, so this is likely an error finding
// that component. The worker only needs to run once. We can assume it already has.
Log.w(TAG, "Could not start SetupWizardExitWorker. It has likely already run.", e);
return;
}
}
public static void finishSetupWizard(Context context) {
if (LOGV) {
Log.v(TAG, "finishSetupWizard");
}
ContentResolver contentResolver = context.getContentResolver();
Settings.Global.putInt(contentResolver,
Settings.Global.DEVICE_PROVISIONED, 1);
final int userSetupComplete =
Settings.Secure.getInt(contentResolver, Settings.Secure.USER_SETUP_COMPLETE, 0);
if (userSetupComplete != 0 && !SetupWizardUtils.isManagedProfile(context)) {
Log.e(TAG, "finishSetupWizard, but userSetupComplete=" + userSetupComplete + "! "
+ "This should not happen!");
}
Settings.Secure.putInt(contentResolver,
Settings.Secure.USER_SETUP_COMPLETE, 1);
if (hasLeanback(context)) {
@@ -218,9 +247,20 @@ public class SetupWizardUtils {
Settings.Secure.TV_USER_SETUP_COMPLETE, 1);
}
disableComponent(context, WizardManager.class);
disableComponentsAndSendFinishedBroadcast(context);
}
private static void disableComponentsAndSendFinishedBroadcast(Context context) {
if (LOGV) {
Log.v(TAG, "Disabling Setup Wizard components and sending FINISHED broadcast.");
}
disableHome(context);
context.sendStickyBroadcastAsUser(
new Intent(SetupWizardApp.ACTION_FINISHED),
Binder.getCallingUserHandle());
disableComponentSets(context, GET_RECEIVERS | GET_SERVICES);
// Note: The WizardManager component is disabled when the WizardManager exits,
// which happens when FinishActivity calls nextAction while completing.
}
public static boolean isBluetoothDisabled() {