blob: 9c87e1b120917f4923be5aad773d5f162c125084 [file] [log] [blame]
Anthony Chen54daefe2017-04-07 17:19:54 -07001/*
2 * Copyright (C) 2017 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
17package com.android.systemui.qs;
18
Charles Hece2a7c02017-10-11 20:25:20 +010019import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
20
Anthony Chen54daefe2017-04-07 17:19:54 -070021import android.content.Context;
22import android.content.Intent;
23import android.content.res.Configuration;
24import android.content.res.Resources;
25import android.graphics.PorterDuff.Mode;
26import android.graphics.drawable.Drawable;
27import android.graphics.drawable.RippleDrawable;
28import android.os.UserManager;
Anthony Chen54daefe2017-04-07 17:19:54 -070029import android.support.annotation.Nullable;
30import android.support.annotation.VisibleForTesting;
31import android.util.AttributeSet;
32import android.view.View;
33import android.view.View.OnClickListener;
34import android.widget.FrameLayout;
35import android.widget.ImageView;
Anthony Chen54daefe2017-04-07 17:19:54 -070036import android.widget.Toast;
37
38import com.android.internal.logging.MetricsLogger;
39import com.android.internal.logging.nano.MetricsProto;
Selim Cinek1a891a92017-12-04 17:41:27 +010040import com.android.keyguard.KeyguardUpdateMonitor;
Anthony Chen54daefe2017-04-07 17:19:54 -070041import com.android.settingslib.Utils;
Jason Monk826b6092017-08-29 11:30:52 -040042import com.android.settingslib.drawable.UserIconDrawable;
Anthony Chen54daefe2017-04-07 17:19:54 -070043import com.android.systemui.Dependency;
Anthony Chen54daefe2017-04-07 17:19:54 -070044import com.android.systemui.R;
45import com.android.systemui.R.dimen;
Charles Hece2a7c02017-10-11 20:25:20 +010046import com.android.systemui.SysUiServiceProvider;
Anthony Chen54daefe2017-04-07 17:19:54 -070047import com.android.systemui.plugins.ActivityStarter;
48import com.android.systemui.qs.TouchAnimator.Builder;
Charles Hece2a7c02017-10-11 20:25:20 +010049import com.android.systemui.statusbar.CommandQueue;
Anthony Chen54daefe2017-04-07 17:19:54 -070050import com.android.systemui.statusbar.phone.ExpandableIndicator;
51import com.android.systemui.statusbar.phone.MultiUserSwitch;
52import com.android.systemui.statusbar.phone.SettingsButton;
53import com.android.systemui.statusbar.policy.DeviceProvisionedController;
54import com.android.systemui.statusbar.policy.NetworkController;
55import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
56import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
Anthony Chen54daefe2017-04-07 17:19:54 -070057import com.android.systemui.statusbar.policy.UserInfoController;
58import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
59import com.android.systemui.tuner.TunerService;
60
61public class QSFooterImpl extends FrameLayout implements QSFooter,
Evan Laird2cf56822017-12-18 11:22:39 -050062 OnClickListener, OnUserInfoChangedListener, EmergencyListener,
Charles Hece2a7c02017-10-11 20:25:20 +010063 SignalCallback, CommandQueue.Callbacks {
Anthony Chen54daefe2017-04-07 17:19:54 -070064 private ActivityStarter mActivityStarter;
Anthony Chen54daefe2017-04-07 17:19:54 -070065 private UserInfoController mUserInfoController;
66 private SettingsButton mSettingsButton;
67 protected View mSettingsContainer;
Evan Laird39254d42018-01-18 16:05:30 -050068 private View mCarrierText;
Anthony Chen54daefe2017-04-07 17:19:54 -070069
Charles Hece2a7c02017-10-11 20:25:20 +010070 private boolean mQsDisabled;
Anthony Chen54daefe2017-04-07 17:19:54 -070071 private QSPanel mQsPanel;
72
73 private boolean mExpanded;
Anthony Chen54daefe2017-04-07 17:19:54 -070074
75 private boolean mListening;
Anthony Chen54daefe2017-04-07 17:19:54 -070076
77 private boolean mShowEmergencyCallsOnly;
Amin Shaikhacf322d2018-01-31 17:04:56 -050078 private View mDivider;
Anthony Chen54daefe2017-04-07 17:19:54 -070079 protected MultiUserSwitch mMultiUserSwitch;
80 private ImageView mMultiUserAvatar;
81
82 protected TouchAnimator mSettingsAlpha;
83 private float mExpansionAmount;
84
85 protected View mEdit;
86 private TouchAnimator mAnimator;
Anthony Chen54daefe2017-04-07 17:19:54 -070087
Evan Laird00e43c42018-01-22 20:25:45 -050088 private View mActionsContainer;
89
Anthony Chen54daefe2017-04-07 17:19:54 -070090 public QSFooterImpl(Context context, AttributeSet attrs) {
91 super(context, attrs);
92 }
93
94 @Override
95 protected void onFinishInflate() {
96 super.onFinishInflate();
Amin Shaikhacf322d2018-01-31 17:04:56 -050097 mDivider = findViewById(R.id.qs_footer_divider);
Anthony Chen54daefe2017-04-07 17:19:54 -070098 mEdit = findViewById(android.R.id.edit);
99 mEdit.setOnClickListener(view ->
100 Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() ->
101 mQsPanel.showEdit(view)));
102
Anthony Chen54daefe2017-04-07 17:19:54 -0700103 mSettingsButton = findViewById(R.id.settings_button);
104 mSettingsContainer = findViewById(R.id.settings_button_container);
105 mSettingsButton.setOnClickListener(this);
106
Evan Laird39254d42018-01-18 16:05:30 -0500107 mCarrierText = findViewById(R.id.qs_carrier_text);
108
Anthony Chen54daefe2017-04-07 17:19:54 -0700109 mMultiUserSwitch = findViewById(R.id.multi_user_switch);
110 mMultiUserAvatar = mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
111
Evan Laird00e43c42018-01-22 20:25:45 -0500112 mActionsContainer = findViewById(R.id.qs_footer_actions_container);
113
Anthony Chen54daefe2017-04-07 17:19:54 -0700114 // RenderThread is doing more harm than good when touching the header (to expand quick
115 // settings), so disable it for this view
116 ((RippleDrawable) mSettingsButton.getBackground()).setForceSoftware(true);
Anthony Chen54daefe2017-04-07 17:19:54 -0700117
118 updateResources();
119
Anthony Chen54daefe2017-04-07 17:19:54 -0700120 mUserInfoController = Dependency.get(UserInfoController.class);
121 mActivityStarter = Dependency.get(ActivityStarter.class);
122 addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight,
123 oldBottom) -> updateAnimator(right - left));
124 }
125
126 private void updateAnimator(int width) {
127 int numTiles = QuickQSPanel.getNumQuickTiles(mContext);
128 int size = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size)
129 - mContext.getResources().getDimensionPixelSize(dimen.qs_quick_tile_padding);
130 int remaining = (width - numTiles * size) / (numTiles - 1);
131 int defSpace = mContext.getResources().getDimensionPixelOffset(R.dimen.default_gear_space);
132
133 mAnimator = new Builder()
Jason Monk6dadd3e42017-09-01 09:36:19 -0400134 .addFloat(mSettingsContainer, "translationX",
135 isLayoutRtl() ? (remaining - defSpace) : -(remaining - defSpace), 0)
Anthony Chen54daefe2017-04-07 17:19:54 -0700136 .addFloat(mSettingsButton, "rotation", -120, 0)
137 .build();
Anthony Chen54daefe2017-04-07 17:19:54 -0700138
Anthony Chen54daefe2017-04-07 17:19:54 -0700139 setExpansion(mExpansionAmount);
140 }
141
142 @Override
143 protected void onConfigurationChanged(Configuration newConfig) {
144 super.onConfigurationChanged(newConfig);
145 updateResources();
146 }
147
148 @Override
149 public void onRtlPropertiesChanged(int layoutDirection) {
150 super.onRtlPropertiesChanged(layoutDirection);
151 updateResources();
152 }
153
154 private void updateResources() {
Anthony Chen54daefe2017-04-07 17:19:54 -0700155 updateSettingsAnimator();
156 }
157
158 private void updateSettingsAnimator() {
159 mSettingsAlpha = createSettingsAlphaAnimator();
Anthony Chen54daefe2017-04-07 17:19:54 -0700160 }
161
162 @Nullable
163 private TouchAnimator createSettingsAlphaAnimator() {
164 return new TouchAnimator.Builder()
Amin Shaikhacf322d2018-01-31 17:04:56 -0500165 .addFloat(mDivider, "alpha", 0, 1)
Evan Laird39254d42018-01-18 16:05:30 -0500166 .addFloat(mCarrierText, "alpha", 0, 1)
Evan Laird00e43c42018-01-22 20:25:45 -0500167 .addFloat(mActionsContainer, "alpha", 0, 1)
Anthony Chen54daefe2017-04-07 17:19:54 -0700168 .build();
169 }
170
171 @Override
172 public void setKeyguardShowing(boolean keyguardShowing) {
Anthony Chen54daefe2017-04-07 17:19:54 -0700173 setExpansion(mExpansionAmount);
174 }
175
176 @Override
177 public void setExpanded(boolean expanded) {
178 if (mExpanded == expanded) return;
179 mExpanded = expanded;
180 updateEverything();
181 }
182
183 @Override
Anthony Chen54daefe2017-04-07 17:19:54 -0700184 public void setExpansion(float headerExpansionFraction) {
185 mExpansionAmount = headerExpansionFraction;
186 if (mAnimator != null) mAnimator.setPosition(headerExpansionFraction);
Anthony Chen54daefe2017-04-07 17:19:54 -0700187
188 if (mSettingsAlpha != null) {
189 mSettingsAlpha.setPosition(headerExpansionFraction);
190 }
Anthony Chen54daefe2017-04-07 17:19:54 -0700191 }
192
193 @Override
Charles Hece2a7c02017-10-11 20:25:20 +0100194 public void onAttachedToWindow() {
195 super.onAttachedToWindow();
196 SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).addCallbacks(this);
197 }
198
199 @Override
Anthony Chen54daefe2017-04-07 17:19:54 -0700200 @VisibleForTesting
201 public void onDetachedFromWindow() {
202 setListening(false);
Charles Hece2a7c02017-10-11 20:25:20 +0100203 SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).removeCallbacks(this);
Anthony Chen54daefe2017-04-07 17:19:54 -0700204 super.onDetachedFromWindow();
205 }
206
Anthony Chen54daefe2017-04-07 17:19:54 -0700207 @Override
208 public void setListening(boolean listening) {
209 if (listening == mListening) {
210 return;
211 }
212 mListening = listening;
213 updateListeners();
214 }
215
216 @Override
217 public View getExpandView() {
218 return findViewById(R.id.expand_indicator);
219 }
220
Charles Hece2a7c02017-10-11 20:25:20 +0100221 @Override
222 public void disable(int state1, int state2, boolean animate) {
223 final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
224 if (disabled == mQsDisabled) return;
225 mQsDisabled = disabled;
226 updateEverything();
227 }
228
Anthony Chen54daefe2017-04-07 17:19:54 -0700229 public void updateEverything() {
230 post(() -> {
231 updateVisibilities();
232 setClickable(false);
233 });
234 }
235
236 private void updateVisibilities() {
Charles Hece2a7c02017-10-11 20:25:20 +0100237 mSettingsContainer.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
Anthony Chen54daefe2017-04-07 17:19:54 -0700238 mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility(
239 TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE);
Charles Hece2a7c02017-10-11 20:25:20 +0100240
Anthony Chen54daefe2017-04-07 17:19:54 -0700241 final boolean isDemo = UserManager.isDeviceInDemoMode(mContext);
242
Benjamin Franzff66fa92017-08-10 10:39:44 +0100243
244 mMultiUserSwitch.setVisibility(mExpanded
245 && UserManager.get(mContext).isUserSwitcherEnabled()
Anthony Chen54daefe2017-04-07 17:19:54 -0700246 ? View.VISIBLE : View.INVISIBLE);
247
248 mEdit.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE);
249 }
250
251 private void updateListeners() {
252 if (mListening) {
Anthony Chen54daefe2017-04-07 17:19:54 -0700253 mUserInfoController.addCallback(this);
254 if (Dependency.get(NetworkController.class).hasVoiceCallingFeature()) {
255 Dependency.get(NetworkController.class).addEmergencyListener(this);
256 Dependency.get(NetworkController.class).addCallback(this);
257 }
258 } else {
Anthony Chen54daefe2017-04-07 17:19:54 -0700259 mUserInfoController.removeCallback(this);
260 Dependency.get(NetworkController.class).removeEmergencyListener(this);
261 Dependency.get(NetworkController.class).removeCallback(this);
262 }
263 }
264
265 @Override
266 public void setQSPanel(final QSPanel qsPanel) {
267 mQsPanel = qsPanel;
268 if (mQsPanel != null) {
269 mMultiUserSwitch.setQsPanel(qsPanel);
270 }
271 }
272
273 @Override
274 public void onClick(View v) {
Evan Laird00e43c42018-01-22 20:25:45 -0500275 // Don't do anything until view are unhidden
276 if (!mExpanded) {
277 return;
278 }
279
Anthony Chen54daefe2017-04-07 17:19:54 -0700280 if (v == mSettingsButton) {
281 if (!Dependency.get(DeviceProvisionedController.class).isCurrentUserSetup()) {
282 // If user isn't setup just unlock the device and dump them back at SUW.
283 mActivityStarter.postQSRunnableDismissingKeyguard(() -> { });
284 return;
285 }
286 MetricsLogger.action(mContext,
287 mExpanded ? MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH
288 : MetricsProto.MetricsEvent.ACTION_QS_COLLAPSED_SETTINGS_LAUNCH);
289 if (mSettingsButton.isTunerClick()) {
290 Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() -> {
291 if (TunerService.isTunerEnabled(mContext)) {
292 TunerService.showResetRequest(mContext, () -> {
293 // Relaunch settings so that the tuner disappears.
294 startSettingsActivity();
295 });
296 } else {
297 Toast.makeText(getContext(), R.string.tuner_toast,
298 Toast.LENGTH_LONG).show();
299 TunerService.setTunerEnabled(mContext, true);
300 }
301 startSettingsActivity();
302
303 });
304 } else {
305 startSettingsActivity();
306 }
Anthony Chen54daefe2017-04-07 17:19:54 -0700307 }
308 }
309
310 private void startSettingsActivity() {
311 mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS),
312 true /* dismissShade */);
313 }
314
315 @Override
316 public void setEmergencyCallsOnly(boolean show) {
317 boolean changed = show != mShowEmergencyCallsOnly;
318 if (changed) {
319 mShowEmergencyCallsOnly = show;
320 if (mExpanded) {
321 updateEverything();
322 }
323 }
324 }
325
326 @Override
327 public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
328 if (picture != null &&
Selim Cinek1a891a92017-12-04 17:41:27 +0100329 UserManager.get(mContext).isGuestUser(KeyguardUpdateMonitor.getCurrentUser()) &&
Jason Monk826b6092017-08-29 11:30:52 -0400330 !(picture instanceof UserIconDrawable)) {
331 picture = picture.getConstantState().newDrawable(mContext.getResources()).mutate();
Anthony Chen54daefe2017-04-07 17:19:54 -0700332 picture.setColorFilter(
333 Utils.getColorAttr(mContext, android.R.attr.colorForeground),
334 Mode.SRC_IN);
335 }
336 mMultiUserAvatar.setImageDrawable(picture);
337 }
338}