PageRenderTime 63ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/src/com/cyanogenmod/trebuchet/Launcher.java

https://bitbucket.org/smartguy044/android_packages_apps_trebuchet
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

  1. /*
  2. * Copyright (C) 2008 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. package com.cyanogenmod.trebuchet;
  17. import android.accounts.Account;
  18. import android.accounts.AccountManager;
  19. import android.animation.Animator;
  20. import android.animation.AnimatorListenerAdapter;
  21. import android.animation.AnimatorSet;
  22. import android.animation.ObjectAnimator;
  23. import android.animation.PropertyValuesHolder;
  24. import android.animation.ValueAnimator;
  25. import android.animation.ValueAnimator.AnimatorUpdateListener;
  26. import android.app.Activity;
  27. import android.app.ActivityManager;
  28. import android.app.ActivityOptions;
  29. import android.app.AlertDialog;
  30. import android.app.SearchManager;
  31. import android.app.StatusBarManager;
  32. import android.appwidget.AppWidgetHostView;
  33. import android.appwidget.AppWidgetManager;
  34. import android.appwidget.AppWidgetProviderInfo;
  35. import android.content.ActivityNotFoundException;
  36. import android.content.BroadcastReceiver;
  37. import android.content.ComponentCallbacks2;
  38. import android.content.ComponentName;
  39. import android.content.ContentResolver;
  40. import android.content.Context;
  41. import android.content.DialogInterface;
  42. import android.content.Intent;
  43. import android.content.IntentFilter;
  44. import android.content.SharedPreferences;
  45. import android.content.pm.ActivityInfo;
  46. import android.content.pm.PackageManager;
  47. import android.content.pm.PackageManager.NameNotFoundException;
  48. import android.content.pm.ResolveInfo;
  49. import android.content.res.Configuration;
  50. import android.content.res.Resources;
  51. import android.database.ContentObserver;
  52. import android.graphics.Bitmap;
  53. import android.graphics.Canvas;
  54. import android.graphics.Color;
  55. import android.graphics.PorterDuff;
  56. import android.graphics.Rect;
  57. import android.graphics.drawable.BitmapDrawable;
  58. import android.graphics.drawable.ColorDrawable;
  59. import android.graphics.drawable.Drawable;
  60. import android.net.Uri;
  61. import android.os.AsyncTask;
  62. import android.os.Bundle;
  63. import android.os.Environment;
  64. import android.os.Handler;
  65. import android.os.Message;
  66. import android.os.StrictMode;
  67. import android.os.SystemClock;
  68. import android.provider.Settings;
  69. import android.speech.RecognizerIntent;
  70. import android.text.Selection;
  71. import android.text.SpannableStringBuilder;
  72. import android.text.TextUtils;
  73. import android.text.method.TextKeyListener;
  74. import android.util.Log;
  75. import android.view.Display;
  76. import android.view.HapticFeedbackConstants;
  77. import android.view.KeyEvent;
  78. import android.view.LayoutInflater;
  79. import android.view.Menu;
  80. import android.view.MenuItem;
  81. import android.view.MotionEvent;
  82. import android.view.Surface;
  83. import android.view.View;
  84. import android.view.View.OnLongClickListener;
  85. import android.view.ViewConfiguration;
  86. import android.view.ViewGroup;
  87. import android.view.ViewTreeObserver;
  88. import android.view.ViewGroup.MarginLayoutParams;
  89. import android.view.ViewTreeObserver.OnGlobalLayoutListener;
  90. import android.view.WindowManager;
  91. import android.view.accessibility.AccessibilityEvent;
  92. import android.view.animation.AccelerateDecelerateInterpolator;
  93. import android.view.animation.AccelerateInterpolator;
  94. import android.view.animation.DecelerateInterpolator;
  95. import android.view.inputmethod.InputMethodManager;
  96. import android.widget.Advanceable;
  97. import android.widget.EditText;
  98. import android.widget.ImageView;
  99. import android.widget.PopupMenu;
  100. import android.widget.TextView;
  101. import android.widget.Toast;
  102. import com.android.common.Search;
  103. import com.cyanogenmod.trebuchet.DropTarget.DragObject;
  104. import com.cyanogenmod.trebuchet.preference.*;
  105. import java.io.DataInputStream;
  106. import java.io.DataOutputStream;
  107. import java.io.FileDescriptor;
  108. import java.io.FileNotFoundException;
  109. import java.io.IOException;
  110. import java.io.PrintWriter;
  111. import java.util.ArrayList;
  112. import java.util.Collection;
  113. import java.util.Collections;
  114. import java.util.Comparator;
  115. import java.util.HashMap;
  116. import java.util.HashSet;
  117. import java.util.List;
  118. import java.util.Set;
  119. /**
  120. * Default launcher application.
  121. */
  122. public final class Launcher extends Activity
  123. implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,
  124. View.OnTouchListener {
  125. private static final String TAG = "Trebuchet.Launcher";
  126. static final boolean PROFILE_STARTUP = false;
  127. static final boolean DEBUG_WIDGETS = false;
  128. static final boolean DEBUG_STRICT_MODE = false;
  129. private static final int MENU_GROUP_WALLPAPER = 1;
  130. private static final int MENU_GROUP_DRAWER = MENU_GROUP_WALLPAPER + 1;
  131. private static final int MENU_DRAWER = Menu.FIRST + 1;
  132. private static final int MENU_MANAGE_APPS = MENU_DRAWER + 1;
  133. private static final int MENU_SYSTEM_SETTINGS = MENU_MANAGE_APPS + 1;
  134. private static final int MENU_PREFERENCES = MENU_SYSTEM_SETTINGS + 1;
  135. private static final int MENU_WALLPAPER_SETTINGS = MENU_PREFERENCES + 1;
  136. private static final int MENU_LOCK_WORKSPACE = MENU_WALLPAPER_SETTINGS + 1;
  137. private static final int MENU_HELP = MENU_WALLPAPER_SETTINGS + 1;
  138. private static final int REQUEST_CREATE_SHORTCUT = 1;
  139. private static final int REQUEST_CREATE_APPWIDGET = 5;
  140. private static final int REQUEST_PICK_APPLICATION = 6;
  141. private static final int REQUEST_PICK_SHORTCUT = 7;
  142. private static final int REQUEST_PICK_APPWIDGET = 9;
  143. private static final int REQUEST_PICK_WALLPAPER = 10;
  144. private static final int REQUEST_BIND_APPWIDGET = 11;
  145. static final String EXTRA_SHORTCUT_DUPLICATE = "duplicate";
  146. static final int MAX_WORKSPACE_SCREEN_COUNT = 7;
  147. static final int MAX_HOTSEAT_SCREEN_COUNT = 3;
  148. static final int MAX_SCREEN_COUNT = MAX_WORKSPACE_SCREEN_COUNT + MAX_HOTSEAT_SCREEN_COUNT;
  149. static final int DEFAULT_SCREEN = 2;
  150. private static final String PREFERENCES = "launcher.preferences";
  151. // To turn on these properties, type
  152. // adb shell setprop log.tag.PROPERTY_NAME [VERBOSE | SUPPRESS]
  153. static final String FORCE_ENABLE_ROTATION_PROPERTY = "launcher_force_rotate";
  154. static final String DUMP_STATE_PROPERTY = "launcher_dump_state";
  155. // The Intent extra that defines whether to ignore the launch animation
  156. static final String INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION =
  157. "com.cyanogenmod.trebuchet.intent.extra.shortcut.INGORE_LAUNCH_ANIMATION";
  158. // Type: int
  159. private static final String RUNTIME_STATE_CURRENT_SCREEN = "launcher.current_screen";
  160. // Type: int
  161. private static final String RUNTIME_STATE_CURRENT_HOTSEAT_SCREEN = "launcher.hotseat.current_screen";
  162. // Type: int
  163. private static final String RUNTIME_STATE = "launcher.state";
  164. // Type: int
  165. private static final String RUNTIME_STATE_PENDING_ADD_CONTAINER = "launcher.add_container";
  166. // Type: int
  167. private static final String RUNTIME_STATE_PENDING_ADD_SCREEN = "launcher.add_screen";
  168. // Type: int
  169. private static final String RUNTIME_STATE_PENDING_ADD_CELL_X = "launcher.add_cell_x";
  170. // Type: int
  171. private static final String RUNTIME_STATE_PENDING_ADD_CELL_Y = "launcher.add_cell_y";
  172. // Type: boolean
  173. private static final String RUNTIME_STATE_PENDING_FOLDER_RENAME = "launcher.rename_folder";
  174. // Type: long
  175. private static final String RUNTIME_STATE_PENDING_FOLDER_RENAME_ID = "launcher.rename_folder_id";
  176. // Type: int
  177. private static final String RUNTIME_STATE_PENDING_ADD_SPAN_X = "launcher.add_span_x";
  178. // Type: int
  179. private static final String RUNTIME_STATE_PENDING_ADD_SPAN_Y = "launcher.add_span_y";
  180. // Type: parcelable
  181. private static final String RUNTIME_STATE_PENDING_ADD_WIDGET_INFO = "launcher.add_widget_info";
  182. private static final String TOOLBAR_ICON_METADATA_NAME = "com.android.launcher.toolbar_icon";
  183. private static final String TOOLBAR_SEARCH_ICON_METADATA_NAME =
  184. "com.android.launcher.toolbar_search_icon";
  185. private static final String TOOLBAR_VOICE_SEARCH_ICON_METADATA_NAME =
  186. "com.android.launcher.toolbar_voice_search_icon";
  187. /** The different states that Launcher can be in. */
  188. private enum State { NONE, WORKSPACE, APPS_CUSTOMIZE, APPS_CUSTOMIZE_SPRING_LOADED }
  189. private State mState = State.WORKSPACE;
  190. private AnimatorSet mStateAnimation;
  191. private AnimatorSet mDividerAnimator;
  192. static final int APPWIDGET_HOST_ID = 1024;
  193. private static final int EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT = 300;
  194. private static final int EXIT_SPRINGLOADED_MODE_LONG_TIMEOUT = 600;
  195. private static final int SHOW_CLING_DURATION = 550;
  196. private static final int DISMISS_CLING_DURATION = 250;
  197. // How long to wait before the new-shortcut animation automatically pans the workspace
  198. private static final int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 10;
  199. private final BroadcastReceiver mCloseSystemDialogsReceiver
  200. = new CloseSystemDialogsIntentReceiver();
  201. private final ContentObserver mWidgetObserver = new AppWidgetResetObserver();
  202. private LayoutInflater mInflater;
  203. private Workspace mWorkspace;
  204. private View mQsbDivider;
  205. private View mDockDivider;
  206. private View mLauncherView;
  207. private DragLayer mDragLayer;
  208. private DragController mDragController;
  209. private AppWidgetManager mAppWidgetManager;
  210. private LauncherAppWidgetHost mAppWidgetHost;
  211. private ItemInfo mPendingAddInfo = new ItemInfo();
  212. private AppWidgetProviderInfo mPendingAddWidgetInfo;
  213. private int[] mTmpAddItemCellCoordinates = new int[2];
  214. private FolderInfo mFolderInfo;
  215. private Hotseat mHotseat;
  216. private SearchDropTargetBar mSearchDropTargetBar;
  217. private AppsCustomizeTabHost mAppsCustomizeTabHost;
  218. private AppsCustomizePagedView mAppsCustomizeContent;
  219. private boolean mAutoAdvanceRunning = false;
  220. private Bundle mSavedState;
  221. // We set the state in both onCreate and then onNewIntent in some cases, which causes both
  222. // scroll issues (because the workspace may not have been measured yet) and extra work.
  223. // Instead, just save the state that we need to restore Launcher to, and commit it in onResume.
  224. private State mOnResumeState = State.NONE;
  225. private SpannableStringBuilder mDefaultKeySsb = null;
  226. private boolean mWorkspaceLoading = true;
  227. private boolean mPaused = true;
  228. private boolean mRestoring;
  229. private boolean mWaitingForResult;
  230. private boolean mOnResumeNeedsLoad;
  231. // Keep track of whether the user has left launcher
  232. private static boolean sPausedFromUserAction = false;
  233. private LauncherModel mModel;
  234. private IconCache mIconCache;
  235. private boolean mUserPresent = true;
  236. private boolean mVisible = false;
  237. private boolean mAttached = false;
  238. private static LocaleConfiguration sLocaleConfiguration = null;
  239. private static HashMap<Long, FolderInfo> sFolders = new HashMap<Long, FolderInfo>();
  240. private Intent mAppMarketIntent = null;
  241. // Related to the auto-advancing of widgets
  242. private final int ADVANCE_MSG = 1;
  243. private final int mAdvanceInterval = 20000;
  244. private final int mAdvanceStagger = 250;
  245. private long mAutoAdvanceSentTime;
  246. private long mAutoAdvanceTimeLeft = -1;
  247. private HashMap<View, AppWidgetProviderInfo> mWidgetsToAdvance =
  248. new HashMap<View, AppWidgetProviderInfo>();
  249. // Determines how long to wait after a rotation before restoring the screen orientation to
  250. // match the sensor state.
  251. private static final int RESTORE_SCREEN_ORIENTATION_DELAY = 500;
  252. // External icons saved in case of resource changes, orientation, etc.
  253. private static Drawable.ConstantState[] sGlobalSearchIcon = new Drawable.ConstantState[2];
  254. private static Drawable.ConstantState[] sVoiceSearchIcon = new Drawable.ConstantState[2];
  255. private static Drawable.ConstantState[] sAppMarketIcon = new Drawable.ConstantState[2];
  256. private Drawable mWorkspaceBackgroundDrawable;
  257. private Drawable mBlackBackgroundDrawable;
  258. private final ArrayList<Integer> mSynchronouslyBoundPages = new ArrayList<Integer>();
  259. static final ArrayList<String> sDumpLogs = new ArrayList<String>();
  260. // We only want to get the SharedPreferences once since it does an FS stat each time we get
  261. // it from the context.
  262. private SharedPreferences mSharedPrefs;
  263. // Holds the page that we need to animate to, and the icon views that we need to animate up
  264. // when we scroll to that page on resume.
  265. private int mNewShortcutAnimatePage = -1;
  266. private ArrayList<View> mNewShortcutAnimateViews = new ArrayList<View>();
  267. private ImageView mFolderIconImageView;
  268. private Bitmap mFolderIconBitmap;
  269. private Canvas mFolderIconCanvas;
  270. private Rect mRectForFolderAnimation = new Rect();
  271. private BubbleTextView mWaitingForResume;
  272. private HideFromAccessibilityHelper mHideFromAccessibilityHelper
  273. = new HideFromAccessibilityHelper();
  274. // Preferences
  275. private boolean mShowSearchBar;
  276. private boolean mShowHotseat;
  277. private boolean mShowDockDivider;
  278. private boolean mHideIconLabels;
  279. private boolean mHideDockIconLabels;
  280. private boolean mAutoRotate;
  281. private boolean mLockWorkspace;
  282. private boolean mFullscreenMode;
  283. private int mHomescreenDoubleTap;
  284. private int mHomescreenSwipeUp;
  285. private int mHomescreenSwipeDown;
  286. private StatusBarManager mStatusBarManager;
  287. private boolean mWallpaperVisible;
  288. private Runnable mBuildLayersRunnable = new Runnable() {
  289. public void run() {
  290. if (mWorkspace != null) {
  291. mWorkspace.buildPageHardwareLayers();
  292. }
  293. }
  294. };
  295. private static ArrayList<PendingAddArguments> sPendingAddList
  296. = new ArrayList<PendingAddArguments>();
  297. private static boolean sForceEnableRotation = isPropertyEnabled(FORCE_ENABLE_ROTATION_PROPERTY);
  298. private static class PendingAddArguments {
  299. int requestCode;
  300. Intent intent;
  301. long container;
  302. int screen;
  303. int cellX;
  304. int cellY;
  305. }
  306. private static boolean isPropertyEnabled(String propertyName) {
  307. return Log.isLoggable(propertyName, Log.VERBOSE);
  308. }
  309. @Override
  310. protected void onCreate(Bundle savedInstanceState) {
  311. if (DEBUG_STRICT_MODE) {
  312. StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
  313. .detectDiskReads()
  314. .detectDiskWrites()
  315. .detectNetwork() // or .detectAll() for all detectable problems
  316. .penaltyLog()
  317. .build());
  318. StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
  319. .detectLeakedSqlLiteObjects()
  320. .detectLeakedClosableObjects()
  321. .penaltyLog()
  322. .penaltyDeath()
  323. .build());
  324. }
  325. super.onCreate(savedInstanceState);
  326. LauncherApplication app = ((LauncherApplication)getApplication());
  327. mSharedPrefs = getSharedPreferences(LauncherApplication.getSharedPreferencesKey(),
  328. Context.MODE_PRIVATE);
  329. mModel = app.setLauncher(this);
  330. mIconCache = app.getIconCache();
  331. mDragController = new DragController(this);
  332. mInflater = getLayoutInflater();
  333. final Resources res = getResources();
  334. // Load all preferences
  335. PreferencesProvider.load(this);
  336. mAppWidgetManager = AppWidgetManager.getInstance(this);
  337. mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID);
  338. mAppWidgetHost.startListening();
  339. // If we are getting an onCreate, we can actually preempt onResume and unset mPaused here,
  340. // this also ensures that any synchronous binding below doesn't re-trigger another
  341. // LauncherModel load.
  342. mPaused = false;
  343. // Preferences
  344. mShowSearchBar = PreferencesProvider.Interface.Homescreen.getShowSearchBar();
  345. mShowHotseat = PreferencesProvider.Interface.Dock.getShowDock();
  346. mShowDockDivider = PreferencesProvider.Interface.Dock.getShowDivider() && mShowHotseat;
  347. mHideIconLabels = PreferencesProvider.Interface.Homescreen.getHideIconLabels();
  348. mHideDockIconLabels = PreferencesProvider.Interface.Dock.getHideIconLabels();
  349. boolean verticalHotseat =
  350. res.getBoolean(R.bool.hotseat_transpose_layout_with_orientation) &&
  351. res.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
  352. mHideDockIconLabels = PreferencesProvider.Interface.Dock.getHideIconLabels() ||
  353. (!mShowHotseat || (verticalHotseat && !LauncherApplication.isScreenLarge()));
  354. mAutoRotate = PreferencesProvider.Interface.General.getAutoRotate(getResources().getBoolean(R.bool.allow_rotation));
  355. mLockWorkspace = PreferencesProvider.Interface.General.getLockWorkspace(getResources().getBoolean(R.bool.lock_workspace));
  356. mFullscreenMode = PreferencesProvider.Interface.General.getFullscreenMode();
  357. mHomescreenDoubleTap = PreferencesProvider.Interface.Gestures.getHomescreenDoubleTap();
  358. mHomescreenSwipeUp = PreferencesProvider.Interface.Gestures.getHomescreenSwipeUp();
  359. mHomescreenSwipeDown = PreferencesProvider.Interface.Gestures.getHomescreenSwipeDown();
  360. if (PROFILE_STARTUP) {
  361. android.os.Debug.startMethodTracing(
  362. Environment.getExternalStorageDirectory() + "/launcher");
  363. }
  364. checkForLocaleChange();
  365. setContentView(R.layout.launcher);
  366. setupViews();
  367. showFirstRunWorkspaceCling();
  368. registerContentObservers();
  369. lockAllApps();
  370. mSavedState = savedInstanceState;
  371. restoreState(mSavedState);
  372. // Update customization drawer _after_ restoring the states
  373. if (mAppsCustomizeContent != null) {
  374. mAppsCustomizeContent.onPackagesUpdated();
  375. }
  376. if (PROFILE_STARTUP) {
  377. android.os.Debug.stopMethodTracing();
  378. }
  379. if (!mRestoring) {
  380. if (sPausedFromUserAction) {
  381. // If the user leaves launcher, then we should just load items asynchronously when
  382. // they return.
  383. mModel.startLoader(true, -1);
  384. } else {
  385. // We only load the page synchronously if the user rotates (or triggers a
  386. // configuration change) while launcher is in the foreground
  387. mModel.startLoader(true, mWorkspace.getCurrentPage());
  388. }
  389. }
  390. if (!mModel.isAllAppsLoaded()) {
  391. ViewGroup appsCustomizeContentParent = (ViewGroup) mAppsCustomizeContent.getParent();
  392. mInflater.inflate(R.layout.apps_customize_progressbar, appsCustomizeContentParent);
  393. }
  394. // For handling default keys
  395. mDefaultKeySsb = new SpannableStringBuilder();
  396. Selection.setSelection(mDefaultKeySsb, 0);
  397. IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
  398. registerReceiver(mCloseSystemDialogsReceiver, filter);
  399. updateGlobalIcons();
  400. // On large interfaces, we want the screen to auto-rotate based on the current orientation
  401. unlockScreenOrientation(true);
  402. mStatusBarManager = (StatusBarManager) getSystemService(Context.STATUS_BAR_SERVICE);
  403. }
  404. protected void onUserLeaveHint() {
  405. super.onUserLeaveHint();
  406. sPausedFromUserAction = true;
  407. }
  408. private void updateGlobalIcons() {
  409. boolean searchVisible = false;
  410. boolean voiceVisible = false;
  411. // If we have a saved version of these external icons, we load them up immediately
  412. int coi = getCurrentOrientationIndexForGlobalIcons();
  413. if (sGlobalSearchIcon[coi] == null || sVoiceSearchIcon[coi] == null ||
  414. sAppMarketIcon[coi] == null) {
  415. updateAppMarketIcon();
  416. searchVisible = updateGlobalSearchIcon();
  417. voiceVisible = updateVoiceSearchIcon(searchVisible);
  418. }
  419. if (sGlobalSearchIcon[coi] != null) {
  420. updateGlobalSearchIcon(sGlobalSearchIcon[coi]);
  421. searchVisible = true;
  422. }
  423. if (sVoiceSearchIcon[coi] != null) {
  424. updateVoiceSearchIcon(sVoiceSearchIcon[coi]);
  425. voiceVisible = true;
  426. }
  427. if (sAppMarketIcon[coi] != null) {
  428. updateAppMarketIcon(sAppMarketIcon[coi]);
  429. }
  430. if (mSearchDropTargetBar != null) {
  431. mSearchDropTargetBar.onSearchPackagesChanged(searchVisible, voiceVisible);
  432. }
  433. }
  434. private void checkForLocaleChange() {
  435. if (sLocaleConfiguration == null) {
  436. new AsyncTask<Void, Void, LocaleConfiguration>() {
  437. @Override
  438. protected LocaleConfiguration doInBackground(Void... unused) {
  439. LocaleConfiguration localeConfiguration = new LocaleConfiguration();
  440. readConfiguration(Launcher.this, localeConfiguration);
  441. return localeConfiguration;
  442. }
  443. @Override
  444. protected void onPostExecute(LocaleConfiguration result) {
  445. sLocaleConfiguration = result;
  446. checkForLocaleChange(); // recursive, but now with a locale configuration
  447. }
  448. }.execute();
  449. return;
  450. }
  451. final Configuration configuration = getResources().getConfiguration();
  452. final String previousLocale = sLocaleConfiguration.locale;
  453. final String locale = configuration.locale.toString();
  454. final int previousMcc = sLocaleConfiguration.mcc;
  455. final int mcc = configuration.mcc;
  456. final int previousMnc = sLocaleConfiguration.mnc;
  457. final int mnc = configuration.mnc;
  458. boolean localeChanged = !locale.equals(previousLocale) || mcc != previousMcc || mnc != previousMnc;
  459. if (localeChanged) {
  460. sLocaleConfiguration.locale = locale;
  461. sLocaleConfiguration.mcc = mcc;
  462. sLocaleConfiguration.mnc = mnc;
  463. mIconCache.flush();
  464. final LocaleConfiguration localeConfiguration = sLocaleConfiguration;
  465. new Thread("WriteLocaleConfiguration") {
  466. @Override
  467. public void run() {
  468. writeConfiguration(Launcher.this, localeConfiguration);
  469. }
  470. }.start();
  471. }
  472. }
  473. private static class LocaleConfiguration {
  474. public String locale;
  475. public int mcc = -1;
  476. public int mnc = -1;
  477. }
  478. private static void readConfiguration(Context context, LocaleConfiguration configuration) {
  479. DataInputStream in = null;
  480. try {
  481. in = new DataInputStream(context.openFileInput(PREFERENCES));
  482. configuration.locale = in.readUTF();
  483. configuration.mcc = in.readInt();
  484. configuration.mnc = in.readInt();
  485. } catch (FileNotFoundException e) {
  486. // Ignore
  487. } catch (IOException e) {
  488. // Ignore
  489. } finally {
  490. if (in != null) {
  491. try {
  492. in.close();
  493. } catch (IOException e) {
  494. // Ignore
  495. }
  496. }
  497. }
  498. }
  499. private static void writeConfiguration(Context context, LocaleConfiguration configuration) {
  500. DataOutputStream out = null;
  501. try {
  502. out = new DataOutputStream(context.openFileOutput(PREFERENCES, MODE_PRIVATE));
  503. out.writeUTF(configuration.locale);
  504. out.writeInt(configuration.mcc);
  505. out.writeInt(configuration.mnc);
  506. out.flush();
  507. } catch (FileNotFoundException e) {
  508. // Ignore
  509. } catch (IOException e) {
  510. //noinspection ResultOfMethodCallIgnored
  511. context.getFileStreamPath(PREFERENCES).delete();
  512. } finally {
  513. if (out != null) {
  514. try {
  515. out.close();
  516. } catch (IOException e) {
  517. // Ignore
  518. }
  519. }
  520. }
  521. }
  522. public DragLayer getDragLayer() {
  523. return mDragLayer;
  524. }
  525. boolean isDraggingEnabled() {
  526. // We prevent dragging when we are loading the workspace as it is possible to pick up a view
  527. // that is subsequently removed from the workspace in startBinding().
  528. return !mModel.isLoadingWorkspace();
  529. }
  530. /**
  531. * Returns whether we should delay spring loaded mode -- for shortcuts and widgets that have
  532. * a configuration step, this allows the proper animations to run after other transitions.
  533. */
  534. private boolean completeAdd(PendingAddArguments args) {
  535. boolean result = false;
  536. switch (args.requestCode) {
  537. case REQUEST_PICK_APPLICATION:
  538. completeAddApplication(args.intent, args.container, args.screen, args.cellX,
  539. args.cellY);
  540. break;
  541. case REQUEST_PICK_SHORTCUT:
  542. processShortcut(args.intent);
  543. // Don't remove pending add info
  544. return false;
  545. case REQUEST_CREATE_SHORTCUT:
  546. completeAddShortcut(args.intent, args.container, args.screen, args.cellX,
  547. args.cellY);
  548. result = true;
  549. break;
  550. case REQUEST_CREATE_APPWIDGET:
  551. int appWidgetId = args.intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
  552. completeAddAppWidget(appWidgetId, args.container, args.screen, null, null);
  553. result = true;
  554. break;
  555. case REQUEST_PICK_WALLPAPER:
  556. // We just wanted the activity result here so we can clear mWaitingForResult
  557. break;
  558. }
  559. // Before adding this resetAddInfo(), after a shortcut was added to a workspace screen,
  560. // if you turned the screen off and then back while in All Apps, Launcher would not
  561. // return to the workspace. Clearing mAddInfo.container here fixes this issue
  562. resetAddInfo();
  563. return result;
  564. }
  565. @Override
  566. protected void onActivityResult(
  567. final int requestCode, final int resultCode, final Intent data) {
  568. if (requestCode == REQUEST_BIND_APPWIDGET) {
  569. int appWidgetId = data != null ?
  570. data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1) : -1;
  571. if (resultCode == RESULT_CANCELED) {
  572. completeTwoStageWidgetDrop(RESULT_CANCELED, appWidgetId);
  573. } else if (resultCode == RESULT_OK) {
  574. addAppWidgetImpl(appWidgetId, mPendingAddInfo, null, mPendingAddWidgetInfo);
  575. }
  576. return;
  577. }
  578. boolean delayExitSpringLoadedMode = false;
  579. boolean isWidgetDrop = (requestCode == REQUEST_PICK_APPWIDGET ||
  580. requestCode == REQUEST_CREATE_APPWIDGET);
  581. mWaitingForResult = false;
  582. // We have special handling for widgets
  583. if (isWidgetDrop) {
  584. int appWidgetId = data != null ?
  585. data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1) : -1;
  586. if (appWidgetId < 0) {
  587. Log.e(TAG, "Error: appWidgetId (EXTRA_APPWIDGET_ID) was not returned from the \\" +
  588. "widget configuration activity.");
  589. completeTwoStageWidgetDrop(RESULT_CANCELED, appWidgetId);
  590. } else {
  591. completeTwoStageWidgetDrop(resultCode, appWidgetId);
  592. }
  593. return;
  594. }
  595. // The pattern used here is that a user PICKs a specific application,
  596. // which, depending on the target, might need to CREATE the actual target.
  597. // For example, the user would PICK_SHORTCUT for "Music playlist", and we
  598. // launch over to the Music app to actually CREATE_SHORTCUT.
  599. if (resultCode == RESULT_OK && mPendingAddInfo.container != com.cyanogenmod.trebuchet.ItemInfo.NO_ID) {
  600. final PendingAddArguments args = new PendingAddArguments();
  601. args.requestCode = requestCode;
  602. args.intent = data;
  603. args.container = mPendingAddInfo.container;
  604. args.screen = mPendingAddInfo.screen;
  605. args.cellX = mPendingAddInfo.cellX;
  606. args.cellY = mPendingAddInfo.cellY;
  607. if (isWorkspaceLocked()) {
  608. sPendingAddList.add(args);
  609. } else {
  610. delayExitSpringLoadedMode = completeAdd(args);
  611. }
  612. }
  613. mDragLayer.clearAnimatedView();
  614. // Exit spring loaded mode if necessary after cancelling the configuration of a widget
  615. exitSpringLoadedDragModeDelayed((resultCode != RESULT_CANCELED), delayExitSpringLoadedMode,
  616. null);
  617. }
  618. private void completeTwoStageWidgetDrop(final int resultCode, final int appWidgetId) {
  619. CellLayout cellLayout =
  620. (CellLayout) mWorkspace.getChildAt(mPendingAddInfo.screen);
  621. Runnable onCompleteRunnable = null;
  622. int animationType = 0;
  623. AppWidgetHostView boundWidget = null;
  624. if (resultCode == RESULT_OK) {
  625. animationType = Workspace.COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION;
  626. final AppWidgetHostView layout = mAppWidgetHost.createView(this, appWidgetId,
  627. mPendingAddWidgetInfo);
  628. boundWidget = layout;
  629. onCompleteRunnable = new Runnable() {
  630. @Override
  631. public void run() {
  632. completeAddAppWidget(appWidgetId, mPendingAddInfo.container,
  633. mPendingAddInfo.screen, layout, null);
  634. exitSpringLoadedDragModeDelayed(true, false, null);
  635. }
  636. };
  637. } else if (resultCode == RESULT_CANCELED) {
  638. animationType = Workspace.CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION;
  639. onCompleteRunnable = new Runnable() {
  640. @Override
  641. public void run() {
  642. exitSpringLoadedDragModeDelayed(false, false, null);
  643. }
  644. };
  645. }
  646. if (mDragLayer.getAnimatedView() != null) {
  647. mWorkspace.animateWidgetDrop(mPendingAddInfo, cellLayout,
  648. (DragView) mDragLayer.getAnimatedView(), onCompleteRunnable,
  649. animationType, boundWidget, true);
  650. } else {
  651. // The animated view may be null in the case of a rotation during widget configuration
  652. if (onCompleteRunnable != null) {
  653. onCompleteRunnable.run();
  654. }
  655. }
  656. }
  657. @Override
  658. protected void onResume() {
  659. super.onResume();
  660. // Restore the previous launcher state
  661. if (mOnResumeState == State.WORKSPACE) {
  662. showWorkspace(false);
  663. } else if (mOnResumeState == State.APPS_CUSTOMIZE) {
  664. showAllApps(false);
  665. }
  666. mOnResumeState = State.NONE;
  667. // Background was set to gradient in onPause(), restore to black if in all apps.
  668. setWorkspaceBackground(mState == State.WORKSPACE);
  669. // Process any items that were added while Launcher was away
  670. InstallShortcutReceiver.flushInstallQueue(this);
  671. mPaused = false;
  672. sPausedFromUserAction = false;
  673. // Restart launcher when preferences are changed
  674. if (preferencesChanged()) {
  675. android.os.Process.killProcess(android.os.Process.myPid());
  676. }
  677. if (mRestoring || mOnResumeNeedsLoad) {
  678. mWorkspaceLoading = true;
  679. mModel.startLoader(true, -1);
  680. mRestoring = false;
  681. mOnResumeNeedsLoad = false;
  682. }
  683. // Reset the pressed state of icons that were locked in the press state while activities
  684. // were launching
  685. if (mWaitingForResume != null) {
  686. // Resets the previous workspace icon press state
  687. mWaitingForResume.setStayPressed(false);
  688. }
  689. if (mAppsCustomizeContent != null) {
  690. // Resets the previous all apps icon press state
  691. mAppsCustomizeContent.resetDrawableState();
  692. }
  693. // It is possible that widgets can receive updates while launcher is not in the foreground.
  694. // Consequently, the widgets will be inflated in the orientation of the foreground activity
  695. // (framework issue). On resuming, we ensure that any widgets are inflated for the current
  696. // orientation.
  697. getWorkspace().reinflateWidgetsIfNecessary();
  698. getWorkspace().checkWallpaper();
  699. // Again, as with the above scenario, it's possible that one or more of the global icons
  700. // were updated in the wrong orientation.
  701. updateGlobalIcons();
  702. }
  703. @Override
  704. protected void onPause() {
  705. // NOTE: We want all transitions from launcher to act as if the wallpaper were enabled
  706. // to be consistent. So re-enable the flag here, and we will re-disable it as necessary
  707. // when Launcher resumes and we are still in AllApps.
  708. updateWallpaperVisibility(true);
  709. super.onPause();
  710. mPaused = true;
  711. mDragController.cancelDrag();
  712. mDragController.resetLastGestureUpTime();
  713. }
  714. @Override
  715. public Object onRetainNonConfigurationInstance() {
  716. // Flag the loader to stop early before switching
  717. mModel.stopLoader();
  718. if (mAppsCustomizeContent != null) {
  719. mAppsCustomizeContent.surrender();
  720. }
  721. return Boolean.TRUE;
  722. }
  723. private boolean acceptFilter() {
  724. final InputMethodManager inputManager = (InputMethodManager)
  725. getSystemService(Context.INPUT_METHOD_SERVICE);
  726. return !inputManager.isFullscreenMode();
  727. }
  728. @Override
  729. public boolean onKeyDown(int keyCode, KeyEvent event) {
  730. final int uniChar = event.getUnicodeChar();
  731. final boolean handled = super.onKeyDown(keyCode, event);
  732. final boolean isKeyNotWhitespace = uniChar > 0 && !Character.isWhitespace(uniChar);
  733. if (!handled && acceptFilter() && isKeyNotWhitespace) {
  734. boolean gotKey = TextKeyListener.getInstance().onKeyDown(mWorkspace, mDefaultKeySsb,
  735. keyCode, event);
  736. if (gotKey && mDefaultKeySsb != null && mDefaultKeySsb.length() > 0) {
  737. // something usable has been typed - start a search
  738. // the typed text will be retrieved and cleared by
  739. // showSearchDialog()
  740. // If there are multiple keystrokes before the search dialog takes focus,
  741. // onSearchRequested() will be called for every keystroke,
  742. // but it is idempotent, so it's fine.
  743. return onSearchRequested();
  744. }
  745. }
  746. // Eat the long press event so the keyboard doesn't come up.
  747. if (keyCode == KeyEvent.KEYCODE_MENU && event.isLongPress()) {
  748. return true;
  749. }
  750. return handled;
  751. }
  752. private String getTypedText() {
  753. return mDefaultKeySsb.toString();
  754. }
  755. private void clearTypedText() {
  756. mDefaultKeySsb.clear();
  757. mDefaultKeySsb.clearSpans();
  758. Selection.setSelection(mDefaultKeySsb, 0);
  759. }
  760. /**
  761. * Given the integer (ordinal) value of a State enum instance, convert it to a variable of type
  762. * State
  763. */
  764. private static State intToState(int stateOrdinal) {
  765. State state = State.WORKSPACE;
  766. final State[] stateValues = State.values();
  767. for (State stateValue : stateValues) {
  768. if (stateValue.ordinal() == stateOrdinal) {
  769. state = stateValue;
  770. break;
  771. }
  772. }
  773. return state;
  774. }
  775. /**
  776. * Restores the previous state, if it exists.
  777. *
  778. * @param savedState The previous state.
  779. */
  780. private void restoreState(Bundle savedState) {
  781. if (savedState == null) {
  782. return;
  783. }
  784. State state = intToState(savedState.getInt(RUNTIME_STATE, State.WORKSPACE.ordinal()));
  785. if (state == State.APPS_CUSTOMIZE) {
  786. mOnResumeState = State.APPS_CUSTOMIZE;
  787. }
  788. int currentScreen = savedState.getInt(RUNTIME_STATE_CURRENT_SCREEN, -1);
  789. if (currentScreen > -1) {
  790. mWorkspace.setCurrentPage(currentScreen);
  791. }
  792. int currentHotseatScreen = savedState.getInt(RUNTIME_STATE_CURRENT_HOTSEAT_SCREEN, -1);
  793. if (currentHotseatScreen > -1) {
  794. mHotseat.setCurrentPage(mHotseat.getScreenFromOrder(currentHotseatScreen));
  795. }
  796. final long pendingAddContainer = savedState.getLong(RUNTIME_STATE_PENDING_ADD_CONTAINER, -1);
  797. final int pendingAddScreen = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SCREEN, -1);
  798. if (pendingAddContainer != com.cyanogenmod.trebuchet.ItemInfo.NO_ID && pendingAddScreen > -1) {
  799. mPendingAddInfo.container = pendingAddContainer;
  800. mPendingAddInfo.screen = pendingAddScreen;
  801. mPendingAddInfo.cellX = savedState.getInt(RUNTIME_STATE_PENDING_ADD_CELL_X);
  802. mPendingAddInfo.cellY = savedState.getInt(RUNTIME_STATE_PENDING_ADD_CELL_Y);
  803. mPendingAddInfo.spanX = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SPAN_X);
  804. mPendingAddInfo.spanY = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SPAN_Y);
  805. mPendingAddWidgetInfo = savedState.getParcelable(RUNTIME_STATE_PENDING_ADD_WIDGET_INFO);
  806. mWaitingForResult = true;
  807. mRestoring = true;
  808. }
  809. boolean renameFolder = savedState.getBoolean(RUNTIME_STATE_PENDING_FOLDER_RENAME, false);
  810. if (renameFolder) {
  811. long id = savedState.getLong(RUNTIME_STATE_PENDING_FOLDER_RENAME_ID);
  812. mFolderInfo = mModel.getFolderById(this, sFolders, id);
  813. mRestoring = true;
  814. }
  815. // Restore the AppsCustomize tab
  816. if (mAppsCustomizeTabHost != null) {
  817. String curTab = savedState.getString("apps_customize_currentTab");
  818. if (curTab != null) {
  819. mAppsCustomizeTabHost.setContentTypeImmediate(
  820. mAppsCustomizeTabHost.getContentTypeForTabTag(curTab));
  821. mAppsCustomizeContent.loadAssociatedPages(
  822. mAppsCustomizeContent.getCurrentPage());
  823. }
  824. int currentIndex = savedState.getInt("apps_customize_currentIndex");
  825. mAppsCustomizeContent.restorePageForIndex(currentIndex);
  826. }
  827. }
  828. /**
  829. * Finds all the views we need and configure them properly.
  830. */
  831. private void setupViews() {
  832. final DragController dragController = mDragController;
  833. mLauncherView = findViewById(R.id.launcher);
  834. mDragLayer = (DragLayer) findViewById(R.id.drag_layer);
  835. mWorkspace = (Workspace) mDragLayer.findViewById(R.id.workspace);
  836. mQsbDivider = findViewById(R.id.qsb_divider);
  837. mDockDivider = findViewById(R.id.dock_divider);
  838. mLauncherView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
  839. mWorkspaceBackgroundDrawable = getResources().getDrawable(R.drawable.workspace_bg);
  840. mBlackBackgroundDrawable = new ColorDrawable(Color.BLACK);
  841. // Setup the drag layer
  842. mDragLayer.setup(this, dragController);
  843. // Setup the hotseat
  844. mHotseat = (Hotseat) findViewById(R.id.hotseat);
  845. // Setup the workspace
  846. mWorkspace.setHapticFeedbackEnabled(false);
  847. mWorkspace.setOnLongClickListener(this);
  848. mWorkspace.setup(dragController);
  849. dragController.addDragListener(mWorkspace);
  850. if (mHomescreenDoubleTap != 0) {
  851. mWorkspace.setOnDoubleTapCallback(new Runnable() {
  852. public void run() {
  853. performGesture(mHomescreenDoubleTap, 0);
  854. }
  855. });
  856. }
  857. if (mHomescreenSwipeUp != 0) {
  858. mWorkspace.setOnSwipeUpCallback(new Runnable() {
  859. public void run() {
  860. performGesture(mHomescreenSwipeUp, 1);
  861. }
  862. });
  863. }
  864. if (mHomescreenSwipeDown != 0) {
  865. mWorkspace.setOnSwipeDownCallback(new Runnable() {
  866. public void run() {
  867. performGesture(mHomescreenSwipeDown, 2);
  868. }
  869. });
  870. }
  871. // Get the search/delete bar
  872. mSearchDropTargetBar = (SearchDropTargetBar) mDragLayer.findViewById(R.id.qsb_bar);
  873. // Hide the search divider if we are hiding search bar
  874. if (!mShowSearchBar && mQsbDivider != null && getCurrentOrientation() == Configuration.ORIENTATION_LANDSCAPE) {
  875. mQsbDivider.setVisibility(View.GONE);
  876. }
  877. if (!mShowHotseat) {
  878. mHotseat.setVisibility(View.GONE);
  879. }
  880. if (!mShowDockDivider && mDockDivider != null) {
  881. mDockDivider.setVisibility(View.GONE);
  882. }
  883. // Redim the hotseat and statusbar to let some extra size for the item text
  884. if (mShowHotseat && !mHideDockIconLabels && !mHotseat.hasVerticalHotseat()) {
  885. Resources res = getResources();
  886. int bottomMarginWithText = res.getDimensionPixelSize(R.dimen.button_bar_height_with_text);
  887. // Divider
  888. if (mDockDivider != null) {
  889. ((MarginLayoutParams)mDockDivider.getLayoutParams()).bottomMargin = bottomMarginWithText;
  890. }
  891. // Divider indicator
  892. View dockScrollingIndicator = findViewById(R.id.paged_view_indicator_dock);
  893. if (dockScrollingIndicator != null) {
  894. ((MarginLayoutParams)dockScrollingIndicator.getLayoutParams()).bottomMargin = bottomMarginWithText;
  895. }
  896. // Hotseat
  897. mHotseat.getLayoutParams().height = res.getDimensionPixelSize(R.dimen.button_bar_height_plus_padding_with_text);
  898. // Workspace
  899. mWorkspace.setPadding(
  900. mWorkspace.getPaddingLeft(),
  901. mWorkspace.getPaddingTop(),
  902. mWorkspace.getPaddingRight(),
  903. res.getDimensionPixelSize(R.dimen.workspace_bottom_padding_port_with_text));
  904. }
  905. // Setup AppsCustomize
  906. mAppsCustomizeTabHost = (AppsCustomizeTabHost) findViewById(R.id.apps_customize_pane);
  907. mAppsCustomizeContent = (AppsCustomizePagedView)
  908. mAppsCustomizeTabHost.findViewById(R.id.apps_customize_pane_content);
  909. mAppsCustomizeContent.setup(this, dragController);
  910. // Setup the drag controller (drop targets have to be added in reverse order in priority)
  911. dragController.setDragScoller(mWorkspace);
  912. dragController.setScrollView(mDragLayer);
  913. dragController.setMoveTarget(mWorkspace);
  914. dragController.addDropTarget(mWorkspace);
  915. if (mSearchDropTargetBar != null) {
  916. mSearchDropTargetBar.setup(this, dragController);
  917. }
  918. }
  919. /**
  920. * Starts shortcut rename dialog.
  921. *
  922. * @param info The shortcut to be edited
  923. */
  924. void updateShortcut(final ShortcutInfo info) {
  925. AlertDialog.Builder builder = new AlertDialog.Builder(this);
  926. View layout = mInflater.inflate(R.layout.dialog_edit, null);
  927. ImageView icon = (ImageView) layout.findViewById(R.id.dialog_edit_icon);
  928. icon.setImageBitmap(info.getIcon(mIconCache));
  929. final EditText title = (EditText) layout.findViewById(R.id.dialog_edit_text);
  930. title.setText(info.title);
  931. builder.setView(layout)
  932. .setTitle(info.title)
  933. .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
  934. @Override
  935. public void onClick(DialogInterface dialog, int id) {
  936. info.setTitle(title.getText());
  937. LauncherModel.updateItemInDatabase(Launcher.this, info);
  938. }
  939. })
  940. .setNegativeButton(android.R.string.cancel, null);
  941. builder.show();
  942. }
  943. /**
  944. * Creates a view representing a shortcut.
  945. *
  946. * @param info The data structure describing the shortcut.
  947. *
  948. * @return A View inflated from R.layout.application.
  949. */
  950. View createShortcut(ShortcutInfo info) {
  951. return createShortcut(R.layout.application,
  952. (ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentPage()), info);
  953. }
  954. /**
  955. * Creates a view representing a shortcut inflated from the specified resource.
  956. *
  957. * @param layoutResId The id of the XML layout used to create the shortcut.
  958. * @param parent The group the shortcut belongs to.
  959. * @param info The data structure describing the shortcut.
  960. *
  961. * @return A View inflated from layoutResId.
  962. */
  963. View createShortcut(int layoutResId, ViewGroup parent, ShortcutInfo info) {
  964. BubbleTextView favorite = (BubbleTextView) mInflater.inflate(layoutResId, parent, false);
  965. favorite.applyFromShortcutInfo(info, mIconCache);
  966. favorite.setTextVisible(!mHideIconLabels);
  967. favorite.setOnClickListener(this);
  968. favorite.setOnTouchListener(this);
  969. return favorite;
  970. }
  971. /**
  972. * Add an application shortcut to the workspace.
  973. *
  974. * @param data The intent describing the application.
  975. * @param cellInfo The position on screen where to create the shortcut.
  976. */
  977. void completeAddApplication(Intent data, long container, int screen, int cellX, int cellY) {
  978. final int[] cellXY = mTmpAddItemCellCoordinates;
  979. final CellLayout layout = getCellLayout(container, screen);
  980. // First we check if we already know the exact location where we want to add this item.
  981. if (cellX >= 0 && cellY >= 0) {
  982. cellXY[0] = cellX;
  983. cellXY[1] = cellY;
  984. } else if (!layout.findCellForSpan(cellXY, 1, 1)) {
  985. showOutOfSpaceMessage(isHotseatLayout(layout));
  986. return;
  987. }
  988. final ShortcutInfo info = mModel.getShortcutInfo(getPackageManager(), data, this);
  989. if (info != null) {
  990. info.setActivity(data.getComponent(), Intent.FLAG_ACTIVITY_NEW_TASK |
  991. Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
  992. info.container = com.cyanogenmod.trebuchet.ItemInfo.NO_ID;
  993. mWorkspace.addApplicationShortcut(info, layout, container, screen,
  994. isWorkspaceLocked(), cellX, cellY);
  995. } else {
  996. Log.e(TAG, "Couldn't find ActivityInfo for selected application: " + data);
  997. }
  998. }
  999. private void restoreShortcut(ShortcutInfo info) {
  1000. final View view = createShortcut(info);
  1001. FolderInfo folderInfo = info.mFolderInfo;
  1002. if (info.container >= 0 && folderInfo != null) {
  1003. // The shortcut was contained by a folder
  1004. // It's necessary to recreate the folder or just to add to the existing one?
  1005. CellLayout layout = getCellLayout(folderInfo.container, folderInfo.screen);
  1006. View v = layout.getChildAt(folderInfo.cellX, folderInfo.cellY);
  1007. if (v == null) {
  1008. // Weird. Should not there be a shortcut or folder here?
  1009. return;
  1010. }
  1011. if (v.getTag() != null && v.getTag() instanceof ShortcutInfo) {
  1012. // Create a new folder
  1013. ShortcutInfo target = (ShortcutInfo)v.getTag();
  1014. // Remove the target item to allow to be occupied by the folder
  1015. layout.removeView(v);
  1016. // Create the folder and its new items
  1017. FolderIcon fi = addFolder(
  1018. layout, folderInfo.container, folderInfo.screen,
  1019. folderInfo.cellX, folderInfo.cellY);
  1020. int cellX = info.cellX;
  1021. int cellY = info.cellY;
  1022. info.cellX = -1;
  1023. info.cellY = -1;
  1024. target.cellX = -1;
  1025. target.cellY = -1;
  1026. if (cellX == 0 && cellY == 0) {
  1027. fi.addItem(info);
  1028. fi.addItem(target);
  1029. } else {
  1030. fi.addItem(target);
  1031. fi.addItem(info);
  1032. }
  1033. }
  1034. } else if (info.container >= 0) {
  1035. // The shortcut was contained by a folder and the folder still exists
  1036. FolderIcon folderIcon = null;
  1037. // We need to find the container in the workspace, because the shortcut has lost
  1038. // its information
  1039. ArrayList<ShortcutAndWidgetContainer> allSwc =
  1040. mWorkspace.getAllShortcutAndWidgetContainers();
  1041. for (ShortcutAndWidgetContainer swc : allSwc) {
  1042. int cc = swc.getChildCount();
  1043. for (int i = 0; i < cc; i++) {
  1044. View v = swc.getChildAt(i);
  1045. if (v instanceof FolderIcon) {
  1046. FolderInfo fi = (FolderInfo)v.getTag();
  1047. if (fi != null && fi.id == info.container) {
  1048. folderIcon = (FolderIcon)v;
  1049. break;
  1050. }
  1051. }
  1052. }
  1053. if (folderIcon != null) {
  1054. break;
  1055. }
  1056. }
  1057. if (folderIcon != null) {
  1058. folderIcon.addItem(info);
  1059. }
  1060. } else {
  1061. // Just restore the shortcut in its last position
  1062. long con

Large files files are truncated, but you can click here to view the full file