/* * 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.softwinner.launcher; import android.app.Activity; import android.app.WallpaperManager; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Configuration; import android.database.ContentObserver; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.os.SystemClock; import android.text.method.TextKeyListener; import android.util.Log; import android.view.Display; import android.view.LayoutInflater; import android.view.Menu; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.io.DataOutputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.DataInputStream; import java.lang.ref.WeakReference; import com.softwinner.launcher.R; import com.softwinner.launcher.ui.CellLayout; import com.softwinner.launcher.ui.CellLayout.CellInfo; import com.softwinner.launcher.ui.WorkSpace; /** * Default launcher application. */ public final class Launcher extends Activity{ static final String TAG = "Launcher"; static final boolean LOGD = true; static final boolean PROFILE_STARTUP = false; static final boolean DEBUG_WIDGETS = false; static final boolean DEBUG_USER_INTERFACE = false; private static final int MENU_GROUP_ADD = 1; private static final int MENU_GROUP_WALLPAPER = MENU_GROUP_ADD + 1; private static final int MENU_ADD = Menu.FIRST + 1; private static final int MENU_MANAGE_APPS = MENU_ADD + 1; private static final int MENU_WALLPAPER_SETTINGS = MENU_MANAGE_APPS + 1; private static final int MENU_SEARCH = MENU_WALLPAPER_SETTINGS + 1; private static final int MENU_NOTIFICATIONS = MENU_SEARCH + 1; private static final int MENU_SETTINGS = MENU_NOTIFICATIONS + 1; private static final int REQUEST_CREATE_SHORTCUT = 1; private static final int REQUEST_CREATE_LIVE_FOLDER = 4; 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_LIVE_FOLDER = 8; private static final int REQUEST_PICK_APPWIDGET = 9; private static final int REQUEST_PICK_WALLPAPER = 10; static final String EXTRA_SHORTCUT_DUPLICATE = "duplicate"; static final int SCREEN_COUNT = 1; static final int DEFAULT_SCREEN = 1; static final int NUMBER_CELLS_X = 6; static final int NUMBER_CELLS_Y = 4; static final int DIALOG_CREATE_SHORTCUT = 1; static final int DIALOG_RENAME_FOLDER = 2; private static final String PREFERENCES = "launcher.preferences"; // Type: int private static final String RUNTIME_STATE_CURRENT_SCREEN = "launcher.current_screen"; // Type: boolean private static final String RUNTIME_STATE_ALL_APPS_FOLDER = "launcher.all_apps_folder"; // Type: long private static final String RUNTIME_STATE_USER_FOLDERS = "launcher.user_folder"; // 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_cellX"; // Type: int private static final String RUNTIME_STATE_PENDING_ADD_CELL_Y = "launcher.add_cellY"; // Type: int private static final String RUNTIME_STATE_PENDING_ADD_SPAN_X = "launcher.add_spanX"; // Type: int private static final String RUNTIME_STATE_PENDING_ADD_SPAN_Y = "launcher.add_spanY"; // Type: int private static final String RUNTIME_STATE_PENDING_ADD_COUNT_X = "launcher.add_countX"; // Type: int private static final String RUNTIME_STATE_PENDING_ADD_COUNT_Y = "launcher.add_countY"; // Type: int[] private static final String RUNTIME_STATE_PENDING_ADD_OCCUPIED_CELLS = "launcher.add_occupied_cells"; // 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"; static final int APPWIDGET_HOST_ID = 1024; private static final Object sLock = new Object(); private static int sScreen = DEFAULT_SCREEN; private final BroadcastReceiver mCloseSystemDialogsReceiver = new CloseSystemDialogsIntentReceiver(); private final ContentObserver mWidgetObserver = new AppWidgetResetObserver(); private LayoutInflater mInflater; private AppWidgetManager mAppWidgetManager; private LauncherAppWidgetHost mAppWidgetHost; private CellLayout.CellInfo mAddItemCellInfo; private final int[] mCellCoordinates = new int[2]; private IAllAppsView mAllAppsGrid; private IAllAppsView mAppsFavorites; private Bundle mSavedState; private boolean mWorkspaceLoading = true; private boolean mPaused = true; private boolean mRestoring; private boolean mWaitingForResult; private boolean mOnResumeNeedsLoad; private Bundle mSavedInstanceState; private LauncherModel mModel; private IconCache mIconCache; private static LocaleConfiguration sLocaleConfiguration = null; public ArrayList<ItemInfo> mDesktopItems = new ArrayList<ItemInfo>(); private static HashMap<Long, FolderInfo> sFolders = new HashMap<Long, FolderInfo>(); public static final String LAUNCHER_CATEGORY_START_APP = "com.softwinner.category.app"; private WeakReference<ActivityRuntimeInterface> mView; /** * ------------------------------------------------------------------------- * 1.life time affair */ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (PROFILE_STARTUP) { android.os.Debug.startMethodTracing("/sdcard/launcher"); } //Get application instance mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID); mAppWidgetHost.startListening(); //Set Launcher model mModel = LauncherApplication.getModel(); LauncherApplication.setLauncher(this); //mModel.setCallbacks(this); //get the icon cache mIconCache = LauncherApplication.getIconCache(); //get the app widget manager mAppWidgetManager = AppWidgetManager.getInstance(this); //set the wall paper the suit self window setWallpaperDimension(); //load base view to window setupViews(); //Model start load workspace item & applist if (!mRestoring) { mModel.startLoader(this, true); } restoreState(savedInstanceState); //register the close system dialogs intent filters IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); registerReceiver(mCloseSystemDialogsReceiver, filter); if (PROFILE_STARTUP) { android.os.Debug.stopMethodTracing(); } List<AppWidgetProviderInfo> installed = mAppWidgetManager.getInstalledProviders(); if(LOGD){ for(AppWidgetProviderInfo widget:installed){ int id[] = mAppWidgetManager.getAppWidgetIds(widget.provider); for(int i=0;i<id.length;i++){ Log.w(TAG, "" + id[i]); } } } } @Override protected void onResume() { super.onResume(); mPaused = false; if (mRestoring || mOnResumeNeedsLoad ) { mWorkspaceLoading = true; mModel.startLoader(this, true); mRestoring = false; mOnResumeNeedsLoad = false; } ActivityRuntimeInterface callbacks = mView.get(); if(callbacks != null){ callbacks.onResume(); } } @Override protected void onPause() { super.onPause(); mPaused = true; } @Override protected void onDestroy() { super.onDestroy(); try { mAppWidgetHost.stopListening(); } catch (NullPointerException ex) { Log.w(TAG, "problem while stopping AppWidgetHost during Launcher destruction", ex); } TextKeyListener.getInstance().release(); mModel.stopLoader(); getContentResolver().unregisterContentObserver(mWidgetObserver); unregisterReceiver(mCloseSystemDialogsReceiver); ActivityRuntimeInterface callbacks = mView.get(); if(callbacks != null){ callbacks.onDestroy(); } } /** * ----------------------------------------------------------------- * 2.communicate between activity affair */ @Override protected void onNewIntent(Intent intent) { if(LOGD) Log.d(TAG,"receive a new intent " + intent); super.onNewIntent(intent); ActivityRuntimeInterface callbacks = mView!=null ? mView.get():null; if(callbacks != null){ callbacks.onNewIntent(intent); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK) { switch(requestCode){ case REQUEST_PICK_APPWIDGET: addAppWidget(data); break; case REQUEST_CREATE_APPWIDGET: completeAddAppWidget(data, mAddItemCellInfo); break; } } } /** * ----------------------------------------------------------------- * 3.runtime instance state store */ @Override protected void onSaveInstanceState(Bundle outState) { /* if (isAllAppsVisible()) { outState.putBoolean(RUNTIME_STATE_ALL_APPS_FOLDER, true); } if (mAddItemCellInfo != null && mAddItemCellInfo.valid && mWaitingForResult) { final CellLayout.CellInfo addItemCellInfo = mAddItemCellInfo; final CellLayout layout = (CellLayout) mMainLayout.getWidgetLayout(); outState.putInt(RUNTIME_STATE_PENDING_ADD_SCREEN, addItemCellInfo.screen); outState.putInt(RUNTIME_STATE_PENDING_ADD_CELL_X, addItemCellInfo.cellX); outState.putInt(RUNTIME_STATE_PENDING_ADD_CELL_Y, addItemCellInfo.cellY); outState.putInt(RUNTIME_STATE_PENDING_ADD_SPAN_X, addItemCellInfo.spanX); outState.putInt(RUNTIME_STATE_PENDING_ADD_SPAN_Y, addItemCellInfo.spanY); outState.putInt(RUNTIME_STATE_PENDING_ADD_COUNT_X, layout.getCountX()); outState.putInt(RUNTIME_STATE_PENDING_ADD_COUNT_Y, layout.getCountY()); outState.putBooleanArray(RUNTIME_STATE_PENDING_ADD_OCCUPIED_CELLS, layout.getOccupiedCells()); } */ } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { // Do not call super here mSavedInstanceState = savedInstanceState; } public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); checkForLocaleChange(); mModel.setAllAppsLoaded(false); // Set force load all apps list; mModel.startLoader(this, true); // Reload apps list ActivityRuntimeInterface callback = mView != null?mView.get():null; if(callback != null){ callback.onConfigurationChanged(newConfig); } } @Override public Object onRetainNonConfigurationInstance() { // Flag the loader to stop early before switching //Log.d(TAG,"Rumtime" + mModel); //mModel.stopLoader(); return Boolean.TRUE; } /** * -------------------------------------------------------------- * 4.globle key event */ @Override public void onBackPressed() { ActivityRuntimeInterface callback = mView !=null ? mView.get() : null; if(callback != null){ callback.onBackPressed(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { return super.onCreateOptionsMenu(menu); } @Override public boolean onSearchRequested() { startSearch(null, false, null, true); return true; } /** * ---------------------------------------------------------------- */ 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") { 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 } } } } private void setWallpaperDimension() { WallpaperManager wpm = (WallpaperManager)getSystemService(WALLPAPER_SERVICE); Display display = getWindowManager().getDefaultDisplay(); final int width = display.getWidth(); final int height = display.getHeight(); /* try { wpm.setResource(R.drawable.background); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }*/ wpm.suggestDesiredDimensions(width, height); } /** * Restores the previous state, if it exists. * * @param savedState The previous state. */ private void restoreState(Bundle savedState) { /* if (savedState == null) { return; } //restore app state final boolean allApps = savedState.getBoolean(RUNTIME_STATE_ALL_APPS_FOLDER, false); if (allApps) { showAllApps(false); } //restore widgets info mAddItemCellInfo = new CellLayout.CellInfo(); final CellLayout.CellInfo addItemCellInfo = mAddItemCellInfo; addItemCellInfo.valid = true; addItemCellInfo.cellX = savedState.getInt(RUNTIME_STATE_PENDING_ADD_CELL_X); addItemCellInfo.cellY = savedState.getInt(RUNTIME_STATE_PENDING_ADD_CELL_Y); addItemCellInfo.spanX = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SPAN_X); addItemCellInfo.spanY = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SPAN_Y); addItemCellInfo.findVacantCellsFromOccupied( savedState.getBooleanArray(RUNTIME_STATE_PENDING_ADD_OCCUPIED_CELLS), savedState.getInt(RUNTIME_STATE_PENDING_ADD_COUNT_X), savedState.getInt(RUNTIME_STATE_PENDING_ADD_COUNT_Y)); mRestoring = true; */ } /** * Finds all the views we need and configure them properly. */ private void setupViews() { setContentView(R.layout.launcher); //mAllAppsGrid = (IAllAppsView)findViewById(R.id.all_apps_view); WorkSpace mainLayout = (WorkSpace)findViewById(R.id.mainlayout); mainLayout.setLauncher(this); mModel.setCallbacks(mainLayout); mView = new WeakReference<ActivityRuntimeInterface>(mainLayout); } /** * ----------------------------------------------------------------- * API For app widgets */ /** * Receives notifications whenever the appwidgets are reset. */ private class AppWidgetResetObserver extends ContentObserver { public AppWidgetResetObserver() { super(new Handler()); } @Override public void onChange(boolean selfChange) { onAppWidgetReset(); } } public AppWidgetManager getAppWidgetManager(){ return mAppWidgetManager; } public void pickAppWidget(){ int appWidgetId = Launcher.this.mAppWidgetHost.allocateAppWidgetId(); Intent pickIntent = new Intent(Utilities.ACTION_TVD_WIDGETS_PICKER); pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); // start the pick activity startActivityForResult(pickIntent, REQUEST_PICK_APPWIDGET); } public void addAppWidget(Intent data) { // TODO: catch bad widget exception when sent int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); AppWidgetProviderInfo appWidget = mAppWidgetManager.getAppWidgetInfo(appWidgetId); if (appWidget.configure != null) { // Launch over to configure widget, if needed Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE); intent.setComponent(appWidget.configure); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); startActivityForResultSafely(intent, REQUEST_CREATE_APPWIDGET); } else { // Otherwise just add it onActivityResult(REQUEST_CREATE_APPWIDGET, Activity.RESULT_OK, data); } } public void removeAppWidget(LauncherAppWidgetInfo launcherInfo) { mDesktopItems.remove(launcherInfo); launcherInfo.hostView = null; final LauncherAppWidgetInfo launcherAppWidgetInfo = launcherInfo; final LauncherAppWidgetHost appWidgetHost = getAppWidgetHost(); if (appWidgetHost != null) { final int appWidgetId = launcherAppWidgetInfo.appWidgetId; // Deleting an app widget ID is a void call but writes to disk before returning // to the caller... new Thread("deleteAppWidgetId") { public void run() { appWidgetHost.deleteAppWidgetId(launcherAppWidgetInfo.appWidgetId); } }.start(); } LauncherModel.deleteItemFromDatabase(this, launcherInfo); } public LauncherAppWidgetHost getAppWidgetHost() { return mAppWidgetHost; } /** * Re-listen when widgets are reset. */ private void onAppWidgetReset() { mAppWidgetHost.startListening(); } /** * Add a widget to the workspace. * * @param data The intent describing the appWidgetId. * @param cellInfo The position on screen where to create the widget. */ private void completeAddAppWidget(Intent data, CellLayout.CellInfo cellInfo) { Bundle extras = data.getExtras(); int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); if (LOGD) Log.d(TAG, "dumping extras content=" + extras.toString()); AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId); LauncherAppWidgetInfo launcherInfo = new LauncherAppWidgetInfo(appWidgetId); launcherInfo.title = appWidgetInfo.label; launcherInfo.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo); launcherInfo.hostView.setAppWidget(appWidgetId, appWidgetInfo); launcherInfo.hostView.setTag(launcherInfo); if(!mModel.addWidgetRumtime(appWidgetInfo, appWidgetId, launcherInfo)){ mAppWidgetHost.deleteAppWidgetId(appWidgetId); launcherInfo.hostView = null; return; } } /** * API For app widgets * ----------------------------------------------------------------- */ public void closeSystemDialogs() { getWindow().closeAllPanels(); try { dismissDialog(DIALOG_CREATE_SHORTCUT); // Unlock the workspace if the dialog was showing } catch (Exception e) { // An exception is thrown if the dialog is not visible, which is fine } try { dismissDialog(DIALOG_RENAME_FOLDER); // Unlock the workspace if the dialog was showing } catch (Exception e) { // An exception is thrown if the dialog is not visible, which is fine } // Whatever we were doing is hereby canceled. mWaitingForResult = false; } /** * Indicates that we want global search for this activity by setting the globalSearch * argument for {@link #startSearch} to true. */ public boolean isWorkspaceLocked() { return mWorkspaceLoading || mWaitingForResult; } /** * Registers various content observers. The current implementation registers * only a favorites observer to keep track of the favorites applications. */ private void registerContentObservers() { ContentResolver resolver = getContentResolver(); resolver.registerContentObserver(LauncherProvider.CONTENT_APPWIDGET_RESET_URI, true, mWidgetObserver); } @Override public void startActivityForResult(Intent intent, int requestCode) { if (requestCode >= 0) mWaitingForResult = true; super.startActivityForResult(intent, requestCode); } public void startActivitySafely(Intent intent, Object tag) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { startActivity(intent); } catch (ActivityNotFoundException e) { Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e); } catch (SecurityException e) { Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); Log.e(TAG, "Launcher does not have the permission to launch " + intent + ". Make sure to create a MAIN intent-filter for the corresponding activity " + "or use the exported attribute for this activity. " + "tag="+ tag + " intent=" + intent, e); } } public void startActivityForResultSafely(Intent intent, int requestCode) { try { startActivityForResult(intent, requestCode); } catch (ActivityNotFoundException e) { Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); } catch (SecurityException e) { Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); Log.e(TAG, "Launcher does not have the permission to launch " + intent + ". Make sure to create a MAIN intent-filter for the corresponding activity " + "or use the exported attribute for this activity.", e); } } /** * Receives notifications when applications are added/removed. */ private class CloseSystemDialogsIntentReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { closeSystemDialogs(); String reason = intent.getStringExtra("reason"); if (!"homekey".equals(reason)) { boolean animate = true; if (mPaused || "lock".equals(reason)) { animate = false; } //closeAllApps(animate); //closeAppsFavorites(animate); } } } }