SUW: add page for navigation mode

Skip the page if device has HW-keys and does not enable software keys.

Change-Id: I9efb49ddb1c2a101e6395c9034eacbeb0cfec6b6
diff --git a/src/org/lineageos/setupwizard/FinishActivity.java b/src/org/lineageos/setupwizard/FinishActivity.java
index e6091e4..95e3166 100644
--- a/src/org/lineageos/setupwizard/FinishActivity.java
+++ b/src/org/lineageos/setupwizard/FinishActivity.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2016 The CyanogenMod Project
- * Copyright (C) 2017-2020 The LineageOS Project
+ * Copyright (C) 2017-2020, 2022 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.
@@ -18,6 +18,9 @@
 package org.lineageos.setupwizard;
 
 import static android.os.Binder.getCallingUserHandle;
+import static android.os.UserHandle.USER_CURRENT;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
 
 import static org.lineageos.setupwizard.Manifest.permission.FINISH_SETUP;
 import static org.lineageos.setupwizard.SetupWizardApp.ACTION_SETUP_COMPLETE;
@@ -25,6 +28,7 @@
 import static org.lineageos.setupwizard.SetupWizardApp.ENABLE_RECOVERY_UPDATE;
 import static org.lineageos.setupwizard.SetupWizardApp.KEY_SEND_METRICS;
 import static org.lineageos.setupwizard.SetupWizardApp.LOGV;
+import static org.lineageos.setupwizard.SetupWizardApp.NAVIGATION_OPTION_KEY;
 import static org.lineageos.setupwizard.SetupWizardApp.UPDATE_RECOVERY_PROP;
 
 import android.animation.Animator;
@@ -33,11 +37,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
+import android.content.om.IOverlayManager;
 import android.content.pm.ActivityInfo;
 import android.graphics.Bitmap;
 import android.graphics.Point;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.preference.PreferenceManager;
@@ -172,6 +178,7 @@
         handleEnableMetrics(mSetupWizardApp);
         handleNavKeys(mSetupWizardApp);
         handleRecoveryUpdate(mSetupWizardApp);
+        handleNavigationOption(mSetupWizardApp);
         final WallpaperManager wallpaperManager =
                 WallpaperManager.getInstance(mSetupWizardApp);
         wallpaperManager.forgetLoadedWallpaper();
@@ -209,6 +216,19 @@
         }
     }
 
