Create camera toggle tile

Bug: 162549680
Test: None (tested with subsequent change)
Change-Id: I35c2528fa2bf5800c3329a7b5448addf476d12ff
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 101124e..86817f7 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -107,7 +107,7 @@
 
     <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
     <string name="quick_settings_tiles_stock" translatable="false">
-        wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,dark,work,cast,night,screenrecord,reverse,reduce_brightness
+        wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,dark,work,cast,night,screenrecord,reverse,reduce_brightness,cameratoggle
     </string>
 
     <!-- The tiles to display in QuickSettings -->
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index 6eec5dc..9f229b1 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -50,6 +50,10 @@
             android:key="bluetooth"
             android:title="@string/quick_settings_bluetooth_label" />
 
+        <com.android.systemui.tuner.StatusBarSwitch
+            android:key="cameratoggle"
+            android:title="Camera Toggle" />
+
         <!-- nfc -->
         <!-- tty -->
         <!-- speakerphone -->
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index ba71fa6..69ddd25 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -30,6 +30,7 @@
 import com.android.systemui.qs.tiles.AirplaneModeTile;
 import com.android.systemui.qs.tiles.BatterySaverTile;
 import com.android.systemui.qs.tiles.BluetoothTile;
+import com.android.systemui.qs.tiles.CameraToggleTile;
 import com.android.systemui.qs.tiles.CastTile;
 import com.android.systemui.qs.tiles.CellularTile;
 import com.android.systemui.qs.tiles.ColorInversionTile;
@@ -83,6 +84,7 @@
     private final Provider<UiModeNightTile> mUiModeNightTileProvider;
     private final Provider<ScreenRecordTile> mScreenRecordTileProvider;
     private final Provider<ReduceBrightColorsTile> mReduceBrightColorsTileProvider;
+    private final Provider<CameraToggleTile> mCameraToggleTileProvider;
 
     private final Lazy<QSHost> mQsHostLazy;
     private final Provider<CustomTile.Builder> mCustomTileBuilderProvider;
@@ -115,7 +117,8 @@
             Provider<GarbageMonitor.MemoryTile> memoryTileProvider,
             Provider<UiModeNightTile> uiModeNightTileProvider,
             Provider<ScreenRecordTile> screenRecordTileProvider,
