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