Merge "Support accessibility shorcut secondary action (2/n)"
diff --git a/res/drawable/ic_keyboard_arrow_down.xml b/res/drawable/ic_keyboard_arrow_down.xml
new file mode 100644
index 0000000..d72f3df
--- /dev/null
+++ b/res/drawable/ic_keyboard_arrow_down.xml
@@ -0,0 +1,25 @@
+<!--
+    Copyright (C) 2019 The Android Open Source 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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:height="32dp"
+        android:viewportHeight="48"
+        android:viewportWidth="48"
+        android:width="32dp">
+    <path
+        android:fillColor="#757575"
+        android:pathData="M14.83,16.42L24,25.59l9.17,-9.17L36,19.25l-12,12 -12,-12z"/>
+</vector>
diff --git a/res/layout/accessibility_edit_shortcut.xml b/res/layout/accessibility_edit_shortcut.xml
new file mode 100644
index 0000000..753adb1b
--- /dev/null
+++ b/res/layout/accessibility_edit_shortcut.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2019 The Android Open Source 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
+  -->
+
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:scrollbarStyle="outsideOverlay">
+
+    <LinearLayout
+        android:theme="@style/Theme.AlertDialog"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:paddingTop="24dp"
+        android:paddingStart="24dp"
+        android:paddingEnd="24dp">
+
+        <include android:id="@+id/software_shortcut"
+                 layout="@layout/accessibility_edit_shortcut_component"/>
+
+        <include android:id="@+id/hardware_shortcut"
+                 layout="@layout/accessibility_edit_shortcut_component"/>
+
+    </LinearLayout>
+
+</ScrollView>
\ No newline at end of file
diff --git a/res/layout/accessibility_edit_shortcut_component.xml b/res/layout/accessibility_edit_shortcut_component.xml
new file mode 100644
index 0000000..2e1ad2d
--- /dev/null
+++ b/res/layout/accessibility_edit_shortcut_component.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2019 The Android Open Source 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
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <CheckBox
+        android:id="@+id/checkbox"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"/>
+
+    <TextView
+        android:id="@+id/summary"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:textColor="?android:attr/textColorSecondary"
+        android:paddingStart="32dp"/>
+
+    <ImageView
+        android:id="@+id/image"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingStart="32dp"
+        android:scaleType="fitCenter"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/accessibility_edit_shortcut_magnification.xml b/res/layout/accessibility_edit_shortcut_magnification.xml
new file mode 100644
index 0000000..76a1fad
--- /dev/null
+++ b/res/layout/accessibility_edit_shortcut_magnification.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2019 The Android Open Source 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
+  -->
+
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:scrollbarStyle="outsideOverlay">
+
+    <LinearLayout
+        android:theme="@style/Theme.AlertDialog"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:paddingTop="24dp"
+        android:paddingStart="24dp"
+        android:paddingEnd="24dp">
+
+        <include android:id="@+id/software_shortcut"
+                 layout="@layout/accessibility_edit_shortcut_component"/>
+
+        <include android:id="@+id/hardware_shortcut"
+                 layout="@layout/accessibility_edit_shortcut_component"/>
+
+        <LinearLayout
+            android:id="@+id/advanced_shortcut"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal">
+
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:src="@drawable/ic_keyboard_arrow_down"
+                android:scaleType="fitCenter"/>
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:gravity="center_vertical"
+                android:textColor="?android:attr/colorAccent"
+                android:text="@string/accessibility_shortcut_edit_dialog_title_advance"/>
+
+        </LinearLayout>>
+
+        <include android:id="@+id/triple_tap_shortcut"
+                 layout="@layout/accessibility_edit_shortcut_component"
+                 android:visibility="gone"/>
+
+    </LinearLayout>
+
+</ScrollView>
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index bb180df..f468746 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4782,6 +4782,24 @@
     <string name="accessibility_tutorial_dialog_message_gesture_settings_with_talkback">To turn an accessibility service on or off, swipe up from the bottom of the screen with three fingers.\n\nTo switch between services, swipe up with three fingers and hold.</string>
     <!-- Button for the Accessibility tutorial dialog to dismiss the dialog when user clicks it. [CHAR LIMIT=10] -->
     <string name="accessibility_tutorial_dialog_button">Got it</string>
