make quick setting distraction optimized

Bug: 76805265

Test: manual
Change-Id: I0e1336c75ecb47a14a550c8bf0fe6a4880c2883c
diff --git a/Android.mk b/Android.mk
index 99a4003..d9a7784 100644
--- a/Android.mk
+++ b/Android.mk
@@ -22,7 +22,7 @@
 # (for example, projected). See b/30064991
 ifeq (,$(TARGET_BUILD_APPS))
   LOCAL_PACKAGE_NAME := CarSettings
-LOCAL_PRIVATE_PLATFORM_APIS := true
+  LOCAL_PRIVATE_PLATFORM_APIS := true
 
   LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 20006e2..01aa181 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -82,6 +82,7 @@
                 <category android:name="android.intent.category.DEFAULT"/>
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
+            <meta-data android:name="distractionOptimized" android:value="true"/>
         </activity>
 
         <activity android:name=".bluetooth.BluetoothPairingDialog"
diff --git a/res/drawable/circle_bg.xml b/res/drawable/circle_bg.xml
new file mode 100644
index 0000000..b002eba
--- /dev/null
+++ b/res/drawable/circle_bg.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2018 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.
+-->
+
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+
+  <solid
+      android:color="@color/car_accent"/>
+
+  <size
+      android:width="@dimen/car_touch_target_size"
+      android:height="@dimen/car_touch_target_size"/>
+</shape>
\ No newline at end of file
diff --git a/res/layout/action_bar_quick_settings.xml b/res/layout/action_bar_quick_settings.xml
new file mode 100644
index 0000000..88856dd
--- /dev/null
+++ b/res/layout/action_bar_quick_settings.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 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
+  -->
+
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/car_app_bar_height">
+
+    <FrameLayout
+        android:id="@+id/action_bar_icon_container"
+        android:layout_width="@dimen/car_margin"
+        android:layout_height="match_parent"
+        android:layout_alignParentStart="true">
+
+        <ImageView
+            android:id="@+id/exit_button"
+            android:layout_gravity="center"
+            android:src="@drawable/ic_close"
+            style="@style/ListIcon.ActionBar"/>
+    </FrameLayout>
+
+    <TextView
+        android:id="@+id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_marginEnd="@dimen/car_keyline_1"
+        android:layout_toEndOf="@id/action_bar_icon_container"
+        android:text="@string/settings_label"
+        android:gravity="center_vertical"
+        android:textAppearance="@style/TextAppearance.Car.Title2"
+        android:textColor="@color/car_accent"/>
+
+    <LinearLayout
+        android:id="@+id/button_container"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_alignParentEnd="true"
+        android:layout_marginEnd="@dimen/car_keyline_1"
+        android:orientation="horizontal">
+
+        <LinearLayout
+            android:id="@+id/user_switcher_btn"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:layout_marginEnd="@dimen/car_padding_4"
+            style="@style/Widget.Car.Settings.ActionBar.Button.Borderless.Colored"
+            android:orientation="horizontal">
+            <ImageView
+                android:id="@+id/user_icon"
+                android:src="@drawable/ic_user"
+                style="@style/ListIcon"/>
+            <TextView
+                android:id="@+id/user_switcher_text"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                android:textAppearance="@style/TextAppearance.Car.Label1"
+                android:layout_marginStart="@dimen/car_padding_2"
+                android:layout_marginEnd="@dimen/car_padding_2"/>
+        </LinearLayout>
+        <LinearLayout
+            android:id="@+id/full_setting_btn"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:layout_marginEnd="@dimen/car_padding_4"
+            style="@style/Widget.Car.Settings.ActionBar.Button.Borderless.Colored"
+            android:orientation="horizontal">
+            <ImageView
+                android:src="@drawable/ic_settings_gear"
+                style="@style/ListIcon"/>
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                android:text="@string/more_settings_label"
+                android:textAppearance="@style/TextAppearance.Car.Label1"
+                android:layout_marginStart="@dimen/car_padding_2"
+                android:layout_marginEnd="@dimen/car_padding_2"/>
+        </LinearLayout>
+    </LinearLayout>
+    <View
+        android:layout_alignParentBottom="true"
+        android:background="@color/car_list_divider"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/car_list_divider_height" />
+</RelativeLayout>
diff --git a/res/layout/tile.xml b/res/layout/tile.xml
index 9f1ebcc..58e3b88 100644
--- a/res/layout/tile.xml
+++ b/res/layout/tile.xml
@@ -18,26 +18,35 @@
 <com.android.car.list.InterceptTouchRelativeLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/tile_container"
