diff options
4 files changed, 111 insertions, 11 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java index b610cf394a32..75e3bc1d3db3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java @@ -62,7 +62,9 @@ public class FlashlightTile extends QSTile<QSTile.BooleanState> implements if (arg instanceof Boolean) { state.value = (Boolean) arg; } - state.visible = mFlashlightController.isAvailable(); + // Always show the tile when the flashlight is on. This is needed because + // the camera is not available while it is being used for the flashlight. + state.visible = state.value || mFlashlightController.isAvailable(); state.label = mHost.getContext().getString(R.string.quick_settings_flashlight_label); state.iconId = state.value ? R.drawable.ic_qs_flashlight_on : R.drawable.ic_qs_flashlight_off; @@ -77,4 +79,9 @@ public class FlashlightTile extends QSTile<QSTile.BooleanState> implements public void onFlashlightError() { refreshState(false); } + + @Override + public void onFlashlightAvailabilityChanged(boolean available) { + refreshState(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index b5f38ae468ce..74bc6984d137 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -38,6 +38,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.R; +import com.android.systemui.statusbar.policy.FlashlightController; /** * Implementation for the bottom area of the Keyguard, including camera/phone affordance and status @@ -63,6 +64,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private ActivityStarter mActivityStarter; private UnlockMethodCache mUnlockMethodCache; private LockPatternUtils mLockPatternUtils; + private FlashlightController mFlashlightController; public KeyguardBottomAreaView(Context context) { super(context); @@ -102,6 +104,10 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mActivityStarter = activityStarter; } + public void setFlashlightController(FlashlightController flashlightController) { + mFlashlightController = flashlightController; + } + private Intent getCameraIntent() { KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext); boolean currentUserHasTrust = updateMonitor.getUserHasTrust( @@ -189,6 +195,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL } public void launchCamera() { + mFlashlightController.killFlashlight(); Intent intent = getCameraIntent(); if (intent == SECURE_CAMERA_INTENT) { mContext.startActivityAsUser(intent, UserHandle.CURRENT); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index a5dee6d6fe2f..59becd391d49 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -752,6 +752,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } mFlashlightController = new FlashlightController(mContext); + mKeyguardBottomArea.setFlashlightController(mFlashlightController); mUserSwitcherController = new UserSwitcherController(mContext); mKeyguardMonitor = new KeyguardMonitor(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java index b059043eb586..e05e34bcbe37 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java @@ -28,6 +28,7 @@ import android.hardware.camera2.CaptureRequest; import android.os.Handler; import android.os.HandlerThread; import android.os.Process; +import android.os.SystemProperties; import android.util.Log; import android.util.Size; import android.view.Surface; @@ -41,6 +42,14 @@ import java.util.ArrayList; public class FlashlightController { private static final String TAG = "FlashlightController"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + private static final boolean ENFORCE_AVAILABILITY_LISTENER = + SystemProperties.getBoolean("persist.sysui.flash.listener", false); + + private static final int DISPATCH_ERROR = 0; + private static final int DISPATCH_OFF = 1; + private static final int DISPATCH_AVAILABILITY_CHANGED = 2; private final CameraManager mCameraManager; /** Call {@link #ensureHandler()} before using */ @@ -52,6 +61,8 @@ public class FlashlightController { /** Lock on {@code this} when accessing */ private boolean mFlashlightEnabled; + private String mCameraId; + private boolean mCameraAvailable; private CameraDevice mCameraDevice; private CaptureRequest mFlashlightRequest; private CameraCaptureSession mSession; @@ -60,6 +71,20 @@ public class FlashlightController { public FlashlightController(Context mContext) { mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE); + initialize(); + } + + public void initialize() { + try { + mCameraId = getCameraId(); + } catch (CameraAccessException e) { + Log.e(TAG, "Couldn't initialize.", e); + return; + } + + ensureHandler(); + mCameraAvailable = true; + mCameraManager.addAvailabilityListener(mAvailabilityListener, mHandler); } public synchronized void setFlashlight(boolean enabled) { @@ -69,14 +94,20 @@ public class FlashlightController { } } - public boolean isAvailable() { - try { - return getCameraId() != null; - } catch (CameraAccessException e) { - return false; + public void killFlashlight() { + boolean enabled; + synchronized (this) { + enabled = mFlashlightEnabled; + } + if (enabled) { + mHandler.post(mKillFlashlightRunnable); } } + public synchronized boolean isAvailable() { + return ENFORCE_AVAILABILITY_LISTENER ? mCameraAvailable : (mCameraId != null); + } + public void addListener(FlashlightListener l) { synchronized (mListeners) { cleanUpListenersLocked(l); @@ -207,24 +238,30 @@ public class FlashlightController { } private void dispatchOff() { - dispatchListeners(false, true /* off */); + dispatchListeners(DISPATCH_OFF, false /* argument (ignored) */); } private void dispatchError() { - dispatchListeners(true /* error */, false); + dispatchListeners(DISPATCH_ERROR, false /* argument (ignored) */); } - private void dispatchListeners(boolean error, boolean off) { + private void dispatchAvailabilityChanged(boolean available) { + dispatchListeners(DISPATCH_AVAILABILITY_CHANGED, available); + } + + private void dispatchListeners(int message, boolean argument) { synchronized (mListeners) { final int N = mListeners.size(); boolean cleanup = false; for (int i = 0; i < N; i++) { FlashlightListener l = mListeners.get(i).get(); if (l != null) { - if (error) { + if (message == DISPATCH_ERROR) { l.onFlashlightError(); - } else if (off) { + } else if (message == DISPATCH_OFF) { l.onFlashlightOff(); + } else if (message == DISPATCH_AVAILABILITY_CHANGED) { + l.onFlashlightAvailabilityChanged(argument); } } else { cleanup = true; @@ -293,6 +330,48 @@ public class FlashlightController { } }; + private final Runnable mKillFlashlightRunnable = new Runnable() { + @Override + public void run() { + synchronized (this) { + mFlashlightEnabled = false; + } + updateFlashlight(true /* forceDisable */); + dispatchOff(); + } + }; + + private final CameraManager.AvailabilityListener mAvailabilityListener = + new CameraManager.AvailabilityListener() { + @Override + public void onCameraAvailable(String cameraId) { + if (DEBUG) Log.d(TAG, "onCameraAvailable(" + cameraId + ")"); + if (cameraId.equals(mCameraId)) { + setCameraAvailable(true); + } + } + + @Override + public void onCameraUnavailable(String cameraId) { + if (DEBUG) Log.d(TAG, "onCameraUnavailable(" + cameraId + ")"); + if (cameraId.equals(mCameraId)) { + setCameraAvailable(false); + } + } + + private void setCameraAvailable(boolean available) { + boolean changed; + synchronized (FlashlightController.this) { + changed = mCameraAvailable != available; + mCameraAvailable = available; + } + if (changed) { + if (DEBUG) Log.d(TAG, "dispatchAvailabilityChanged(" + available + ")"); + dispatchAvailabilityChanged(available); + } + } + }; + public interface FlashlightListener { /** @@ -304,5 +383,11 @@ public class FlashlightController { * Called when there is an error that turns the flashlight off. */ void onFlashlightError(); + + /** + * Called when there is a change in availability of the flashlight functionality + * @param available true if the flashlight is currently available. + */ + void onFlashlightAvailabilityChanged(boolean available); } } |