+    <!-- Title for software shortcut in Accessibility edit shortcut dialog. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_shortcut_edit_dialog_title_software">Accessibility Button</string>
+    <!-- Title for software shortcut in gesture mode in Accessibility edit shortcut dialog. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_shortcut_edit_dialog_title_software_gesture">2-finger swipe up from bottom</string>
+    <!-- Summary for software shortcut in Accessibility edit shortcut dialog. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_shortcut_edit_dialog_summary_software">Tap the <xliff:g id="accessibility_icon" example="[Icon]">%s</xliff:g> button at the bottom of your screen</string>
+    <!-- Summary for software shortcut in gesture mode in Accessibility edit shortcut dialog. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_shortcut_edit_dialog_summary_software_gesture">Swipe up with 2 fingers from edge of screen</string>
+    <!-- Title for hardware shortcut in Accessibility edit shortcut dialog. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_shortcut_edit_dialog_title_hardware">Hold volume keys</string>
+    <!-- Summary for hardware shortcut in Accessibility edit shortcut dialog. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_shortcut_edit_dialog_summary_hardware">Press and hold both volume keys for 1 second</string>
+    <!-- Title for triple tap shortcut in Accessibility edit shortcut dialog. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_shortcut_edit_dialog_title_triple_tap">Triple tap screen</string>
+    <!-- Summary for triple tap shortcut in Accessibility edit shortcut dialog. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_shortcut_edit_dialog_summary_triple_tap">Quickly tap screen 3 times (this can slow down your device)</string>
+    <!-- Title for the Accessibility edit shortcut dialog to save the preference when user clicks it. [CHAR LIMIT=10] -->
+    <string name="accessibility_shortcut_edit_dialog_title_advance">Advanced</string>
     <!-- Summary text appearing on the accessibility preference screen to enable screen magnification from the nav bar when the feature is enabled, but the accessibility button is not configured correctly for the feature to be used [CHAR LIMIT=none] -->
     <string name="accessibility_screen_magnification_navbar_configuration_warning">The Accessibility button is set to <xliff:g id="service" example="Select to Speak">%1$s</xliff:g>. To use magnification, touch &amp; hold the Accessibility button, then select magnification.</string>
     <!-- Summary text appearing on the accessibility preference screen to enable screen magnification from the nav bar when the feature is enabled, but the accessibility button is not configured correctly for the feature to be used [CHAR LIMIT=none] -->