-    android:foreground="@drawable/car_list_item_background"
+    android:padding="@dimen/toggle_padding"
+    android:layout_marginStart="@dimen/car_padding_2"
+    android:layout_marginEnd="@dimen/car_padding_2"
+    android:layout_marginBottom="@dimen/car_padding_5"
     android:layout_width="match_parent"
     android:layout_height="wrap_content">
-    <ImageButton
-        android:id="@+id/tile_icon"
+    <FrameLayout
+        android:id="@+id/icon_container"
         android:layout_width="@dimen/car_touch_target_size"
         android:layout_height="@dimen/car_touch_target_size"
-        android:layout_marginBottom="@dimen/car_padding_1"
-        android:layout_alignParentTop="true"
+        android:background="@drawable/circle_bg"
         android:layout_centerHorizontal="true"
-        android:src="@drawable/ic_settings_wifi"
-        android:tint="@color/car_label1"
-        android:background="@null"
-        style="@style/ListIcon" />
+        android:layout_marginBottom="@dimen/car_padding_4">
+        <ImageButton
+            android:id="@+id/tile_icon"
+            android:layout_width="@dimen/car_primary_icon_size"
+            android:layout_height="@dimen/car_primary_icon_size"
+            android:layout_gravity="center"
+            android:src="@drawable/ic_settings_wifi"
+            android:tint="@color/car_card"
+            android:background="@null"
+            style="@style/ListIcon" />
+    </FrameLayout>
     <TextView
         android:id="@+id/tile_text"
         android:layout_height="wrap_content"
         android:layout_width="wrap_content"
         android:paddingTop="@dimen/car_padding_1"
         android:layout_centerHorizontal="true"
-        android:layout_below="@+id/tile_icon"
+        android:layout_below="@id/icon_container"
         android:textAppearance="@style/TextAppearance.Car.Label1"/>
 </com.android.car.list.InterceptTouchRelativeLayout>
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index cfc2d1d..23caf72 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -38,5 +38,5 @@
     <dimen name="pin_pad_key_text_size">48sp</dimen>
 
     <dimen name="lockscreen_title_drawable_padding">5dp</dimen>
-
+    <dimen name="toggle_padding">10dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 0c2cc41..a35f667 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -19,7 +19,7 @@
     <!-- Application name, temporarily misspelled to allow it to live alongside the regular
          android settings without confusion. -->
     <string name="settings_label">Settings</string>
-    <string name="advanced_settings_label">More settings</string>
+    <string name="more_settings_label">More</string>
     <string name="display_settings">Display</string>
     <!-- Sound & display settings screen, setting option name to change brightness level -->
     <string name="brightness">Brightness level</string>
