1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.accessibility;
18 
19 import android.content.Context;
20 import android.hardware.camera2.CameraAccessException;
21 import android.hardware.camera2.CameraCharacteristics;
22 import android.hardware.camera2.CameraManager;
23 import android.provider.Settings;
24 import android.util.Log;
25 
26 import androidx.annotation.ColorInt;
27 import androidx.annotation.IntDef;
28 import androidx.annotation.NonNull;
29 
30 import java.lang.annotation.Retention;
31 import java.lang.annotation.RetentionPolicy;
32 
33 class FlashNotificationsUtil {
34     static final String LOG_TAG = "FlashNotificationsUtil";
35     static final String ACTION_FLASH_NOTIFICATION_START_PREVIEW =
36             "com.android.internal.intent.action.FLASH_NOTIFICATION_START_PREVIEW";
37     static final String ACTION_FLASH_NOTIFICATION_STOP_PREVIEW =
38             "com.android.internal.intent.action.FLASH_NOTIFICATION_STOP_PREVIEW";
39     static final String EXTRA_FLASH_NOTIFICATION_PREVIEW_COLOR =
40             "com.android.internal.intent.extra.FLASH_NOTIFICATION_PREVIEW_COLOR";
41     static final String EXTRA_FLASH_NOTIFICATION_PREVIEW_TYPE =
42             "com.android.internal.intent.extra.FLASH_NOTIFICATION_PREVIEW_TYPE";
43 
44     static final int TYPE_SHORT_PREVIEW = 0;
45     static final int TYPE_LONG_PREVIEW = 1;
46 
47     static final int DEFAULT_SCREEN_FLASH_COLOR = ScreenFlashNotificationColor.YELLOW.mColorInt;
48 
49     @Retention(RetentionPolicy.SOURCE)
50     @IntDef({
51             FlashNotificationsUtil.State.OFF,
52             FlashNotificationsUtil.State.CAMERA,
53             FlashNotificationsUtil.State.SCREEN,
54             FlashNotificationsUtil.State.CAMERA_SCREEN,
55     })
56     @interface State {
57         int OFF = 0;
58         int CAMERA = 1;
59         int SCREEN = 2;
60         int CAMERA_SCREEN = 3;
61     }
62 
isTorchAvailable(@onNull Context context)63     static boolean isTorchAvailable(@NonNull Context context) {
64         // TODO This is duplicated logic of FlashNotificationsController.getCameraId.
65         final CameraManager cameraManager = context.getSystemService(CameraManager.class);
66         if (cameraManager == null) return false;
67 
68         try {
69             final String[] ids = cameraManager.getCameraIdList();
70 
71             for (String id : ids) {
72                 final CameraCharacteristics c = cameraManager.getCameraCharacteristics(id);
73 
74                 final Boolean flashAvailable = c.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
75                 if (flashAvailable == null) continue;
76 
77                 final Integer lensFacing = c.get(CameraCharacteristics.LENS_FACING);
78                 if (lensFacing == null) continue;
79 
80                 if (flashAvailable && lensFacing == CameraCharacteristics.LENS_FACING_BACK) {
81                     return true;
82                 }
83             }
84         } catch (CameraAccessException ignored) {
85             Log.w(LOG_TAG, "Failed to get valid camera for camera flash notification.");
86         }
87         return false;
88     }
89 
getScreenColor(@olorInt int colorInt)90     static ScreenFlashNotificationColor getScreenColor(@ColorInt int colorInt)
91             throws ScreenColorNotFoundException {
92 
93         colorInt |= ScreenFlashNotificationColor.ALPHA_MASK;
94         for (ScreenFlashNotificationColor color : ScreenFlashNotificationColor.values()) {
95             if (colorInt == color.mOpaqueColorInt) {
96                 return color;
97             }
98         }
99 
100         throw new ScreenColorNotFoundException();
101     }
102 
103     @NonNull
getColorDescriptionText(@onNull Context context, @ColorInt int color)104     static String getColorDescriptionText(@NonNull Context context, @ColorInt int color) {
105         try {
106             return context.getString(getScreenColor(color).mStringRes);
107         } catch (ScreenColorNotFoundException e) {
108             return "";
109         }
110     }
111 
112     @State
getFlashNotificationsState(Context context)113     static int getFlashNotificationsState(Context context) {
114         if (context == null) {
115             return State.OFF;
116         }
117 
118         final boolean isTorchAvailable = FlashNotificationsUtil.isTorchAvailable(context);
119         final boolean isCameraFlashEnabled = Settings.System.getInt(context.getContentResolver(),
120                 Settings.System.CAMERA_FLASH_NOTIFICATION, State.OFF) != State.OFF;
121         final boolean isScreenFlashEnabled = Settings.System.getInt(context.getContentResolver(),
122                 Settings.System.SCREEN_FLASH_NOTIFICATION, State.OFF) != State.OFF;
123 
124         return ((isTorchAvailable && isCameraFlashEnabled) ? State.CAMERA : State.OFF)
125                 | (isScreenFlashEnabled ? State.SCREEN : State.OFF);
126     }
127 
128     static class ScreenColorNotFoundException extends Exception {
129     }
130 }
131