diff --git a/src/com/android/settings/accessibility/AccessibilityEditDialogUtils.java b/src/com/android/settings/accessibility/AccessibilityEditDialogUtils.java
new file mode 100644
index 0000000..62d6d34
--- /dev/null
+++ b/src/com/android/settings/accessibility/AccessibilityEditDialogUtils.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2019 The Android Open Source 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 com.android.settings.accessibility;
+
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.style.ImageSpan;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.IntDef;
+import androidx.appcompat.app.AlertDialog;
+import androidx.core.content.ContextCompat;
+
+import com.android.settings.R;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Utility class for creating the edit dialog.
+ */
+public class AccessibilityEditDialogUtils {
+
+    /**
+     * IntDef enum for dialog type that indicates different dialog for user to choose the shortcut
+     * type.
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            DialogType.EDIT_SHORTCUT_GENERIC,
+            DialogType.EDIT_SHORTCUT_MAGNIFICATION,
+    })
+
+    private @interface DialogType {
+        int EDIT_SHORTCUT_GENERIC = 0;
+        int EDIT_SHORTCUT_MAGNIFICATION = 1;
+    }
+
+    /**
+     * Method to show the edit shortcut dialog.
+     *
+     * @param context A valid context
+     * @param dialogTitle The title of edit shortcut dialog
+     * @param listener The listener to determine the action of edit shortcut dialog
+     * @return A edit shortcut dialog for showing
+     */
+    public static AlertDialog showEditShortcutDialog(Context context, CharSequence dialogTitle,
+            DialogInterface.OnClickListener listener) {
+        final AlertDialog alertDialog = createDialog(context, DialogType.EDIT_SHORTCUT_GENERIC,
+                dialogTitle, listener);
+        alertDialog.show();
+
+        return alertDialog;
+    }
+
+    /**
+     * Method to show the edit shortcut dialog in Magnification.
+     *
+     * @param context A valid context
+     * @param dialogTitle The title of edit shortcut dialog
+     * @param listener The listener to determine the action of edit shortcut dialog
+     * @return A edit shortcut dialog for showing in Magnification
+     */
+    public static AlertDialog showMagnificationEditShortcutDialog(Context context,
+            CharSequence dialogTitle, DialogInterface.OnClickListener listener) {
+        final AlertDialog alertDialog = createDialog(context,
+                DialogType.EDIT_SHORTCUT_MAGNIFICATION, dialogTitle, listener);
+        alertDialog.show();
+
+        return alertDialog;
+    }
+
+    private static AlertDialog createDialog(Context context, int dialogType,
+            CharSequence dialogTitle, DialogInterface.OnClickListener listener) {
+
+        final AlertDialog alertDialog = new AlertDialog.Builder(context)
+                .setView(createEditDialogContentView(context, dialogType))
+                .setTitle(dialogTitle)
+                .setPositiveButton(R.string.save, listener)
+                .setNegativeButton(R.string.cancel,
+                        (DialogInterface dialog, int which) -> dialog.dismiss())
+                .create();
+
+        return alertDialog;
+    }
+
+    /**
+     * Get a content View for the edit shortcut dialog.
+     *
+     * @param context A valid context
+     * @param dialogType The type of edit shortcut dialog
+     * @return A content view suitable for viewing
+     */
+    private static View createEditDialogContentView(Context context, int dialogType) {
+        final LayoutInflater inflater = (LayoutInflater) context.getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
+
+        View contentView = null;
+
+        switch (dialogType) {
+            case DialogType.EDIT_SHORTCUT_GENERIC:
+                contentView = inflater.inflate(
+                        R.layout.accessibility_edit_shortcut, null);
+                initSoftwareShortcut(context, contentView);
+                initHardwareShortcut(context, contentView);
+                break;
+            case DialogType.EDIT_SHORTCUT_MAGNIFICATION:
+                contentView = inflater.inflate(
+                        R.layout.accessibility_edit_shortcut_magnification, null);
+                initSoftwareShortcut(context, contentView);
+                initHardwareShortcut(context, contentView);
+                initMagnifyShortcut(context, contentView);
+                initAdvancedWidget(contentView);
+                break;
+            default:
+                throw new IllegalArgumentException();
+        }
+
+        return contentView;
+    }
+
+    private static void setupShortcutWidget(View view, CharSequence titleText,
+            CharSequence summaryText, int imageResId) {
+        final CheckBox checkBox = view.findViewById(R.id.checkbox);
+        checkBox.setText(titleText);
+        final TextView summary = view.findViewById(R.id.summary);
+        summary.setText(summaryText);
+        final ImageView image = view.findViewById(R.id.image);
+        image.setImageResource(imageResId);
+    }
+
+    private static void initSoftwareShortcut(Context context, View view) {
+        final View dialogView = view.findViewById(R.id.software_shortcut);
+        final TextView summary = dialogView.findViewById(R.id.summary);
+        final int lineHeight = summary.getLineHeight();
+        setupShortcutWidget(dialogView, retrieveTitle(context),
+                retrieveSummary(context, lineHeight), retrieveImageResId(context));
+    }
+
+    private static void initHardwareShortcut(Context context, View view) {
+        final View dialogView = view.findViewById(R.id.hardware_shortcut);
+        final String title = context.getString(
+                R.string.accessibility_shortcut_edit_dialog_title_hardware);
+        final String summary = context.getString(
+                R.string.accessibility_shortcut_edit_dialog_summary_hardware);
+        setupShortcutWidget(dialogView, title, summary,
+                R.drawable.illustration_accessibility_button);
+    }
+
+    private static void initMagnifyShortcut(Context context, View view) {
+        final View dialogView = view.findViewById(R.id.triple_tap_shortcut);
+        final String title = context.getString(
+                R.string.accessibility_shortcut_edit_dialog_title_triple_tap);
+        final String summary = context.getString(
+                R.string.accessibility_shortcut_edit_dialog_summary_triple_tap);
+        setupShortcutWidget(dialogView, title, summary,
+                R.drawable.illustration_accessibility_button);
+    }
+
+    private static void initAdvancedWidget(View view) {
+        final LinearLayout advanced = view.findViewById(R.id.advanced_shortcut);
+        final View tripleTap = view.findViewById(R.id.triple_tap_shortcut);
+        advanced.setOnClickListener((View v) -> {
+            advanced.setVisibility(View.GONE);
+            tripleTap.setVisibility(View.VISIBLE);
+        });
+    }
+
+    private static boolean isGestureNavigateEnabled(Context context) {
+        return context.getResources().getInteger(
+                com.android.internal.R.integer.config_navBarInteractionMode)
+                == NAV_BAR_MODE_GESTURAL;
+    }
+
+    private static CharSequence retrieveTitle(Context context) {
+        return context.getString(isGestureNavigateEnabled(context)
+                ? R.string.accessibility_shortcut_edit_dialog_title_software_gesture
+                : R.string.accessibility_shortcut_edit_dialog_title_software);
+    }
+
+    private static CharSequence retrieveSummary(Context context, int lineHeight) {
+        return isGestureNavigateEnabled(context)
+                ? context.getString(
+                R.string.accessibility_shortcut_edit_dialog_summary_software_gesture)
+                : getSummaryStringWithIcon(context, lineHeight);
+    }
+
+    private static int retrieveImageResId(Context context) {
+        return isGestureNavigateEnabled(context)
+                ? R.drawable.illustration_accessibility_button
+                : R.drawable.illustration_accessibility_button;
+    }
+
+    private static SpannableString getSummaryStringWithIcon(Context context, int lineHeight) {
+        final String summary = context
+                .getString(R.string.accessibility_shortcut_edit_dialog_summary_software);
+        final SpannableString spannableMessage = SpannableString.valueOf(summary);
+
+        // Icon
+        final int indexIconStart = summary.indexOf("%s");
+        final int indexIconEnd = indexIconStart + 2;
+        final Drawable icon = context.getDrawable(R.drawable.ic_accessibility_new);
+        final ImageSpan imageSpan = new ImageSpan(icon);
+        imageSpan.setContentDescription("");
+        icon.setTint(getThemeAttrColor(context, android.R.attr.textColorPrimary));
+        icon.setBounds(0, 0, lineHeight, lineHeight);
+        spannableMessage.setSpan(
+                imageSpan, indexIconStart, indexIconEnd,
+                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+        return spannableMessage;
+    }
+
+    /**
+     * Returns the color associated with the specified attribute in the context's theme.
+     */
+    @ColorInt
+    private static int getThemeAttrColor(final Context context, final int attributeColor) {
+        final int colorResId = getAttrResourceId(context, attributeColor);
+        return ContextCompat.getColor(context, colorResId);
+    }
+
+    /**
+     * Returns the identifier of the resolved resource assigned to the given attribute.
+     */
+    private static int getAttrResourceId(final Context context, final int attributeColor) {
+        final int[] attrs = {attributeColor};
+        final TypedArray typedArray = context.obtainStyledAttributes(attrs);
+        final int colorResId = typedArray.getResourceId(0, 0);
+        typedArray.recycle();
+        return colorResId;
+    }
+}