blob: 541eaddd0d5a4a32caf0b0023ba42b5575917463 [file] [log] [blame]
/*
* 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.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.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 boolean DISABLE_CUSTOM_CLINGS = true;
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(R.id.cling_scrim);
}
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 isClingsEnabled() {
if (DISABLE_CLINGS) {
return false;
}
// For now, limit only to phones
LauncherAppState app = LauncherAppState.getInstance();
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
if (grid.isTablet()) {
return false;
}
if (grid.isLandscape) {
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);
}
}
/** Shows the first run cling */
public void showFirstRunCling() {
SharedPreferences sharedPrefs = mLauncher.getSharedPrefs();
if (isClingsEnabled() &&
!sharedPrefs.getBoolean(FIRST_RUN_CLING_DISMISSED_KEY, false) &&
!skipCustomClingIfNoAccounts() ) {
// If we're not using the default workspace layout, replace workspace cling
// with a custom workspace cling (usually specified in an overlay)
// For now, only do this on tablets
if (!DISABLE_CUSTOM_CLINGS) {
if (sharedPrefs.getInt(LauncherProvider.DEFAULT_WORKSPACE_RESOURCE_ID, 0) != 0 &&
mLauncher.getResources().getBoolean(R.bool.config_useCustomClings)) {
// Use a custom cling
View cling = mLauncher.findViewById(R.id.workspace_cling);
ViewGroup clingParent = (ViewGroup) cling.getParent();
int clingIndex = clingParent.indexOfChild(cling);
clingParent.removeViewAt(clingIndex);
View customCling = mInflater.inflate(R.layout.custom_workspace_cling,
clingParent, false);
clingParent.addView(customCling, clingIndex);
customCling.setId(R.id.workspace_cling);
}
}
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 {
removeCling(R.id.first_run_cling);
}
}
public void showMigrationCling() {
// Enable the clings only if they have not been dismissed before
if (isClingsEnabled() && !mLauncher.getSharedPrefs().getBoolean(
MIGRATION_CLING_DISMISSED_KEY, false)) {
mLauncher.hideWorkspaceSearchAndHotseat();
Cling c = initCling(R.id.migration_cling, 0, false, true);
c.bringScrimToFront();
c.bringToFront();
} else {
removeCling(R.id.migration_cling);
}
}
public void showMigrationWorkspaceCling() {
// Enable the clings only if they have not been dismissed before
if (isClingsEnabled() && !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 (isClingsEnabled() && !mLauncher.getSharedPrefs().getBoolean(
WORKSPACE_CLING_DISMISSED_KEY, false)) {
Cling c = initCling(R.id.workspace_cling, 0, false, true);
// 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 (isClingsEnabled() &&
!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);
return cling;
} else {
removeCling(R.id.folder_cling);
return null;
}
}
/** 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, WORKSPACE_CLING_DISMISSED_KEY,
DISMISS_CLING_DURATION, true);
}
};
mLauncher.getWorkspace().post(dismissCb);
}
private void dismissAnyWorkspaceCling(Cling cling, View v) {
Runnable cb = null;
if (v == null) {
cb = new Runnable() {
public void run() {
mLauncher.getWorkspace().enterOverviewMode();
}
};
}
dismissCling(cling, cb, WORKSPACE_CLING_DISMISSED_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, v);
}
public void dismissWorkspaceCling(View v) {
Cling cling = (Cling) mLauncher.findViewById(R.id.workspace_cling);
dismissAnyWorkspaceCling(cling, 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);
}
}