1 /* 2 * Copyright (C) 2018 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.systemui.recents; 18 19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 20 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; 21 22 import static com.android.systemui.Prefs.Key.DISMISSED_RECENTS_SWIPE_UP_ONBOARDING_COUNT; 23 import static com.android.systemui.Prefs.Key.HAS_DISMISSED_RECENTS_QUICK_SCRUB_ONBOARDING_ONCE; 24 import static com.android.systemui.Prefs.Key.HAS_SEEN_RECENTS_QUICK_SCRUB_ONBOARDING; 25 import static com.android.systemui.Prefs.Key.HAS_SEEN_RECENTS_SWIPE_UP_ONBOARDING; 26 import static com.android.systemui.Prefs.Key.OVERVIEW_OPENED_COUNT; 27 import static com.android.systemui.Prefs.Key.OVERVIEW_OPENED_FROM_HOME_COUNT; 28 import static com.android.systemui.shared.system.LauncherEventUtil.DISMISS; 29 import static com.android.systemui.shared.system.LauncherEventUtil.RECENTS_QUICK_SCRUB_ONBOARDING_TIP; 30 import static com.android.systemui.shared.system.LauncherEventUtil.RECENTS_SWIPE_UP_ONBOARDING_TIP; 31 import static com.android.systemui.shared.system.LauncherEventUtil.VISIBLE; 32 33 import android.annotation.StringRes; 34 import android.annotation.TargetApi; 35 import android.app.ActivityManager; 36 import android.content.BroadcastReceiver; 37 import android.content.ComponentName; 38 import android.content.Context; 39 import android.content.Intent; 40 import android.content.IntentFilter; 41 import android.content.res.Configuration; 42 import android.content.res.Resources; 43 import android.graphics.CornerPathEffect; 44 import android.graphics.Paint; 45 import android.graphics.PixelFormat; 46 import android.graphics.drawable.ShapeDrawable; 47 import android.os.Build; 48 import android.os.RemoteException; 49 import android.os.SystemProperties; 50 import android.os.UserManager; 51 import android.util.TypedValue; 52 import android.view.Gravity; 53 import android.view.LayoutInflater; 54 import android.view.View; 55 import android.view.ViewGroup; 56 import android.view.WindowManager; 57 import android.view.animation.AccelerateInterpolator; 58 import android.view.animation.DecelerateInterpolator; 59 import android.widget.ImageView; 60 import android.widget.TextView; 61 62 import com.android.systemui.Dependency; 63 import com.android.systemui.Prefs; 64 import com.android.systemui.R; 65 import com.android.systemui.broadcast.BroadcastDispatcher; 66 import com.android.systemui.shared.recents.IOverviewProxy; 67 import com.android.systemui.shared.system.ActivityManagerWrapper; 68 import com.android.systemui.shared.system.QuickStepContract; 69 import com.android.systemui.shared.system.TaskStackChangeListener; 70 71 import java.io.PrintWriter; 72 import java.util.Collections; 73 import java.util.HashSet; 74 import java.util.Set; 75 76 /** 77 * Shows onboarding for the new recents interaction in P (codenamed quickstep). 78 */ 79 @TargetApi(Build.VERSION_CODES.P) 80 public class RecentsOnboarding { 81 82 private static final String TAG = "RecentsOnboarding"; 83 private static final boolean RESET_PREFS_FOR_DEBUG = false; 84 private static final boolean ONBOARDING_ENABLED = true; 85 private static final long SHOW_DELAY_MS = 500; 86 private static final long SHOW_DURATION_MS = 300; 87 private static final long HIDE_DURATION_MS = 100; 88 // Show swipe-up tips after opening overview from home this number of times. 89 private static final int SWIPE_UP_SHOW_ON_OVERVIEW_OPENED_FROM_HOME_COUNT = 3; 90 // Show quick scrub tips after opening overview this number of times. 91 private static final int QUICK_SCRUB_SHOW_ON_OVERVIEW_OPENED_COUNT = 10; 92 // Maximum number of dismissals while still showing swipe-up tips. 93 private static final int MAX_DISMISSAL_ON_SWIPE_UP_SHOW = 2; 94 // Number of dismissals for swipe-up tips when exponential backoff starts. 95 private static final int BACKOFF_DISMISSAL_COUNT_ON_SWIPE_UP_SHOW = 1; 96 // After explicitly dismissing for <= BACKOFF_DISMISSAL_COUNT_ON_SWIPE_UP_SHOW times, show again 97 // after launching this number of apps for swipe-up tips. 98 private static final int SWIPE_UP_SHOW_ON_APP_LAUNCH_AFTER_DISMISS = 5; 99 // After explicitly dismissing for > BACKOFF_DISMISSAL_COUNT_ON_SWIPE_UP_SHOW but 100 // <= MAX_DISMISSAL_ON_SWIPE_UP_SHOW times, show again after launching this number of apps for 101 // swipe-up tips. 102 private static final int SWIPE_UP_SHOW_ON_APP_LAUNCH_AFTER_DISMISS_BACK_OFF = 40; 103 104 private final Context mContext; 105 private final WindowManager mWindowManager; 106 private final OverviewProxyService mOverviewProxyService; 107 private Set<String> mBlacklistedPackages; 108 private final View mLayout; 109 private final TextView mTextView; 110 private final ImageView mDismissView; 111 private final View mArrowView; 112 private final int mOnboardingToastColor; 113 private final int mOnboardingToastArrowRadius; 114 private int mNavBarHeight; 115 private int mNavBarMode = NAV_BAR_MODE_3BUTTON; 116 117 private boolean mOverviewProxyListenerRegistered; 118 private boolean mTaskListenerRegistered; 119 private boolean mLayoutAttachedToWindow; 120 private boolean mHasDismissedSwipeUpTip; 121 private boolean mHasDismissedQuickScrubTip; 122 private int mNumAppsLaunchedSinceSwipeUpTipDismiss; 123 private int mOverviewOpenedCountSinceQuickScrubTipDismiss; 124 125 private final TaskStackChangeListener mTaskListener = new TaskStackChangeListener() { 126 private String mLastPackageName; 127 128 @Override 129 public void onTaskCreated(int taskId, ComponentName componentName) { 130 onAppLaunch(); 131 } 132 133 @Override 134 public void onTaskMovedToFront(int taskId) { 135 onAppLaunch(); 136 } 137 138 private void onAppLaunch() { 139 ActivityManager.RunningTaskInfo info = ActivityManagerWrapper.getInstance() 140 .getRunningTask(); 141 if (info == null) { 142 return; 143 } 144 if (mBlacklistedPackages.contains(info.baseActivity.getPackageName())) { 145 hide(true); 146 return; 147 } 148 if (info.baseActivity.getPackageName().equals(mLastPackageName)) { 149 return; 150 } 151 mLastPackageName = info.baseActivity.getPackageName(); 152 int activityType = info.configuration.windowConfiguration.getActivityType(); 153 if (activityType == ACTIVITY_TYPE_STANDARD) { 154 boolean alreadySeenSwipeUpOnboarding = hasSeenSwipeUpOnboarding(); 155 boolean alreadySeenQuickScrubsOnboarding = hasSeenQuickScrubOnboarding(); 156 if (alreadySeenSwipeUpOnboarding && alreadySeenQuickScrubsOnboarding) { 157 onDisconnectedFromLauncher(); 158 return; 159 } 160 161 boolean shouldLog = false; 162 if (!alreadySeenSwipeUpOnboarding) { 163 if (getOpenedOverviewFromHomeCount() 164 >= SWIPE_UP_SHOW_ON_OVERVIEW_OPENED_FROM_HOME_COUNT) { 165 if (mHasDismissedSwipeUpTip) { 166 int hasDimissedSwipeUpOnboardingCount = 167 getDismissedSwipeUpOnboardingCount(); 168 if (hasDimissedSwipeUpOnboardingCount 169 > MAX_DISMISSAL_ON_SWIPE_UP_SHOW) { 170 return; 171 } 172 final int swipeUpShowOnAppLauncherAfterDismiss = 173 hasDimissedSwipeUpOnboardingCount 174 <= BACKOFF_DISMISSAL_COUNT_ON_SWIPE_UP_SHOW 175 ? SWIPE_UP_SHOW_ON_APP_LAUNCH_AFTER_DISMISS 176 : SWIPE_UP_SHOW_ON_APP_LAUNCH_AFTER_DISMISS_BACK_OFF; 177 mNumAppsLaunchedSinceSwipeUpTipDismiss++; 178 if (mNumAppsLaunchedSinceSwipeUpTipDismiss 179 >= swipeUpShowOnAppLauncherAfterDismiss) { 180 mNumAppsLaunchedSinceSwipeUpTipDismiss = 0; 181 shouldLog = show(R.string.recents_swipe_up_onboarding); 182 } 183 } else { 184 shouldLog = show(R.string.recents_swipe_up_onboarding); 185 } 186 if (shouldLog) { 187 notifyOnTip(VISIBLE, RECENTS_SWIPE_UP_ONBOARDING_TIP); 188 } 189 } 190 } else { 191 if (getOpenedOverviewCount() >= QUICK_SCRUB_SHOW_ON_OVERVIEW_OPENED_COUNT) { 192 if (mHasDismissedQuickScrubTip) { 193 if (mOverviewOpenedCountSinceQuickScrubTipDismiss 194 >= QUICK_SCRUB_SHOW_ON_OVERVIEW_OPENED_COUNT) { 195 mOverviewOpenedCountSinceQuickScrubTipDismiss = 0; 196 shouldLog = show(R.string.recents_quick_scrub_onboarding); 197 } 198 } else { 199 shouldLog = show(R.string.recents_quick_scrub_onboarding); 200 } 201 if (shouldLog) { 202 notifyOnTip(VISIBLE, RECENTS_QUICK_SCRUB_ONBOARDING_TIP); 203 } 204 } 205 206 } 207 } else { 208 hide(false); 209 } 210 } 211 }; 212 213 private OverviewProxyService.OverviewProxyListener mOverviewProxyListener = 214 new OverviewProxyService.OverviewProxyListener() { 215 @Override 216 public void onOverviewShown(boolean fromHome) { 217 if (!hasSeenSwipeUpOnboarding() && !fromHome) { 218 setHasSeenSwipeUpOnboarding(true); 219 } 220 if (fromHome) { 221 incrementOpenedOverviewFromHomeCount(); 222 } 223 incrementOpenedOverviewCount(); 224 225 if (getOpenedOverviewCount() >= QUICK_SCRUB_SHOW_ON_OVERVIEW_OPENED_COUNT) { 226 if (mHasDismissedQuickScrubTip) { 227 mOverviewOpenedCountSinceQuickScrubTipDismiss++; 228 } 229 } 230 } 231 232 @Override 233 public void onQuickStepStarted() { 234 hide(true); 235 } 236 237 @Override 238 public void onQuickScrubStarted() { 239 boolean alreadySeenQuickScrubsOnboarding = hasSeenQuickScrubOnboarding(); 240 if (!alreadySeenQuickScrubsOnboarding) { 241 setHasSeenQuickScrubOnboarding(true); 242 } 243 } 244 }; 245 246 private final View.OnAttachStateChangeListener mOnAttachStateChangeListener 247 = new View.OnAttachStateChangeListener() { 248 249 private final BroadcastDispatcher mBroadcastDispatcher = Dependency.get( 250 BroadcastDispatcher.class); 251 252 @Override 253 public void onViewAttachedToWindow(View view) { 254 if (view == mLayout) { 255 mBroadcastDispatcher.registerReceiver(mReceiver, 256 new IntentFilter(Intent.ACTION_SCREEN_OFF)); 257 mLayoutAttachedToWindow = true; 258 if (view.getTag().equals(R.string.recents_swipe_up_onboarding)) { 259 mHasDismissedSwipeUpTip = false; 260 } else { 261 mHasDismissedQuickScrubTip = false; 262 } 263 } 264 } 265 266 @Override 267 public void onViewDetachedFromWindow(View view) { 268 if (view == mLayout) { 269 mLayoutAttachedToWindow = false; 270 if (view.getTag().equals(R.string.recents_quick_scrub_onboarding)) { 271 mHasDismissedQuickScrubTip = true; 272 if (hasDismissedQuickScrubOnboardingOnce()) { 273 // If user dismisses the quick scrub tip twice, we consider user has seen it 274 // and do not show it again. 275 setHasSeenQuickScrubOnboarding(true); 276 } else { 277 setHasDismissedQuickScrubOnboardingOnce(true); 278 } 279 mOverviewOpenedCountSinceQuickScrubTipDismiss = 0; 280 } 281 mBroadcastDispatcher.unregisterReceiver(mReceiver); 282 } 283 } 284 }; 285 RecentsOnboarding(Context context, OverviewProxyService overviewProxyService)286 public RecentsOnboarding(Context context, OverviewProxyService overviewProxyService) { 287 mContext = context; 288 mOverviewProxyService = overviewProxyService; 289 final Resources res = context.getResources(); 290 mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); 291 mBlacklistedPackages = new HashSet<>(); 292 Collections.addAll(mBlacklistedPackages, res.getStringArray( 293 R.array.recents_onboarding_blacklisted_packages)); 294 mLayout = LayoutInflater.from(mContext).inflate(R.layout.recents_onboarding, null); 295 mTextView = mLayout.findViewById(R.id.onboarding_text); 296 mDismissView = mLayout.findViewById(R.id.dismiss); 297 mArrowView = mLayout.findViewById(R.id.arrow); 298 299 TypedValue typedValue = new TypedValue(); 300 context.getTheme().resolveAttribute(android.R.attr.colorAccent, typedValue, true); 301 mOnboardingToastColor = res.getColor(typedValue.resourceId); 302 mOnboardingToastArrowRadius = res.getDimensionPixelSize( 303 R.dimen.recents_onboarding_toast_arrow_corner_radius); 304 305 mLayout.addOnAttachStateChangeListener(mOnAttachStateChangeListener); 306 mDismissView.setOnClickListener(v -> { 307 hide(true); 308 if (v.getTag().equals(R.string.recents_swipe_up_onboarding)) { 309 mHasDismissedSwipeUpTip = true; 310 mNumAppsLaunchedSinceSwipeUpTipDismiss = 0; 311 setDismissedSwipeUpOnboardingCount(getDismissedSwipeUpOnboardingCount() + 1); 312 if (getDismissedSwipeUpOnboardingCount() > MAX_DISMISSAL_ON_SWIPE_UP_SHOW) { 313 setHasSeenSwipeUpOnboarding(true); 314 } 315 notifyOnTip(DISMISS, RECENTS_SWIPE_UP_ONBOARDING_TIP); 316 } else { 317 notifyOnTip(DISMISS, RECENTS_QUICK_SCRUB_ONBOARDING_TIP); 318 } 319 }); 320 321 ViewGroup.LayoutParams arrowLp = mArrowView.getLayoutParams(); 322 ShapeDrawable arrowDrawable = new ShapeDrawable(TriangleShape.create( 323 arrowLp.width, arrowLp.height, false)); 324 Paint arrowPaint = arrowDrawable.getPaint(); 325 arrowPaint.setColor(mOnboardingToastColor); 326 // The corner path effect won't be reflected in the shadow, but shouldn't be noticeable. 327 arrowPaint.setPathEffect(new CornerPathEffect(mOnboardingToastArrowRadius)); 328 mArrowView.setBackground(arrowDrawable); 329 330 if (RESET_PREFS_FOR_DEBUG) { 331 setHasSeenSwipeUpOnboarding(false); 332 setHasSeenQuickScrubOnboarding(false); 333 setDismissedSwipeUpOnboardingCount(0); 334 setHasDismissedQuickScrubOnboardingOnce(false); 335 setOpenedOverviewCount(0); 336 setOpenedOverviewFromHomeCount(0); 337 } 338 } 339 notifyOnTip(int action, int target)340 private void notifyOnTip(int action, int target) { 341 try { 342 IOverviewProxy overviewProxy = mOverviewProxyService.getProxy(); 343 if (overviewProxy != null) { 344 overviewProxy.onTip(action, target); 345 } 346 } catch (RemoteException e) { 347 } 348 } 349 onNavigationModeChanged(int mode)350 public void onNavigationModeChanged(int mode) { 351 mNavBarMode = mode; 352 } 353 onConnectedToLauncher()354 public void onConnectedToLauncher() { 355 if (!ONBOARDING_ENABLED || QuickStepContract.isGesturalMode(mNavBarMode)) { 356 return; 357 } 358 359 if (hasSeenSwipeUpOnboarding() && hasSeenQuickScrubOnboarding()) { 360 return; 361 } 362 363 if (!mOverviewProxyListenerRegistered) { 364 mOverviewProxyService.addCallback(mOverviewProxyListener); 365 mOverviewProxyListenerRegistered = true; 366 } 367 if (!mTaskListenerRegistered) { 368 ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskListener); 369 mTaskListenerRegistered = true; 370 } 371 } 372 onDisconnectedFromLauncher()373 public void onDisconnectedFromLauncher() { 374 375 if (mOverviewProxyListenerRegistered) { 376 mOverviewProxyService.removeCallback(mOverviewProxyListener); 377 mOverviewProxyListenerRegistered = false; 378 } 379 if (mTaskListenerRegistered) { 380 ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskListener); 381 mTaskListenerRegistered = false; 382 } 383 384 mHasDismissedSwipeUpTip = false; 385 mHasDismissedQuickScrubTip = false; 386 mNumAppsLaunchedSinceSwipeUpTipDismiss = 0; 387 mOverviewOpenedCountSinceQuickScrubTipDismiss = 0; 388 hide(true); 389 } 390 onConfigurationChanged(Configuration newConfiguration)391 public void onConfigurationChanged(Configuration newConfiguration) { 392 if (newConfiguration.orientation != Configuration.ORIENTATION_PORTRAIT) { 393 hide(false); 394 } 395 } 396 show(@tringRes int stringRes)397 public boolean show(@StringRes int stringRes) { 398 if (!shouldShow()) { 399 return false; 400 } 401 mDismissView.setTag(stringRes); 402 mLayout.setTag(stringRes); 403 mTextView.setText(stringRes); 404 // Only show in portrait. 405 int orientation = mContext.getResources().getConfiguration().orientation; 406 if (!mLayoutAttachedToWindow && orientation == Configuration.ORIENTATION_PORTRAIT) { 407 mLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE); 408 409 final int gravity; 410 final int x; 411 if (stringRes == R.string.recents_swipe_up_onboarding) { 412 gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; 413 x = 0; 414 } else { 415 int layoutDirection = 416 mContext.getResources().getConfiguration().getLayoutDirection(); 417 gravity = Gravity.BOTTOM | (layoutDirection == View.LAYOUT_DIRECTION_LTR 418 ? Gravity.LEFT : Gravity.RIGHT); 419 x = mContext.getResources().getDimensionPixelSize( 420 R.dimen.recents_quick_scrub_onboarding_margin_start); 421 } 422 mWindowManager.addView(mLayout, getWindowLayoutParams(gravity, x)); 423 mLayout.setAlpha(0); 424 mLayout.animate() 425 .alpha(1f) 426 .withLayer() 427 .setStartDelay(SHOW_DELAY_MS) 428 .setDuration(SHOW_DURATION_MS) 429 .setInterpolator(new DecelerateInterpolator()) 430 .start(); 431 return true; 432 } 433 return false; 434 } 435 436 /** 437 * @return True unless setprop has been set to false, we're in demo mode, or running tests in 438 * automation. 439 */ shouldShow()440 private boolean shouldShow() { 441 return SystemProperties.getBoolean("persist.quickstep.onboarding.enabled", 442 !(mContext.getSystemService(UserManager.class)).isDemoUser() && 443 !ActivityManager.isRunningInTestHarness()); 444 } 445 hide(boolean animate)446 public void hide(boolean animate) { 447 if (mLayoutAttachedToWindow) { 448 if (animate) { 449 mLayout.animate() 450 .alpha(0f) 451 .withLayer() 452 .setStartDelay(0) 453 .setDuration(HIDE_DURATION_MS) 454 .setInterpolator(new AccelerateInterpolator()) 455 .withEndAction(() -> mWindowManager.removeViewImmediate(mLayout)) 456 .start(); 457 } else { 458 mLayout.animate().cancel(); 459 mWindowManager.removeViewImmediate(mLayout); 460 } 461 } 462 } 463 setNavBarHeight(int navBarHeight)464 public void setNavBarHeight(int navBarHeight) { 465 mNavBarHeight = navBarHeight; 466 } 467 dump(PrintWriter pw)468 public void dump(PrintWriter pw) { 469 pw.println("RecentsOnboarding {"); 470 pw.println(" mTaskListenerRegistered: " + mTaskListenerRegistered); 471 pw.println(" mOverviewProxyListenerRegistered: " + mOverviewProxyListenerRegistered); 472 pw.println(" mLayoutAttachedToWindow: " + mLayoutAttachedToWindow); 473 pw.println(" mHasDismissedSwipeUpTip: " + mHasDismissedSwipeUpTip); 474 pw.println(" mHasDismissedQuickScrubTip: " + mHasDismissedQuickScrubTip); 475 pw.println(" mNumAppsLaunchedSinceSwipeUpTipDismiss: " 476 + mNumAppsLaunchedSinceSwipeUpTipDismiss); 477 pw.println(" hasSeenSwipeUpOnboarding: " + hasSeenSwipeUpOnboarding()); 478 pw.println(" hasSeenQuickScrubOnboarding: " + hasSeenQuickScrubOnboarding()); 479 pw.println(" getDismissedSwipeUpOnboardingCount: " 480 + getDismissedSwipeUpOnboardingCount()); 481 pw.println(" hasDismissedQuickScrubOnboardingOnce: " 482 + hasDismissedQuickScrubOnboardingOnce()); 483 pw.println(" getOpenedOverviewCount: " + getOpenedOverviewCount()); 484 pw.println(" getOpenedOverviewFromHomeCount: " + getOpenedOverviewFromHomeCount()); 485 pw.println(" }"); 486 } 487 getWindowLayoutParams(int gravity, int x)488 private WindowManager.LayoutParams getWindowLayoutParams(int gravity, int x) { 489 int flags = WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS 490 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; 491 final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 492 ViewGroup.LayoutParams.WRAP_CONTENT, 493 ViewGroup.LayoutParams.WRAP_CONTENT, 494 x, -mNavBarHeight / 2, 495 WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, 496 flags, 497 PixelFormat.TRANSLUCENT); 498 lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; 499 lp.setTitle("RecentsOnboarding"); 500 lp.gravity = gravity; 501 return lp; 502 } 503 hasSeenSwipeUpOnboarding()504 private boolean hasSeenSwipeUpOnboarding() { 505 return Prefs.getBoolean(mContext, HAS_SEEN_RECENTS_SWIPE_UP_ONBOARDING, false); 506 } 507 setHasSeenSwipeUpOnboarding(boolean hasSeenSwipeUpOnboarding)508 private void setHasSeenSwipeUpOnboarding(boolean hasSeenSwipeUpOnboarding) { 509 Prefs.putBoolean(mContext, HAS_SEEN_RECENTS_SWIPE_UP_ONBOARDING, hasSeenSwipeUpOnboarding); 510 if (hasSeenSwipeUpOnboarding && hasSeenQuickScrubOnboarding()) { 511 onDisconnectedFromLauncher(); 512 } 513 } 514 hasSeenQuickScrubOnboarding()515 private boolean hasSeenQuickScrubOnboarding() { 516 return Prefs.getBoolean(mContext, HAS_SEEN_RECENTS_QUICK_SCRUB_ONBOARDING, false); 517 } 518 setHasSeenQuickScrubOnboarding(boolean hasSeenQuickScrubOnboarding)519 private void setHasSeenQuickScrubOnboarding(boolean hasSeenQuickScrubOnboarding) { 520 Prefs.putBoolean(mContext, HAS_SEEN_RECENTS_QUICK_SCRUB_ONBOARDING, 521 hasSeenQuickScrubOnboarding); 522 if (hasSeenQuickScrubOnboarding && hasSeenSwipeUpOnboarding()) { 523 onDisconnectedFromLauncher(); 524 } 525 } 526 getDismissedSwipeUpOnboardingCount()527 private int getDismissedSwipeUpOnboardingCount() { 528 return Prefs.getInt(mContext, DISMISSED_RECENTS_SWIPE_UP_ONBOARDING_COUNT, 0); 529 } 530 setDismissedSwipeUpOnboardingCount(int dismissedSwipeUpOnboardingCount)531 private void setDismissedSwipeUpOnboardingCount(int dismissedSwipeUpOnboardingCount) { 532 Prefs.putInt(mContext, DISMISSED_RECENTS_SWIPE_UP_ONBOARDING_COUNT, 533 dismissedSwipeUpOnboardingCount); 534 } 535 hasDismissedQuickScrubOnboardingOnce()536 private boolean hasDismissedQuickScrubOnboardingOnce() { 537 return Prefs.getBoolean(mContext, HAS_DISMISSED_RECENTS_QUICK_SCRUB_ONBOARDING_ONCE, false); 538 } 539 setHasDismissedQuickScrubOnboardingOnce( boolean hasDismissedQuickScrubOnboardingOnce)540 private void setHasDismissedQuickScrubOnboardingOnce( 541 boolean hasDismissedQuickScrubOnboardingOnce) { 542 Prefs.putBoolean(mContext, HAS_DISMISSED_RECENTS_QUICK_SCRUB_ONBOARDING_ONCE, 543 hasDismissedQuickScrubOnboardingOnce); 544 } 545 getOpenedOverviewFromHomeCount()546 private int getOpenedOverviewFromHomeCount() { 547 return Prefs.getInt(mContext, OVERVIEW_OPENED_FROM_HOME_COUNT, 0); 548 } 549 incrementOpenedOverviewFromHomeCount()550 private void incrementOpenedOverviewFromHomeCount() { 551 int openedOverviewFromHomeCount = getOpenedOverviewFromHomeCount(); 552 if (openedOverviewFromHomeCount >= SWIPE_UP_SHOW_ON_OVERVIEW_OPENED_FROM_HOME_COUNT) { 553 return; 554 } 555 setOpenedOverviewFromHomeCount(openedOverviewFromHomeCount + 1); 556 } 557 setOpenedOverviewFromHomeCount(int openedOverviewFromHomeCount)558 private void setOpenedOverviewFromHomeCount(int openedOverviewFromHomeCount) { 559 Prefs.putInt(mContext, OVERVIEW_OPENED_FROM_HOME_COUNT, openedOverviewFromHomeCount); 560 } 561 getOpenedOverviewCount()562 private int getOpenedOverviewCount() { 563 return Prefs.getInt(mContext, OVERVIEW_OPENED_COUNT, 0); 564 } 565 incrementOpenedOverviewCount()566 private void incrementOpenedOverviewCount() { 567 int openedOverviewCount = getOpenedOverviewCount(); 568 if (openedOverviewCount >= QUICK_SCRUB_SHOW_ON_OVERVIEW_OPENED_COUNT) { 569 return; 570 } 571 setOpenedOverviewCount(openedOverviewCount + 1); 572 } 573 setOpenedOverviewCount(int openedOverviewCount)574 private void setOpenedOverviewCount(int openedOverviewCount) { 575 Prefs.putInt(mContext, OVERVIEW_OPENED_COUNT, openedOverviewCount); 576 } 577 578 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 579 @Override 580 public void onReceive(Context context, Intent intent) { 581 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { 582 hide(false); 583 } 584 } 585 }; 586 } 587