blob: e24135775e7957aa0da5797101f6f425a8c42f34 [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;
Anthony Chen54daefe2017-04-07 17:19:54 -070024import android.graphics.PorterDuff.Mode;
25import android.graphics.drawable.Drawable;
26import android.graphics.drawable.RippleDrawable;
27import android.os.UserManager;
Anthony Chen54daefe2017-04-07 17:19:54 -070028import android.support.annotation.Nullable;
29import android.support.annotation.VisibleForTesting;
30import android.util.AttributeSet;
31import android.view.View;
32import android.view.View.OnClickListener;
33import android.widget.FrameLayout;
34import android.widget.ImageView;
Anthony Chen54daefe2017-04-07 17:19:54 -070035import android.widget.Toast;
36
37import com.android.internal.logging.MetricsLogger;
38import com.android.internal.logging.nano.MetricsProto;
Selim Cinek1a891a92017-12-04 17:41:27 +010039import com.android.keyguard.KeyguardUpdateMonitor;
Anthony Chen54daefe2017-04-07 17:19:54 -070040import com.android.settingslib.Utils;
Jason Monk826b6092017-08-29 11:30:52 -040041import com.android.settingslib.drawable.UserIconDrawable;
Anthony Chen54daefe2017-04-07 17:19:54 -070042import com.android.systemui.Dependency;
Anthony Chen54daefe2017-04-07 17:19:54 -070043import com.android.systemui.R;
44import com.android.systemui.R.dimen;
Charles Hece2a7c02017-10-11 20:25:20 +010045import com.android.systemui.SysUiServiceProvider;
Anthony Chen54daefe2017-04-07 17:19:54 -070046import com.android.systemui.plugins.ActivityStarter;
47import com.android.systemui.qs.TouchAnimator.Builder;
Charles Hece2a7c02017-10-11 20:25:20 +010048import com.android.systemui.statusbar.CommandQueue;
Anthony Chen54daefe2017-04-07 17:19:54 -070049import com.android.systemui.statusbar.phone.MultiUserSwitch;
50import com.android.systemui.statusbar.phone.SettingsButton;
51import com.android.systemui.statusbar.policy.DeviceProvisionedController;
52import com.android.systemui.statusbar.policy.NetworkController;
53import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
54import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
Anthony Chen54daefe2017-04-07 17:19:54 -070055import com.android.systemui.statusbar.policy.UserInfoController;
56import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
57import com.android.systemui.tuner.TunerService;
58
59public class QSFooterImpl extends FrameLayout implements QSFooter,
Evan Laird2cf56822017-12-18 11:22:39 -050060 OnClickListener, OnUserInfoChangedListener, EmergencyListener,
Charles Hece2a7c02017-10-11 20:25:20 +010061 SignalCallback, CommandQueue.Callbacks {
Evan Lairdeb38aa72018-02-02 11:10:30 -050062
Anthony Chen54daefe2017-04-07 17:19:54 -070063 private ActivityStarter mActivityStarter;
Anthony Chen54daefe2017-04-07 17:19:54 -070064 private UserInfoController mUserInfoController;
65 private SettingsButton mSettingsButton;
66 protected View mSettingsContainer;
Evan Laird39254d42018-01-18 16:05:30 -050067 private View mCarrierText;
Anthony Chen54daefe2017-04-07 17:19:54 -070068
Charles Hece2a7c02017-10-11 20:25:20 +010069 private boolean mQsDisabled;
Anthony Chen54daefe2017-04-07 17:19:54 -070070 private QSPanel mQsPanel;
71
72 private boolean mExpanded;
Anthony Chen54daefe2017-04-07 17:19:54 -070073
74 private boolean mListening;
Anthony Chen54daefe2017-04-07 17:19:54 -070075
76 private boolean mShowEmergencyCallsOnly;
Amin Shaikhacf322d2018-01-31 17:04:56 -050077 private View mDivider;
Anthony Chen54daefe2017-04-07 17:19:54 -070078 protected MultiUserSwitch mMultiUserSwitch;
79 private ImageView mMultiUserAvatar;
80
Evan Lairdeb38aa72018-02-02 11:10:30 -050081 protected TouchAnimator mFooterAnimator;
Anthony Chen54daefe2017-04-07 17:19:54 -070082 private float mExpansionAmount;
83
84 protected View mEdit;
Evan Lairdeb38aa72018-02-02 11:10:30 -050085 private TouchAnimator mSettingsCogAnimator;
Anthony Chen54daefe2017-04-07 17:19:54 -070086
Evan Laird00e43c42018-01-22 20:25:45 -050087 private View mActionsContainer;
Evan Lairdeb38aa72018-02-02 11:10:30 -050088 private View mDragHandle;
89 private final int mDragHandleExpandOffset;
Amin Shaikhc225e322018-01-31 18:08:34 -050090 private View mBackground;
Evan Laird00e43c42018-01-22 20:25:45 -050091
Anthony Chen54daefe2017-04-07 17:19:54 -070092 public QSFooterImpl(Context context, AttributeSet attrs) {
93 super(context, attrs);
Evan Lairdeb38aa72018-02-02 11:10:30 -050094
95 mDragHandleExpandOffset = getResources().
96 getDimensionPixelSize(R.dimen.qs_footer_drag_handle_offset);
97
Anthony Chen54daefe2017-04-07 17:19:54 -070098 }
99
100 @Override
101 protected void onFinishInflate() {
102 super.onFinishInflate();
Amin Shaikhc225e322018-01-31 18:08:34 -0500103 mBackground = findViewById(R.id.qs_footer_background);
Amin Shaikhacf322d2018-01-31 17:04:56 -0500104 mDivider = findViewById(R.id.qs_footer_divider);
Anthony Chen54daefe2017-04-07 17:19:54 -0700105 mEdit = findViewById(android.R.id.edit);
106 mEdit.setOnClickListener(view ->
107 Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() ->
108 mQsPanel.showEdit(view)));
109
Anthony Chen54daefe2017-04-07 17:19:54 -0700110 mSettingsButton = findViewById(R.id.settings_button);
111 mSettingsContainer = findViewById(R.id.settings_button_container);
112 mSettingsButton.setOnClickListener(this);
113
Evan Laird39254d42018-01-18 16:05:30 -0500114 mCarrierText = findViewById(R.id.qs_carrier_text);
115
Anthony Chen54daefe2017-04-07 17:19:54 -0700116 mMultiUserSwitch = findViewById(R.id.multi_user_switch);
117 mMultiUserAvatar = mMultiUserSwitch.findViewById(R.id.multi_user_avatar);
118
Evan Lairdeb38aa72018-02-02 11:10:30 -0500119 mDragHandle = findViewById(R.id.qs_drag_handle_view);
Evan Laird00e43c42018-01-22 20:25:45 -0500120 mActionsContainer = findViewById(R.id.qs_footer_actions_container);
121
Anthony Chen54daefe2017-04-07 17:19:54 -0700122 // RenderThread is doing more harm than good when touching the header (to expand quick
123 // settings), so disable it for this view
124 ((RippleDrawable) mSettingsButton.getBackground()).setForceSoftware(true);
Anthony Chen54daefe2017-04-07 17:19:54 -0700125
126 updateResources();
127
Anthony Chen54daefe2017-04-07 17:19:54 -0700128 mUserInfoController = Dependency.get(UserInfoController.class);
129 mActivityStarter = Dependency.get(ActivityStarter.class);
130 addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight,
131 oldBottom) -> updateAnimator(right - left));
132 }
133
134 private void updateAnimator(int width) {
135 int numTiles = QuickQSPanel.getNumQuickTiles(mContext);
136 int size = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size)
137 - mContext.getResources().getDimensionPixelSize(dimen.qs_quick_tile_padding);
138 int remaining = (width - numTiles * size) / (numTiles - 1);
139 int defSpace = mContext.getResources().getDimensionPixelOffset(R.dimen.default_gear_space);
140
Evan Lairdeb38aa72018-02-02 11:10:30 -0500141 mSettingsCogAnimator = new Builder()
Jason Monk6dadd3e42017-09-01 09:36:19 -0400142 .addFloat(mSettingsContainer, "translationX",
143 isLayoutRtl() ? (remaining - defSpace) : -(remaining - defSpace), 0)
Anthony Chen54daefe2017-04-07 17:19:54 -0700144 .addFloat(mSettingsButton, "rotation", -120, 0)
145 .build();
Anthony Chen54daefe2017-04-07 17:19:54 -0700146
Anthony Chen54daefe2017-04-07 17:19:54 -0700147 setExpansion(mExpansionAmount);
148 }
149
150 @Override
151 protected void onConfigurationChanged(Configuration newConfig) {
152 super.onConfigurationChanged(newConfig);
153 updateResources();
154 }
155
156 @Override
157 public void onRtlPropertiesChanged(int layoutDirection) {
158 super.onRtlPropertiesChanged(layoutDirection);
159 updateResources();
160 }
161
162 private void updateResources() {
Evan Lairdeb38aa72018-02-02 11:10:30 -0500163 updateFooterAnimator();
Anthony Chen54daefe2017-04-07 17:19:54 -0700164 }
165
Evan Lairdeb38aa72018-02-02 11:10:30 -0500166 private void updateFooterAnimator() {
167 mFooterAnimator = createFooterAnimator();
Anthony Chen54daefe2017-04-07 17:19:54 -0700168 }
169
170 @Nullable
Evan Lairdeb38aa72018-02-02 11:10:30 -0500171 private TouchAnimator createFooterAnimator() {
Anthony Chen54daefe2017-04-07 17:19:54 -0700172 return new TouchAnimator.Builder()
Amin Shaikhc225e322018-01-31 18:08:34 -0500173 .addFloat(mBackground, "alpha", 0, 0.90f)
Amin Shaikhacf322d2018-01-31 17:04:56 -0500174 .addFloat(mDivider, "alpha", 0, 1)
Evan Laird39254d42018-01-18 16:05:30 -0500175 .addFloat(mCarrierText, "alpha", 0, 1)
Evan Laird00e43c42018-01-22 20:25:45 -0500176 .addFloat(mActionsContainer, "alpha", 0, 1)
Amin Shaikh4f3f5522018-02-13 17:55:14 -0500177 .addFloat(mDragHandle, "translationY", mDragHandleExpandOffset, 0)
178 .addFloat(mDragHandle, "alpha", 1, 0)
Amin Shaikh92fac562018-02-16 15:08:16 -0500179 .setStartDelay(0.15f)
Anthony Chen54daefe2017-04-07 17:19:54 -0700180 .build();
181 }
182
183 @Override
184 public void setKeyguardShowing(boolean keyguardShowing) {
Anthony Chen54daefe2017-04-07 17:19:54 -0700185 setExpansion(mExpansionAmount);
186 }
187
188 @Override
189 public void setExpanded(boolean expanded) {
190 if (mExpanded == expanded) return;
191 mExpanded = expanded;
192 updateEverything();
193 }
194
195 @Override
Anthony Chen54daefe2017-04-07 17:19:54 -0700196 public void setExpansion(float headerExpansionFraction) {
197 mExpansionAmount = headerExpansionFraction;
Evan Lairdeb38aa72018-02-02 11:10:30 -0500198 if (mSettingsCogAnimator != null) mSettingsCogAnimator.setPosition(headerExpansionFraction);
Anthony Chen54daefe2017-04-07 17:19:54 -0700199
Evan Lairdeb38aa72018-02-02 11:10:30 -0500200 if (mFooterAnimator != null) {
201 mFooterAnimator.setPosition(headerExpansionFraction);
Anthony Chen54daefe2017-04-07 17:19:54 -0700202 }
Anthony Chen54daefe2017-04-07 17:19:54 -0700203 }
204
205 @Override
Charles Hece2a7c02017-10-11 20:25:20 +0100206 public void onAttachedToWindow() {
207 super.onAttachedToWindow();
208 SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).addCallbacks(this);
209 }
210
211 @Override
Anthony Chen54daefe2017-04-07 17:19:54 -0700212 @VisibleForTesting
213 public void onDetachedFromWindow() {
214 setListening(false);
Charles Hece2a7c02017-10-11 20:25:20 +0100215 SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).removeCallbacks(this);
Anthony Chen54daefe2017-04-07 17:19:54 -0700216 super.onDetachedFromWindow();
217 }
218
Anthony Chen54daefe2017-04-07 17:19:54 -0700219 @Override
220 public void setListening(boolean listening) {
221 if (listening == mListening) {
222 return;
223 }
224 mListening = listening;
225 updateListeners();
226 }
227
228 @Override
229 public View getExpandView() {
230 return findViewById(R.id.expand_indicator);
231 }
232
Charles Hece2a7c02017-10-11 20:25:20 +0100233 @Override
234 public void disable(int state1, int state2, boolean animate) {
235 final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
236 if (disabled == mQsDisabled) return;
237 mQsDisabled = disabled;
238 updateEverything();
239 }
240
Anthony Chen54daefe2017-04-07 17:19:54 -0700241 public void updateEverything() {
242 post(() -> {
243 updateVisibilities();
244 setClickable(false);
245 });
246 }
247
248 private void updateVisibilities() {
Charles Hece2a7c02017-10-11 20:25:20 +0100249 mSettingsContainer.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
Anthony Chen54daefe2017-04-07 17:19:54 -0700250 mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility(
251 TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE);
Charles Hece2a7c02017-10-11 20:25:20 +0100252
Anthony Chen54daefe2017-04-07 17:19:54 -0700253 final boolean isDemo = UserManager.isDeviceInDemoMode(mContext);
254
Benjamin Franzff66fa92017-08-10 10:39:44 +0100255
256 mMultiUserSwitch.setVisibility(mExpanded
257 && UserManager.get(mContext).isUserSwitcherEnabled()
Anthony Chen54daefe2017-04-07 17:19:54 -0700258 ? View.VISIBLE : View.INVISIBLE);
259
260 mEdit.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE);
261 }
262
263 private void updateListeners() {
264 if (mListening) {
Anthony Chen54daefe2017-04-07 17:19:54 -0700265 mUserInfoController.addCallback(this);
266 if (Dependency.get(NetworkController.class).hasVoiceCallingFeature()) {
267 Dependency.get(NetworkController.class).addEmergencyListener(this);
268 Dependency.get(NetworkController.class).addCallback(this);
269 }
270 } else {
Anthony Chen54daefe2017-04-07 17:19:54 -0700271 mUserInfoController.removeCallback(this);
272 Dependency.get(NetworkController.class).removeEmergencyListener(this);
273 Dependency.get(NetworkController.class).removeCallback(this);
274 }
275 }
276
277 @Override
278 public void setQSPanel(final QSPanel qsPanel) {
279 mQsPanel = qsPanel;
280 if (mQsPanel != null) {
281 mMultiUserSwitch.setQsPanel(qsPanel);
282 }
283 }
284
285 @Override
286 public void onClick(View v) {
Evan Laird00e43c42018-01-22 20:25:45 -0500287 // Don't do anything until view are unhidden
288 if (!mExpanded) {
289 return;
290 }
291
Anthony Chen54daefe2017-04-07 17:19:54 -0700292 if (v == mSettingsButton) {
293 if (!Dependency.get(DeviceProvisionedController.class).isCurrentUserSetup()) {
294 // If user isn't setup just unlock the device and dump them back at SUW.
295 mActivityStarter.postQSRunnableDismissingKeyguard(() -> { });
296 return;
297 }
298 MetricsLogger.action(mContext,
299 mExpanded ? MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH
300 : MetricsProto.MetricsEvent.ACTION_QS_COLLAPSED_SETTINGS_LAUNCH);
301 if (mSettingsButton.isTunerClick()) {
302 Dependency.get(ActivityStarter.class).postQSRunnableDismissingKeyguard(() -> {
303 if (TunerService.isTunerEnabled(mContext)) {
304 TunerService.showResetRequest(mContext, () -> {
305 // Relaunch settings so that the tuner disappears.
306 startSettingsActivity();
307 });
308 } else {
309 Toast.makeText(getContext(), R.string.tuner_toast,
310 Toast.LENGTH_LONG).show();
311 TunerService.setTunerEnabled(mContext, true);
312 }
313 startSettingsActivity();
314
315 });
316 } else {
317 startSettingsActivity();
318 }
Anthony Chen54daefe2017-04-07 17:19:54 -0700319 }
320 }
321
322 private void startSettingsActivity() {
323 mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS),
324 true /* dismissShade */);
325 }
326
327 @Override
328 public void setEmergencyCallsOnly(boolean show) {
329 boolean changed = show != mShowEmergencyCallsOnly;
330 if (changed) {
331 mShowEmergencyCallsOnly = show;
332 if (mExpanded) {
333 updateEverything();
334 }
335 }
336 }
337
338 @Override
339 public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
340 if (picture != null &&
Selim Cinek1a891a92017-12-04 17:41:27 +0100341 UserManager.get(mContext).isGuestUser(KeyguardUpdateMonitor.getCurrentUser()) &&
Jason Monk826b6092017-08-29 11:30:52 -0400342 !(picture instanceof UserIconDrawable)) {
343 picture = picture.getConstantState().newDrawable(mContext.getResources()).mutate();
Anthony Chen54daefe2017-04-07 17:19:54 -0700344 picture.setColorFilter(
345 Utils.getColorAttr(mContext, android.R.attr.colorForeground),
346 Mode.SRC_IN);
347 }
348 mMultiUserAvatar.setImageDrawable(picture);
349 }
350}