Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2016 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file |
| 5 | * except in compliance with the License. You may obtain a copy of the License at |
| 6 | * |
| 7 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | * |
| 9 | * Unless required by applicable law or agreed to in writing, software distributed under the |
| 10 | * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 11 | * KIND, either express or implied. See the License for the specific language governing |
| 12 | * permissions and limitations under the License. |
| 13 | */ |
| 14 | |
| 15 | package com.android.systemui.qs; |
| 16 | |
Jason Monk | 8c09ac7 | 2017-03-16 11:53:40 -0400 | [diff] [blame] | 17 | import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_MORE_SETTINGS; |
| 18 | |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 19 | import android.animation.Animator; |
| 20 | import android.animation.Animator.AnimatorListener; |
| 21 | import android.animation.AnimatorListenerAdapter; |
| 22 | import android.annotation.Nullable; |
| 23 | import android.content.Context; |
| 24 | import android.content.Intent; |
| 25 | import android.content.res.Configuration; |
| 26 | import android.graphics.drawable.Animatable; |
| 27 | import android.util.AttributeSet; |
Fabian Kozynski | dcd3b3b | 2020-02-18 15:05:04 -0500 | [diff] [blame] | 28 | import android.util.Pair; |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 29 | import android.util.SparseArray; |
Fabian Kozynski | dcd3b3b | 2020-02-18 15:05:04 -0500 | [diff] [blame] | 30 | import android.view.DisplayCutout; |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 31 | import android.view.View; |
| 32 | import android.view.ViewGroup; |
Fabian Kozynski | 8a86795 | 2019-12-02 10:32:00 -0500 | [diff] [blame] | 33 | import android.view.ViewStub; |
Fabian Kozynski | dcd3b3b | 2020-02-18 15:05:04 -0500 | [diff] [blame] | 34 | import android.view.WindowInsets; |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 35 | import android.view.accessibility.AccessibilityEvent; |
| 36 | import android.widget.ImageView; |
| 37 | import android.widget.LinearLayout; |
| 38 | import android.widget.Switch; |
| 39 | import android.widget.TextView; |
Xiaohui Chen | 6644893 | 2016-04-18 12:53:28 -0700 | [diff] [blame] | 40 | |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 41 | import com.android.internal.logging.MetricsLogger; |
Fabian Kozynski | 2ff6df9 | 2020-04-24 12:00:49 -0400 | [diff] [blame] | 42 | import com.android.internal.logging.UiEventLogger; |
Jason Monk | 9c7844c | 2017-01-18 15:21:53 -0500 | [diff] [blame] | 43 | import com.android.systemui.Dependency; |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 44 | import com.android.systemui.FontSizeUtils; |
| 45 | import com.android.systemui.R; |
Jason Monk | ec34da8 | 2017-02-24 15:57:05 -0500 | [diff] [blame] | 46 | import com.android.systemui.plugins.ActivityStarter; |
Jason Monk | e5b770e | 2017-03-03 21:49:29 -0500 | [diff] [blame] | 47 | import com.android.systemui.plugins.qs.DetailAdapter; |
Jason Monk | 9c7844c | 2017-01-18 15:21:53 -0500 | [diff] [blame] | 48 | import com.android.systemui.statusbar.CommandQueue; |
Fabian Kozynski | dcd3b3b | 2020-02-18 15:05:04 -0500 | [diff] [blame] | 49 | import com.android.systemui.statusbar.phone.StatusBarWindowView; |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 50 | |
| 51 | public class QSDetail extends LinearLayout { |
| 52 | |
| 53 | private static final String TAG = "QSDetail"; |
| 54 | private static final long FADE_DURATION = 300; |
| 55 | |
| 56 | private final SparseArray<View> mDetailViews = new SparseArray<>(); |
Fabian Kozynski | 2ff6df9 | 2020-04-24 12:00:49 -0400 | [diff] [blame] | 57 | private final UiEventLogger mUiEventLogger = QSEvents.INSTANCE.getQsUiEventsLogger(); |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 58 | |
| 59 | private ViewGroup mDetailContent; |
Muyuan Li | 0e9f538 | 2016-04-27 15:51:15 -0700 | [diff] [blame] | 60 | protected TextView mDetailSettingsButton; |
| 61 | protected TextView mDetailDoneButton; |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 62 | private QSDetailClipper mClipper; |
| 63 | private DetailAdapter mDetailAdapter; |
| 64 | private QSPanel mQsPanel; |
| 65 | |
Muyuan Li | 0e9f538 | 2016-04-27 15:51:15 -0700 | [diff] [blame] | 66 | protected View mQsDetailHeader; |
| 67 | protected TextView mQsDetailHeaderTitle; |
Fabian Kozynski | 8a86795 | 2019-12-02 10:32:00 -0500 | [diff] [blame] | 68 | private ViewStub mQsDetailHeaderSwitchStub; |
| 69 | private Switch mQsDetailHeaderSwitch; |
Muyuan Li | e3cecd7 | 2016-05-14 12:35:12 -0700 | [diff] [blame] | 70 | protected ImageView mQsDetailHeaderProgress; |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 71 | |
Muyuan Li | 0e9f538 | 2016-04-27 15:51:15 -0700 | [diff] [blame] | 72 | protected QSTileHost mHost; |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 73 | |
| 74 | private boolean mScanState; |
| 75 | private boolean mClosingDetail; |
| 76 | private boolean mFullyExpanded; |
Jason Monk | e5b770e | 2017-03-03 21:49:29 -0500 | [diff] [blame] | 77 | private QuickStatusBarHeader mHeader; |
Xiaohui Chen | 6644893 | 2016-04-18 12:53:28 -0700 | [diff] [blame] | 78 | private boolean mTriggeredExpand; |
| 79 | private int mOpenX; |
| 80 | private int mOpenY; |
Jason Monk | 35a9c14 | 2016-07-25 10:18:30 -0400 | [diff] [blame] | 81 | private boolean mAnimatingOpen; |
Jason Monk | 48e093e | 2016-07-15 10:37:07 -0400 | [diff] [blame] | 82 | private boolean mSwitchState; |
Jason Monk | b4ec0b9 | 2017-06-13 13:47:54 -0400 | [diff] [blame] | 83 | private View mFooter; |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 84 | |
| 85 | public QSDetail(Context context, @Nullable AttributeSet attrs) { |
| 86 | super(context, attrs); |
| 87 | } |
| 88 | |
| 89 | @Override |
| 90 | protected void onConfigurationChanged(Configuration newConfig) { |
| 91 | super.onConfigurationChanged(newConfig); |
| 92 | FontSizeUtils.updateFontSize(mDetailDoneButton, R.dimen.qs_detail_button_text_size); |
| 93 | FontSizeUtils.updateFontSize(mDetailSettingsButton, R.dimen.qs_detail_button_text_size); |
| 94 | |
| 95 | for (int i = 0; i < mDetailViews.size(); i++) { |
| 96 | mDetailViews.valueAt(i).dispatchConfigurationChanged(newConfig); |
| 97 | } |
| 98 | } |
| 99 | |
| 100 | @Override |
| 101 | protected void onFinishInflate() { |
| 102 | super.onFinishInflate(); |
Alan Viverette | 51efddb | 2017-04-05 10:00:01 -0400 | [diff] [blame] | 103 | mDetailContent = findViewById(android.R.id.content); |
| 104 | mDetailSettingsButton = findViewById(android.R.id.button2); |
| 105 | mDetailDoneButton = findViewById(android.R.id.button1); |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 106 | |
| 107 | mQsDetailHeader = findViewById(R.id.qs_detail_header); |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 108 | mQsDetailHeaderTitle = (TextView) mQsDetailHeader.findViewById(android.R.id.title); |
Fabian Kozynski | 8a86795 | 2019-12-02 10:32:00 -0500 | [diff] [blame] | 109 | mQsDetailHeaderSwitchStub = mQsDetailHeader.findViewById(R.id.toggle_stub); |
Alan Viverette | 51efddb | 2017-04-05 10:00:01 -0400 | [diff] [blame] | 110 | mQsDetailHeaderProgress = findViewById(R.id.qs_detail_header_progress); |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 111 | |
| 112 | updateDetailText(); |
| 113 | |
| 114 | mClipper = new QSDetailClipper(this); |
| 115 | |
| 116 | final OnClickListener doneListener = new OnClickListener() { |
| 117 | @Override |
| 118 | public void onClick(View v) { |
| 119 | announceForAccessibility( |
| 120 | mContext.getString(R.string.accessibility_desc_quick_settings)); |
| 121 | mQsPanel.closeDetail(); |
| 122 | } |
| 123 | }; |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 124 | mDetailDoneButton.setOnClickListener(doneListener); |
| 125 | } |
| 126 | |
Jason Monk | b4ec0b9 | 2017-06-13 13:47:54 -0400 | [diff] [blame] | 127 | public void setQsPanel(QSPanel panel, QuickStatusBarHeader header, View footer) { |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 128 | mQsPanel = panel; |
Jason Monk | 589bb70 | 2016-04-12 15:44:43 -0400 | [diff] [blame] | 129 | mHeader = header; |
Jason Monk | b4ec0b9 | 2017-06-13 13:47:54 -0400 | [diff] [blame] | 130 | mFooter = footer; |
Xiaohui Chen | 6644893 | 2016-04-18 12:53:28 -0700 | [diff] [blame] | 131 | mHeader.setCallback(mQsPanelCallback); |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 132 | mQsPanel.setCallback(mQsPanelCallback); |
| 133 | } |
| 134 | |
| 135 | public void setHost(QSTileHost host) { |
| 136 | mHost = host; |
| 137 | } |
| 138 | public boolean isShowingDetail() { |
| 139 | return mDetailAdapter != null; |
| 140 | } |
| 141 | |
| 142 | public void setFullyExpanded(boolean fullyExpanded) { |
| 143 | mFullyExpanded = fullyExpanded; |
| 144 | } |
| 145 | |
Xiaohui Chen | 6644893 | 2016-04-18 12:53:28 -0700 | [diff] [blame] | 146 | public void setExpanded(boolean qsExpanded) { |
| 147 | if (!qsExpanded) { |
| 148 | mTriggeredExpand = false; |
| 149 | } |
| 150 | } |
| 151 | |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 152 | private void updateDetailText() { |
| 153 | mDetailDoneButton.setText(R.string.quick_settings_done); |
| 154 | mDetailSettingsButton.setText(R.string.quick_settings_more_settings); |
| 155 | } |
| 156 | |
| 157 | public void updateResources() { |
| 158 | updateDetailText(); |
| 159 | } |
| 160 | |
| 161 | public boolean isClosingDetail() { |
| 162 | return mClosingDetail; |
| 163 | } |
| 164 | |
Jason Monk | e5b770e | 2017-03-03 21:49:29 -0500 | [diff] [blame] | 165 | public interface Callback { |
| 166 | void onShowingDetail(DetailAdapter detail, int x, int y); |
| 167 | void onToggleStateChanged(boolean state); |
| 168 | void onScanStateChanged(boolean state); |
| 169 | } |
Muyuan Li | 0e9f538 | 2016-04-27 15:51:15 -0700 | [diff] [blame] | 170 | |
Jason Monk | 46767b7 | 2016-08-18 10:58:04 -0400 | [diff] [blame] | 171 | public void handleShowingDetail(final DetailAdapter adapter, int x, int y, |
Muyuan Li | bc55b2a | 2016-06-24 15:40:51 -0700 | [diff] [blame] | 172 | boolean toggleQs) { |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 173 | final boolean showingDetail = adapter != null; |
| 174 | setClickable(showingDetail); |
| 175 | if (showingDetail) { |
Muyuan Li | 0e9f538 | 2016-04-27 15:51:15 -0700 | [diff] [blame] | 176 | setupDetailHeader(adapter); |
Muyuan Li | bc55b2a | 2016-06-24 15:40:51 -0700 | [diff] [blame] | 177 | if (toggleQs && !mFullyExpanded) { |
Xiaohui Chen | 6644893 | 2016-04-18 12:53:28 -0700 | [diff] [blame] | 178 | mTriggeredExpand = true; |
Dave Mankoff | bcaca8a | 2019-10-31 18:04:08 -0400 | [diff] [blame] | 179 | Dependency.get(CommandQueue.class).animateExpandSettingsPanel(null); |
Xiaohui Chen | 6644893 | 2016-04-18 12:53:28 -0700 | [diff] [blame] | 180 | } else { |
| 181 | mTriggeredExpand = false; |
| 182 | } |
| 183 | mOpenX = x; |
| 184 | mOpenY = y; |
| 185 | } else { |
| 186 | // Ensure we collapse into the same point we opened from. |
| 187 | x = mOpenX; |
| 188 | y = mOpenY; |
Muyuan Li | bc55b2a | 2016-06-24 15:40:51 -0700 | [diff] [blame] | 189 | if (toggleQs && mTriggeredExpand) { |
Dave Mankoff | bcaca8a | 2019-10-31 18:04:08 -0400 | [diff] [blame] | 190 | Dependency.get(CommandQueue.class).animateCollapsePanels(); |
Xiaohui Chen | 6644893 | 2016-04-18 12:53:28 -0700 | [diff] [blame] | 191 | mTriggeredExpand = false; |
| 192 | } |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 193 | } |
| 194 | |
| 195 | boolean visibleDiff = (mDetailAdapter != null) != (adapter != null); |
| 196 | if (!visibleDiff && mDetailAdapter == adapter) return; // already in right state |
| 197 | AnimatorListener listener = null; |
| 198 | if (adapter != null) { |
| 199 | int viewCacheIndex = adapter.getMetricsCategory(); |
| 200 | View detailView = adapter.createDetailView(mContext, mDetailViews.get(viewCacheIndex), |
| 201 | mDetailContent); |
| 202 | if (detailView == null) throw new IllegalStateException("Must return detail view"); |
| 203 | |
Muyuan Li | 0e9f538 | 2016-04-27 15:51:15 -0700 | [diff] [blame] | 204 | setupDetailFooter(adapter); |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 205 | |
| 206 | mDetailContent.removeAllViews(); |
| 207 | mDetailContent.addView(detailView); |
| 208 | mDetailViews.put(viewCacheIndex, detailView); |
Jason Monk | 8c09ac7 | 2017-03-16 11:53:40 -0400 | [diff] [blame] | 209 | Dependency.get(MetricsLogger.class).visible(adapter.getMetricsCategory()); |
Fabian Kozynski | 2ff6df9 | 2020-04-24 12:00:49 -0400 | [diff] [blame] | 210 | mUiEventLogger.log(adapter.openDetailEvent()); |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 211 | announceForAccessibility(mContext.getString( |
| 212 | R.string.accessibility_quick_settings_detail, |
| 213 | adapter.getTitle())); |
| 214 | mDetailAdapter = adapter; |
| 215 | listener = mHideGridContentWhenDone; |
| 216 | setVisibility(View.VISIBLE); |
| 217 | } else { |
| 218 | if (mDetailAdapter != null) { |
Jason Monk | 8c09ac7 | 2017-03-16 11:53:40 -0400 | [diff] [blame] | 219 | Dependency.get(MetricsLogger.class).hidden(mDetailAdapter.getMetricsCategory()); |
Fabian Kozynski | 2ff6df9 | 2020-04-24 12:00:49 -0400 | [diff] [blame] | 220 | mUiEventLogger.log(mDetailAdapter.closeDetailEvent()); |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 221 | } |
| 222 | mClosingDetail = true; |
| 223 | mDetailAdapter = null; |
| 224 | listener = mTeardownDetailWhenDone; |
Jason Monk | 589bb70 | 2016-04-12 15:44:43 -0400 | [diff] [blame] | 225 | mHeader.setVisibility(View.VISIBLE); |
Jason Monk | b4ec0b9 | 2017-06-13 13:47:54 -0400 | [diff] [blame] | 226 | mFooter.setVisibility(View.VISIBLE); |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 227 | mQsPanel.setGridContentVisibility(true); |
| 228 | mQsPanelCallback.onScanStateChanged(false); |
| 229 | } |
| 230 | sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); |
Muyuan Li | 0e9f538 | 2016-04-27 15:51:15 -0700 | [diff] [blame] | 231 | |
| 232 | animateDetailVisibleDiff(x, y, visibleDiff, listener); |
| 233 | } |
| 234 | |
| 235 | protected void animateDetailVisibleDiff(int x, int y, boolean visibleDiff, AnimatorListener listener) { |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 236 | if (visibleDiff) { |
Jason Monk | ac3dec9 | 2016-07-26 09:22:18 -0400 | [diff] [blame] | 237 | mAnimatingOpen = mDetailAdapter != null; |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 238 | if (mFullyExpanded || mDetailAdapter != null) { |
| 239 | setAlpha(1); |
| 240 | mClipper.animateCircularClip(x, y, mDetailAdapter != null, listener); |
| 241 | } else { |
| 242 | animate().alpha(0) |
| 243 | .setDuration(FADE_DURATION) |
| 244 | .setListener(listener) |
| 245 | .start(); |
| 246 | } |
| 247 | } |
| 248 | } |
| 249 | |
Muyuan Li | 0e9f538 | 2016-04-27 15:51:15 -0700 | [diff] [blame] | 250 | protected void setupDetailFooter(DetailAdapter adapter) { |
| 251 | final Intent settingsIntent = adapter.getSettingsIntent(); |
| 252 | mDetailSettingsButton.setVisibility(settingsIntent != null ? VISIBLE : GONE); |
Jason Monk | 8c09ac7 | 2017-03-16 11:53:40 -0400 | [diff] [blame] | 253 | mDetailSettingsButton.setOnClickListener(v -> { |
| 254 | Dependency.get(MetricsLogger.class).action(ACTION_QS_MORE_SETTINGS, |
Jason Monk | 6997da7 | 2017-04-03 15:22:54 -0400 | [diff] [blame] | 255 | adapter.getMetricsCategory()); |
Fabian Kozynski | 2ff6df9 | 2020-04-24 12:00:49 -0400 | [diff] [blame] | 256 | mUiEventLogger.log(adapter.moreSettingsEvent()); |
Jason Monk | 8c09ac7 | 2017-03-16 11:53:40 -0400 | [diff] [blame] | 257 | Dependency.get(ActivityStarter.class) |
| 258 | .postStartActivityDismissingKeyguard(settingsIntent, 0); |
| 259 | }); |
Muyuan Li | 0e9f538 | 2016-04-27 15:51:15 -0700 | [diff] [blame] | 260 | } |
| 261 | |
| 262 | protected void setupDetailHeader(final DetailAdapter adapter) { |
| 263 | mQsDetailHeaderTitle.setText(adapter.getTitle()); |
| 264 | final Boolean toggleState = adapter.getToggleState(); |
| 265 | if (toggleState == null) { |
Fabian Kozynski | 8a86795 | 2019-12-02 10:32:00 -0500 | [diff] [blame] | 266 | if (mQsDetailHeaderSwitch != null) mQsDetailHeaderSwitch.setVisibility(INVISIBLE); |
Muyuan Li | 0e9f538 | 2016-04-27 15:51:15 -0700 | [diff] [blame] | 267 | mQsDetailHeader.setClickable(false); |
| 268 | } else { |
Fabian Kozynski | 8a86795 | 2019-12-02 10:32:00 -0500 | [diff] [blame] | 269 | if (mQsDetailHeaderSwitch == null) { |
| 270 | mQsDetailHeaderSwitch = (Switch) mQsDetailHeaderSwitchStub.inflate(); |
| 271 | } |
Muyuan Li | 0e9f538 | 2016-04-27 15:51:15 -0700 | [diff] [blame] | 272 | mQsDetailHeaderSwitch.setVisibility(VISIBLE); |
Jason Monk | ac3dec9 | 2016-07-26 09:22:18 -0400 | [diff] [blame] | 273 | handleToggleStateChanged(toggleState, adapter.getToggleEnabled()); |
Muyuan Li | 0e9f538 | 2016-04-27 15:51:15 -0700 | [diff] [blame] | 274 | mQsDetailHeader.setClickable(true); |
| 275 | mQsDetailHeader.setOnClickListener(new OnClickListener() { |
| 276 | @Override |
| 277 | public void onClick(View v) { |
| 278 | boolean checked = !mQsDetailHeaderSwitch.isChecked(); |
| 279 | mQsDetailHeaderSwitch.setChecked(checked); |
| 280 | adapter.setToggleState(checked); |
| 281 | } |
| 282 | }); |
| 283 | } |
| 284 | } |
| 285 | |
Fabian Kozynski | dcd3b3b | 2020-02-18 15:05:04 -0500 | [diff] [blame] | 286 | @Override |
| 287 | public WindowInsets onApplyWindowInsets(WindowInsets insets) { |
| 288 | DisplayCutout cutout = insets.getDisplayCutout(); |
| 289 | |
| 290 | Pair<Integer, Integer> padding = StatusBarWindowView.cornerCutoutMargins( |
| 291 | cutout, getDisplay()); |
| 292 | |
| 293 | if (padding == null) { |
| 294 | mQsDetailHeader.setPaddingRelative( |
| 295 | getResources().getDimensionPixelSize(R.dimen.qs_detail_header_padding), |
| 296 | getPaddingTop(), |
| 297 | getResources().getDimensionPixelSize(R.dimen.qs_detail_header_padding), |
| 298 | getPaddingBottom() |
| 299 | ); |
| 300 | } else { |
| 301 | mQsDetailHeader.setPadding( |
| 302 | padding.first, |
| 303 | getPaddingTop(), |
| 304 | padding.second, |
| 305 | getPaddingBottom() |
| 306 | ); |
| 307 | } |
| 308 | |
| 309 | return super.onApplyWindowInsets(insets); |
| 310 | } |
| 311 | |
Jason Monk | 35a9c14 | 2016-07-25 10:18:30 -0400 | [diff] [blame] | 312 | private void handleToggleStateChanged(boolean state, boolean toggleEnabled) { |
Jason Monk | 48e093e | 2016-07-15 10:37:07 -0400 | [diff] [blame] | 313 | mSwitchState = state; |
Jason Monk | 35a9c14 | 2016-07-25 10:18:30 -0400 | [diff] [blame] | 314 | if (mAnimatingOpen) { |
Jason Monk | 48e093e | 2016-07-15 10:37:07 -0400 | [diff] [blame] | 315 | return; |
| 316 | } |
Fabian Kozynski | 8a86795 | 2019-12-02 10:32:00 -0500 | [diff] [blame] | 317 | if (mQsDetailHeaderSwitch != null) mQsDetailHeaderSwitch.setChecked(state); |
Jason Monk | fac2538 | 2016-07-19 14:13:37 -0400 | [diff] [blame] | 318 | mQsDetailHeader.setEnabled(toggleEnabled); |
Fabian Kozynski | 8a86795 | 2019-12-02 10:32:00 -0500 | [diff] [blame] | 319 | if (mQsDetailHeaderSwitch != null) mQsDetailHeaderSwitch.setEnabled(toggleEnabled); |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 320 | } |
| 321 | |
| 322 | private void handleScanStateChanged(boolean state) { |
| 323 | if (mScanState == state) return; |
| 324 | mScanState = state; |
| 325 | final Animatable anim = (Animatable) mQsDetailHeaderProgress.getDrawable(); |
| 326 | if (state) { |
Jason Monk | d9fcc64 | 2017-08-01 10:13:43 -0400 | [diff] [blame] | 327 | mQsDetailHeaderProgress.animate().cancel(); |
| 328 | mQsDetailHeaderProgress.animate() |
| 329 | .alpha(1) |
| 330 | .withEndAction(anim::start) |
| 331 | .start(); |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 332 | } else { |
Jason Monk | d9fcc64 | 2017-08-01 10:13:43 -0400 | [diff] [blame] | 333 | mQsDetailHeaderProgress.animate().cancel(); |
| 334 | mQsDetailHeaderProgress.animate() |
| 335 | .alpha(0f) |
| 336 | .withEndAction(anim::stop) |
| 337 | .start(); |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 338 | } |
| 339 | } |
| 340 | |
Jason Monk | 48e093e | 2016-07-15 10:37:07 -0400 | [diff] [blame] | 341 | private void checkPendingAnimations() { |
Jason Monk | 35a9c14 | 2016-07-25 10:18:30 -0400 | [diff] [blame] | 342 | handleToggleStateChanged(mSwitchState, |
| 343 | mDetailAdapter != null && mDetailAdapter.getToggleEnabled()); |
Jason Monk | 48e093e | 2016-07-15 10:37:07 -0400 | [diff] [blame] | 344 | } |
| 345 | |
Jason Monk | 46767b7 | 2016-08-18 10:58:04 -0400 | [diff] [blame] | 346 | protected Callback mQsPanelCallback = new Callback() { |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 347 | @Override |
| 348 | public void onToggleStateChanged(final boolean state) { |
| 349 | post(new Runnable() { |
| 350 | @Override |
| 351 | public void run() { |
Jason Monk | 35a9c14 | 2016-07-25 10:18:30 -0400 | [diff] [blame] | 352 | handleToggleStateChanged(state, |
| 353 | mDetailAdapter != null && mDetailAdapter.getToggleEnabled()); |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 354 | } |
| 355 | }); |
| 356 | } |
| 357 | |
| 358 | @Override |
| 359 | public void onShowingDetail(final DetailAdapter detail, final int x, final int y) { |
| 360 | post(new Runnable() { |
| 361 | @Override |
| 362 | public void run() { |
Fabian Kozynski | 511e8b9 | 2018-10-10 12:31:35 -0400 | [diff] [blame] | 363 | if (isAttachedToWindow()) { |
| 364 | handleShowingDetail(detail, x, y, false /* toggleQs */); |
| 365 | } |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 366 | } |
| 367 | }); |
| 368 | } |
| 369 | |
| 370 | @Override |
| 371 | public void onScanStateChanged(final boolean state) { |
| 372 | post(new Runnable() { |
| 373 | @Override |
| 374 | public void run() { |
| 375 | handleScanStateChanged(state); |
| 376 | } |
| 377 | }); |
| 378 | } |
| 379 | }; |
| 380 | |
| 381 | private final AnimatorListenerAdapter mHideGridContentWhenDone = new AnimatorListenerAdapter() { |
| 382 | public void onAnimationCancel(Animator animation) { |
| 383 | // If we have been cancelled, remove the listener so that onAnimationEnd doesn't get |
| 384 | // called, this will avoid accidentally turning off the grid when we don't want to. |
| 385 | animation.removeListener(this); |
Jason Monk | 35a9c14 | 2016-07-25 10:18:30 -0400 | [diff] [blame] | 386 | mAnimatingOpen = false; |
Jason Monk | 48e093e | 2016-07-15 10:37:07 -0400 | [diff] [blame] | 387 | checkPendingAnimations(); |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 388 | }; |
| 389 | |
| 390 | @Override |
| 391 | public void onAnimationEnd(Animator animation) { |
| 392 | // Only hide content if still in detail state. |
| 393 | if (mDetailAdapter != null) { |
| 394 | mQsPanel.setGridContentVisibility(false); |
Jason Monk | 589bb70 | 2016-04-12 15:44:43 -0400 | [diff] [blame] | 395 | mHeader.setVisibility(View.INVISIBLE); |
Jason Monk | b4ec0b9 | 2017-06-13 13:47:54 -0400 | [diff] [blame] | 396 | mFooter.setVisibility(View.INVISIBLE); |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 397 | } |
Jason Monk | 35a9c14 | 2016-07-25 10:18:30 -0400 | [diff] [blame] | 398 | mAnimatingOpen = false; |
Jason Monk | 48e093e | 2016-07-15 10:37:07 -0400 | [diff] [blame] | 399 | checkPendingAnimations(); |
Jason Monk | 377e7ad | 2016-02-16 14:03:21 -0500 | [diff] [blame] | 400 | } |
| 401 | }; |
| 402 | |
| 403 | private final AnimatorListenerAdapter mTeardownDetailWhenDone = new AnimatorListenerAdapter() { |
| 404 | public void onAnimationEnd(Animator animation) { |
| 405 | mDetailContent.removeAllViews(); |
| 406 | setVisibility(View.INVISIBLE); |
| 407 | mClosingDetail = false; |
| 408 | }; |
| 409 | }; |
| 410 | } |