@@ -590,4 +590,8 @@
     <string name="suggestion_primary_button">finish setup</string>
     <!-- Button that dismisses the suggestion to finish setting up their device (changed to all caps so case doesn't matter) [CHAR_LIMIT=30] -->
     <string name="suggestion_secondary_button">not now</string>
+
+    <!-- Warn user that the action they are trying to perform is blocked while the car is in
+         motion [CHAR LIMIT=60] -->
+    <string name="restricted_while_driving">Action not available while driving.</string>
 </resources>
diff --git a/src/com/android/car/settings/common/CarUxRestrictionsHelper.java b/src/com/android/car/settings/common/CarUxRestrictionsHelper.java
new file mode 100644
index 0000000..492367a
--- /dev/null
+++ b/src/com/android/car/settings/common/CarUxRestrictionsHelper.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2018 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.car.settings.common;
+
+import android.app.Activity;
+import android.car.Car;
+import android.car.CarNotConnectedException;
+import android.car.drivingstate.CarUxRestrictions;
+import android.car.drivingstate.CarUxRestrictionsManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+/**
+ * Class that helps registering {@link CarUxRestrictionsManager.onUxRestrictionsChangedListener} and
+ * managing car connection.
+ */
+public class CarUxRestrictionsHelper {
+    private static final String TAG = "CarUxRestrictionsHelper";
+
+    // mCar is created in the constructor, but can be null if connection to the car is not
+    // successful.
+    @Nullable private final Car mCar;
+    @Nullable private CarUxRestrictionsManager mCarUxRestrictionsManager;
+
+    private final CarUxRestrictionsManager.onUxRestrictionsChangedListener mListener;
+
+    public CarUxRestrictionsHelper(Context context,
+            CarUxRestrictionsManager.onUxRestrictionsChangedListener listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException("Listener cannot be null.");
+        }
+        mListener = listener;
+        mCar = Car.createCar(context, mServiceConnection);
+    };
+
+    /**
+     * Starts monitoring any changes in {@link CarUxRestrictions}.
+     *
+     * <p>This method can be called from {@code Activity}'s {@link Activity#onStart()}, or at the
+     * time of construction.
+     *
+     * <p>This method must be accompanied with a matching {@link #stop()} to avoid leak.
+     */
+    public void start() {
+        try {
+            if (mCar != null && !mCar.isConnected()) {
+                mCar.connect();
+            }
+        } catch (IllegalStateException e) {
+            // Do nothing.
+            Log.w(TAG, "start(); cannot connect to Car");
+        }
+    }
+
+    /**
+     * Stops monitoring any changes in {@link CarUxRestrictions}.
+     *
+     * <p>This method should be called from {@code Activity}'s {@link Activity#onStop()}, or at the
+     * time of this adapter being discarded.
+     */
+    public void stop() {
+        try {
+            if (mCar != null && mCar.isConnected()) {
+                mCar.disconnect();
+            }
+        } catch (IllegalStateException e) {
+            // Do nothing.
+            Log.w(TAG, "stop(); cannot disconnect from Car");
+        }
+    }
+
+    private final ServiceConnection mServiceConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            try {
+                mCarUxRestrictionsManager = (CarUxRestrictionsManager)
+                        mCar.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE);
+                mCarUxRestrictionsManager.registerListener(mListener);
+
+                mListener.onUxRestrictionsChanged(
+                        mCarUxRestrictionsManager.getCurrentCarUxRestrictions());
+            } catch (CarNotConnectedException e) {
+                e.printStackTrace();
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            try {
+                mCarUxRestrictionsManager.unregisterListener();
+                mCarUxRestrictionsManager = null;
+            } catch (CarNotConnectedException e) {
+                e.printStackTrace();
+            }
+        }
+    };
+}
diff --git a/src/com/android/car/settings/quicksettings/QuickSettingActivity.java b/src/com/android/car/settings/quicksettings/QuickSettingActivity.java
index 9edc015..be2ac37 100644
--- a/src/com/android/car/settings/quicksettings/QuickSettingActivity.java
+++ b/src/com/android/car/settings/quicksettings/QuickSettingActivity.java
@@ -15,35 +15,77 @@
  */
 package com.android.car.settings.quicksettings;
 
+import android.app.Dialog;
+import android.car.drivingstate.CarUxRestrictions;
+import android.content.Context;
 import android.content.Intent;
+import android.content.pm.UserInfo;
 import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
 import android.support.v7.app.ActionBar;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.Toolbar;
 import android.view.View;
-import android.widget.Button;
+import android.view.View.OnClickListener;
 import android.widget.ImageView;
+import android.widget.TextView;
 
+import androidx.car.app.CarAlertDialog;
 import androidx.car.widget.PagedListView;
 
 import com.android.car.settings.R;
 import com.android.car.settings.common.CarSettingActivity;