+    private void handleNavigationOption(Context context) {
+        Bundle settingsBundle = mSetupWizardApp.getSettingsBundle();
+        if (settingsBundle.containsKey(NAVIGATION_OPTION_KEY)) {
+            IOverlayManager overlayManager = IOverlayManager.Stub.asInterface(
+                    ServiceManager.getService(Context.OVERLAY_SERVICE));
+            String selectedNavMode = settingsBundle.getString(NAVIGATION_OPTION_KEY);
+
+            try {
+                overlayManager.setEnabledExclusiveInCategory(selectedNavMode, USER_CURRENT);
+            } catch (Exception e) {}
+        }
+    }
+
     private static void writeDisableNavkeysOption(Context context, boolean enabled) {
         final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
 
diff --git a/src/org/lineageos/setupwizard/NavigationSettingsActivity.java b/src/org/lineageos/setupwizard/NavigationSettingsActivity.java
new file mode 100644
index 0000000..c5f6195
--- /dev/null
+++ b/src/org/lineageos/setupwizard/NavigationSettingsActivity.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2022 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.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
+
+import static org.lineageos.internal.util.DeviceKeysConstants.KEY_MASK_APP_SWITCH;
+import static org.lineageos.setupwizard.SetupWizardApp.DISABLE_NAV_KEYS;
+import static org.lineageos.setupwizard.SetupWizardApp.NAVIGATION_OPTION_KEY;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.content.Context;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.RadioButton;
+import android.widget.RadioGroup;
+import android.widget.RadioGroup.OnCheckedChangeListener;
+
+import com.airbnb.lottie.LottieAnimationView;
+import com.google.android.setupcompat.util.WizardManagerHelper;
+
+import lineageos.providers.LineageSettings;
+
+import org.lineageos.setupwizard.util.SetupWizardUtils;
+
+public class NavigationSettingsActivity extends BaseSetupWizardActivity {
+
+    public static final String TAG = NavigationSettingsActivity.class.getSimpleName();
+
+    private SetupWizardApp mSetupWizardApp;
+
+    private String mSelection = NAV_BAR_MODE_GESTURAL_OVERLAY;
+
+    private CheckBox mHideGesturalHint;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mSetupWizardApp = (SetupWizardApp) getApplication();
+        boolean navBarEnabled = false;
+        if (mSetupWizardApp.getSettingsBundle().containsKey(DISABLE_NAV_KEYS)) {
+            navBarEnabled = mSetupWizardApp.getSettingsBundle().getBoolean(DISABLE_NAV_KEYS);
+        }
+
+        int deviceKeys = getResources().getInteger(
+                org.lineageos.platform.internal.R.integer.config_deviceHardwareKeys);
+        boolean hasHomeKey = (deviceKeys & KEY_MASK_APP_SWITCH) != 0;
+
+        getGlifLayout().setDescriptionText(getString(R.string.navigation_summary));
+        setNextText(R.string.next);
+
+        int available = 3;
+        // Hide unavailable navigation modes
+        if (!isOverlayPackageAvailable(this, NAV_BAR_MODE_GESTURAL_OVERLAY)) {
+            findViewById(R.id.radio_gesture).setVisibility(View.GONE);
+            ((RadioButton) findViewById(R.id.radio_sw_keys)).setChecked(true);
+            available--;
+        }
+
+        if (!isOverlayPackageAvailable(this, NAV_BAR_MODE_2BUTTON_OVERLAY)) {
+            findViewById(R.id.radio_two_button).setVisibility(View.GONE);
+            available--;
+        }
+
+        if (!isOverlayPackageAvailable(this, NAV_BAR_MODE_3BUTTON_OVERLAY)) {
+            findViewById(R.id.radio_sw_keys).setVisibility(View.GONE);
+            available--;
+        }
+
+
+        // Hide this page if the device has hardware keys but didn't enable navbar
+        // or if there's <= 1 available navigation modes
+        if (!navBarEnabled && hasHomeKey || available <= 1) {
+            mSetupWizardApp.getSettingsBundle().putString(NAVIGATION_OPTION_KEY,
+                    NAV_BAR_MODE_3BUTTON_OVERLAY);
+            Intent intent = WizardManagerHelper.getNextIntent(getIntent(), Activity.RESULT_OK);
+            finishAction(RESULT_OK, intent);
+        }
+
+        final LottieAnimationView navigationIllustration =
+                findViewById(R.id.navigation_illustration);
+        final RadioGroup radioGroup = findViewById(R.id.navigation_radio_group);
+        mHideGesturalHint = findViewById(R.id.hide_navigation_hint);
+        radioGroup.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+            @Override
+            public void onCheckedChanged(RadioGroup group, int checkedId) {
+                switch (checkedId) {
+                case R.id.radio_gesture:
+                    mSelection = NAV_BAR_MODE_GESTURAL_OVERLAY;
+                    navigationIllustration
+                            .setAnimation(R.raw.lottie_system_nav_fully_gestural);
+                    revealHintCheckbox();
+                    break;
+                case R.id.radio_two_button:
+                    mSelection = NAV_BAR_MODE_2BUTTON_OVERLAY;
+                    navigationIllustration.setAnimation(R.raw.lottie_system_nav_2_button);
+                    hideHintCheckBox();
+                    break;
+                case R.id.radio_sw_keys:
+                    mSelection = NAV_BAR_MODE_3BUTTON_OVERLAY;
+                    navigationIllustration.setAnimation(R.raw.lottie_system_nav_3_button);
+                    hideHintCheckBox();
+                    break;
+                }
+
+                navigationIllustration.playAnimation();
+            }
+        });
+    }
+
+    private void revealHintCheckbox() {
+        if (mHideGesturalHint.getVisibility() == View.VISIBLE) {
+            return;
+        }
+
+        mHideGesturalHint.setVisibility(View.VISIBLE);
+        mHideGesturalHint.setAlpha(0.0f);
+        mHideGesturalHint.animate()
+            .translationY(0)
+            .alpha(1.0f)
+            .setListener(null);
+    }
+
+    private void hideHintCheckBox() {
+        if (mHideGesturalHint.getVisibility() == View.INVISIBLE) {
+            return;
+        }
+
+        mHideGesturalHint.animate()
+            .translationY(-mHideGesturalHint.getHeight())
+            .alpha(0.0f)
+            .setListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    super.onAnimationEnd(animation);
+                    mHideGesturalHint.setVisibility(View.INVISIBLE);
+                }
+            });
+    }
+
+    @Override
+    protected void onNextPressed() {
+        mSetupWizardApp.getSettingsBundle().putString(NAVIGATION_OPTION_KEY, mSelection);
+        boolean hideHint = mHideGesturalHint.isChecked();
+        LineageSettings.System.putIntForUser(getContentResolver(),
+                LineageSettings.System.NAVIGATION_BAR_HINT, hideHint ? 0 : 1,
+                UserHandle.USER_CURRENT);
+        Intent intent = WizardManagerHelper.getNextIntent(getIntent(), Activity.RESULT_OK);
+        nextAction(NEXT_REQUEST, intent);
+    }
+
+    @Override
+    protected int getLayoutResId() {
+        return R.layout.setup_navigation;
+    }
+
+    @Override
+    protected int getTitleResId() {
+        return R.string.setup_navigation;
+    }
+
+    @Override
+    protected int getIconResId() {
+        return R.drawable.ic_navigation;
+    }
+
+    private static boolean isOverlayPackageAvailable(Context context, String overlayPackage) {
+        try {
+            return context.getPackageManager().getPackageInfo(overlayPackage, 0) != null;
+        } catch (Exception e) {
+            // Not found, just return unavailable
+            return false;
+        }
+    }
+}
diff --git a/src/org/lineageos/setupwizard/SetupWizardApp.java b/src/org/lineageos/setupwizard/SetupWizardApp.java
index 74f88a8..dcfe3bc 100644
--- a/src/org/lineageos/setupwizard/SetupWizardApp.java
+++ b/src/org/lineageos/setupwizard/SetupWizardApp.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2013 The CyanogenMod Project
- * Copyright (C) 2017-2021 The LineageOS Project
+ * Copyright (C) 2017-2022 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.
@@ -65,6 +65,8 @@
     public static final String ENABLE_RECOVERY_UPDATE = "enable_recovery_update";
     public static final String UPDATE_RECOVERY_PROP = "persist.vendor.recovery_update";
 
+    public static final String NAVIGATION_OPTION_KEY = "navigation_option";
+
     public static final int REQUEST_CODE_SETUP_NETWORK = 0;
     public static final int REQUEST_CODE_SETUP_CAPTIVE_PORTAL = 4;
     public static final int REQUEST_CODE_SETUP_BLUETOOTH = 5;