1 /* 2 * Copyright (C) 2020 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.systemui.settings.brightness; 18 19 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; 20 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; 21 import static android.view.WindowManagerPolicyConstants.EXTRA_FROM_BRIGHTNESS_KEY; 22 23 import android.app.Activity; 24 import android.graphics.Rect; 25 import android.os.Bundle; 26 import android.view.Gravity; 27 import android.view.KeyEvent; 28 import android.view.View; 29 import android.view.ViewGroup; 30 import android.view.Window; 31 import android.view.WindowManager; 32 import android.view.accessibility.AccessibilityManager; 33 import android.widget.FrameLayout; 34 35 import com.android.internal.annotations.VisibleForTesting; 36 import com.android.internal.logging.MetricsLogger; 37 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 38 import com.android.systemui.R; 39 import com.android.systemui.dagger.qualifiers.Main; 40 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; 41 import com.android.systemui.util.concurrency.DelayableExecutor; 42 43 import java.util.List; 44 45 import javax.inject.Inject; 46 47 /** A dialog that provides controls for adjusting the screen brightness. */ 48 public class BrightnessDialog extends Activity { 49 50 @VisibleForTesting 51 static final int DIALOG_TIMEOUT_MILLIS = 3000; 52 53 private BrightnessController mBrightnessController; 54 private final BrightnessSliderController.Factory mToggleSliderFactory; 55 private final BrightnessController.Factory mBrightnessControllerFactory; 56 private final DelayableExecutor mMainExecutor; 57 private final AccessibilityManagerWrapper mAccessibilityMgr; 58 private Runnable mCancelTimeoutRunnable; 59 60 @Inject BrightnessDialog( BrightnessSliderController.Factory brightnessSliderfactory, BrightnessController.Factory brightnessControllerFactory, @Main DelayableExecutor mainExecutor, AccessibilityManagerWrapper accessibilityMgr )61 public BrightnessDialog( 62 BrightnessSliderController.Factory brightnessSliderfactory, 63 BrightnessController.Factory brightnessControllerFactory, 64 @Main DelayableExecutor mainExecutor, 65 AccessibilityManagerWrapper accessibilityMgr 66 ) { 67 mToggleSliderFactory = brightnessSliderfactory; 68 mBrightnessControllerFactory = brightnessControllerFactory; 69 mMainExecutor = mainExecutor; 70 mAccessibilityMgr = accessibilityMgr; 71 } 72 73 74 @Override onCreate(Bundle savedInstanceState)75 protected void onCreate(Bundle savedInstanceState) { 76 super.onCreate(savedInstanceState); 77 78 final Window window = getWindow(); 79 80 window.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL); 81 window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); 82 window.requestFeature(Window.FEATURE_NO_TITLE); 83 84 // Calling this creates the decor View, so setLayout takes proper effect 85 // (see Dialog#onWindowAttributesChanged) 86 window.getDecorView(); 87 window.setLayout( 88 WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT); 89 getTheme().applyStyle(R.style.Theme_SystemUI_QuickSettings, false); 90 91 setContentView(R.layout.brightness_mirror_container); 92 FrameLayout frame = findViewById(R.id.brightness_mirror_container); 93 // The brightness mirror container is INVISIBLE by default. 94 frame.setVisibility(View.VISIBLE); 95 ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) frame.getLayoutParams(); 96 int horizontalMargin = 97 getResources().getDimensionPixelSize(R.dimen.notification_side_paddings); 98 lp.leftMargin = horizontalMargin; 99 lp.rightMargin = horizontalMargin; 100 frame.setLayoutParams(lp); 101 Rect bounds = new Rect(); 102 frame.addOnLayoutChangeListener( 103 (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { 104 // Exclude this view (and its horizontal margins) from triggering gestures. 105 // This prevents back gesture from being triggered by dragging close to the 106 // edge of the slider (0% or 100%). 107 bounds.set(-horizontalMargin, 0, right - left + horizontalMargin, bottom - top); 108 v.setSystemGestureExclusionRects(List.of(bounds)); 109 }); 110 111 BrightnessSliderController controller = mToggleSliderFactory.create(this, frame); 112 controller.init(); 113 frame.addView(controller.getRootView(), MATCH_PARENT, WRAP_CONTENT); 114 115 mBrightnessController = mBrightnessControllerFactory.create(controller); 116 } 117 118 @Override onStart()119 protected void onStart() { 120 super.onStart(); 121 mBrightnessController.registerCallbacks(); 122 MetricsLogger.visible(this, MetricsEvent.BRIGHTNESS_DIALOG); 123 } 124 125 @Override onResume()126 protected void onResume() { 127 super.onResume(); 128 if (triggeredByBrightnessKey()) { 129 scheduleTimeout(); 130 } 131 } 132 133 @Override onPause()134 protected void onPause() { 135 super.onPause(); 136 overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); 137 } 138 139 @Override onStop()140 protected void onStop() { 141 super.onStop(); 142 MetricsLogger.hidden(this, MetricsEvent.BRIGHTNESS_DIALOG); 143 mBrightnessController.unregisterCallbacks(); 144 } 145 146 @Override onKeyDown(int keyCode, KeyEvent event)147 public boolean onKeyDown(int keyCode, KeyEvent event) { 148 if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN 149 || keyCode == KeyEvent.KEYCODE_VOLUME_UP 150 || keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) { 151 if (mCancelTimeoutRunnable != null) { 152 mCancelTimeoutRunnable.run(); 153 } 154 finish(); 155 } 156 157 return super.onKeyDown(keyCode, event); 158 } 159 triggeredByBrightnessKey()160 private boolean triggeredByBrightnessKey() { 161 return getIntent().getBooleanExtra(EXTRA_FROM_BRIGHTNESS_KEY, false); 162 } 163 scheduleTimeout()164 private void scheduleTimeout() { 165 if (mCancelTimeoutRunnable != null) { 166 mCancelTimeoutRunnable.run(); 167 } 168 final int timeout = mAccessibilityMgr.getRecommendedTimeoutMillis(DIALOG_TIMEOUT_MILLIS, 169 AccessibilityManager.FLAG_CONTENT_CONTROLS); 170 mCancelTimeoutRunnable = mMainExecutor.executeDelayed(this::finish, timeout); 171 } 172 } 173