-            Provider<ReduceBrightColorsTile> reduceBrightColorsTileProvider) {
+            Provider<ReduceBrightColorsTile> reduceBrightColorsTileProvider,
+            Provider<CameraToggleTile> cameraToggleTileProvider) {
         mQsHostLazy = qsHostLazy;
         mCustomTileBuilderProvider = customTileBuilderProvider;
 
@@ -143,6 +146,7 @@
         mUiModeNightTileProvider = uiModeNightTileProvider;
         mScreenRecordTileProvider = screenRecordTileProvider;
         mReduceBrightColorsTileProvider = reduceBrightColorsTileProvider;
+        mCameraToggleTileProvider = cameraToggleTileProvider;
     }
 
     public QSTile createTile(String tileSpec) {
@@ -198,6 +202,8 @@
                 return mScreenRecordTileProvider.get();
             case "reduce_brightness":
                 return mReduceBrightColorsTileProvider.get();
+            case "cameratoggle":
+                return mCameraToggleTileProvider.get();
         }
 
         // Custom tiles
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
new file mode 100644
index 0000000..d719fc3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2020 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.systemui.qs.tiles;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
+import android.service.quicksettings.Tile;
+import android.widget.Switch;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.statusbar.policy.CameraToggleController;
+
+import javax.inject.Inject;
+
+public class CameraToggleTile extends QSTileImpl<QSTile.BooleanState> {
+
+    private CameraToggleController mCameraToggleController;
+
+    @Inject
+    protected CameraToggleTile(QSHost host,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            CameraToggleController cameraToggleController) {
+        super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+                activityStarter, qsLogger);
+        mCameraToggleController = cameraToggleController;
+        mCameraToggleController.addCallback((b) -> refreshState());
+    }
+
+    @Override
+    public BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    @Override
+    protected void handleClick() {
+        mCameraToggleController.setCameraEnabled(!mCameraToggleController.isCameraEnabled());
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        state.icon = new CameraToggleTileIcon();
+        state.state = mCameraToggleController.isCameraEnabled()
+                ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+        state.value = mCameraToggleController.isCameraEnabled();
+        state.label = "Camera";
+        if (!mCameraToggleController.isCameraAvailable()) {
+            state.secondaryLabel = "Currently in use";
+        } else {
+            state.secondaryLabel = null;
+        }
+        state.handlesLongClick = false;
+        state.contentDescription = state.label;
+        state.expandedAccessibilityClassName = Switch.class.getName();
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return 0;
+    }
+
+    @Override
+    public Intent getLongClickIntent() {
+        return null;
+    }
+
+    @Override
+    public CharSequence getTileLabel() {
+        return "Camera";
+    }
+
+    class CameraToggleTileIcon extends Icon {
+
+        @Override
+        public Drawable getDrawable(Context context) {
+            return context.getDrawable(R.drawable.ic_camera);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CameraToggleController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CameraToggleController.java
new file mode 100644
index 0000000..544f005
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CameraToggleController.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 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.systemui.statusbar.policy;
+
+import com.android.systemui.Dumpable;
+
+public interface CameraToggleController extends CallbackController<CameraToggleController.Callback>,
+        Dumpable {
+
+    boolean isCameraEnabled();
+    void setCameraEnabled(boolean enabled);
+
+    boolean isCameraAvailable();
+
+    interface Callback {
+        void onCameraEnabledChanged(boolean enable);
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CameraToggleControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CameraToggleControllerImpl.java
new file mode 100644
index 0000000..7496813
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CameraToggleControllerImpl.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2020 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.systemui.statusbar.policy;
+
+import android.content.Context;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CameraToggleManager;
+import android.os.Looper;
+import android.util.ArraySet;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dump.DumpManager;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Set;
+
+import javax.inject.Inject;
+
+public class CameraToggleControllerImpl implements CameraToggleController {
+
+    private final Context mContext;
+    private final DumpManager mDumpManager;
+    private final CameraToggleManager mCameraToggleManager;
+
+    private boolean mState = true;
+
+    Set<Callback> mCallbacks = new ArraySet<>();
+
+    Set<String> mUsedCameras = new ArraySet<>();
+
+    /**
+     */
+    @Inject
+    public CameraToggleControllerImpl(
+            Context context,
+            DumpManager dumpManager,
+            @Background Looper bgLooper,
+            @Main Looper mainLooper) {
+        mContext = context;
+        mDumpManager = dumpManager;
+        mCameraToggleManager = context.getSystemService(CameraToggleManager.class);
+        mCameraToggleManager.addCameraToggleChangeListener(this::onCameraChanged);
+        mState = mCameraToggleManager.isCameraEnabled();
+        mContext.getSystemService(CameraManager.class).registerAvailabilityCallback(
+                context.getMainExecutor(), new CameraManager.AvailabilityCallback() {
+                    @Override
+                    public void onCameraAvailable(@NonNull String cameraId) {
+                        mUsedCameras.remove(cameraId);
+                        onCameraChanged(mState);
+                    }
+
+                    @Override
+                    public void onCameraUnavailable(@NonNull String cameraId) {
+                        mUsedCameras.add(cameraId);
+                        onCameraChanged(mState);
+                    }
+                });
+    }
+
+    @Override
+    public boolean isCameraEnabled() {
+        return mState;
+    }
+
+    @Override
+    public void setCameraEnabled(boolean enabled) {
+        if (!/*mCameraToggleManager.setCameraEnabled(enabled)*/true) {
+            Toast.makeText(mContext, "Can't disable camera while in use", Toast.LENGTH_LONG);
+        }
+    }
+
+    @Override
+    public boolean isCameraAvailable() {
+        return false;/*mUsedCameras.isEmpty();*/
+    }
+
+    @Override
+    public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+
+    }
+
+    @Override
+    public void addCallback(@NonNull Callback listener) {
+        mCallbacks.add(listener);
+    }
+
+    @Override
+    public void removeCallback(@NonNull Callback listener) {
+        mCallbacks.remove(listener);
+    }
+
+    private void onCameraChanged(boolean state) {
+        mState = state;
+        for (Callback callback : mCallbacks) {
+            callback.onCameraEnabledChanged(state);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
index 069b405..916a1a8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
@@ -24,6 +24,8 @@
 import com.android.systemui.statusbar.policy.AccessPointControllerImpl;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
+import com.android.systemui.statusbar.policy.CameraToggleController;
+import com.android.systemui.statusbar.policy.CameraToggleControllerImpl;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.CastControllerImpl;
 import com.android.systemui.statusbar.policy.ExtensionController;
@@ -124,6 +126,10 @@
             AccessPointControllerImpl accessPointControllerImpl);
 
     /** */
+    @Binds
+    CameraToggleController provideCameraToggleController(CameraToggleControllerImpl controllerImpl);
+
+    /** */
     @SysUISingleton
     @Provides
     static AccessPointControllerImpl  provideAccessPointControllerImpl(