/src/com/cyanogenmod/trebuchet/Launcher.java
Java | 4330 lines | 4158 code | 93 blank | 79 comment | 60 complexity | 2be094720c2dc352ad0d3d709bcca764 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- /*
- * 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.cyanogenmod.trebuchet;
- import android.accounts.Account;
- import android.accounts.AccountManager;
- import android.animation.Animator;
- import android.animation.AnimatorListenerAdapter;
- import android.animation.AnimatorSet;
- import android.animation.ObjectAnimator;
- import android.animation.PropertyValuesHolder;
- import android.animation.ValueAnimator;
- import android.animation.ValueAnimator.AnimatorUpdateListener;
- import android.app.Activity;
- import android.app.ActivityManager;
- import android.app.ActivityOptions;
- import android.app.AlertDialog;
- import android.app.SearchManager;
- import android.app.StatusBarManager;
- import android.appwidget.AppWidgetHostView;
- import android.appwidget.AppWidgetManager;
- import android.appwidget.AppWidgetProviderInfo;
- import android.content.ActivityNotFoundException;
- import android.content.BroadcastReceiver;
- import android.content.ComponentCallbacks2;
- import android.content.ComponentName;
- import android.content.ContentResolver;
- import android.content.Context;
- import android.content.DialogInterface;
- import android.content.Intent;
- import android.content.IntentFilter;
- import android.content.SharedPreferences;
- import android.content.pm.ActivityInfo;
- import android.content.pm.PackageManager;
- import android.content.pm.PackageManager.NameNotFoundException;
- import android.content.pm.ResolveInfo;
- import android.content.res.Configuration;
- import android.content.res.Resources;
- import android.database.ContentObserver;
- import android.graphics.Bitmap;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.PorterDuff;
- import android.graphics.Rect;
- import android.graphics.drawable.BitmapDrawable;
- import android.graphics.drawable.ColorDrawable;
- import android.graphics.drawable.Drawable;
- import android.net.Uri;
- import android.os.AsyncTask;
- import android.os.Bundle;
- import android.os.Environment;
- import android.os.Handler;
- import android.os.Message;
- import android.os.StrictMode;
- import android.os.SystemClock;
- import android.provider.Settings;
- import android.speech.RecognizerIntent;
- import android.text.Selection;
- import android.text.SpannableStringBuilder;
- import android.text.TextUtils;
- import android.text.method.TextKeyListener;
- import android.util.Log;
- import android.view.Display;
- import android.view.HapticFeedbackConstants;
- import android.view.KeyEvent;
- import android.view.LayoutInflater;
- import android.view.Menu;
- import android.view.MenuItem;
- import android.view.MotionEvent;
- import android.view.Surface;
- import android.view.View;
- import android.view.View.OnLongClickListener;
- import android.view.ViewConfiguration;
- import android.view.ViewGroup;
- import android.view.ViewTreeObserver;
- import android.view.ViewGroup.MarginLayoutParams;
- import android.view.ViewTreeObserver.OnGlobalLayoutListener;
- import android.view.WindowManager;
- import android.view.accessibility.AccessibilityEvent;
- import android.view.animation.AccelerateDecelerateInterpolator;
- import android.view.animation.AccelerateInterpolator;
- import android.view.animation.DecelerateInterpolator;
- import android.view.inputmethod.InputMethodManager;
- import android.widget.Advanceable;
- import android.widget.EditText;
- import android.widget.ImageView;
- import android.widget.PopupMenu;
- import android.widget.TextView;
- import android.widget.Toast;
- import com.android.common.Search;
- import com.cyanogenmod.trebuchet.DropTarget.DragObject;
- import com.cyanogenmod.trebuchet.preference.*;
- import java.io.DataInputStream;
- import java.io.DataOutputStream;
- import java.io.FileDescriptor;
- import java.io.FileNotFoundException;
- import java.io.IOException;
- import java.io.PrintWriter;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.Comparator;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.List;
- import java.util.Set;
- /**
- * Default launcher application.
- */
- public final class Launcher extends Activity
- implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,
- View.OnTouchListener {
- private static final String TAG = "Trebuchet.Launcher";
- static final boolean PROFILE_STARTUP = false;
- static final boolean DEBUG_WIDGETS = false;
- static final boolean DEBUG_STRICT_MODE = false;
- private static final int MENU_GROUP_WALLPAPER = 1;
- private static final int MENU_GROUP_DRAWER = MENU_GROUP_WALLPAPER + 1;
- private static final int MENU_DRAWER = Menu.FIRST + 1;
- private static final int MENU_MANAGE_APPS = MENU_DRAWER + 1;
- private static final int MENU_SYSTEM_SETTINGS = MENU_MANAGE_APPS + 1;
- private static final int MENU_PREFERENCES = MENU_SYSTEM_SETTINGS + 1;
- private static final int MENU_WALLPAPER_SETTINGS = MENU_PREFERENCES + 1;
- private static final int MENU_LOCK_WORKSPACE = MENU_WALLPAPER_SETTINGS + 1;
- private static final int MENU_HELP = MENU_WALLPAPER_SETTINGS + 1;
- private static final int REQUEST_CREATE_SHORTCUT = 1;
- private static final int REQUEST_CREATE_APPWIDGET = 5;
- private static final int REQUEST_PICK_APPLICATION = 6;
- private static final int REQUEST_PICK_SHORTCUT = 7;
- private static final int REQUEST_PICK_APPWIDGET = 9;
- private static final int REQUEST_PICK_WALLPAPER = 10;
- private static final int REQUEST_BIND_APPWIDGET = 11;
- static final String EXTRA_SHORTCUT_DUPLICATE = "duplicate";
- static final int MAX_WORKSPACE_SCREEN_COUNT = 7;
- static final int MAX_HOTSEAT_SCREEN_COUNT = 3;
- static final int MAX_SCREEN_COUNT = MAX_WORKSPACE_SCREEN_COUNT + MAX_HOTSEAT_SCREEN_COUNT;
- static final int DEFAULT_SCREEN = 2;
- private static final String PREFERENCES = "launcher.preferences";
- // To turn on these properties, type
- // adb shell setprop log.tag.PROPERTY_NAME [VERBOSE | SUPPRESS]
- static final String FORCE_ENABLE_ROTATION_PROPERTY = "launcher_force_rotate";
- static final String DUMP_STATE_PROPERTY = "launcher_dump_state";
- // The Intent extra that defines whether to ignore the launch animation
- static final String INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION =
- "com.cyanogenmod.trebuchet.intent.extra.shortcut.INGORE_LAUNCH_ANIMATION";
- // Type: int
- private static final String RUNTIME_STATE_CURRENT_SCREEN = "launcher.current_screen";
- // Type: int
- private static final String RUNTIME_STATE_CURRENT_HOTSEAT_SCREEN = "launcher.hotseat.current_screen";
- // Type: int
- private static final String RUNTIME_STATE = "launcher.state";
- // Type: int
- private static final String RUNTIME_STATE_PENDING_ADD_CONTAINER = "launcher.add_container";
- // Type: int
- private static final String RUNTIME_STATE_PENDING_ADD_SCREEN = "launcher.add_screen";
- // Type: int
- private static final String RUNTIME_STATE_PENDING_ADD_CELL_X = "launcher.add_cell_x";
- // Type: int
- private static final String RUNTIME_STATE_PENDING_ADD_CELL_Y = "launcher.add_cell_y";
- // Type: boolean
- private static final String RUNTIME_STATE_PENDING_FOLDER_RENAME = "launcher.rename_folder";
- // Type: long
- private static final String RUNTIME_STATE_PENDING_FOLDER_RENAME_ID = "launcher.rename_folder_id";
- // Type: int
- private static final String RUNTIME_STATE_PENDING_ADD_SPAN_X = "launcher.add_span_x";
- // Type: int
- private static final String RUNTIME_STATE_PENDING_ADD_SPAN_Y = "launcher.add_span_y";
- // Type: parcelable
- private static final String RUNTIME_STATE_PENDING_ADD_WIDGET_INFO = "launcher.add_widget_info";
- private static final String TOOLBAR_ICON_METADATA_NAME = "com.android.launcher.toolbar_icon";
- private static final String TOOLBAR_SEARCH_ICON_METADATA_NAME =
- "com.android.launcher.toolbar_search_icon";
- private static final String TOOLBAR_VOICE_SEARCH_ICON_METADATA_NAME =
- "com.android.launcher.toolbar_voice_search_icon";
- /** The different states that Launcher can be in. */
- private enum State { NONE, WORKSPACE, APPS_CUSTOMIZE, APPS_CUSTOMIZE_SPRING_LOADED }
- private State mState = State.WORKSPACE;
- private AnimatorSet mStateAnimation;
- private AnimatorSet mDividerAnimator;
- static final int APPWIDGET_HOST_ID = 1024;
- private static final int EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT = 300;
- private static final int EXIT_SPRINGLOADED_MODE_LONG_TIMEOUT = 600;
- private static final int SHOW_CLING_DURATION = 550;
- private static final int DISMISS_CLING_DURATION = 250;
- // How long to wait before the new-shortcut animation automatically pans the workspace
- private static final int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 10;
- private final BroadcastReceiver mCloseSystemDialogsReceiver
- = new CloseSystemDialogsIntentReceiver();
- private final ContentObserver mWidgetObserver = new AppWidgetResetObserver();
- private LayoutInflater mInflater;
- private Workspace mWorkspace;
- private View mQsbDivider;
- private View mDockDivider;
- private View mLauncherView;
- private DragLayer mDragLayer;
- private DragController mDragController;
- private AppWidgetManager mAppWidgetManager;
- private LauncherAppWidgetHost mAppWidgetHost;
- private ItemInfo mPendingAddInfo = new ItemInfo();
- private AppWidgetProviderInfo mPendingAddWidgetInfo;
- private int[] mTmpAddItemCellCoordinates = new int[2];
- private FolderInfo mFolderInfo;
- private Hotseat mHotseat;
- private SearchDropTargetBar mSearchDropTargetBar;
- private AppsCustomizeTabHost mAppsCustomizeTabHost;
- private AppsCustomizePagedView mAppsCustomizeContent;
- private boolean mAutoAdvanceRunning = false;
- private Bundle mSavedState;
- // We set the state in both onCreate and then onNewIntent in some cases, which causes both
- // scroll issues (because the workspace may not have been measured yet) and extra work.
- // Instead, just save the state that we need to restore Launcher to, and commit it in onResume.
- private State mOnResumeState = State.NONE;
- private SpannableStringBuilder mDefaultKeySsb = null;
- private boolean mWorkspaceLoading = true;
- private boolean mPaused = true;
- private boolean mRestoring;
- private boolean mWaitingForResult;
- private boolean mOnResumeNeedsLoad;
- // Keep track of whether the user has left launcher
- private static boolean sPausedFromUserAction = false;
- private LauncherModel mModel;
- private IconCache mIconCache;
- private boolean mUserPresent = true;
- private boolean mVisible = false;
- private boolean mAttached = false;
- private static LocaleConfiguration sLocaleConfiguration = null;
- private static HashMap<Long, FolderInfo> sFolders = new HashMap<Long, FolderInfo>();
- private Intent mAppMarketIntent = null;
- // Related to the auto-advancing of widgets
- private final int ADVANCE_MSG = 1;
- private final int mAdvanceInterval = 20000;
- private final int mAdvanceStagger = 250;
- private long mAutoAdvanceSentTime;
- private long mAutoAdvanceTimeLeft = -1;
- private HashMap<View, AppWidgetProviderInfo> mWidgetsToAdvance =
- new HashMap<View, AppWidgetProviderInfo>();
- // Determines how long to wait after a rotation before restoring the screen orientation to
- // match the sensor state.
- private static final int RESTORE_SCREEN_ORIENTATION_DELAY = 500;
- // External icons saved in case of resource changes, orientation, etc.
- private static Drawable.ConstantState[] sGlobalSearchIcon = new Drawable.ConstantState[2];
- private static Drawable.ConstantState[] sVoiceSearchIcon = new Drawable.ConstantState[2];
- private static Drawable.ConstantState[] sAppMarketIcon = new Drawable.ConstantState[2];
- private Drawable mWorkspaceBackgroundDrawable;
- private Drawable mBlackBackgroundDrawable;
- private final ArrayList<Integer> mSynchronouslyBoundPages = new ArrayList<Integer>();
- static final ArrayList<String> sDumpLogs = new ArrayList<String>();
- // We only want to get the SharedPreferences once since it does an FS stat each time we get
- // it from the context.
- private SharedPreferences mSharedPrefs;
- // Holds the page that we need to animate to, and the icon views that we need to animate up
- // when we scroll to that page on resume.
- private int mNewShortcutAnimatePage = -1;
- private ArrayList<View> mNewShortcutAnimateViews = new ArrayList<View>();
- private ImageView mFolderIconImageView;
- private Bitmap mFolderIconBitmap;
- private Canvas mFolderIconCanvas;
- private Rect mRectForFolderAnimation = new Rect();
- private BubbleTextView mWaitingForResume;
- private HideFromAccessibilityHelper mHideFromAccessibilityHelper
- = new HideFromAccessibilityHelper();
- // Preferences
- private boolean mShowSearchBar;
- private boolean mShowHotseat;
- private boolean mShowDockDivider;
- private boolean mHideIconLabels;
- private boolean mHideDockIconLabels;
- private boolean mAutoRotate;
- private boolean mLockWorkspace;
- private boolean mFullscreenMode;
- private int mHomescreenDoubleTap;
- private int mHomescreenSwipeUp;
- private int mHomescreenSwipeDown;
- private StatusBarManager mStatusBarManager;
- private boolean mWallpaperVisible;
- private Runnable mBuildLayersRunnable = new Runnable() {
- public void run() {
- if (mWorkspace != null) {
- mWorkspace.buildPageHardwareLayers();
- }
- }
- };
- private static ArrayList<PendingAddArguments> sPendingAddList
- = new ArrayList<PendingAddArguments>();
- private static boolean sForceEnableRotation = isPropertyEnabled(FORCE_ENABLE_ROTATION_PROPERTY);
- private static class PendingAddArguments {
- int requestCode;
- Intent intent;
- long container;
- int screen;
- int cellX;
- int cellY;
- }
- private static boolean isPropertyEnabled(String propertyName) {
- return Log.isLoggable(propertyName, Log.VERBOSE);
- }
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- if (DEBUG_STRICT_MODE) {
- StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
- .detectDiskReads()
- .detectDiskWrites()
- .detectNetwork() // or .detectAll() for all detectable problems
- .penaltyLog()
- .build());
- StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
- .detectLeakedSqlLiteObjects()
- .detectLeakedClosableObjects()
- .penaltyLog()
- .penaltyDeath()
- .build());
- }
- super.onCreate(savedInstanceState);
- LauncherApplication app = ((LauncherApplication)getApplication());
- mSharedPrefs = getSharedPreferences(LauncherApplication.getSharedPreferencesKey(),
- Context.MODE_PRIVATE);
- mModel = app.setLauncher(this);
- mIconCache = app.getIconCache();
- mDragController = new DragController(this);
- mInflater = getLayoutInflater();
- final Resources res = getResources();
- // Load all preferences
- PreferencesProvider.load(this);
- mAppWidgetManager = AppWidgetManager.getInstance(this);
- mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID);
- mAppWidgetHost.startListening();
- // If we are getting an onCreate, we can actually preempt onResume and unset mPaused here,
- // this also ensures that any synchronous binding below doesn't re-trigger another
- // LauncherModel load.
- mPaused = false;
- // Preferences
- mShowSearchBar = PreferencesProvider.Interface.Homescreen.getShowSearchBar();
- mShowHotseat = PreferencesProvider.Interface.Dock.getShowDock();
- mShowDockDivider = PreferencesProvider.Interface.Dock.getShowDivider() && mShowHotseat;
- mHideIconLabels = PreferencesProvider.Interface.Homescreen.getHideIconLabels();
- mHideDockIconLabels = PreferencesProvider.Interface.Dock.getHideIconLabels();
- boolean verticalHotseat =
- res.getBoolean(R.bool.hotseat_transpose_layout_with_orientation) &&
- res.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
- mHideDockIconLabels = PreferencesProvider.Interface.Dock.getHideIconLabels() ||
- (!mShowHotseat || (verticalHotseat && !LauncherApplication.isScreenLarge()));
- mAutoRotate = PreferencesProvider.Interface.General.getAutoRotate(getResources().getBoolean(R.bool.allow_rotation));
- mLockWorkspace = PreferencesProvider.Interface.General.getLockWorkspace(getResources().getBoolean(R.bool.lock_workspace));
- mFullscreenMode = PreferencesProvider.Interface.General.getFullscreenMode();
- mHomescreenDoubleTap = PreferencesProvider.Interface.Gestures.getHomescreenDoubleTap();
- mHomescreenSwipeUp = PreferencesProvider.Interface.Gestures.getHomescreenSwipeUp();
- mHomescreenSwipeDown = PreferencesProvider.Interface.Gestures.getHomescreenSwipeDown();
- if (PROFILE_STARTUP) {
- android.os.Debug.startMethodTracing(
- Environment.getExternalStorageDirectory() + "/launcher");
- }
- checkForLocaleChange();
- setContentView(R.layout.launcher);
- setupViews();
- showFirstRunWorkspaceCling();
- registerContentObservers();
- lockAllApps();
- mSavedState = savedInstanceState;
- restoreState(mSavedState);
- // Update customization drawer _after_ restoring the states
- if (mAppsCustomizeContent != null) {
- mAppsCustomizeContent.onPackagesUpdated();
- }
- if (PROFILE_STARTUP) {
- android.os.Debug.stopMethodTracing();
- }
- if (!mRestoring) {
- if (sPausedFromUserAction) {
- // If the user leaves launcher, then we should just load items asynchronously when
- // they return.
- mModel.startLoader(true, -1);
- } else {
- // We only load the page synchronously if the user rotates (or triggers a
- // configuration change) while launcher is in the foreground
- mModel.startLoader(true, mWorkspace.getCurrentPage());
- }
- }
- if (!mModel.isAllAppsLoaded()) {
- ViewGroup appsCustomizeContentParent = (ViewGroup) mAppsCustomizeContent.getParent();
- mInflater.inflate(R.layout.apps_customize_progressbar, appsCustomizeContentParent);
- }
- // For handling default keys
- mDefaultKeySsb = new SpannableStringBuilder();
- Selection.setSelection(mDefaultKeySsb, 0);
- IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- registerReceiver(mCloseSystemDialogsReceiver, filter);
- updateGlobalIcons();
- // On large interfaces, we want the screen to auto-rotate based on the current orientation
- unlockScreenOrientation(true);
- mStatusBarManager = (StatusBarManager) getSystemService(Context.STATUS_BAR_SERVICE);
- }
- protected void onUserLeaveHint() {
- super.onUserLeaveHint();
- sPausedFromUserAction = true;
- }
- private void updateGlobalIcons() {
- boolean searchVisible = false;
- boolean voiceVisible = false;
- // If we have a saved version of these external icons, we load them up immediately
- int coi = getCurrentOrientationIndexForGlobalIcons();
- if (sGlobalSearchIcon[coi] == null || sVoiceSearchIcon[coi] == null ||
- sAppMarketIcon[coi] == null) {
- updateAppMarketIcon();
- searchVisible = updateGlobalSearchIcon();
- voiceVisible = updateVoiceSearchIcon(searchVisible);
- }
- if (sGlobalSearchIcon[coi] != null) {
- updateGlobalSearchIcon(sGlobalSearchIcon[coi]);
- searchVisible = true;
- }
- if (sVoiceSearchIcon[coi] != null) {
- updateVoiceSearchIcon(sVoiceSearchIcon[coi]);
- voiceVisible = true;
- }
- if (sAppMarketIcon[coi] != null) {
- updateAppMarketIcon(sAppMarketIcon[coi]);
- }
- if (mSearchDropTargetBar != null) {
- mSearchDropTargetBar.onSearchPackagesChanged(searchVisible, voiceVisible);
- }
- }
- private void checkForLocaleChange() {
- if (sLocaleConfiguration == null) {
- new AsyncTask<Void, Void, LocaleConfiguration>() {
- @Override
- protected LocaleConfiguration doInBackground(Void... unused) {
- LocaleConfiguration localeConfiguration = new LocaleConfiguration();
- readConfiguration(Launcher.this, localeConfiguration);
- return localeConfiguration;
- }
- @Override
- protected void onPostExecute(LocaleConfiguration result) {
- sLocaleConfiguration = result;
- checkForLocaleChange(); // recursive, but now with a locale configuration
- }
- }.execute();
- return;
- }
- final Configuration configuration = getResources().getConfiguration();
- final String previousLocale = sLocaleConfiguration.locale;
- final String locale = configuration.locale.toString();
- final int previousMcc = sLocaleConfiguration.mcc;
- final int mcc = configuration.mcc;
- final int previousMnc = sLocaleConfiguration.mnc;
- final int mnc = configuration.mnc;
- boolean localeChanged = !locale.equals(previousLocale) || mcc != previousMcc || mnc != previousMnc;
- if (localeChanged) {
- sLocaleConfiguration.locale = locale;
- sLocaleConfiguration.mcc = mcc;
- sLocaleConfiguration.mnc = mnc;
- mIconCache.flush();
- final LocaleConfiguration localeConfiguration = sLocaleConfiguration;
- new Thread("WriteLocaleConfiguration") {
- @Override
- public void run() {
- writeConfiguration(Launcher.this, localeConfiguration);
- }
- }.start();
- }
- }
- private static class LocaleConfiguration {
- public String locale;
- public int mcc = -1;
- public int mnc = -1;
- }
- private static void readConfiguration(Context context, LocaleConfiguration configuration) {
- DataInputStream in = null;
- try {
- in = new DataInputStream(context.openFileInput(PREFERENCES));
- configuration.locale = in.readUTF();
- configuration.mcc = in.readInt();
- configuration.mnc = in.readInt();
- } catch (FileNotFoundException e) {
- // Ignore
- } catch (IOException e) {
- // Ignore
- } finally {
- if (in != null) {
- try {
- in.close();
- } catch (IOException e) {
- // Ignore
- }
- }
- }
- }
- private static void writeConfiguration(Context context, LocaleConfiguration configuration) {
- DataOutputStream out = null;
- try {
- out = new DataOutputStream(context.openFileOutput(PREFERENCES, MODE_PRIVATE));
- out.writeUTF(configuration.locale);
- out.writeInt(configuration.mcc);
- out.writeInt(configuration.mnc);
- out.flush();
- } catch (FileNotFoundException e) {
- // Ignore
- } catch (IOException e) {
- //noinspection ResultOfMethodCallIgnored
- context.getFileStreamPath(PREFERENCES).delete();
- } finally {
- if (out != null) {
- try {
- out.close();
- } catch (IOException e) {
- // Ignore
- }
- }
- }
- }
- public DragLayer getDragLayer() {
- return mDragLayer;
- }
- boolean isDraggingEnabled() {
- // We prevent dragging when we are loading the workspace as it is possible to pick up a view
- // that is subsequently removed from the workspace in startBinding().
- return !mModel.isLoadingWorkspace();
- }
- /**
- * Returns whether we should delay spring loaded mode -- for shortcuts and widgets that have
- * a configuration step, this allows the proper animations to run after other transitions.
- */
- private boolean completeAdd(PendingAddArguments args) {
- boolean result = false;
- switch (args.requestCode) {
- case REQUEST_PICK_APPLICATION:
- completeAddApplication(args.intent, args.container, args.screen, args.cellX,
- args.cellY);
- break;
- case REQUEST_PICK_SHORTCUT:
- processShortcut(args.intent);
- // Don't remove pending add info
- return false;
- case REQUEST_CREATE_SHORTCUT:
- completeAddShortcut(args.intent, args.container, args.screen, args.cellX,
- args.cellY);
- result = true;
- break;
- case REQUEST_CREATE_APPWIDGET:
- int appWidgetId = args.intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
- completeAddAppWidget(appWidgetId, args.container, args.screen, null, null);
- result = true;
- break;
- case REQUEST_PICK_WALLPAPER:
- // We just wanted the activity result here so we can clear mWaitingForResult
- break;
- }
- // Before adding this resetAddInfo(), after a shortcut was added to a workspace screen,
- // if you turned the screen off and then back while in All Apps, Launcher would not
- // return to the workspace. Clearing mAddInfo.container here fixes this issue
- resetAddInfo();
- return result;
- }
- @Override
- protected void onActivityResult(
- final int requestCode, final int resultCode, final Intent data) {
- if (requestCode == REQUEST_BIND_APPWIDGET) {
- int appWidgetId = data != null ?
- data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1) : -1;
- if (resultCode == RESULT_CANCELED) {
- completeTwoStageWidgetDrop(RESULT_CANCELED, appWidgetId);
- } else if (resultCode == RESULT_OK) {
- addAppWidgetImpl(appWidgetId, mPendingAddInfo, null, mPendingAddWidgetInfo);
- }
- return;
- }
- boolean delayExitSpringLoadedMode = false;
- boolean isWidgetDrop = (requestCode == REQUEST_PICK_APPWIDGET ||
- requestCode == REQUEST_CREATE_APPWIDGET);
- mWaitingForResult = false;
- // We have special handling for widgets
- if (isWidgetDrop) {
- int appWidgetId = data != null ?
- data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1) : -1;
- if (appWidgetId < 0) {
- Log.e(TAG, "Error: appWidgetId (EXTRA_APPWIDGET_ID) was not returned from the \\" +
- "widget configuration activity.");
- completeTwoStageWidgetDrop(RESULT_CANCELED, appWidgetId);
- } else {
- completeTwoStageWidgetDrop(resultCode, appWidgetId);
- }
- return;
- }
- // The pattern used here is that a user PICKs a specific application,
- // which, depending on the target, might need to CREATE the actual target.
- // For example, the user would PICK_SHORTCUT for "Music playlist", and we
- // launch over to the Music app to actually CREATE_SHORTCUT.
- if (resultCode == RESULT_OK && mPendingAddInfo.container != com.cyanogenmod.trebuchet.ItemInfo.NO_ID) {
- final PendingAddArguments args = new PendingAddArguments();
- args.requestCode = requestCode;
- args.intent = data;
- args.container = mPendingAddInfo.container;
- args.screen = mPendingAddInfo.screen;
- args.cellX = mPendingAddInfo.cellX;
- args.cellY = mPendingAddInfo.cellY;
- if (isWorkspaceLocked()) {
- sPendingAddList.add(args);
- } else {
- delayExitSpringLoadedMode = completeAdd(args);
- }
- }
- mDragLayer.clearAnimatedView();
- // Exit spring loaded mode if necessary after cancelling the configuration of a widget
- exitSpringLoadedDragModeDelayed((resultCode != RESULT_CANCELED), delayExitSpringLoadedMode,
- null);
- }
- private void completeTwoStageWidgetDrop(final int resultCode, final int appWidgetId) {
- CellLayout cellLayout =
- (CellLayout) mWorkspace.getChildAt(mPendingAddInfo.screen);
- Runnable onCompleteRunnable = null;
- int animationType = 0;
- AppWidgetHostView boundWidget = null;
- if (resultCode == RESULT_OK) {
- animationType = Workspace.COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION;
- final AppWidgetHostView layout = mAppWidgetHost.createView(this, appWidgetId,
- mPendingAddWidgetInfo);
- boundWidget = layout;
- onCompleteRunnable = new Runnable() {
- @Override
- public void run() {
- completeAddAppWidget(appWidgetId, mPendingAddInfo.container,
- mPendingAddInfo.screen, layout, null);
- exitSpringLoadedDragModeDelayed(true, false, null);
- }
- };
- } else if (resultCode == RESULT_CANCELED) {
- animationType = Workspace.CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION;
- onCompleteRunnable = new Runnable() {
- @Override
- public void run() {
- exitSpringLoadedDragModeDelayed(false, false, null);
- }
- };
- }
- if (mDragLayer.getAnimatedView() != null) {
- mWorkspace.animateWidgetDrop(mPendingAddInfo, cellLayout,
- (DragView) mDragLayer.getAnimatedView(), onCompleteRunnable,
- animationType, boundWidget, true);
- } else {
- // The animated view may be null in the case of a rotation during widget configuration
- if (onCompleteRunnable != null) {
- onCompleteRunnable.run();
- }
- }
- }
- @Override
- protected void onResume() {
- super.onResume();
- // Restore the previous launcher state
- if (mOnResumeState == State.WORKSPACE) {
- showWorkspace(false);
- } else if (mOnResumeState == State.APPS_CUSTOMIZE) {
- showAllApps(false);
- }
- mOnResumeState = State.NONE;
- // Background was set to gradient in onPause(), restore to black if in all apps.
- setWorkspaceBackground(mState == State.WORKSPACE);
- // Process any items that were added while Launcher was away
- InstallShortcutReceiver.flushInstallQueue(this);
- mPaused = false;
- sPausedFromUserAction = false;
- // Restart launcher when preferences are changed
- if (preferencesChanged()) {
- android.os.Process.killProcess(android.os.Process.myPid());
- }
- if (mRestoring || mOnResumeNeedsLoad) {
- mWorkspaceLoading = true;
- mModel.startLoader(true, -1);
- mRestoring = false;
- mOnResumeNeedsLoad = false;
- }
- // Reset the pressed state of icons that were locked in the press state while activities
- // were launching
- if (mWaitingForResume != null) {
- // Resets the previous workspace icon press state
- mWaitingForResume.setStayPressed(false);
- }
- if (mAppsCustomizeContent != null) {
- // Resets the previous all apps icon press state
- mAppsCustomizeContent.resetDrawableState();
- }
- // It is possible that widgets can receive updates while launcher is not in the foreground.
- // Consequently, the widgets will be inflated in the orientation of the foreground activity
- // (framework issue). On resuming, we ensure that any widgets are inflated for the current
- // orientation.
- getWorkspace().reinflateWidgetsIfNecessary();
- getWorkspace().checkWallpaper();
- // Again, as with the above scenario, it's possible that one or more of the global icons
- // were updated in the wrong orientation.
- updateGlobalIcons();
- }
- @Override
- protected void onPause() {
- // NOTE: We want all transitions from launcher to act as if the wallpaper were enabled
- // to be consistent. So re-enable the flag here, and we will re-disable it as necessary
- // when Launcher resumes and we are still in AllApps.
- updateWallpaperVisibility(true);
- super.onPause();
- mPaused = true;
- mDragController.cancelDrag();
- mDragController.resetLastGestureUpTime();
- }
- @Override
- public Object onRetainNonConfigurationInstance() {
- // Flag the loader to stop early before switching
- mModel.stopLoader();
- if (mAppsCustomizeContent != null) {
- mAppsCustomizeContent.surrender();
- }
- return Boolean.TRUE;
- }
- private boolean acceptFilter() {
- final InputMethodManager inputManager = (InputMethodManager)
- getSystemService(Context.INPUT_METHOD_SERVICE);
- return !inputManager.isFullscreenMode();
- }
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- final int uniChar = event.getUnicodeChar();
- final boolean handled = super.onKeyDown(keyCode, event);
- final boolean isKeyNotWhitespace = uniChar > 0 && !Character.isWhitespace(uniChar);
- if (!handled && acceptFilter() && isKeyNotWhitespace) {
- boolean gotKey = TextKeyListener.getInstance().onKeyDown(mWorkspace, mDefaultKeySsb,
- keyCode, event);
- if (gotKey && mDefaultKeySsb != null && mDefaultKeySsb.length() > 0) {
- // something usable has been typed - start a search
- // the typed text will be retrieved and cleared by
- // showSearchDialog()
- // If there are multiple keystrokes before the search dialog takes focus,
- // onSearchRequested() will be called for every keystroke,
- // but it is idempotent, so it's fine.
- return onSearchRequested();
- }
- }
- // Eat the long press event so the keyboard doesn't come up.
- if (keyCode == KeyEvent.KEYCODE_MENU && event.isLongPress()) {
- return true;
- }
- return handled;
- }
- private String getTypedText() {
- return mDefaultKeySsb.toString();
- }
- private void clearTypedText() {
- mDefaultKeySsb.clear();
- mDefaultKeySsb.clearSpans();
- Selection.setSelection(mDefaultKeySsb, 0);
- }
- /**
- * Given the integer (ordinal) value of a State enum instance, convert it to a variable of type
- * State
- */
- private static State intToState(int stateOrdinal) {
- State state = State.WORKSPACE;
- final State[] stateValues = State.values();
- for (State stateValue : stateValues) {
- if (stateValue.ordinal() == stateOrdinal) {
- state = stateValue;
- break;
- }
- }
- return state;
- }
- /**
- * Restores the previous state, if it exists.
- *
- * @param savedState The previous state.
- */
- private void restoreState(Bundle savedState) {
- if (savedState == null) {
- return;
- }
- State state = intToState(savedState.getInt(RUNTIME_STATE, State.WORKSPACE.ordinal()));
- if (state == State.APPS_CUSTOMIZE) {
- mOnResumeState = State.APPS_CUSTOMIZE;
- }
- int currentScreen = savedState.getInt(RUNTIME_STATE_CURRENT_SCREEN, -1);
- if (currentScreen > -1) {
- mWorkspace.setCurrentPage(currentScreen);
- }
- int currentHotseatScreen = savedState.getInt(RUNTIME_STATE_CURRENT_HOTSEAT_SCREEN, -1);
- if (currentHotseatScreen > -1) {
- mHotseat.setCurrentPage(mHotseat.getScreenFromOrder(currentHotseatScreen));
- }
- final long pendingAddContainer = savedState.getLong(RUNTIME_STATE_PENDING_ADD_CONTAINER, -1);
- final int pendingAddScreen = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SCREEN, -1);
- if (pendingAddContainer != com.cyanogenmod.trebuchet.ItemInfo.NO_ID && pendingAddScreen > -1) {
- mPendingAddInfo.container = pendingAddContainer;
- mPendingAddInfo.screen = pendingAddScreen;
- mPendingAddInfo.cellX = savedState.getInt(RUNTIME_STATE_PENDING_ADD_CELL_X);
- mPendingAddInfo.cellY = savedState.getInt(RUNTIME_STATE_PENDING_ADD_CELL_Y);
- mPendingAddInfo.spanX = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SPAN_X);
- mPendingAddInfo.spanY = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SPAN_Y);
- mPendingAddWidgetInfo = savedState.getParcelable(RUNTIME_STATE_PENDING_ADD_WIDGET_INFO);
- mWaitingForResult = true;
- mRestoring = true;
- }
- boolean renameFolder = savedState.getBoolean(RUNTIME_STATE_PENDING_FOLDER_RENAME, false);
- if (renameFolder) {
- long id = savedState.getLong(RUNTIME_STATE_PENDING_FOLDER_RENAME_ID);
- mFolderInfo = mModel.getFolderById(this, sFolders, id);
- mRestoring = true;
- }
- // Restore the AppsCustomize tab
- if (mAppsCustomizeTabHost != null) {
- String curTab = savedState.getString("apps_customize_currentTab");
- if (curTab != null) {
- mAppsCustomizeTabHost.setContentTypeImmediate(
- mAppsCustomizeTabHost.getContentTypeForTabTag(curTab));
- mAppsCustomizeContent.loadAssociatedPages(
- mAppsCustomizeContent.getCurrentPage());
- }
- int currentIndex = savedState.getInt("apps_customize_currentIndex");
- mAppsCustomizeContent.restorePageForIndex(currentIndex);
- }
- }
- /**
- * Finds all the views we need and configure them properly.
- */
- private void setupViews() {
- final DragController dragController = mDragController;
- mLauncherView = findViewById(R.id.launcher);
- mDragLayer = (DragLayer) findViewById(R.id.drag_layer);
- mWorkspace = (Workspace) mDragLayer.findViewById(R.id.workspace);
- mQsbDivider = findViewById(R.id.qsb_divider);
- mDockDivider = findViewById(R.id.dock_divider);
- mLauncherView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
- mWorkspaceBackgroundDrawable = getResources().getDrawable(R.drawable.workspace_bg);
- mBlackBackgroundDrawable = new ColorDrawable(Color.BLACK);
- // Setup the drag layer
- mDragLayer.setup(this, dragController);
- // Setup the hotseat
- mHotseat = (Hotseat) findViewById(R.id.hotseat);
- // Setup the workspace
- mWorkspace.setHapticFeedbackEnabled(false);
- mWorkspace.setOnLongClickListener(this);
- mWorkspace.setup(dragController);
- dragController.addDragListener(mWorkspace);
- if (mHomescreenDoubleTap != 0) {
- mWorkspace.setOnDoubleTapCallback(new Runnable() {
- public void run() {
- performGesture(mHomescreenDoubleTap, 0);
- }
- });
- }
- if (mHomescreenSwipeUp != 0) {
- mWorkspace.setOnSwipeUpCallback(new Runnable() {
- public void run() {
- performGesture(mHomescreenSwipeUp, 1);
- }
- });
- }
- if (mHomescreenSwipeDown != 0) {
- mWorkspace.setOnSwipeDownCallback(new Runnable() {
- public void run() {
- performGesture(mHomescreenSwipeDown, 2);
- }
- });
- }
- // Get the search/delete bar
- mSearchDropTargetBar = (SearchDropTargetBar) mDragLayer.findViewById(R.id.qsb_bar);
- // Hide the search divider if we are hiding search bar
- if (!mShowSearchBar && mQsbDivider != null && getCurrentOrientation() == Configuration.ORIENTATION_LANDSCAPE) {
- mQsbDivider.setVisibility(View.GONE);
- }
- if (!mShowHotseat) {
- mHotseat.setVisibility(View.GONE);
- }
- if (!mShowDockDivider && mDockDivider != null) {
- mDockDivider.setVisibility(View.GONE);
- }
- // Redim the hotseat and statusbar to let some extra size for the item text
- if (mShowHotseat && !mHideDockIconLabels && !mHotseat.hasVerticalHotseat()) {
- Resources res = getResources();
- int bottomMarginWithText = res.getDimensionPixelSize(R.dimen.button_bar_height_with_text);
- // Divider
- if (mDockDivider != null) {
- ((MarginLayoutParams)mDockDivider.getLayoutParams()).bottomMargin = bottomMarginWithText;
- }
- // Divider indicator
- View dockScrollingIndicator = findViewById(R.id.paged_view_indicator_dock);
- if (dockScrollingIndicator != null) {
- ((MarginLayoutParams)dockScrollingIndicator.getLayoutParams()).bottomMargin = bottomMarginWithText;
- }
- // Hotseat
- mHotseat.getLayoutParams().height = res.getDimensionPixelSize(R.dimen.button_bar_height_plus_padding_with_text);
- // Workspace
- mWorkspace.setPadding(
- mWorkspace.getPaddingLeft(),
- mWorkspace.getPaddingTop(),
- mWorkspace.getPaddingRight(),
- res.getDimensionPixelSize(R.dimen.workspace_bottom_padding_port_with_text));
- }
- // Setup AppsCustomize
- mAppsCustomizeTabHost = (AppsCustomizeTabHost) findViewById(R.id.apps_customize_pane);
- mAppsCustomizeContent = (AppsCustomizePagedView)
- mAppsCustomizeTabHost.findViewById(R.id.apps_customize_pane_content);
- mAppsCustomizeContent.setup(this, dragController);
- // Setup the drag controller (drop targets have to be added in reverse order in priority)
- dragController.setDragScoller(mWorkspace);
- dragController.setScrollView(mDragLayer);
- dragController.setMoveTarget(mWorkspace);
- dragController.addDropTarget(mWorkspace);
- if (mSearchDropTargetBar != null) {
- mSearchDropTargetBar.setup(this, dragController);
- }
- }
- /**
- * Starts shortcut rename dialog.
- *
- * @param info The shortcut to be edited
- */
- void updateShortcut(final ShortcutInfo info) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- View layout = mInflater.inflate(R.layout.dialog_edit, null);
- ImageView icon = (ImageView) layout.findViewById(R.id.dialog_edit_icon);
- icon.setImageBitmap(info.getIcon(mIconCache));
- final EditText title = (EditText) layout.findViewById(R.id.dialog_edit_text);
- title.setText(info.title);
- builder.setView(layout)
- .setTitle(info.title)
- .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- info.setTitle(title.getText());
- LauncherModel.updateItemInDatabase(Launcher.this, info);
- }
- })
- .setNegativeButton(android.R.string.cancel, null);
- builder.show();
- }
- /**
- * Creates a view representing a shortcut.
- *
- * @param info The data structure describing the shortcut.
- *
- * @return A View inflated from R.layout.application.
- */
- View createShortcut(ShortcutInfo info) {
- return createShortcut(R.layout.application,
- (ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentPage()), info);
- }
- /**
- * Creates a view representing a shortcut inflated from the specified resource.
- *
- * @param layoutResId The id of the XML layout used to create the shortcut.
- * @param parent The group the shortcut belongs to.
- * @param info The data structure describing the shortcut.
- *
- * @return A View inflated from layoutResId.
- */
- View createShortcut(int layoutResId, ViewGroup parent, ShortcutInfo info) {
- BubbleTextView favorite = (BubbleTextView) mInflater.inflate(layoutResId, parent, false);
- favorite.applyFromShortcutInfo(info, mIconCache);
- favorite.setTextVisible(!mHideIconLabels);
- favorite.setOnClickListener(this);
- favorite.setOnTouchListener(this);
- return favorite;
- }
- /**
- * Add an application shortcut to the workspace.
- *
- * @param data The intent describing the application.
- * @param cellInfo The position on screen where to create the shortcut.
- */
- void completeAddApplication(Intent data, long container, int screen, int cellX, int cellY) {
- final int[] cellXY = mTmpAddItemCellCoordinates;
- final CellLayout layout = getCellLayout(container, screen);
- // First we check if we already know the exact location where we want to add this item.
- if (cellX >= 0 && cellY >= 0) {
- cellXY[0] = cellX;
- cellXY[1] = cellY;
- } else if (!layout.findCellForSpan(cellXY, 1, 1)) {
- showOutOfSpaceMessage(isHotseatLayout(layout));
- return;
- }
- final ShortcutInfo info = mModel.getShortcutInfo(getPackageManager(), data, this);
- if (info != null) {
- info.setActivity(data.getComponent(), Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- info.container = com.cyanogenmod.trebuchet.ItemInfo.NO_ID;
- mWorkspace.addApplicationShortcut(info, layout, container, screen,
- isWorkspaceLocked(), cellX, cellY);
- } else {
- Log.e(TAG, "Couldn't find ActivityInfo for selected application: " + data);
- }
- }
- private void restoreShortcut(ShortcutInfo info) {
- final View view = createShortcut(info);
- FolderInfo folderInfo = info.mFolderInfo;
- if (info.container >= 0 && folderInfo != null) {
- // The shortcut was contained by a folder
- // It's necessary to recreate the folder or just to add to the existing one?
- CellLayout layout = getCellLayout(folderInfo.container, folderInfo.screen);
- View v = layout.getChildAt(folderInfo.cellX, folderInfo.cellY);
- if (v == null) {
- // Weird. Should not there be a shortcut or folder here?
- return;
- }
- if (v.getTag() != null && v.getTag() instanceof ShortcutInfo) {
- // Create a new folder
- ShortcutInfo target = (ShortcutInfo)v.getTag();
- // Remove the target item to allow to be occupied by the folder
- layout.removeView(v);
- // Create the folder and its new items
- FolderIcon fi = addFolder(
- layout, folderInfo.container, folderInfo.screen,
- folderInfo.cellX, folderInfo.cellY);
- int cellX = info.cellX;
- int cellY = info.cellY;
- info.cellX = -1;
- info.cellY = -1;
- target.cellX = -1;
- target.cellY = -1;
- if (cellX == 0 && cellY == 0) {
- fi.addItem(info);
- fi.addItem(target);
- } else {
- fi.addItem(target);
- fi.addItem(info);
- }
- }
- } else if (info.container >= 0) {
- // The shortcut was contained by a folder and the folder still exists
- FolderIcon folderIcon = null;
- // We need to find the container in the workspace, because the shortcut has lost
- // its information
- ArrayList<ShortcutAndWidgetContainer> allSwc =
- mWorkspace.getAllShortcutAndWidgetContainers();
- for (ShortcutAndWidgetContainer swc : allSwc) {
- int cc = swc.getChildCount();
- for (int i = 0; i < cc; i++) {
- View v = swc.getChildAt(i);
- if (v instanceof FolderIcon) {
- FolderInfo fi = (FolderInfo)v.getTag();
- if (fi != null && fi.id == info.container) {
- folderIcon = (FolderIcon)v;
- break;
- }
- }
- }
- if (folderIcon != null) {
- break;
- }
- }
- if (folderIcon != null) {
- folderIcon.addItem(info);
- }
- } else {
- // Just restore the shortcut in its last position
- long con…
Large files files are truncated, but you can click here to view the full file