In Native launcher, long-pressed desktop triggers many kinds of behavior. Its categories include: 1. Blank desktop; 2. Desktop content (folders, shortcuts, folders, etc.); 3. Existing desktop controls (two screen switches on the left and right, and all App list buttons) so we can easily understand launcher. the onlongclick function in the Java file:
Public Boolean onlongclick (view v) {Switch (V. GETID () {case R. Id. previous_screen: If (! Isallappsvisible () {mworkspace. initialize mhapticfeedback (hapticfeedbackconstants. long_press, hapticfeedbackconstants. values); showpreviews (V);} return true; case R. Id. next_screen: If (! Isallincluvisible () {mworkspace. initialize mhapticfeedback (hapticfeedbackconstants. long_press, hapticfeedbackconstants. values); showpreviews (V);} return true; case R. Id. all_assist_button: If (! Isallmediavisible () {mworkspace. performhapticfeedback (hapticfeedbackconstants. long_press, hapticfeedbackconstants. flag_ignore_view_setting); showpreviews (V);} return true;} If (isworkspacelocked () {return false;} If (! (V instanceof celllayout) {v = (View) v. getparent ();} // obtain the cellinfo information celllayout. cellinfo = (celllayout. cellinfo) v. gettag (); // This happens when long clicking an item with the DPAD/trackball if (cellinfo = NULL) {return true;} If (mworkspace. allowlongpress () {If (cellinfo. cell = NULL) {// If cellinfo is empty and valid, the Select dialog box if (cellinfo. valid) {// user long pressed on empty space mworkspace. Setallowlongpress (false); // The subsequent long-pressed desktop operation will fail until mworkspace is replied. performhapticfeedback (hapticfeedbackconstants. long_press, hapticfeedbackconstants. flag_ignore_view_setting); showadddifo (cellinfo) ;}} else {If (! (Cellinfo. cell instanceof folder) {// If cellinfo is not empty and it is not a folder, the drag operation is triggered by a long press. // user long pressed on an item mworkspace. performhapticfeedback (hapticfeedbackconstants. long_press, hapticfeedbackconstants. flag_ignore_view_setting); mworkspace. startdrag (cellinfo) ;}} return true ;}
For the moment, we do not care about non-empty content. First, we need to process the operation after the blank desktop is pressed. In this case, the showadddialog (cellinfo) function is called:
private void showAddDialog(CellLayout.CellInfo cellInfo) { mAddItemCellInfo = cellInfo; mWaitingForResult = true; showDialog(DIALOG_CREATE_SHORTCUT); }
This function only calls the showdialog built-in function of view, so we can easily think of a function for creating a dialog box:
@ Override protected dialog oncreatedialog (int id) {Switch (ID) {Case dialog_create_shortcut: return New createshortcut (). createdialog (); // The add content dialog box is displayed. Case dialog_rename_folder: return New renamefolder (). createdialog (); // The folder editing dialog box is displayed.} return Super. oncreatedialog (ID );}
For the add content dialog box, we know the content as follows:
This dialog box involves three aspects: 1. Display and operation of the dialog box; 2. List that can be selected; 3. Operation after clicking a list item:
1. Dialog Box:
/** * Displays the shortcut creation dialog and launches, if necessary, the * appropriate activity. */ private class CreateShortcut implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener, DialogInterface.OnDismissListener, DialogInterface.OnShowListener { private AddAdapter mAdapter; Dialog createDialog() { mAdapter = new AddAdapter(Launcher.this); final AlertDialog.Builder builder = new AlertDialog.Builder(Launcher.this); builder.setTitle(getString(R.string.menu_item_add_item)); builder.setAdapter(mAdapter, this); builder.setInverseBackgroundForced(true); AlertDialog dialog = builder.create(); dialog.setOnCancelListener(this); dialog.setOnDismissListener(this); dialog.setOnShowListener(this); return dialog; } public void onCancel(DialogInterface dialog) { mWaitingForResult = false; cleanup(); } public void onDismiss(DialogInterface dialog) { } private void cleanup() { try { dismissDialog(DIALOG_CREATE_SHORTCUT); } catch (Exception e) { // An exception is thrown if the dialog is not visible, which is fine } } /** * Handle the action clicked in the "Add to home" dialog. */ public void onClick(DialogInterface dialog, int which) { Resources res = getResources(); cleanup(); switch (which) { case AddAdapter.ITEM_SHORTCUT: { // Insert extra item to handle picking application pickShortcut(); break; } case AddAdapter.ITEM_APPWIDGET: { int appWidgetId = Launcher.this.mAppWidgetHost.allocateAppWidgetId(); Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK); pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); // start the pick activity startActivityForResult(pickIntent, REQUEST_PICK_APPWIDGET); break; } case AddAdapter.ITEM_LIVE_FOLDER: { // Insert extra item to handle inserting folder Bundle bundle = new Bundle(); ArrayList<String> shortcutNames = new ArrayList<String>(); shortcutNames.add(res.getString(R.string.group_folder)); bundle.putStringArrayList(Intent.EXTRA_SHORTCUT_NAME, shortcutNames); ArrayList<ShortcutIconResource> shortcutIcons = new ArrayList<ShortcutIconResource>(); shortcutIcons.add(ShortcutIconResource.fromContext(Launcher.this, R.drawable.ic_launcher_folder)); bundle.putParcelableArrayList(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, shortcutIcons); Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY); pickIntent.putExtra(Intent.EXTRA_INTENT, new Intent(LiveFolders.ACTION_CREATE_LIVE_FOLDER)); pickIntent.putExtra(Intent.EXTRA_TITLE, getText(R.string.title_select_live_folder)); pickIntent.putExtras(bundle); startActivityForResult(pickIntent, REQUEST_PICK_LIVE_FOLDER); break; } case AddAdapter.ITEM_WALLPAPER: { startWallpaper(); break; } } } public void onShow(DialogInterface dialog) { mWaitingForResult = true; } }
2. content list addadapter:
public AddAdapter(Launcher launcher) { super(); mInflater = (LayoutInflater) launcher.getSystemService(Context.LAYOUT_INFLATER_SERVICE); // Create default actions Resources res = launcher.getResources(); mItems.add(new ListItem(res, R.string.group_shortcuts, R.drawable.ic_launcher_shortcut, ITEM_SHORTCUT)); mItems.add(new ListItem(res, R.string.group_widgets, R.drawable.ic_launcher_appwidget, ITEM_APPWIDGET)); mItems.add(new ListItem(res, R.string.group_live_folders, R.drawable.ic_launcher_folder, ITEM_LIVE_FOLDER)); mItems.add(new ListItem(res, R.string.group_wallpapers, R.drawable.ic_launcher_wallpaper, ITEM_WALLPAPER)); }
Here we can see that four items are added, which correspond to the four icons of the figure above.
3. Add shortcuts:
The simplest way to add shortcuts is to call the system shortcut list:
Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY); pickIntent.putExtra(Intent.EXTRA_INTENT, new Intent(Intent.ACTION_CREATE_SHORTCUT)); pickIntent.putExtra(Intent.EXTRA_TITLE, res.getString(R.string.title_select_app)); pickIntent.putExtras(bundle); startActivityForResult(pickIntent, REQUEST_PICK_SHORTCUT);
All the shortcuts that can be created are obtained, but what if we need to add other items to this list? As we know, I need to add "application" to this list, so that when we click the application, we can display the Application List. At this time, we only need to input additional information, as shown below:
Resources res = getresources ();/*** use a bundle object, pass two list information * The text of the items to be appended to the shortcut list in a list * the corresponding icon information in a list */bundle = new bundle (); arraylist <string> shortcutnames = new arraylist <string> (); shortcutnames. add (res. getstring (R. string. group_application); shortcutnames. add ("other"); // display the name bundle of the first application shortcut in the list. putstringarraylist (intent. extra_shortcut_name, shortcutnames); // display the icon arraylist <symbol cuticonresource> symbol cuticons = new arraylist <symbol cuticonresource> (); symbol cuticons. add (export cuticonresource. fromcontext (uorderlauncher. this, R. drawable. icon); then cuticons. add (export cuticonresource. fromcontext (uorderlauncher. this, R. drawable. icon); bundle. putparcelablearraylist (intent. extra_shortcut_icon_resource, specify cuticons); intent pickintent = new intent (intent. action_pick_activity); pickintent. putextra (intent. extra_intent, new intent (intent. action_create_shortcut); pickintent. putextra (intent. extra_title, Res. getstring (R. string. title_select_app); // Add the additional information to pickintent. putextras (bundle); startactivityforresult (pickintent, request_pick_shortcut );
After you click it, a selection list is displayed:
The first "applitions" is appended, and the rest are existing shortcut. Therefore, we know that the operations we need to perform are different when we click the first item and other items. At this point, if you click a function to trigger the processshortcut function in the onactivityresult function:
Void processshortcut (intent) {// handle case where user selected "Applications" string applicationname = getresources (). getstring (R. string. group_applications); string shortcutname = intent. getstringextra (intent. extra_shortcut_name); // indicates that the application is selected. Enter the Application List if (applicationname! = NULL & applicationname. equals (shortcutname) {intent mainintent = new intent (intent. action_main, null); mainintent. addcategory (intent. category_launcher); intent pickintent = new intent (intent. action_pick_activity); pickintent. putextra (intent. extra_intent, mainintent); pickintent. putextra (intent. extra_title, gettext (R. string. title_select_application); startactivityforresultsafely (pickintent, request_pick_application);} else {// otherwise, you can directly create a shortcut startactivityforresultsafely (intent, request_create_shortcut );}}
After that, the actual shotcut creation operation is started:
/*** Add a shortcut cut to the workspace. ** @ Param data the intent describing the shortcut. * @ Param cellinfo the position on screen where to create the shortcut. */private void completeaddshortcut (intent data, celllayout. cellinfo) {cellinfo. screen = mworkspace. getcurrentscreen (); If (! Findsingleslot (cellinfo) return; // find an empty single cellinfo final shortcutinfo info = Mmodel. addshortcut (this, Data, cellinfo, false); If (! Mrestoring) {final view = createshortcut (Info); mworkspace. addincurrentscreen (view, cellinfo. cellx, cellinfo. celly, 1, 1, isworkspacelocked ());}}
There are two problems: 1. Search for space on the desktop. You can add shortcuts only when there is space on the desktop. 2. Generate shortcuts and add them to the desktop;
For the first step to find available space:
private boolean findSingleSlot(CellLayout.CellInfo cellInfo) { final int[] xy = new int[2]; if (findSlot(cellInfo, xy, 1, 1)) { cellInfo.cellX = xy[0]; cellInfo.cellY = xy[1]; return true; } return false; } private boolean findSlot(CellLayout.CellInfo cellInfo, int[] xy, int spanX, int spanY) { if (!cellInfo.findCellForSpan(xy, spanX, spanY)) { boolean[] occupied = mSavedState != null ? mSavedState.getBooleanArray(RUNTIME_STATE_PENDING_ADD_OCCUPIED_CELLS) : null; cellInfo = mWorkspace.findAllVacantCells(occupied); if (!cellInfo.findCellForSpan(xy, spanX, spanY)) { Toast.makeText(this, getString(R.string.out_of_space), Toast.LENGTH_SHORT).show(); return false; } } return true; }
In fact, there must be space for adding shortcuts. If there is no space, a message indicating insufficient space is displayed. (Because you long press the blank cellinfo itself, but if other programs occupy the blank space during your operation, there will be problems, therefore, you need to determine whether there is space available ).
If there is space available, create a shortcut and add its information to the database:
ShortcutInfo addShortcut(Context context, Intent data, CellLayout.CellInfo cellInfo, boolean notify) { final ShortcutInfo info = infoFromShortcutIntent(context, data); addItemToDatabase(context, info, LauncherSettings.Favorites.CONTAINER_DESKTOP, cellInfo.screen, cellInfo.cellX, cellInfo.cellY, notify); return info; }
At this time, this shortcut exists only in the database and is not actually displayed on the desktop. Therefore, you need to produce an icon,
/** * 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.getCurrentScreen()), 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) { TextView favorite = (TextView) mInflater.inflate(layoutResId, parent, false); favorite.setCompoundDrawablesWithIntrinsicBounds(null, new FastBitmapDrawable(info.getIcon(mIconCache)), null, null); favorite.setText(info.title); favorite.setTag(info); favorite.setOnClickListener(this); return favorite; }
Finally, add the icon to the desktop for display:
/*** Adds the specified child in the specified screen. the position and dimension of * the child are defined by X, Y, Spanx and spany. ** @ Param child the child to add in one of the workspace's screens. * @ Param screen the screen in which to add the child. * @ Param x the X position of the child in the screen's grid. * @ Param y the Y position of the child in the screen's grid. * @ Param spanx the N Umber of cells spanned horizontally by the child. * @ Param spany the number of cells spanned vertically by the child. * @ Param insert when true, the child is inserted at the beginning of the children list. */void addinscreen (view child, int screen, int X, int y, int spanx, int spany, Boolean insert) {If (screen <0 | screen> = getchildcount () {log. E (TAG, "the screen must be> = 0 and <" + get Childcount () + "(was" + screen + "); skipping child"); return;} clearvacantcache (); Final celllayout group = (celllayout) getchildat (screen); celllayout. layoutparams Lp = (celllayout. layoutparams) child. getlayoutparams (); If (Lp = NULL) {Lp = new celllayout. layoutparams (X, Y, spanx, spany);} else {LP. cellx = x; LP. celly = y; LP. cellhspan = spanx; LP. cellvspan = spany;} group. addview (child, Insert? 0:-1, LP); If (! (Child instanceof folder) {// Add the listener child to the view by the length. sethapticfeedbackenabled (false); child. setonlongclicklistener (mlongclicklistener);} If (Child instanceof droptarget) {mdragcontroller. adddroptarget (droptarget) Child );}}
We have introduced the process of adding shotcut. For other content, such as widgets, the process is similar and we will not introduce it.
References:
Story Behind Android desktop (launcher application) (2)-application addition