ShortcutPickerFragment.java revision 5675ea88d3cc4ba9934d2a54fee008fd324d711f
1/* 2 * Copyright (C) 2011 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 17package com.android.email.activity; 18 19import com.android.email.R; 20import com.android.emailcommon.Logging; 21import com.android.emailcommon.provider.EmailContent.Account; 22import com.android.emailcommon.provider.EmailContent.AccountColumns; 23import com.android.emailcommon.provider.EmailContent.MailboxColumns; 24import com.android.emailcommon.provider.HostAuth; 25import com.android.emailcommon.provider.Mailbox; 26 27import android.app.Activity; 28import android.app.ListFragment; 29import android.app.LoaderManager.LoaderCallbacks; 30import android.content.Context; 31import android.content.CursorLoader; 32import android.content.Intent; 33import android.content.Loader; 34import android.database.Cursor; 35import android.os.Bundle; 36import android.os.Parcelable; 37import android.util.Log; 38import android.view.View; 39import android.widget.AdapterView; 40import android.widget.ListView; 41import android.widget.SimpleCursorAdapter; 42import android.widget.AdapterView.OnItemClickListener; 43 44// TODO restructure this into three classes -- a base class w/ two sub-classes. Intead of using 45// selectingMailbox(), we'd just define the proper methods in the sub-class. 46 47/** 48 * Fragment containing a list of accounts to show during shortcut creation. 49 */ 50public abstract class ShortcutPickerFragment extends ListFragment 51 implements OnItemClickListener, LoaderCallbacks<Cursor> { 52 /** 53 * If true, creates pre-honeycomb style shortcuts. This allows developers to test launching 54 * the app from old style shortcuts (which point sat MessageList rather than Welcome) without 55 * actually carrying over shortcuts from previous versions. 56 */ 57 private final static boolean TEST_CREATE_OLD_STYLE_SHORTCUT = false; // DO NOT SUBMIT WITH TRUE 58 private final static int LOADER_ID = 0; 59 private final static int[] TO_VIEWS = new int[] { 60 android.R.id.text1, 61 }; 62 63 /** Cursor adapter that provides either the account or mailbox list */ 64 private SimpleCursorAdapter mAdapter; 65 66 @Override 67 public void onAttach(Activity activity) { 68 super.onAttach(activity); 69 70 final String[] fromColumns = getFromColumns(); 71 mAdapter = new SimpleCursorAdapter(activity, 72 android.R.layout.simple_expandable_list_item_1, null, fromColumns, TO_VIEWS, 0); 73 setListAdapter(mAdapter); 74 75 getLoaderManager().initLoader(LOADER_ID, null, this); 76 } 77 78 @Override 79 public void onActivityCreated(Bundle savedInstanceState) { 80 super.onActivityCreated(savedInstanceState); 81 82 ListView listView = getListView(); 83 listView.setOnItemClickListener(this); 84 listView.setItemsCanFocus(false); 85 } 86 87 @Override 88 public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 89 // No accounts; close the dialog 90 if (data.getCount() == 0) { 91 // TODO what's the proper handling if the mailbox list is '0'? display toast? 92 getActivity().finish(); 93 return; 94 } 95 // TODO special handle case where there is one account or one mailbox; the user shouldn't 96 // be forced to select anything in either of those cases. 97 mAdapter.swapCursor(data); 98 } 99 100 @Override 101 public void onLoaderReset(Loader<Cursor> loader) { 102 mAdapter.swapCursor(null); 103 } 104 105 /** Returns the cursor columns to map into list */ 106 abstract String[] getFromColumns(); 107 108 /** 109 * This function creates a shortcut and returns it to the caller. There are actually two 110 * intents that you will send back. 111 * 112 * The first intent serves as a container for the shortcut and is returned to the launcher by 113 * setResult(). This intent must contain three fields: 114 * 115 * <ul> 116 * <li>{@link android.content.Intent#EXTRA_SHORTCUT_INTENT} The shortcut intent.</li> 117 * <li>{@link android.content.Intent#EXTRA_SHORTCUT_NAME} The text that will be displayed with 118 * the shortcut.</li> 119 * <li>{@link android.content.Intent#EXTRA_SHORTCUT_ICON} The shortcut's icon, if provided as a 120 * bitmap, <i>or</i> {@link android.content.Intent#EXTRA_SHORTCUT_ICON_RESOURCE} if provided as 121 * a drawable resource.</li> 122 * </ul> 123 * 124 * If you use a simple drawable resource, note that you must wrapper it using 125 * {@link android.content.Intent.ShortcutIconResource}, as shown below. This is required so 126 * that the launcher can access resources that are stored in your application's .apk file. If 127 * you return a bitmap, such as a thumbnail, you can simply put the bitmap into the extras 128 * bundle using {@link android.content.Intent#EXTRA_SHORTCUT_ICON}. 129 * 130 * The shortcut intent can be any intent that you wish the launcher to send, when the user 131 * clicks on the shortcut. Typically this will be {@link android.content.Intent#ACTION_VIEW} 132 * with an appropriate Uri for your content, but any Intent will work here as long as it 133 * triggers the desired action within your Activity. 134 */ 135 void setupShortcut(Account account, long mailboxId) { 136 Activity myActivity = getActivity(); 137 // First, set up the shortcut intent. 138 final Intent shortcutIntent; 139 if (TEST_CREATE_OLD_STYLE_SHORTCUT) { 140 shortcutIntent = MessageList.createFroyoIntent(myActivity, account); 141 Log.d(Logging.LOG_TAG, "Created old style intent: " + shortcutIntent); 142 } else { 143 String uuid = account.mCompatibilityUuid; 144 shortcutIntent = Welcome.createAccountShortcutIntent(myActivity, uuid, mailboxId); 145 } 146 147 // Then, set up the container intent (the response to the caller) 148 Intent intent = new Intent(); 149 intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); 150 intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, account.getDisplayName()); 151 Parcelable iconResource 152 = Intent.ShortcutIconResource.fromContext(myActivity, R.mipmap.ic_launcher_email); 153 intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconResource); 154 155 // Now, return the result to the launcher 156 157 myActivity.setResult(Activity.RESULT_OK, intent); 158 } 159 160 /** Account picker */ 161 public static class AccountShortcutPickerFragment extends ShortcutPickerFragment { 162 private final static String[] ACCOUNT_FROM_COLUMNS = new String[] { 163 AccountColumns.DISPLAY_NAME, 164 }; 165 166 @Override 167 public void onActivityCreated(Bundle savedInstanceState) { 168 super.onActivityCreated(savedInstanceState); 169 getActivity().setTitle(R.string.account_shortcut_picker_title); 170 } 171 172 @Override 173 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 174 Cursor cursor = (Cursor) parent.getItemAtPosition(position); 175 Account account = new Account(); 176 account.restore(cursor); 177 ShortcutPickerFragment fragment = new MailboxShortcutPickerFragment(); 178 final Bundle args = new Bundle(); 179 args.putParcelable(MailboxShortcutPickerFragment.ARG_ACCOUNT, account); 180 fragment.setArguments(args); 181 getFragmentManager() 182 .beginTransaction() 183 .replace(R.id.shortcut_list, fragment) 184 .addToBackStack(null) 185 .commit(); 186 } 187 188 @Override 189 public Loader<Cursor> onCreateLoader(int id, Bundle args) { 190 Context context = getActivity(); 191 // TODO Add ability to insert special account "all accounts" 192 return new CursorLoader( 193 context, Account.CONTENT_URI, Account.CONTENT_PROJECTION, null, null, null); 194 } 195 196 @Override 197 String[] getFromColumns() { 198 return ACCOUNT_FROM_COLUMNS; 199 } 200 } 201 202 /** Mailbox picker */ 203 public static class MailboxShortcutPickerFragment extends ShortcutPickerFragment { 204 static final String ARG_ACCOUNT = "MailboxShortcutPickerFragment.account"; 205 private final static String[] MAILBOX_FROM_COLUMNS = new String[] { 206 MailboxColumns.DISPLAY_NAME, 207 }; 208 /** Loader projection used for IMAP & POP3 accounts */ 209 private final static String[] IMAP_PROJECTION = new String [] { 210 MailboxColumns.ID, MailboxColumns.SERVER_ID + " as " + MailboxColumns.DISPLAY_NAME 211 }; 212 /** Loader projection used for EAS accounts */ 213 private final static String[] EAS_PROJECTION = new String [] { 214 MailboxColumns.ID, MailboxColumns.DISPLAY_NAME 215 }; 216 // TODO This is identical to MailboxesAdapter#ALL_MAILBOX_SELECTION; any way we can create a 217 // common selection? Move this to the Mailbox class? 218 private final static String ALL_MAILBOX_SELECTION = MailboxColumns.ACCOUNT_KEY + "=?" + 219 " AND " + Mailbox.USER_VISIBLE_MAILBOX_SELECTION; 220 221 /** The currently selected account */ 222 private Account mAccount; 223 224 @Override 225 public void onAttach(Activity activity) { 226 // Need to setup the account first thing 227 mAccount = getArguments().getParcelable(ARG_ACCOUNT); 228 super.onAttach(activity); 229 } 230 231 @Override 232 public void onActivityCreated(Bundle savedInstanceState) { 233 super.onActivityCreated(savedInstanceState); 234 getActivity().setTitle(R.string.mailbox_shortcut_picker_title); 235 } 236 237 @Override 238 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 239 Cursor cursor = (Cursor) parent.getItemAtPosition(position); 240 long mailboxId = cursor.getLong(Mailbox.CONTENT_ID_COLUMN); 241 setupShortcut(mAccount, mailboxId); 242 getActivity().finish(); 243 } 244 245 @Override 246 public Loader<Cursor> onCreateLoader(int id, Bundle args) { 247 Context context = getActivity(); 248 // TODO Add ability to insert special mailboxes like "starred", etc... 249 // TODO Create a fully-qualified path name for Exchange accounts [code should also work 250 // for MoveMessageToDialog.java] 251 HostAuth recvAuth = mAccount.getOrCreateHostAuthRecv(context); 252 final String[] projection; 253 final String orderBy; 254 if (recvAuth.isEasConnection()) { 255 projection = EAS_PROJECTION; 256 orderBy = MailboxColumns.DISPLAY_NAME; 257 } else { 258 projection = IMAP_PROJECTION; 259 orderBy = MailboxColumns.SERVER_ID; 260 } 261 return new CursorLoader( 262 context, Mailbox.CONTENT_URI, projection, ALL_MAILBOX_SELECTION, 263 new String[] { Long.toString(mAccount.mId) }, orderBy); 264 } 265 266 @Override 267 String[] getFromColumns() { 268 return MAILBOX_FROM_COLUMNS; 269 } 270 } 271} 272