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 getCameraId(Context context)119 private static String getCameraId(Context context) throws CameraAccessException { 120 final CameraManager cameraManager = context.getSystemService(CameraManager.class); 121 final String[] ids = cameraManager.getCameraIdList(); 122 for (String id : ids) { 123 CameraCharacteristics c = cameraManager.getCameraCharacteristics(id); 124 Boolean flashAvailable = c.get(CameraCharacteristics.FLASH_INFO_AVAILABLE); 125 Integer lensFacing = c.get(CameraCharacteristics.LENS_FACING); 126 if (flashAvailable != null && flashAvailable 127 && lensFacing != null && lensFacing == CameraCharacteristics.LENS_FACING_BACK) { 128 return id; 129 } 130 } 131 return null; 132 } 133 134 isFlashlightAvailable(Context context)135 private static boolean isFlashlightAvailable(Context context) { 136 return Settings.Secure.getInt( 137 context.getContentResolver(), Secure.FLASHLIGHT_AVAILABLE, 0) == 1; 138 } 139 isFlashlightEnabled(Context context)140 private static boolean isFlashlightEnabled(Context context) { 141 return Settings.Secure.getInt( 142 context.getContentResolver(), Secure.FLASHLIGHT_ENABLED, 0) == 1; 143 } 144 } 145