Clara Bayarri | 838e36c | 2015-03-17 23:10:44 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2015 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.internal.view; |
| 18 | |
Abodunrinwa Toki | 17293cc | 2017-05-22 14:16:04 +0100 | [diff] [blame] | 19 | import android.annotation.NonNull; |
Clara Bayarri | 838e36c | 2015-03-17 23:10:44 +0000 | [diff] [blame] | 20 | import android.content.Context; |
Abodunrinwa Toki | 49f1a76 | 2016-08-03 20:07:15 -0700 | [diff] [blame] | 21 | import android.graphics.Point; |
Clara Bayarri | 838e36c | 2015-03-17 23:10:44 +0000 | [diff] [blame] | 22 | import android.graphics.Rect; |
| 23 | import android.view.ActionMode; |
| 24 | import android.view.Menu; |
| 25 | import android.view.MenuInflater; |
| 26 | import android.view.MenuItem; |
| 27 | import android.view.View; |
Abodunrinwa Toki | 9e21128 | 2015-06-05 02:46:57 +0100 | [diff] [blame] | 28 | import android.view.ViewConfiguration; |
Justin Klaassen | 6183b72 | 2016-04-26 20:19:07 -0700 | [diff] [blame] | 29 | import android.view.ViewGroup; |
| 30 | import android.view.ViewParent; |
Abodunrinwa Toki | 49f1a76 | 2016-08-03 20:07:15 -0700 | [diff] [blame] | 31 | import android.view.WindowManager; |
Clara Bayarri | 838e36c | 2015-03-17 23:10:44 +0000 | [diff] [blame] | 32 | |
Abodunrinwa Toki | 15a6c89 | 2015-06-16 23:17:19 +0100 | [diff] [blame] | 33 | import com.android.internal.R; |
Clara Bayarri | 0d7d4ef | 2015-05-13 15:12:12 +0100 | [diff] [blame] | 34 | import com.android.internal.util.Preconditions; |
Clara Bayarri | 838e36c | 2015-03-17 23:10:44 +0000 | [diff] [blame] | 35 | import com.android.internal.view.menu.MenuBuilder; |
| 36 | import com.android.internal.widget.FloatingToolbar; |
| 37 | |
Abodunrinwa Toki | c107b0e | 2015-06-25 21:33:51 -0700 | [diff] [blame] | 38 | import java.util.Arrays; |
| 39 | |
Abodunrinwa Toki | 17293cc | 2017-05-22 14:16:04 +0100 | [diff] [blame] | 40 | public final class FloatingActionMode extends ActionMode { |
Clara Bayarri | 838e36c | 2015-03-17 23:10:44 +0000 | [diff] [blame] | 41 | |
Abodunrinwa Toki | 9e21128 | 2015-06-05 02:46:57 +0100 | [diff] [blame] | 42 | private static final int MAX_HIDE_DURATION = 3000; |
Abodunrinwa Toki | b9acbe4 | 2015-09-16 19:47:38 +0100 | [diff] [blame] | 43 | private static final int MOVING_HIDE_DELAY = 50; |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 44 | |
Abodunrinwa Toki | 17293cc | 2017-05-22 14:16:04 +0100 | [diff] [blame] | 45 | @NonNull private final Context mContext; |
| 46 | @NonNull private final ActionMode.Callback2 mCallback; |
| 47 | @NonNull private final MenuBuilder mMenu; |
| 48 | @NonNull private final Rect mContentRect; |
| 49 | @NonNull private final Rect mContentRectOnScreen; |
| 50 | @NonNull private final Rect mPreviousContentRectOnScreen; |
| 51 | @NonNull private final int[] mViewPositionOnScreen; |
| 52 | @NonNull private final int[] mPreviousViewPositionOnScreen; |
| 53 | @NonNull private final int[] mRootViewPositionOnScreen; |
| 54 | @NonNull private final Rect mViewRectOnScreen; |
| 55 | @NonNull private final Rect mPreviousViewRectOnScreen; |
| 56 | @NonNull private final Rect mScreenRect; |
| 57 | @NonNull private final View mOriginatingView; |
| 58 | @NonNull private final Point mDisplaySize; |
Abodunrinwa Toki | 15a6c89 | 2015-06-16 23:17:19 +0100 | [diff] [blame] | 59 | private final int mBottomAllowance; |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 60 | |
| 61 | private final Runnable mMovingOff = new Runnable() { |
| 62 | public void run() { |
Abodunrinwa Toki | d1eb19c | 2016-07-21 11:10:19 +0100 | [diff] [blame] | 63 | if (isViewStillActive()) { |
| 64 | mFloatingToolbarVisibilityHelper.setMoving(false); |
| 65 | mFloatingToolbarVisibilityHelper.updateToolbarVisibility(); |
| 66 | } |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 67 | } |
| 68 | }; |
| 69 | |
Abodunrinwa Toki | 9e21128 | 2015-06-05 02:46:57 +0100 | [diff] [blame] | 70 | private final Runnable mHideOff = new Runnable() { |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 71 | public void run() { |
Abodunrinwa Toki | d1eb19c | 2016-07-21 11:10:19 +0100 | [diff] [blame] | 72 | if (isViewStillActive()) { |
| 73 | mFloatingToolbarVisibilityHelper.setHideRequested(false); |
| 74 | mFloatingToolbarVisibilityHelper.updateToolbarVisibility(); |
| 75 | } |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 76 | } |
| 77 | }; |
| 78 | |
Abodunrinwa Toki | 17293cc | 2017-05-22 14:16:04 +0100 | [diff] [blame] | 79 | @NonNull private FloatingToolbar mFloatingToolbar; |
| 80 | @NonNull private FloatingToolbarVisibilityHelper mFloatingToolbarVisibilityHelper; |
Clara Bayarri | 838e36c | 2015-03-17 23:10:44 +0000 | [diff] [blame] | 81 | |
| 82 | public FloatingActionMode( |
Abodunrinwa Toki | 17293cc | 2017-05-22 14:16:04 +0100 | [diff] [blame] | 83 | Context context, ActionMode.Callback2 callback, |
| 84 | View originatingView, FloatingToolbar floatingToolbar) { |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 85 | mContext = Preconditions.checkNotNull(context); |
| 86 | mCallback = Preconditions.checkNotNull(callback); |
Clara Bayarri | 838e36c | 2015-03-17 23:10:44 +0000 | [diff] [blame] | 87 | mMenu = new MenuBuilder(context).setDefaultShowAsAction( |
| 88 | MenuItem.SHOW_AS_ACTION_IF_ROOM); |
Clara Bayarri | 0d7d4ef | 2015-05-13 15:12:12 +0100 | [diff] [blame] | 89 | setType(ActionMode.TYPE_FLOATING); |
Clara Bayarri | ea2d644 | 2015-09-01 11:26:46 +0100 | [diff] [blame] | 90 | mMenu.setCallback(new MenuBuilder.Callback() { |
| 91 | @Override |
| 92 | public void onMenuModeChange(MenuBuilder menu) {} |
| 93 | |
| 94 | @Override |
| 95 | public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { |
| 96 | return mCallback.onActionItemClicked(FloatingActionMode.this, item); |
| 97 | } |
| 98 | }); |
Clara Bayarri | 0d7d4ef | 2015-05-13 15:12:12 +0100 | [diff] [blame] | 99 | mContentRect = new Rect(); |
Yohei Yukawa | bafc908 | 2015-07-14 05:59:05 -0700 | [diff] [blame] | 100 | mContentRectOnScreen = new Rect(); |
| 101 | mPreviousContentRectOnScreen = new Rect(); |
| 102 | mViewPositionOnScreen = new int[2]; |
| 103 | mPreviousViewPositionOnScreen = new int[2]; |
| 104 | mRootViewPositionOnScreen = new int[2]; |
| 105 | mViewRectOnScreen = new Rect(); |
| 106 | mPreviousViewRectOnScreen = new Rect(); |
Abodunrinwa Toki | a8151e4 | 2015-05-06 18:57:06 +0100 | [diff] [blame] | 107 | mScreenRect = new Rect(); |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 108 | mOriginatingView = Preconditions.checkNotNull(originatingView); |
Yohei Yukawa | bafc908 | 2015-07-14 05:59:05 -0700 | [diff] [blame] | 109 | mOriginatingView.getLocationOnScreen(mViewPositionOnScreen); |
Abodunrinwa Toki | 15a6c89 | 2015-06-16 23:17:19 +0100 | [diff] [blame] | 110 | // Allow the content rect to overshoot a little bit beyond the |
| 111 | // bottom view bound if necessary. |
| 112 | mBottomAllowance = context.getResources() |
| 113 | .getDimensionPixelSize(R.dimen.content_rect_bottom_clip_allowance); |
Abodunrinwa Toki | 49f1a76 | 2016-08-03 20:07:15 -0700 | [diff] [blame] | 114 | mDisplaySize = new Point(); |
Abodunrinwa Toki | 17293cc | 2017-05-22 14:16:04 +0100 | [diff] [blame] | 115 | setFloatingToolbar(Preconditions.checkNotNull(floatingToolbar)); |
Clara Bayarri | 0d7d4ef | 2015-05-13 15:12:12 +0100 | [diff] [blame] | 116 | } |
| 117 | |
Abodunrinwa Toki | 17293cc | 2017-05-22 14:16:04 +0100 | [diff] [blame] | 118 | private void setFloatingToolbar(FloatingToolbar floatingToolbar) { |
Clara Bayarri | 838e36c | 2015-03-17 23:10:44 +0000 | [diff] [blame] | 119 | mFloatingToolbar = floatingToolbar |
| 120 | .setMenu(mMenu) |
Abodunrinwa Toki | 17293cc | 2017-05-22 14:16:04 +0100 | [diff] [blame] | 121 | .setOnMenuItemClickListener(item -> mMenu.performItemAction(item, 0)); |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 122 | mFloatingToolbarVisibilityHelper = new FloatingToolbarVisibilityHelper(mFloatingToolbar); |
Abodunrinwa Toki | f444b5c | 2015-06-16 15:47:04 +0100 | [diff] [blame] | 123 | mFloatingToolbarVisibilityHelper.activate(); |
Clara Bayarri | 838e36c | 2015-03-17 23:10:44 +0000 | [diff] [blame] | 124 | } |
| 125 | |
| 126 | @Override |
| 127 | public void setTitle(CharSequence title) {} |
| 128 | |
| 129 | @Override |
| 130 | public void setTitle(int resId) {} |
| 131 | |
| 132 | @Override |
| 133 | public void setSubtitle(CharSequence subtitle) {} |
| 134 | |
| 135 | @Override |
| 136 | public void setSubtitle(int resId) {} |
| 137 | |
| 138 | @Override |
| 139 | public void setCustomView(View view) {} |
| 140 | |
| 141 | @Override |
| 142 | public void invalidate() { |
| 143 | mCallback.onPrepareActionMode(this, mMenu); |
Abodunrinwa Toki | f444b5c | 2015-06-16 15:47:04 +0100 | [diff] [blame] | 144 | invalidateContentRect(); // Will re-layout and show the toolbar if necessary. |
Clara Bayarri | 838e36c | 2015-03-17 23:10:44 +0000 | [diff] [blame] | 145 | } |
| 146 | |
| 147 | @Override |
| 148 | public void invalidateContentRect() { |
| 149 | mCallback.onGetContentRect(this, mOriginatingView, mContentRect); |
| 150 | repositionToolbar(); |
| 151 | } |
| 152 | |
| 153 | public void updateViewLocationInWindow() { |
Yohei Yukawa | bafc908 | 2015-07-14 05:59:05 -0700 | [diff] [blame] | 154 | mOriginatingView.getLocationOnScreen(mViewPositionOnScreen); |
| 155 | mOriginatingView.getRootView().getLocationOnScreen(mRootViewPositionOnScreen); |
| 156 | mOriginatingView.getGlobalVisibleRect(mViewRectOnScreen); |
| 157 | mViewRectOnScreen.offset(mRootViewPositionOnScreen[0], mRootViewPositionOnScreen[1]); |
Abodunrinwa Toki | c107b0e | 2015-06-25 21:33:51 -0700 | [diff] [blame] | 158 | |
Yohei Yukawa | bafc908 | 2015-07-14 05:59:05 -0700 | [diff] [blame] | 159 | if (!Arrays.equals(mViewPositionOnScreen, mPreviousViewPositionOnScreen) |
| 160 | || !mViewRectOnScreen.equals(mPreviousViewRectOnScreen)) { |
Abodunrinwa Toki | c107b0e | 2015-06-25 21:33:51 -0700 | [diff] [blame] | 161 | repositionToolbar(); |
Yohei Yukawa | bafc908 | 2015-07-14 05:59:05 -0700 | [diff] [blame] | 162 | mPreviousViewPositionOnScreen[0] = mViewPositionOnScreen[0]; |
| 163 | mPreviousViewPositionOnScreen[1] = mViewPositionOnScreen[1]; |
| 164 | mPreviousViewRectOnScreen.set(mViewRectOnScreen); |
Abodunrinwa Toki | c107b0e | 2015-06-25 21:33:51 -0700 | [diff] [blame] | 165 | } |
Clara Bayarri | 838e36c | 2015-03-17 23:10:44 +0000 | [diff] [blame] | 166 | } |
| 167 | |
| 168 | private void repositionToolbar() { |
Yohei Yukawa | bafc908 | 2015-07-14 05:59:05 -0700 | [diff] [blame] | 169 | mContentRectOnScreen.set(mContentRect); |
Justin Klaassen | 6183b72 | 2016-04-26 20:19:07 -0700 | [diff] [blame] | 170 | |
| 171 | // Offset the content rect into screen coordinates, taking into account any transformations |
| 172 | // that may be applied to the originating view or its ancestors. |
| 173 | final ViewParent parent = mOriginatingView.getParent(); |
| 174 | if (parent instanceof ViewGroup) { |
| 175 | ((ViewGroup) parent).getChildVisibleRect( |
Abodunrinwa Toki | 4e7a120 | 2016-05-03 18:23:12 +0100 | [diff] [blame] | 176 | mOriginatingView, mContentRectOnScreen, |
| 177 | null /* offset */, true /* forceParentCheck */); |
Justin Klaassen | 6183b72 | 2016-04-26 20:19:07 -0700 | [diff] [blame] | 178 | mContentRectOnScreen.offset(mRootViewPositionOnScreen[0], mRootViewPositionOnScreen[1]); |
| 179 | } else { |
| 180 | mContentRectOnScreen.offset(mViewPositionOnScreen[0], mViewPositionOnScreen[1]); |
| 181 | } |
Abodunrinwa Toki | a8151e4 | 2015-05-06 18:57:06 +0100 | [diff] [blame] | 182 | |
| 183 | if (isContentRectWithinBounds()) { |
| 184 | mFloatingToolbarVisibilityHelper.setOutOfBounds(false); |
Abodunrinwa Toki | f444b5c | 2015-06-16 15:47:04 +0100 | [diff] [blame] | 185 | // Make sure that content rect is not out of the view's visible bounds. |
Yohei Yukawa | bafc908 | 2015-07-14 05:59:05 -0700 | [diff] [blame] | 186 | mContentRectOnScreen.set( |
| 187 | Math.max(mContentRectOnScreen.left, mViewRectOnScreen.left), |
| 188 | Math.max(mContentRectOnScreen.top, mViewRectOnScreen.top), |
| 189 | Math.min(mContentRectOnScreen.right, mViewRectOnScreen.right), |
| 190 | Math.min(mContentRectOnScreen.bottom, |
| 191 | mViewRectOnScreen.bottom + mBottomAllowance)); |
Abodunrinwa Toki | f444b5c | 2015-06-16 15:47:04 +0100 | [diff] [blame] | 192 | |
Yohei Yukawa | bafc908 | 2015-07-14 05:59:05 -0700 | [diff] [blame] | 193 | if (!mContentRectOnScreen.equals(mPreviousContentRectOnScreen)) { |
Abodunrinwa Toki | f444b5c | 2015-06-16 15:47:04 +0100 | [diff] [blame] | 194 | // Content rect is moving. |
| 195 | mOriginatingView.removeCallbacks(mMovingOff); |
| 196 | mFloatingToolbarVisibilityHelper.setMoving(true); |
| 197 | mOriginatingView.postDelayed(mMovingOff, MOVING_HIDE_DELAY); |
| 198 | |
Yohei Yukawa | bafc908 | 2015-07-14 05:59:05 -0700 | [diff] [blame] | 199 | mFloatingToolbar.setContentRect(mContentRectOnScreen); |
Abodunrinwa Toki | f444b5c | 2015-06-16 15:47:04 +0100 | [diff] [blame] | 200 | mFloatingToolbar.updateLayout(); |
| 201 | } |
Abodunrinwa Toki | a8151e4 | 2015-05-06 18:57:06 +0100 | [diff] [blame] | 202 | } else { |
| 203 | mFloatingToolbarVisibilityHelper.setOutOfBounds(true); |
Yohei Yukawa | bafc908 | 2015-07-14 05:59:05 -0700 | [diff] [blame] | 204 | mContentRectOnScreen.setEmpty(); |
Abodunrinwa Toki | a8151e4 | 2015-05-06 18:57:06 +0100 | [diff] [blame] | 205 | } |
Abodunrinwa Toki | b9acbe4 | 2015-09-16 19:47:38 +0100 | [diff] [blame] | 206 | mFloatingToolbarVisibilityHelper.updateToolbarVisibility(); |
Abodunrinwa Toki | f444b5c | 2015-06-16 15:47:04 +0100 | [diff] [blame] | 207 | |
Yohei Yukawa | bafc908 | 2015-07-14 05:59:05 -0700 | [diff] [blame] | 208 | mPreviousContentRectOnScreen.set(mContentRectOnScreen); |
Abodunrinwa Toki | a8151e4 | 2015-05-06 18:57:06 +0100 | [diff] [blame] | 209 | } |
| 210 | |
| 211 | private boolean isContentRectWithinBounds() { |
Abodunrinwa Toki | 49f1a76 | 2016-08-03 20:07:15 -0700 | [diff] [blame] | 212 | mContext.getSystemService(WindowManager.class) |
| 213 | .getDefaultDisplay().getRealSize(mDisplaySize); |
| 214 | mScreenRect.set(0, 0, mDisplaySize.x, mDisplaySize.y); |
Abodunrinwa Toki | a8151e4 | 2015-05-06 18:57:06 +0100 | [diff] [blame] | 215 | |
Clara Bayarri | f95ed10 | 2015-08-12 19:46:47 +0100 | [diff] [blame] | 216 | return intersectsClosed(mContentRectOnScreen, mScreenRect) |
| 217 | && intersectsClosed(mContentRectOnScreen, mViewRectOnScreen); |
| 218 | } |
| 219 | |
| 220 | /* |
| 221 | * Same as Rect.intersects, but includes cases where the rectangles touch. |
| 222 | */ |
| 223 | private static boolean intersectsClosed(Rect a, Rect b) { |
| 224 | return a.left <= b.right && b.left <= a.right |
| 225 | && a.top <= b.bottom && b.top <= a.bottom; |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 226 | } |
| 227 | |
| 228 | @Override |
Abodunrinwa Toki | 9e21128 | 2015-06-05 02:46:57 +0100 | [diff] [blame] | 229 | public void hide(long duration) { |
Abodunrinwa Toki | 9e21128 | 2015-06-05 02:46:57 +0100 | [diff] [blame] | 230 | if (duration == ActionMode.DEFAULT_HIDE_DURATION) { |
| 231 | duration = ViewConfiguration.getDefaultActionModeHideDuration(); |
| 232 | } |
| 233 | duration = Math.min(MAX_HIDE_DURATION, duration); |
| 234 | mOriginatingView.removeCallbacks(mHideOff); |
| 235 | if (duration <= 0) { |
| 236 | mHideOff.run(); |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 237 | } else { |
Abodunrinwa Toki | 9e21128 | 2015-06-05 02:46:57 +0100 | [diff] [blame] | 238 | mFloatingToolbarVisibilityHelper.setHideRequested(true); |
Abodunrinwa Toki | f444b5c | 2015-06-16 15:47:04 +0100 | [diff] [blame] | 239 | mFloatingToolbarVisibilityHelper.updateToolbarVisibility(); |
Abodunrinwa Toki | 9e21128 | 2015-06-05 02:46:57 +0100 | [diff] [blame] | 240 | mOriginatingView.postDelayed(mHideOff, duration); |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 241 | } |
| 242 | } |
| 243 | |
Clara Bayarri | 838e36c | 2015-03-17 23:10:44 +0000 | [diff] [blame] | 244 | @Override |
Abodunrinwa Toki | 972ab4f | 2015-06-17 18:04:23 +0100 | [diff] [blame] | 245 | public void onWindowFocusChanged(boolean hasWindowFocus) { |
Abodunrinwa Toki | 972ab4f | 2015-06-17 18:04:23 +0100 | [diff] [blame] | 246 | mFloatingToolbarVisibilityHelper.setWindowFocused(hasWindowFocus); |
| 247 | mFloatingToolbarVisibilityHelper.updateToolbarVisibility(); |
| 248 | } |
| 249 | |
| 250 | @Override |
Clara Bayarri | 838e36c | 2015-03-17 23:10:44 +0000 | [diff] [blame] | 251 | public void finish() { |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 252 | reset(); |
Clara Bayarri | 838e36c | 2015-03-17 23:10:44 +0000 | [diff] [blame] | 253 | mCallback.onDestroyActionMode(this); |
| 254 | } |
| 255 | |
| 256 | @Override |
| 257 | public Menu getMenu() { |
| 258 | return mMenu; |
| 259 | } |
| 260 | |
| 261 | @Override |
| 262 | public CharSequence getTitle() { |
| 263 | return null; |
| 264 | } |
| 265 | |
| 266 | @Override |
| 267 | public CharSequence getSubtitle() { |
| 268 | return null; |
| 269 | } |
| 270 | |
| 271 | @Override |
| 272 | public View getCustomView() { |
| 273 | return null; |
| 274 | } |
| 275 | |
| 276 | @Override |
| 277 | public MenuInflater getMenuInflater() { |
| 278 | return new MenuInflater(mContext); |
| 279 | } |
| 280 | |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 281 | private void reset() { |
Abodunrinwa Toki | 972ab4f | 2015-06-17 18:04:23 +0100 | [diff] [blame] | 282 | mFloatingToolbar.dismiss(); |
Abodunrinwa Toki | f444b5c | 2015-06-16 15:47:04 +0100 | [diff] [blame] | 283 | mFloatingToolbarVisibilityHelper.deactivate(); |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 284 | mOriginatingView.removeCallbacks(mMovingOff); |
Abodunrinwa Toki | 9e21128 | 2015-06-05 02:46:57 +0100 | [diff] [blame] | 285 | mOriginatingView.removeCallbacks(mHideOff); |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 286 | } |
| 287 | |
Abodunrinwa Toki | d1eb19c | 2016-07-21 11:10:19 +0100 | [diff] [blame] | 288 | private boolean isViewStillActive() { |
| 289 | return mOriginatingView.getWindowVisibility() == View.VISIBLE |
| 290 | && mOriginatingView.isShown(); |
| 291 | } |
| 292 | |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 293 | /** |
Abodunrinwa Toki | f444b5c | 2015-06-16 15:47:04 +0100 | [diff] [blame] | 294 | * A helper for showing/hiding the floating toolbar depending on certain states. |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 295 | */ |
| 296 | private static final class FloatingToolbarVisibilityHelper { |
| 297 | |
Abodunrinwa Toki | 4a7aeb3 | 2017-07-13 02:06:56 +0100 | [diff] [blame] | 298 | private static final long MIN_SHOW_DURATION_FOR_MOVE_HIDE = 500; |
| 299 | |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 300 | private final FloatingToolbar mToolbar; |
| 301 | |
Abodunrinwa Toki | 9e21128 | 2015-06-05 02:46:57 +0100 | [diff] [blame] | 302 | private boolean mHideRequested; |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 303 | private boolean mMoving; |
| 304 | private boolean mOutOfBounds; |
Abodunrinwa Toki | 972ab4f | 2015-06-17 18:04:23 +0100 | [diff] [blame] | 305 | private boolean mWindowFocused = true; |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 306 | |
Abodunrinwa Toki | f444b5c | 2015-06-16 15:47:04 +0100 | [diff] [blame] | 307 | private boolean mActive; |
| 308 | |
Abodunrinwa Toki | 4a7aeb3 | 2017-07-13 02:06:56 +0100 | [diff] [blame] | 309 | private long mLastShowTime; |
| 310 | |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 311 | public FloatingToolbarVisibilityHelper(FloatingToolbar toolbar) { |
| 312 | mToolbar = Preconditions.checkNotNull(toolbar); |
| 313 | } |
| 314 | |
Abodunrinwa Toki | f444b5c | 2015-06-16 15:47:04 +0100 | [diff] [blame] | 315 | public void activate() { |
| 316 | mHideRequested = false; |
| 317 | mMoving = false; |
| 318 | mOutOfBounds = false; |
Abodunrinwa Toki | 972ab4f | 2015-06-17 18:04:23 +0100 | [diff] [blame] | 319 | mWindowFocused = true; |
Abodunrinwa Toki | f444b5c | 2015-06-16 15:47:04 +0100 | [diff] [blame] | 320 | |
| 321 | mActive = true; |
| 322 | } |
| 323 | |
| 324 | public void deactivate() { |
| 325 | mActive = false; |
| 326 | mToolbar.dismiss(); |
| 327 | } |
| 328 | |
Abodunrinwa Toki | 9e21128 | 2015-06-05 02:46:57 +0100 | [diff] [blame] | 329 | public void setHideRequested(boolean hide) { |
| 330 | mHideRequested = hide; |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 331 | } |
| 332 | |
| 333 | public void setMoving(boolean moving) { |
Abodunrinwa Toki | 4a7aeb3 | 2017-07-13 02:06:56 +0100 | [diff] [blame] | 334 | // Avoid unintended flickering by allowing the toolbar to show long enough before |
| 335 | // triggering the 'moving' flag - which signals a hide. |
| 336 | final boolean showingLongEnough = |
| 337 | System.currentTimeMillis() - mLastShowTime > MIN_SHOW_DURATION_FOR_MOVE_HIDE; |
| 338 | if (!moving || showingLongEnough) { |
| 339 | mMoving = moving; |
| 340 | } |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 341 | } |
| 342 | |
| 343 | public void setOutOfBounds(boolean outOfBounds) { |
| 344 | mOutOfBounds = outOfBounds; |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 345 | } |
| 346 | |
Abodunrinwa Toki | 972ab4f | 2015-06-17 18:04:23 +0100 | [diff] [blame] | 347 | public void setWindowFocused(boolean windowFocused) { |
| 348 | mWindowFocused = windowFocused; |
| 349 | } |
| 350 | |
Abodunrinwa Toki | f444b5c | 2015-06-16 15:47:04 +0100 | [diff] [blame] | 351 | public void updateToolbarVisibility() { |
| 352 | if (!mActive) { |
| 353 | return; |
| 354 | } |
| 355 | |
Abodunrinwa Toki | 972ab4f | 2015-06-17 18:04:23 +0100 | [diff] [blame] | 356 | if (mHideRequested || mMoving || mOutOfBounds || !mWindowFocused) { |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 357 | mToolbar.hide(); |
Abodunrinwa Toki | f444b5c | 2015-06-16 15:47:04 +0100 | [diff] [blame] | 358 | } else { |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 359 | mToolbar.show(); |
Abodunrinwa Toki | 4a7aeb3 | 2017-07-13 02:06:56 +0100 | [diff] [blame] | 360 | mLastShowTime = System.currentTimeMillis(); |
Abodunrinwa Toki | fd3a3a1 | 2015-05-05 20:04:34 +0100 | [diff] [blame] | 361 | } |
| 362 | } |
| 363 | } |
Clara Bayarri | 838e36c | 2015-03-17 23:10:44 +0000 | [diff] [blame] | 364 | } |