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