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.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 21 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; 22 23 import static com.android.systemui.Prefs.Key.DISMISSED_RECENTS_SWIPE_UP_ONBOARDING_COUNT; 24 import static com.android.systemui.Prefs.Key.HAS_DISMISSED_RECENTS_QUICK_SCRUB_ONBOARDING_ONCE; 25 import static com.android.systemui.Prefs.Key.HAS_SEEN_RECENTS_QUICK_SCRUB_ONBOARDING; 26 import static com.android.systemui.Prefs.Key.HAS_SEEN_RECENTS_SWIPE_UP_ONBOARDING; 27 import static com.android.systemui.Prefs.Key.OVERVIEW_OPENED_COUNT; 28 import static com.android.systemui.Prefs.Key.OVERVIEW_OPENED_FROM_HOME_COUNT; 29 import static com.android.systemui.shared.system.LauncherEventUtil.DISMISS; 30 import static com.android.systemui.shared.system.LauncherEventUtil 31 .RECENTS_QUICK_SCRUB_ONBOARDING_TIP; 32 import static com.android.systemui.shared.system.LauncherEventUtil.RECENTS_SWIPE_UP_ONBOARDING_TIP; 33 import static com.android.systemui.shared.system.LauncherEventUtil.VISIBLE; 34 35 import android.annotation.StringRes; 36 import android.annotation.TargetApi; 37 import android.app.ActivityManager; 38 import android.content.BroadcastReceiver; 39 import android.content.ComponentName; 40 import android.content.Context; 41 import android.content.Intent; 42 import android.content.IntentFilter; 43 import android.content.res.Configuration; 44 import android.content.res.Resources; 45 import android.graphics.CornerPathEffect; 46 import android.graphics.Paint; 47 import android.graphics.PixelFormat; 48 import android.graphics.drawable.ShapeDrawable; 49 import android.os.Build; 50 import android.os.RemoteException; 51 import android.os.SystemProperties; 52 import android.os.UserManager; 53 import android.util.TypedValue; 54 import android.view.Gravity; 55 import android.view.LayoutInflater; 56 import android.view.View; 57 import android.view.ViewGroup; 58 import android.view.WindowManager; 59 import android.view.animation.AccelerateInterpolator; 60 import android.view.animation.DecelerateInterpolator; 61 import android.widget.ImageView; 62 import android.widget.TextView; 63 64 import com.android.systemui.Prefs; 65 import com.android.systemui.R; 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(ACTIVITY_TYPE_UNDEFINED /* ignoreActivityType */); 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 @Override 249 public void onViewAttachedToWindow(View view) { 250 if (view == mLayout) { 251 mContext.registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF)); 252 mLayoutAttachedToWindow = true; 253 if (view.getTag().equals(R.string.recents_swipe_up_onboarding)) { 254 mHasDismissedSwipeUpTip = false; 255 } else { 256 mHasDismissedQuickScrubTip = false; 257 } 258 } 259 } 260 261 @Override 262 public void onViewDetachedFromWindow(View view) { 263 if (view == mLayout) { 264 mLayoutAttachedToWindow = false; 265 if (view.getTag().equals(R.string.recents_quick_scrub_onboarding)) { 266 mHasDismissedQuickScrubTip = true; 267 if (hasDismissedQuickScrubOnboardingOnce()) { 268 // If user dismisses the quick scrub tip twice, we consider user has seen it 269 // and do not show it again. 270 setHasSeenQuickScrubOnboarding(true); 271 } else { 272 setHasDismissedQuickScrubOnboardingOnce(true); 273 } 274 mOverviewOpenedCountSinceQuickScrubTipDismiss = 0; 275 } 276 mContext.unregisterReceiver(mReceiver); 277 } 278 } 279 }; 280 RecentsOnboarding(Context context, OverviewProxyService overviewProxyService)281 public RecentsOnboarding(Context context, OverviewProxyService overviewProxyService) { 282 mContext = context; 283 mOverviewProxyService = overviewProxyService; 284 final Resources res = context.getResources(); 285 mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); 286 mBlacklistedPackages = new HashSet<>(); 287 Collections.addAll(mBlacklistedPackages, res.getStringArray( 288 R.array.recents_onboarding_blacklisted_packages)); 289 mLayout = LayoutInflater.from(mContext).inflate(R.layout.recents_onboarding, null); 290 mTextView = mLayout.findViewById(R.id.onboarding_text); 291 mDismissView = mLayout.findViewById(R.id.dismiss); 292 mArrowView = mLayout.findViewById(R.id.arrow); 293 294 TypedValue typedValue = new TypedValue(); 295 context.getTheme().resolveAttribute(android.R.attr.colorAccent, typedValue, true); 296 mOnboardingToastColor = res.getColor(typedValue.resourceId); 297 mOnboardingToastArrowRadius = res.getDimensionPixelSize( 298 R.dimen.recents_onboarding_toast_arrow_corner_radius); 299 300 mLayout.addOnAttachStateChangeListener(mOnAttachStateChangeListener); 301 mDismissView.setOnClickListener(v -> { 302 hide(true); 303 if (v.getTag().equals(R.string.recents_swipe_up_onboarding)) { 304 mHasDismissedSwipeUpTip = true; 305 mNumAppsLaunchedSinceSwipeUpTipDismiss = 0; 306 setDismissedSwipeUpOnboardingCount(getDismissedSwipeUpOnboardingCount() + 1); 307 if (getDismissedSwipeUpOnboardingCount() > MAX_DISMISSAL_ON_SWIPE_UP_SHOW) { 308 setHasSeenSwipeUpOnboarding(true); 309 } 310 notifyOnTip(DISMISS, RECENTS_SWIPE_UP_ONBOARDING_TIP); 311 } else { 312 notifyOnTip(DISMISS, RECENTS_QUICK_SCRUB_ONBOARDING_TIP); 313 } 314 }); 315 316 ViewGroup.LayoutParams arrowLp = mArrowView.getLayoutParams(); 317 ShapeDrawable arrowDrawable = new ShapeDrawable(TriangleShape.create( 318 arrowLp.width, arrowLp.height, false)); 319 Paint arrowPaint = arrowDrawable.getPaint(); 320 arrowPaint.setColor(mOnboardingToastColor); 321 // The corner path effect won't be reflected in the shadow, but shouldn't be noticeable. 322 arrowPaint.setPathEffect(new CornerPathEffect(mOnboardingToastArrowRadius)); 323 mArrowView.setBackground(arrowDrawable); 324 325 if (RESET_PREFS_FOR_DEBUG) { 326 setHasSeenSwipeUpOnboarding(false); 327 setHasSeenQuickScrubOnboarding(false); 328 setDismissedSwipeUpOnboardingCount(0); 329 setHasDismissedQuickScrubOnboardingOnce(false); 330 setOpenedOverviewCount(0); 331 setOpenedOverviewFromHomeCount(0); 332 } 333 } 334 notifyOnTip(int action, int target)335 private void notifyOnTip(int action, int target) { 336 try { 337 IOverviewProxy overviewProxy = mOverviewProxyService.getProxy(); 338 if(overviewProxy != null) { 339 overviewProxy.onTip(action, target); 340 } 341 } catch (RemoteException e) {} 342 } 343 onNavigationModeChanged(int mode)344 public void onNavigationModeChanged(int mode) { 345 mNavBarMode = mode; 346 } 347 onConnectedToLauncher()348 public void onConnectedToLauncher() { 349 if (!ONBOARDING_ENABLED || QuickStepContract.isGesturalMode(mNavBarMode)) { 350 return; 351 } 352 353 if (hasSeenSwipeUpOnboarding() && hasSeenQuickScrubOnboarding()) { 354 return; 355 } 356 357 if (!mOverviewProxyListenerRegistered) { 358 mOverviewProxyService.addCallback(mOverviewProxyListener); 359 mOverviewProxyListenerRegistered = true; 360 } 361 if (!mTaskListenerRegistered) { 362 ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskListener); 363 mTaskListenerRegistered = true; 364 } 365 } 366 onDisconnectedFromLauncher()367 public void onDisconnectedFromLauncher() { 368 369 if (mOverviewProxyListenerRegistered) { 370 mOverviewProxyService.removeCallback(mOverviewProxyListener); 371 mOverviewProxyListenerRegistered = false; 372 } 373 if (mTaskListenerRegistered) { 374 ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskListener); 375 mTaskListenerRegistered = false; 376 } 377 378 mHasDismissedSwipeUpTip = false; 379 mHasDismissedQuickScrubTip = false; 380 mNumAppsLaunchedSinceSwipeUpTipDismiss = 0; 381 mOverviewOpenedCountSinceQuickScrubTipDismiss = 0; 382 hide(true); 383 } 384 onConfigurationChanged(Configuration newConfiguration)385 public void onConfigurationChanged(Configuration newConfiguration) { 386 if (newConfiguration.orientation != Configuration.ORIENTATION_PORTRAIT) { 387 hide(false); 388 } 389 } 390 show(@tringRes int stringRes)391 public boolean show(@StringRes int stringRes) { 392 if (!shouldShow()) { 393 return false; 394 } 395 mDismissView.setTag(stringRes); 396 mLayout.setTag(stringRes); 397 mTextView.setText(stringRes); 398 // Only show in portrait. 399 int orientation = mContext.getResources().getConfiguration().orientation; 400 if (!mLayoutAttachedToWindow && orientation == Configuration.ORIENTATION_PORTRAIT) { 401 mLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE); 402 403 final int gravity; 404 final int x; 405 if (stringRes == R.string.recents_swipe_up_onboarding) { 406 gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; 407 x = 0; 408 } else { 409 int layoutDirection = 410 mContext.getResources().getConfiguration().getLayoutDirection(); 411 gravity = Gravity.BOTTOM | (layoutDirection == View.LAYOUT_DIRECTION_LTR 412 ? Gravity.LEFT : Gravity.RIGHT); 413 x = mContext.getResources().getDimensionPixelSize( 414 R.dimen.recents_quick_scrub_onboarding_margin_start); 415 } 416 mWindowManager.addView(mLayout, getWindowLayoutParams(gravity, x)); 417 mLayout.setAlpha(0); 418 mLayout.animate() 419 .alpha(1f) 420 .withLayer() 421 .setStartDelay(SHOW_DELAY_MS) 422 .setDuration(SHOW_DURATION_MS) 423 .setInterpolator(new DecelerateInterpolator()) 424 .start(); 425 return true; 426 } 427 return false; 428 } 429 430 /** 431 * @return True unless setprop has been set to false, we're in demo mode, or running tests in 432 * automation. 433 */ shouldShow()434 private boolean shouldShow() { 435 return SystemProperties.getBoolean("persist.quickstep.onboarding.enabled", 436 !(mContext.getSystemService(UserManager.class)).isDemoUser() && 437 !ActivityManager.isRunningInTestHarness()); 438 } 439 hide(boolean animate)440 public void hide(boolean animate) { 441 if (mLayoutAttachedToWindow) { 442 if (animate) { 443 mLayout.animate() 444 .alpha(0f) 445 .withLayer() 446 .setStartDelay(0) 447 .setDuration(HIDE_DURATION_MS) 448 .setInterpolator(new AccelerateInterpolator()) 449 .withEndAction(() -> mWindowManager.removeViewImmediate(mLayout)) 450 .start(); 451 } else { 452 mLayout.animate().cancel(); 453 mWindowManager.removeViewImmediate(mLayout); 454 } 455 } 456 } 457 setNavBarHeight(int navBarHeight)458 public void setNavBarHeight(int navBarHeight) { 459 mNavBarHeight = navBarHeight; 460 } 461 dump(PrintWriter pw)462 public void dump(PrintWriter pw) { 463 pw.println("RecentsOnboarding {"); 464 pw.println(" mTaskListenerRegistered: " + mTaskListenerRegistered); 465 pw.println(" mOverviewProxyListenerRegistered: " + mOverviewProxyListenerRegistered); 466 pw.println(" mLayoutAttachedToWindow: " + mLayoutAttachedToWindow); 467 pw.println(" mHasDismissedSwipeUpTip: " + mHasDismissedSwipeUpTip); 468 pw.println(" mHasDismissedQuickScrubTip: " + mHasDismissedQuickScrubTip); 469 pw.println(" mNumAppsLaunchedSinceSwipeUpTipDismiss: " 470 + mNumAppsLaunchedSinceSwipeUpTipDismiss); 471 pw.println(" hasSeenSwipeUpOnboarding: " + hasSeenSwipeUpOnboarding()); 472 pw.println(" hasSeenQuickScrubOnboarding: " + hasSeenQuickScrubOnboarding()); 473 pw.println(" getDismissedSwipeUpOnboardingCount: " 474 + getDismissedSwipeUpOnboardingCount()); 475 pw.println(" hasDismissedQuickScrubOnboardingOnce: " 476 + hasDismissedQuickScrubOnboardingOnce()); 477 pw.println(" getOpenedOverviewCount: " + getOpenedOverviewCount()); 478 pw.println(" getOpenedOverviewFromHomeCount: " + getOpenedOverviewFromHomeCount()); 479 pw.println(" }"); 480 } 481 getWindowLayoutParams(int gravity, int x)482 private WindowManager.LayoutParams getWindowLayoutParams(int gravity, int x) { 483 int flags = WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS 484 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; 485 final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 486 ViewGroup.LayoutParams.WRAP_CONTENT, 487 ViewGroup.LayoutParams.WRAP_CONTENT, 488 x, -mNavBarHeight / 2, 489 WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, 490 flags, 491 PixelFormat.TRANSLUCENT); 492 lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; 493 lp.setTitle("RecentsOnboarding"); 494 lp.gravity = gravity; 495 return lp; 496 } 497 hasSeenSwipeUpOnboarding()498 private boolean hasSeenSwipeUpOnboarding() { 499 return Prefs.getBoolean(mContext, HAS_SEEN_RECENTS_SWIPE_UP_ONBOARDING, false); 500 } 501 setHasSeenSwipeUpOnboarding(boolean hasSeenSwipeUpOnboarding)502 private void setHasSeenSwipeUpOnboarding(boolean hasSeenSwipeUpOnboarding) { 503 Prefs.putBoolean(mContext, HAS_SEEN_RECENTS_SWIPE_UP_ONBOARDING, hasSeenSwipeUpOnboarding); 504 if (hasSeenSwipeUpOnboarding && hasSeenQuickScrubOnboarding()) { 505 onDisconnectedFromLauncher(); 506 } 507 } 508 hasSeenQuickScrubOnboarding()509 private boolean hasSeenQuickScrubOnboarding() { 510 return Prefs.getBoolean(mContext, HAS_SEEN_RECENTS_QUICK_SCRUB_ONBOARDING, false); 511 } 512 setHasSeenQuickScrubOnboarding(boolean hasSeenQuickScrubOnboarding)513 private void setHasSeenQuickScrubOnboarding(boolean hasSeenQuickScrubOnboarding) { 514 Prefs.putBoolean(mContext, HAS_SEEN_RECENTS_QUICK_SCRUB_ONBOARDING, 515 hasSeenQuickScrubOnboarding); 516 if (hasSeenQuickScrubOnboarding && hasSeenSwipeUpOnboarding()) { 517 onDisconnectedFromLauncher(); 518 } 519 } 520 getDismissedSwipeUpOnboardingCount()521 private int getDismissedSwipeUpOnboardingCount() { 522 return Prefs.getInt(mContext, DISMISSED_RECENTS_SWIPE_UP_ONBOARDING_COUNT, 0); 523 } 524 setDismissedSwipeUpOnboardingCount(int dismissedSwipeUpOnboardingCount)525 private void setDismissedSwipeUpOnboardingCount(int dismissedSwipeUpOnboardingCount) { 526 Prefs.putInt(mContext, DISMISSED_RECENTS_SWIPE_UP_ONBOARDING_COUNT, 527 dismissedSwipeUpOnboardingCount); 528 } 529 hasDismissedQuickScrubOnboardingOnce()530 private boolean hasDismissedQuickScrubOnboardingOnce() { 531 return Prefs.getBoolean(mContext, HAS_DISMISSED_RECENTS_QUICK_SCRUB_ONBOARDING_ONCE, false); 532 } 533 setHasDismissedQuickScrubOnboardingOnce( boolean hasDismissedQuickScrubOnboardingOnce)534 private void setHasDismissedQuickScrubOnboardingOnce( 535 boolean hasDismissedQuickScrubOnboardingOnce) { 536 Prefs.putBoolean(mContext, HAS_DISMISSED_RECENTS_QUICK_SCRUB_ONBOARDING_ONCE, 537 hasDismissedQuickScrubOnboardingOnce); 538 } 539 getOpenedOverviewFromHomeCount()540 private int getOpenedOverviewFromHomeCount() { 541 return Prefs.getInt(mContext, OVERVIEW_OPENED_FROM_HOME_COUNT, 0); 542 } 543 incrementOpenedOverviewFromHomeCount()544 private void incrementOpenedOverviewFromHomeCount() { 545 int openedOverviewFromHomeCount = getOpenedOverviewFromHomeCount(); 546 if (openedOverviewFromHomeCount >= SWIPE_UP_SHOW_ON_OVERVIEW_OPENED_FROM_HOME_COUNT) { 547 return; 548 } 549 setOpenedOverviewFromHomeCount(openedOverviewFromHomeCount + 1); 550 } 551 setOpenedOverviewFromHomeCount(int openedOverviewFromHomeCount)552 private void setOpenedOverviewFromHomeCount(int openedOverviewFromHomeCount) { 553 Prefs.putInt(mContext, OVERVIEW_OPENED_FROM_HOME_COUNT, openedOverviewFromHomeCount); 554 } 555 getOpenedOverviewCount()556 private int getOpenedOverviewCount() { 557 return Prefs.getInt(mContext, OVERVIEW_OPENED_COUNT, 0); 558 } 559 incrementOpenedOverviewCount()560 private void incrementOpenedOverviewCount() { 561 int openedOverviewCount = getOpenedOverviewCount(); 562 if (openedOverviewCount >= QUICK_SCRUB_SHOW_ON_OVERVIEW_OPENED_COUNT) { 563 return; 564 } 565 setOpenedOverviewCount(openedOverviewCount + 1); 566 } 567 setOpenedOverviewCount(int openedOverviewCount)568 private void setOpenedOverviewCount(int openedOverviewCount) { 569 Prefs.putInt(mContext, OVERVIEW_OPENED_COUNT, openedOverviewCount); 570 } 571 572 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 573 @Override 574 public void onReceive(Context context, Intent intent) { 575 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { 576 hide(false); 577 } 578 } 579 }; 580 } 581