diff options
Diffstat (limited to 'src/com/android/launcher3/LauncherClings.java')
-rw-r--r-- | src/com/android/launcher3/LauncherClings.java | 451 |
1 files changed, 451 insertions, 0 deletions
diff --git a/src/com/android/launcher3/LauncherClings.java b/src/com/android/launcher3/LauncherClings.java new file mode 100644 index 000000000..e5e0c1621 --- /dev/null +++ b/src/com/android/launcher3/LauncherClings.java @@ -0,0 +1,451 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.app.ActivityManager; +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Rect; +import android.os.Bundle; +import android.os.UserManager; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.accessibility.AccessibilityManager; +import android.widget.TextView; + +class LauncherClings { + private static final String FIRST_RUN_CLING_DISMISSED_KEY = "cling_gel.first_run.dismissed"; + private static final String MIGRATION_CLING_DISMISSED_KEY = "cling_gel.migration.dismissed"; + private static final String MIGRATION_WORKSPACE_CLING_DISMISSED_KEY = + "cling_gel.migration_workspace.dismissed"; + private static final String WORKSPACE_CLING_DISMISSED_KEY = "cling_gel.workspace.dismissed"; + private static final String FOLDER_CLING_DISMISSED_KEY = "cling_gel.folder.dismissed"; + + private static final boolean DISABLE_CLINGS = false; + + private static final int SHOW_CLING_DURATION = 250; + private static final int DISMISS_CLING_DURATION = 200; + + private Launcher mLauncher; + private LayoutInflater mInflater; + private HideFromAccessibilityHelper mHideFromAccessibilityHelper + = new HideFromAccessibilityHelper(); + + /** Ctor */ + public LauncherClings(Launcher launcher) { + mLauncher = launcher; + mInflater = mLauncher.getLayoutInflater(); + } + + /** Initializes a cling */ + private Cling initCling(int clingId, int scrimId, boolean animate, + boolean dimNavBarVisibilty) { + Cling cling = (Cling) mLauncher.findViewById(clingId); + View scrim = null; + if (scrimId > 0) { + scrim = mLauncher.findViewById(scrimId); + } + if (cling != null) { + cling.init(mLauncher, scrim); + cling.show(animate, SHOW_CLING_DURATION); + + if (dimNavBarVisibilty) { + cling.setSystemUiVisibility(cling.getSystemUiVisibility() | + View.SYSTEM_UI_FLAG_LOW_PROFILE); + } + } + return cling; + } + + /** Returns whether the clings are enabled or should be shown */ + private boolean areClingsEnabled() { + if (DISABLE_CLINGS) { + return false; + } + + // disable clings when running in a test harness + if(ActivityManager.isRunningInTestHarness()) return false; + + // Disable clings for accessibility when explore by touch is enabled + final AccessibilityManager a11yManager = (AccessibilityManager) mLauncher.getSystemService( + Launcher.ACCESSIBILITY_SERVICE); + if (a11yManager.isTouchExplorationEnabled()) { + return false; + } + + // Restricted secondary users (child mode) will potentially have very few apps + // seeded when they start up for the first time. Clings won't work well with that + boolean supportsLimitedUsers = + android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; + Account[] accounts = AccountManager.get(mLauncher).getAccounts(); + if (supportsLimitedUsers && accounts.length == 0) { + UserManager um = (UserManager) mLauncher.getSystemService(Context.USER_SERVICE); + Bundle restrictions = um.getUserRestrictions(); + if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) { + return false; + } + } + return true; + } + + /** Returns whether the folder cling is visible. */ + public boolean isFolderClingVisible() { + Cling cling = (Cling) mLauncher.findViewById(R.id.folder_cling); + if (cling != null) { + return cling.getVisibility() == View.VISIBLE; + } + return false; + } + + private boolean skipCustomClingIfNoAccounts() { + Cling cling = (Cling) mLauncher.findViewById(R.id.workspace_cling); + boolean customCling = cling.getDrawIdentifier().equals("workspace_custom"); + if (customCling) { + AccountManager am = AccountManager.get(mLauncher); + if (am == null) return false; + Account[] accounts = am.getAccountsByType("com.google"); + return accounts.length == 0; + } + return false; + } + + /** Updates the first run cling custom content hint */ + private void setCustomContentHintVisibility(Cling cling, String ccHintStr, boolean visible, + boolean animate) { + final TextView ccHint = (TextView) cling.findViewById(R.id.custom_content_hint); + if (ccHint != null) { + if (visible && !ccHintStr.isEmpty()) { + ccHint.setText(ccHintStr); + ccHint.setVisibility(View.VISIBLE); + if (animate) { + ccHint.setAlpha(0f); + ccHint.animate().alpha(1f) + .setDuration(SHOW_CLING_DURATION) + .start(); + } else { + ccHint.setAlpha(1f); + } + } else { + if (animate) { + ccHint.animate().alpha(0f) + .setDuration(SHOW_CLING_DURATION) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + ccHint.setVisibility(View.GONE); + } + }) + .start(); + } else { + ccHint.setAlpha(0f); + ccHint.setVisibility(View.GONE); + } + } + } + } + + /** Updates the first run cling custom content hint */ + public void updateCustomContentHintVisibility() { + Cling cling = (Cling) mLauncher.findViewById(R.id.first_run_cling); + String ccHintStr = mLauncher.getFirstRunCustomContentHint(); + + if (mLauncher.getWorkspace().hasCustomContent()) { + // Show the custom content hint if ccHintStr is not empty + if (cling != null) { + setCustomContentHintVisibility(cling, ccHintStr, true, true); + } + } else { + // Hide the custom content hint + if (cling != null) { + setCustomContentHintVisibility(cling, ccHintStr, false, true); + } + } + } + + /** Updates the first run cling search bar hint. */ + public void updateSearchBarHint(String hint) { + Cling cling = (Cling) mLauncher.findViewById(R.id.first_run_cling); + if (cling != null && cling.getVisibility() == View.VISIBLE && !hint.isEmpty()) { + TextView sbHint = (TextView) cling.findViewById(R.id.search_bar_hint); + sbHint.setText(hint); + sbHint.setVisibility(View.VISIBLE); + } + } + + public boolean shouldShowFirstRunOrMigrationClings() { + SharedPreferences sharedPrefs = mLauncher.getSharedPrefs(); + return areClingsEnabled() && + !sharedPrefs.getBoolean(FIRST_RUN_CLING_DISMISSED_KEY, false) && + !sharedPrefs.getBoolean(MIGRATION_CLING_DISMISSED_KEY, false); + } + + public void removeFirstRunAndMigrationClings() { + removeCling(R.id.first_run_cling); + removeCling(R.id.migration_cling); + } + + /** + * Shows the first run cling. + * + * This flow is mutually exclusive with showMigrationCling, and only runs if this Launcher + * package was preinstalled or there is no db to migrate from. + */ + public void showFirstRunCling() { + if (!skipCustomClingIfNoAccounts()) { + Cling cling = (Cling) mLauncher.findViewById(R.id.first_run_cling); + if (cling != null) { + String sbHintStr = mLauncher.getFirstRunClingSearchBarHint(); + String ccHintStr = mLauncher.getFirstRunCustomContentHint(); + if (!sbHintStr.isEmpty()) { + TextView sbHint = (TextView) cling.findViewById(R.id.search_bar_hint); + sbHint.setText(sbHintStr); + sbHint.setVisibility(View.VISIBLE); + } + setCustomContentHintVisibility(cling, ccHintStr, true, false); + } + initCling(R.id.first_run_cling, 0, false, true); + } else { + removeFirstRunAndMigrationClings(); + } + } + + /** + * Shows the migration cling. + * + * This flow is mutually exclusive with showFirstRunCling, and only runs if this Launcher + * package was not preinstalled and there exists a db to migrate from. + */ + public void showMigrationCling() { + mLauncher.hideWorkspaceSearchAndHotseat(); + + Cling c = initCling(R.id.migration_cling, 0, false, true); + c.bringScrimToFront(); + c.bringToFront(); + } + + public void showMigrationWorkspaceCling() { + // Enable the clings only if they have not been dismissed before + if (areClingsEnabled() && !mLauncher.getSharedPrefs().getBoolean( + MIGRATION_WORKSPACE_CLING_DISMISSED_KEY, false)) { + Cling c = initCling(R.id.migration_workspace_cling, 0, false, true); + c.updateMigrationWorkspaceBubblePosition(); + c.bringScrimToFront(); + c.bringToFront(); + } else { + removeCling(R.id.migration_workspace_cling); + } + } + + public void showWorkspaceCling() { + // Enable the clings only if they have not been dismissed before + if (areClingsEnabled() && !mLauncher.getSharedPrefs().getBoolean( + WORKSPACE_CLING_DISMISSED_KEY, false)) { + Cling c = initCling(R.id.workspace_cling, 0, false, true); + c.updateWorkspaceBubblePosition(); + + // Set the focused hotseat app if there is one + c.setFocusedHotseatApp(mLauncher.getFirstRunFocusedHotseatAppDrawableId(), + mLauncher.getFirstRunFocusedHotseatAppRank(), + mLauncher.getFirstRunFocusedHotseatAppComponentName(), + mLauncher.getFirstRunFocusedHotseatAppBubbleTitle(), + mLauncher.getFirstRunFocusedHotseatAppBubbleDescription()); + } else { + removeCling(R.id.workspace_cling); + } + } + + public Cling showFoldersCling() { + SharedPreferences sharedPrefs = mLauncher.getSharedPrefs(); + // Enable the clings only if they have not been dismissed before + if (areClingsEnabled() && + !sharedPrefs.getBoolean(FOLDER_CLING_DISMISSED_KEY, false) && + !sharedPrefs.getBoolean(Launcher.USER_HAS_MIGRATED, false)) { + Cling cling = initCling(R.id.folder_cling, R.id.cling_scrim, + true, true); + Folder openFolder = mLauncher.getWorkspace().getOpenFolder(); + if (openFolder != null) { + Rect openFolderRect = new Rect(); + openFolder.getHitRect(openFolderRect); + cling.setOpenFolderRect(openFolderRect); + openFolder.bringToFront(); + } + return cling; + } else { + removeCling(R.id.folder_cling); + return null; + } + } + + public static void synchonouslyMarkFirstRunClingDismissed(Context ctx) { + SharedPreferences prefs = ctx.getSharedPreferences( + LauncherAppState.getSharedPreferencesKey(),Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean(LauncherClings.FIRST_RUN_CLING_DISMISSED_KEY, true); + editor.commit(); + } + + public void markFolderClingDismissed() { + SharedPreferences.Editor editor = mLauncher.getSharedPrefs().edit(); + editor.putBoolean(LauncherClings.FOLDER_CLING_DISMISSED_KEY, true); + editor.apply(); + } + + /** Removes the cling outright from the DragLayer */ + private void removeCling(int id) { + final View cling = mLauncher.findViewById(id); + if (cling != null) { + final ViewGroup parent = (ViewGroup) cling.getParent(); + parent.post(new Runnable() { + @Override + public void run() { + parent.removeView(cling); + } + }); + mHideFromAccessibilityHelper.restoreImportantForAccessibility(mLauncher.getDragLayer()); + } + } + + /** Hides the specified Cling */ + private void dismissCling(final Cling cling, final Runnable postAnimationCb, + final String flag, int duration, boolean restoreNavBarVisibilty) { + // To catch cases where siblings of top-level views are made invisible, just check whether + // the cling is directly set to GONE before dismissing it. + if (cling != null && cling.getVisibility() != View.GONE) { + final Runnable cleanUpClingCb = new Runnable() { + public void run() { + cling.cleanup(); + SharedPreferences.Editor editor = mLauncher.getSharedPrefs().edit(); + editor.putBoolean(flag, true); + editor.apply(); + if (postAnimationCb != null) { + postAnimationCb.run(); + } + } + }; + if (duration <= 0) { + cleanUpClingCb.run(); + } else { + cling.hide(duration, cleanUpClingCb); + } + mHideFromAccessibilityHelper.restoreImportantForAccessibility(mLauncher.getDragLayer()); + + if (restoreNavBarVisibilty) { + cling.setSystemUiVisibility(cling.getSystemUiVisibility() & + ~View.SYSTEM_UI_FLAG_LOW_PROFILE); + } + } + } + + public void dismissFirstRunCling(View v) { + Cling cling = (Cling) mLauncher.findViewById(R.id.first_run_cling); + Runnable cb = new Runnable() { + public void run() { + // Show the workspace cling next + showWorkspaceCling(); + } + }; + dismissCling(cling, cb, FIRST_RUN_CLING_DISMISSED_KEY, + DISMISS_CLING_DURATION, false); + + // Fade out the search bar for the workspace cling coming up + mLauncher.getSearchBar().hideSearchBar(true); + } + + private void dismissMigrationCling() { + mLauncher.showWorkspaceSearchAndHotseat(); + Runnable dismissCb = new Runnable() { + public void run() { + Cling cling = (Cling) mLauncher.findViewById(R.id.migration_cling); + Runnable cb = new Runnable() { + public void run() { + // Show the migration workspace cling next + showMigrationWorkspaceCling(); + } + }; + dismissCling(cling, cb, MIGRATION_CLING_DISMISSED_KEY, + DISMISS_CLING_DURATION, true); + } + }; + mLauncher.getWorkspace().post(dismissCb); + } + + private void dismissAnyWorkspaceCling(Cling cling, String key, View v) { + Runnable cb = null; + if (v == null) { + cb = new Runnable() { + public void run() { + mLauncher.getWorkspace().enterOverviewMode(); + } + }; + } + dismissCling(cling, cb, key, DISMISS_CLING_DURATION, true); + + // Fade in the search bar + mLauncher.getSearchBar().showSearchBar(true); + } + + public void dismissMigrationClingCopyApps(View v) { + // Copy the shortcuts from the old database + LauncherModel model = mLauncher.getModel(); + model.resetLoadedState(false, true); + model.startLoader(false, PagedView.INVALID_RESTORE_PAGE, + LauncherModel.LOADER_FLAG_CLEAR_WORKSPACE + | LauncherModel.LOADER_FLAG_MIGRATE_SHORTCUTS); + + // Set the flag to skip the folder cling + String spKey = LauncherAppState.getSharedPreferencesKey(); + SharedPreferences sp = mLauncher.getSharedPreferences(spKey, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sp.edit(); + editor.putBoolean(Launcher.USER_HAS_MIGRATED, true); + editor.apply(); + + // Disable the migration cling + dismissMigrationCling(); + } + + public void dismissMigrationClingUseDefault(View v) { + // Clear the workspace + LauncherModel model = mLauncher.getModel(); + model.resetLoadedState(false, true); + model.startLoader(false, PagedView.INVALID_RESTORE_PAGE, + LauncherModel.LOADER_FLAG_CLEAR_WORKSPACE); + + // Disable the migration cling + dismissMigrationCling(); + } + + public void dismissMigrationWorkspaceCling(View v) { + Cling cling = (Cling) mLauncher.findViewById(R.id.migration_workspace_cling); + dismissAnyWorkspaceCling(cling, MIGRATION_WORKSPACE_CLING_DISMISSED_KEY, v); + } + + public void dismissWorkspaceCling(View v) { + Cling cling = (Cling) mLauncher.findViewById(R.id.workspace_cling); + dismissAnyWorkspaceCling(cling, WORKSPACE_CLING_DISMISSED_KEY, v); + } + + public void dismissFolderCling(View v) { + Cling cling = (Cling) mLauncher.findViewById(R.id.folder_cling); + dismissCling(cling, null, FOLDER_CLING_DISMISSED_KEY, + DISMISS_CLING_DURATION, true); + } +} |