• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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 
17 package com.android.mail.ui;
18 
19 import android.app.ActionBar;
20 import android.app.Activity;
21 import android.app.Fragment;
22 import android.app.FragmentTransaction;
23 import android.appwidget.AppWidgetManager;
24 import android.content.Context;
25 import android.content.DialogInterface;
26 import android.content.Intent;
27 import android.database.DataSetObservable;
28 import android.database.DataSetObserver;
29 import android.os.Bundle;
30 import android.view.DragEvent;
31 import android.view.View;
32 import android.view.View.OnClickListener;
33 import android.widget.Button;
34 import android.widget.ListView;
35 
36 import com.android.mail.R;
37 import com.android.mail.providers.Account;
38 import com.android.mail.providers.Folder;
39 import com.android.mail.providers.FolderWatcher;
40 import com.android.mail.utils.LogTag;
41 import com.android.mail.utils.LogUtils;
42 import com.android.mail.utils.Observable;
43 import com.android.mail.utils.Utils;
44 import com.android.mail.utils.VeiledAddressMatcher;
45 import com.android.mail.widget.WidgetProvider;
46 
47 import java.util.ArrayList;
48 
49 /**
50  * This activity displays the list of available folders for the current account.
51  */
52 public class FolderSelectionActivity extends Activity implements OnClickListener,
53         DialogInterface.OnClickListener, FolderChangeListener, ControllableActivity,
54         FolderSelector {
55     public static final String EXTRA_ACCOUNT_SHORTCUT = "account-shortcut";
56 
57     private static final String LOG_TAG = LogTag.getLogTag();
58 
59     private static final int CONFIGURE = 0;
60 
61     private static final int VIEW = 1;
62 
63     private Account mAccount;
64     private Folder mSelectedFolder;
65     private boolean mConfigureShortcut;
66     protected boolean mConfigureWidget;
67     private int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
68     private int mMode = -1;
69     /** Empty placeholder for communicating to the consumer of the drawer observer. */
70     private final DataSetObservable mDrawerObservers = new Observable("Drawer");
71 
72     private final AccountController mAccountController = new AccountController() {
73         @Override
74         public void registerAccountObserver(DataSetObserver observer) {
75             // Do nothing
76         }
77 
78         @Override
79         public void unregisterAccountObserver(DataSetObserver observer) {
80             // Do nothing
81         }
82 
83         @Override
84         public Account getAccount() {
85             return mAccount;
86         }
87 
88         @Override
89         public void registerAllAccountObserver(DataSetObserver observer) {
90             // Do nothing
91         }
92 
93         @Override
94         public void unregisterAllAccountObserver(DataSetObserver observer) {
95             // Do nothing
96         }
97 
98         @Override
99         public Account[] getAllAccounts() {
100             return new Account[]{mAccount};
101         }
102 
103         @Override
104         public VeiledAddressMatcher getVeiledAddressMatcher() {
105             return null;
106         }
107 
108         @Override
109         public void changeAccount(Account account) {
110             // Never gets called, so do nothing here.
111             LogUtils.wtf(LOG_TAG,
112                     "FolderSelectionActivity.changeAccount() called when NOT expected.");
113         }
114 
115         @Override
116         public void switchToDefaultInboxOrChangeAccount(Account account) {
117             // Never gets called, so do nothing here.
118             LogUtils.wtf(LOG_TAG,"FolderSelectionActivity.switchToDefaultInboxOrChangeAccount() " +
119                     "called when NOT expected.");
120         }
121 
122         @Override
123         public void registerDrawerClosedObserver(final DataSetObserver observer) {
124             mDrawerObservers.registerObserver(observer);
125         }
126 
127         @Override
128         public void unregisterDrawerClosedObserver(final DataSetObserver observer) {
129             mDrawerObservers.unregisterObserver(observer);
130         }
131 
132         /**
133          * Since there is no drawer to wait for, notifyChanged to the observers.
134          */
135         @Override
136         public void closeDrawer(final boolean hasNewFolderOrAccount,
137                 Account account, Folder folder) {
138             mDrawerObservers.notifyChanged();
139         }
140 
141         @Override
142         public void setFolderWatcher(FolderWatcher watcher) {
143             // Unsupported.
144         }
145 
146         @Override
147         public boolean isDrawerPullEnabled() {
148             // Unsupported
149             return false;
150         }
151 
152         @Override
153         public int getFolderListViewChoiceMode() {
154             return ListView.CHOICE_MODE_NONE;
155         }
156     };
157 
158     @Override
onCreate(Bundle icicle)159     public void onCreate(Bundle icicle) {
160         super.onCreate(icicle);
161 
162         setContentView(R.layout.folders_activity);
163 
164         final Intent intent = getIntent();
165         final String action = intent.getAction();
166         mConfigureShortcut = Intent.ACTION_CREATE_SHORTCUT.equals(action);
167         mConfigureWidget = AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action);
168         if (!mConfigureShortcut && !mConfigureWidget) {
169             LogUtils.wtf(LOG_TAG, "unexpected intent: %s", intent);
170         }
171         if (mConfigureShortcut || mConfigureWidget) {
172             ActionBar actionBar = getActionBar();
173             if (actionBar != null) {
174                 actionBar.setIcon(R.mipmap.ic_launcher_shortcut_folder);
175             }
176             mMode = CONFIGURE;
177         } else {
178             mMode = VIEW;
179         }
180 
181         if (mConfigureWidget) {
182             mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
183                     AppWidgetManager.INVALID_APPWIDGET_ID);
184             if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
185                 LogUtils.wtf(LOG_TAG, "invalid widgetId");
186             }
187         }
188 
189         mAccount = intent.getParcelableExtra(EXTRA_ACCOUNT_SHORTCUT);
190         final Button firstButton = (Button) findViewById(R.id.first_button);
191         firstButton.setVisibility(View.VISIBLE);
192         // TODO(mindyp) disable the manage folders buttons until we have a manage folders screen.
193         if (mMode == VIEW) {
194             firstButton.setEnabled(false);
195         }
196         firstButton.setOnClickListener(this);
197         createFolderListFragment(FolderListFragment.ofTopLevelTree(mAccount.folderListUri,
198                 getExcludedFolderTypes()));
199     }
200 
201     /**
202      * Create a Fragment showing this folder and its children.
203      */
createFolderListFragment(Fragment fragment)204     private void createFolderListFragment(Fragment fragment) {
205         final FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
206         fragmentTransaction.replace(R.id.content_pane, fragment);
207         fragmentTransaction.commitAllowingStateLoss();
208     }
209 
210     /**
211      * Gets an {@link ArrayList} of canonical names of any folders to exclude from displaying.
212      * By default, this list is empty.
213      *
214      * @return An {@link ArrayList} of folder canonical names
215      */
getExcludedFolderTypes()216     protected ArrayList<Integer> getExcludedFolderTypes() {
217         return new ArrayList<Integer>();
218     }
219 
220     @Override
onResume()221     protected void onResume() {
222         super.onResume();
223 
224         // TODO: (mindyp) Make sure we're operating on the same account as
225         // before. If the user switched accounts, switch back.
226     }
227 
228     @Override
onClick(View v)229     public void onClick(View v) {
230         final int id = v.getId();
231         if (id == R.id.first_button) {
232             if (mMode == CONFIGURE) {
233                 doCancel();
234             } else {
235                 // TODO (mindyp): open manage folders screen.
236             }
237         }
238     }
239 
doCancel()240     private void doCancel() {
241         setResult(RESULT_CANCELED);
242         finish();
243     }
244 
245     /**
246      * Create a widget for the specified account and folder
247      */
createWidget(int id, Account account, Folder selectedFolder)248     protected void createWidget(int id, Account account, Folder selectedFolder) {
249         WidgetProvider.updateWidget(this, id, account, selectedFolder.type,
250                 selectedFolder.folderUri.fullUri, selectedFolder.conversationListUri,
251                 selectedFolder.name);
252         final Intent result = new Intent();
253         result.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id);
254         setResult(RESULT_OK, result);
255         finish();
256     }
257 
258     @Override
onClick(DialogInterface dialog, int which)259     public void onClick(DialogInterface dialog, int which) {
260         if (which == DialogInterface.BUTTON_POSITIVE) {
261             // The only dialog that is
262             createWidget(mAppWidgetId, mAccount, mSelectedFolder);
263         } else {
264             doCancel();
265         }
266     }
267 
268     @Override
onFolderChanged(Folder folder, final boolean force)269     public void onFolderChanged(Folder folder, final boolean force) {
270         if (!folder.equals(mSelectedFolder)) {
271             mSelectedFolder = folder;
272             Intent resultIntent = new Intent();
273 
274             if (mConfigureShortcut) {
275                 /*
276                  * Create the shortcut Intent based on it with the additional
277                  * information that we have in this activity: name of the
278                  * account, calculate the human readable name of the folder and
279                  * use it as the shortcut name, etc...
280                  */
281                 final Intent clickIntent = Utils.createViewFolderIntent(this,
282                         mSelectedFolder.folderUri.fullUri, mAccount);
283                 resultIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, clickIntent);
284                 resultIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
285                         Intent.ShortcutIconResource.fromContext(this,
286                                 R.mipmap.ic_launcher_shortcut_folder));
287                 /**
288                  * Note: Email1 created shortcuts using R.mipmap#ic_launcher_email
289                  * so don't delete that resource until we have an upgrade/migration solution
290                  */
291 
292                 final CharSequence humanFolderName = mSelectedFolder.name;
293 
294                 resultIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, humanFolderName);
295 
296                 // Now ask the user what name they want for this shortcut. Pass
297                 // the
298                 // shortcut intent that we just created, the user can modify the
299                 // folder in
300                 // ShortcutNameActivity.
301                 final Intent shortcutNameIntent = new Intent(this, ShortcutNameActivity.class);
302                 shortcutNameIntent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY
303                         | Intent.FLAG_ACTIVITY_FORWARD_RESULT);
304                 shortcutNameIntent.putExtra(ShortcutNameActivity.EXTRA_FOLDER_CLICK_INTENT,
305                         resultIntent);
306                 shortcutNameIntent.putExtra(ShortcutNameActivity.EXTRA_SHORTCUT_NAME,
307                         humanFolderName);
308 
309                 startActivity(shortcutNameIntent);
310                 finish();
311             } else if (mConfigureWidget) {
312                 createWidget(mAppWidgetId, mAccount, mSelectedFolder);
313             }
314         }
315     }
316 
317     @Override
getHelpContext()318     public String getHelpContext() {
319         // TODO Auto-generated method stub
320         return null;
321     }
322 
323     @Override
getActivityContext()324     public Context getActivityContext() {
325         return this;
326     }
327 
328     @Override
getViewMode()329     public ViewMode getViewMode() {
330         return null;
331     }
332 
333     @Override
getListHandler()334     public ConversationListCallbacks getListHandler() {
335         return null;
336     }
337 
338     @Override
getFolderChangeListener()339     public FolderChangeListener getFolderChangeListener() {
340         return this;
341     }
342 
343     @Override
getSelectedSet()344     public ConversationSelectionSet getSelectedSet() {
345         return null;
346     }
347 
348     private Folder mNavigatedFolder;
349     @Override
onFolderSelected(Folder folder)350     public void onFolderSelected(Folder folder) {
351         if (folder.hasChildren && !folder.equals(mNavigatedFolder)) {
352             mNavigatedFolder = folder;
353             // Replace this fragment with a new FolderListFragment
354             // showing this folder's children if we are not already looking
355             // at the child view for this folder.
356             createFolderListFragment(FolderListFragment.ofTree(folder));
357             return;
358         }
359         onFolderChanged(folder, false /* force */);
360     }
361 
362     @Override
getFolderSelector()363     public FolderSelector getFolderSelector() {
364         return this;
365     }
366 
367     @Override
supportsDrag(DragEvent event, Folder folder)368     public boolean supportsDrag(DragEvent event, Folder folder) {
369         return false;
370     }
371 
372     @Override
handleDrop(DragEvent event, Folder folder)373     public void handleDrop(DragEvent event, Folder folder) {
374         // Do nothing.
375     }
376 
377     @Override
onUndoAvailable(ToastBarOperation undoOp)378     public void onUndoAvailable(ToastBarOperation undoOp) {
379         // Do nothing.
380     }
381 
382     @Override
getHierarchyFolder()383     public Folder getHierarchyFolder() {
384         return null;
385     }
386 
387     @Override
getConversationUpdater()388     public ConversationUpdater getConversationUpdater() {
389         return null;
390     }
391 
392     @Override
getErrorListener()393     public ErrorListener getErrorListener() {
394         return null;
395     }
396 
397     @Override
setPendingToastOperation(ToastBarOperation op)398     public void setPendingToastOperation(ToastBarOperation op) {
399         // Do nothing.
400     }
401 
402     @Override
getPendingToastOperation()403     public ToastBarOperation getPendingToastOperation() {
404         return null;
405     }
406 
407     @Override
getFolderController()408     public FolderController getFolderController() {
409         return null;
410     }
411 
412     @Override
onAnimationEnd(AnimatedAdapter animatedAdapter)413     public void onAnimationEnd(AnimatedAdapter animatedAdapter) {
414     }
415 
416     @Override
getAccountController()417     public AccountController getAccountController() {
418         return mAccountController;
419     }
420 
421     @Override
onFooterViewErrorActionClick(Folder folder, int errorStatus)422     public void onFooterViewErrorActionClick(Folder folder, int errorStatus) {
423         // Unsupported
424     }
425 
426     @Override
onFooterViewLoadMoreClick(Folder folder)427     public void onFooterViewLoadMoreClick(Folder folder) {
428         // Unsupported
429     }
430 
431     @Override
startDragMode()432     public void startDragMode() {
433         // Unsupported
434     }
435 
436     @Override
stopDragMode()437     public void stopDragMode() {
438         // Unsupported
439     }
440 
441     @Override
getRecentFolderController()442     public RecentFolderController getRecentFolderController() {
443         // Unsupported
444         return null;
445     }
446 
447     @Override
getUpOrBackController()448     public UpOrBackController getUpOrBackController() {
449         // Unsupported
450         return null;
451     }
452 
453     @Override
isAccessibilityEnabled()454     public boolean isAccessibilityEnabled() {
455         // Unsupported
456         return true;
457     }
458 
459     @Override
getConversationListHelper()460     public ConversationListHelper getConversationListHelper() {
461         // Unsupported
462         return null;
463     }
464 
465     @Override
getFragmentLauncher()466     public FragmentLauncher getFragmentLauncher() {
467         // Unsupported
468         return null;
469     }
470 }
471