• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright (C) 2018 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.flashlight;
18  
19  import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
20  
21  import static androidx.slice.builders.ListBuilder.ICON_IMAGE;
22  
23  import android.annotation.ColorInt;
24  import android.app.PendingIntent;
25  import android.content.Context;
26  import android.content.Intent;
27  import android.content.IntentFilter;
28  import android.hardware.camera2.CameraAccessException;
29  import android.hardware.camera2.CameraCharacteristics;
30  import android.hardware.camera2.CameraManager;
31  import android.net.Uri;
32  import android.provider.Settings;
33  import android.provider.Settings.Secure;
34  import android.util.Log;
35  
36  import androidx.core.graphics.drawable.IconCompat;
37  import androidx.slice.Slice;
38  import androidx.slice.builders.ListBuilder;
39  import androidx.slice.builders.ListBuilder.RowBuilder;
40  import androidx.slice.builders.SliceAction;
41  
42  import com.android.settings.R;
43  import com.android.settings.Utils;
44  import com.android.settings.slices.CustomSliceRegistry;
45  import com.android.settings.slices.CustomSliceable;
46  
47  
48  /**
49   * Utility class to build a Flashlight Slice, and handle all associated actions.
50   */
51  public class FlashlightSlice implements CustomSliceable {
52  
53      private static final String TAG = "FlashlightSlice";
54  
55      /**
56       * Action broadcasting a change on whether flashlight is on or off.
57       */
58      private static final String ACTION_FLASHLIGHT_CHANGED =
59              "com.android.settings.flashlight.action.FLASHLIGHT_CHANGED";
60  
61      private final Context mContext;
62  
FlashlightSlice(Context context)63      public FlashlightSlice(Context context) {
64          mContext = context;
65      }
66  
67      @Override
getSlice()68      public Slice getSlice() {
69          if (!isFlashlightAvailable(mContext)) {
70              return null;
71          }
72          final PendingIntent toggleAction = getBroadcastIntent(mContext);
73          @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext);
74          final IconCompat icon =
75                  IconCompat.createWithResource(mContext, R.drawable.ic_signal_flashlight);
76          return new ListBuilder(mContext, CustomSliceRegistry.FLASHLIGHT_SLICE_URI,
77                  ListBuilder.INFINITY)
78                  .setAccentColor(color)
79                  .addRow(new RowBuilder()
80                          .setTitle(mContext.getText(R.string.power_flashlight))
81                          .setTitleItem(icon, ICON_IMAGE)
82                          .setPrimaryAction(
83                                  SliceAction.createToggle(toggleAction, null,
84                                          isFlashlightEnabled(mContext))))
85                  .build();
86      }
87  
88      @Override
getUri()89      public Uri getUri() {
90          return CustomSliceRegistry.FLASHLIGHT_SLICE_URI;
91      }
92  
93      @Override
getIntentFilter()94      public IntentFilter getIntentFilter() {
95          return new IntentFilter(ACTION_FLASHLIGHT_CHANGED);
96      }
97  
98      @Override
onNotifyChange(Intent intent)99      public void onNotifyChange(Intent intent) {
100          try {
101              final String cameraId = getCameraId(mContext);
102              if (cameraId != null) {
103                  final boolean state = intent.getBooleanExtra(
104                          EXTRA_TOGGLE_STATE, isFlashlightEnabled(mContext));
105                  final CameraManager cameraManager = mContext.getSystemService(CameraManager.class);
106                  cameraManager.setTorchMode(cameraId, state);
107              }
108          } catch (CameraAccessException e) {
109              Log.e(TAG, "Camera couldn't set torch mode.", e);
110          }
111          mContext.getContentResolver().notifyChange(CustomSliceRegistry.FLASHLIGHT_SLICE_URI, null);
112      }
113  
114      @Override
getIntent()115      public Intent getIntent() {
116          return null;
117      }
118  
119      @Override
getSliceHighlightMenuRes()120      public int getSliceHighlightMenuRes() {
121          // no landing page in Settings
122          return NO_RES;
123      }
124  
getCameraId(Context context)125      private static String getCameraId(Context context) throws CameraAccessException {
126          final CameraManager cameraManager = context.getSystemService(CameraManager.class);
127          final String[] ids = cameraManager.getCameraIdList();
128          for (String id : ids) {
129              CameraCharacteristics c = cameraManager.getCameraCharacteristics(id);
130              Boolean flashAvailable = c.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
131              Integer lensFacing = c.get(CameraCharacteristics.LENS_FACING);
132              if (flashAvailable != null && flashAvailable
133                      && lensFacing != null && lensFacing == CameraCharacteristics.LENS_FACING_BACK) {
134                  return id;
135              }
136          }
137          return null;
138      }
139  
isFlashlightAvailable(Context context)140      static boolean isFlashlightAvailable(Context context) {
141          int defaultAvailability = 0;
142          try {
143              // check if there is a flash unit
144              if (getCameraId(context) != null) {
145                  defaultAvailability = 1;
146              }
147          } catch (CameraAccessException e) {
148              Log.e(TAG, "Error getting camera id.", e);
149          }
150          return Secure.getInt(context.getContentResolver(),
151                  Secure.FLASHLIGHT_AVAILABLE, defaultAvailability) == 1;
152      }
153  
isFlashlightEnabled(Context context)154      private static boolean isFlashlightEnabled(Context context) {
155          return Settings.Secure.getInt(
156                  context.getContentResolver(), Secure.FLASHLIGHT_ENABLED, 0) == 1;
157      }
158  }
159