+import com.android.car.settings.common.CarUxRestrictionsHelper;
+import com.android.car.settings.users.UserIconProvider;
+import com.android.settingslib.users.UserManagerHelper;
 
 /**
  * Shows a page to access frequently used settings.
  */
 public class QuickSettingActivity extends AppCompatActivity {
     private static final String TAG = "QS";
+    private static final String DIALOG_TAG = "block_dialog_tag";
 
+    private static final float RESTRICTED_ALPHA = 0.5f;
+    private static final float UNRESTRICTED_ALPHA = 1f;
+
+    private CarUxRestrictionsHelper mUxRestrictionsHelper;
+    private UserManagerHelper  mUserManagerHelper;
     private QuickSettingGridAdapter mGridAdapter;
     private PagedListView mListView;
+    private View mFullSettingBtn;
+    private View mUserSwitcherBtn;
 
+    private final OnClickListener mLaunchSettingListener = v -> {
+        Intent intent = new Intent(this, CarSettingActivity.class);
+        startActivity(intent);
+    };
+
+    private final OnClickListener mBlockingListener = v -> {
+        AlertDialogFragment alertDialog = new AlertDialogFragment();
+        alertDialog.show(getSupportFragmentManager(), DIALOG_TAG);
+    };
+
+    /**
+     * Shows a dialog to notify user that the actions is not available while driving.
+     */
+    public static class AlertDialogFragment extends DialogFragment {
+        @Override
+        public Dialog onCreateDialog(Bundle savedInstanceState) {
+            Context context = getContext();
+            return new CarAlertDialog.Builder(context)
+                    .setBody(context.getString(R.string.restricted_while_driving))
+                    .setPositiveButton(context.getString(R.string.okay),
+                            /* listener= */ null)
+                    .create();
+        }
+    }
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        mUserManagerHelper = new UserManagerHelper(this);
         setContentView(R.layout.quick_settings);
-
         mListView = (PagedListView) findViewById(R.id.list);
         mGridAdapter = new QuickSettingGridAdapter(this);
         mListView.getRecyclerView().setLayoutManager(mGridAdapter.getGridLayoutManager());
@@ -53,28 +95,33 @@
         setSupportActionBar(toolbar);
         ActionBar actionBar = getSupportActionBar();
         actionBar.setDisplayHomeAsUpEnabled(false);
-        actionBar.setCustomView(R.layout.action_bar_with_button);
+        actionBar.setCustomView(R.layout.action_bar_quick_settings);
         actionBar.setDisplayShowCustomEnabled(true);
 
-        Button adavancedSettingBtn = (Button) findViewById(R.id.action_button1);
-        Button userSwitcherBtn = (Button) findViewById(R.id.action_button2);
-        adavancedSettingBtn.setText(R.string.advanced_settings_label);
-        adavancedSettingBtn.setVisibility(View.VISIBLE);
-        adavancedSettingBtn.setOnClickListener(v -> {
-            Intent intent = new Intent(this, CarSettingActivity.class);
-            startActivity(intent);
-        });
-
-        userSwitcherBtn.setText(R.string.user_and_account_settings_title);
-        userSwitcherBtn.setVisibility(View.VISIBLE);
-        userSwitcherBtn.setOnClickListener(v -> {
+        mFullSettingBtn = findViewById(R.id.full_setting_btn);
+        mUserSwitcherBtn = findViewById(R.id.user_switcher_btn);
+        mUserSwitcherBtn.setOnClickListener(v -> {
             Intent intent = new Intent(this, CarSettingActivity.class);
             intent.setAction(CarSettingActivity.ACTION_LIST_USER);
             startActivity(intent);
         });
-        View exitBtn = findViewById(R.id.back_button);
-        ((ImageView) exitBtn).setImageResource(R.drawable.ic_close);
+
+        setupAccountButton();
+        View exitBtn = findViewById(R.id.exit_button);
         exitBtn.setOnClickListener(v -> finish());
+        mUxRestrictionsHelper =
+                new CarUxRestrictionsHelper(
+                        this, QuickSettingActivity.this::onUxRestrictionChagned);
+    }
+
+    private void setupAccountButton() {
+        ImageView userIcon = (ImageView) findViewById(R.id.user_icon);
+        UserInfo currentUserInfo = mUserManagerHelper.getForegroundUserInfo();
+        userIcon.setImageDrawable(
+                UserIconProvider.getUserIcon(currentUserInfo, mUserManagerHelper, this));
+
+        TextView userSwitcherText = (TextView) findViewById(R.id.user_switcher_text);
+        userSwitcherText.setText(currentUserInfo.name);
     }
 
     @Override
@@ -87,11 +134,31 @@
                 .addTile(new DayNightTile(this, mGridAdapter))
                 .addSeekbarTile(new BrightnessTile(this));
         mListView.setAdapter(mGridAdapter);
+        mUxRestrictionsHelper.start();
     }
 
     @Override
     public void onStop() {
         super.onStop();
         mGridAdapter.stop();
+        mUxRestrictionsHelper.stop();
+    }
+
+    private void onUxRestrictionChagned(CarUxRestrictions carUxRestrictions) {
+        // TODO: update tiles
+        applyRestriction(
+                (carUxRestrictions.getActiveRestrictions()
+                        & CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP)
+                        == CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP);
+    }
+
+    private void applyRestriction(boolean restricted) {
+        if (restricted) {
+            mFullSettingBtn.setAlpha(RESTRICTED_ALPHA);
+            mFullSettingBtn.setOnClickListener(mBlockingListener);
+        } else {
+            mFullSettingBtn.setAlpha(UNRESTRICTED_ALPHA);
+            mFullSettingBtn.setOnClickListener(mLaunchSettingListener);
+        }
     }
 }