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 
17 package com.android.gallery3d.app;
18 
19 import android.annotation.TargetApi;
20 import android.app.ActionBar;
21 import android.app.ActionBar.OnMenuVisibilityListener;
22 import android.app.ActionBar.OnNavigationListener;
23 import android.app.Activity;
24 import android.app.AlertDialog;
25 import android.content.Context;
26 import android.content.DialogInterface;
27 import android.content.Intent;
28 import android.content.res.Resources;
29 import android.view.LayoutInflater;
30 import android.view.Menu;
31 import android.view.MenuItem;
32 import android.view.View;
33 import android.view.ViewGroup;
34 import android.widget.BaseAdapter;
35 import android.widget.ShareActionProvider;
36 import android.widget.TextView;
37 import android.widget.TwoLineListItem;
38 
39 import com.android.gallery3d.R;
40 import com.android.gallery3d.common.ApiHelper;
41 
42 import java.util.ArrayList;
43 
44 public class GalleryActionBar implements OnNavigationListener {
45     @SuppressWarnings("unused")
46     private static final String TAG = "GalleryActionBar";
47 
48     private ClusterRunner mClusterRunner;
49     private CharSequence[] mTitles;
50     private ArrayList<Integer> mActions;
51     private Context mContext;
52     private LayoutInflater mInflater;
53     private AbstractGalleryActivity mActivity;
54     private ActionBar mActionBar;
55     private int mCurrentIndex;
56     private ClusterAdapter mAdapter = new ClusterAdapter();
57 
58     private AlbumModeAdapter mAlbumModeAdapter;
59     private OnAlbumModeSelectedListener mAlbumModeListener;
60     private int mLastAlbumModeSelected;
61     private CharSequence [] mAlbumModes;
62     public static final int ALBUM_FILMSTRIP_MODE_SELECTED = 0;
63     public static final int ALBUM_GRID_MODE_SELECTED = 1;
64 
65     public interface ClusterRunner {
doCluster(int id)66         public void doCluster(int id);
67     }
68 
69     public interface OnAlbumModeSelectedListener {
onAlbumModeSelected(int mode)70         public void onAlbumModeSelected(int mode);
71     }
72 
73     private static class ActionItem {
74         public int action;
75         public boolean enabled;
76         public boolean visible;
77         public int spinnerTitle;
78         public int dialogTitle;
79         public int clusterBy;
80 
ActionItem(int action, boolean applied, boolean enabled, int title, int clusterBy)81         public ActionItem(int action, boolean applied, boolean enabled, int title,
82                 int clusterBy) {
83             this(action, applied, enabled, title, title, clusterBy);
84         }
85 
ActionItem(int action, boolean applied, boolean enabled, int spinnerTitle, int dialogTitle, int clusterBy)86         public ActionItem(int action, boolean applied, boolean enabled, int spinnerTitle,
87                 int dialogTitle, int clusterBy) {
88             this.action = action;
89             this.enabled = enabled;
90             this.spinnerTitle = spinnerTitle;
91             this.dialogTitle = dialogTitle;
92             this.clusterBy = clusterBy;
93             this.visible = true;
94         }
95     }
96 
97     private static final ActionItem[] sClusterItems = new ActionItem[] {
98         new ActionItem(FilterUtils.CLUSTER_BY_ALBUM, true, false, R.string.albums,
99                 R.string.group_by_album),
100         new ActionItem(FilterUtils.CLUSTER_BY_LOCATION, true, false,
101                 R.string.locations, R.string.location, R.string.group_by_location),
102         new ActionItem(FilterUtils.CLUSTER_BY_TIME, true, false, R.string.times,
103                 R.string.time, R.string.group_by_time),
104         new ActionItem(FilterUtils.CLUSTER_BY_FACE, true, false, R.string.people,
105                 R.string.group_by_faces),
106         new ActionItem(FilterUtils.CLUSTER_BY_TAG, true, false, R.string.tags,
107                 R.string.group_by_tags)
108     };
109 
110     private class ClusterAdapter extends BaseAdapter {
111 
112         @Override
getCount()113         public int getCount() {
114             return sClusterItems.length;
115         }
116 
117         @Override
getItem(int position)118         public Object getItem(int position) {
119             return sClusterItems[position];
120         }
121 
122         @Override
getItemId(int position)123         public long getItemId(int position) {
124             return sClusterItems[position].action;
125         }
126 
127         @Override
getView(int position, View convertView, ViewGroup parent)128         public View getView(int position, View convertView, ViewGroup parent) {
129             if (convertView == null) {
130                 convertView = mInflater.inflate(R.layout.action_bar_text,
131                         parent, false);
132             }
133             TextView view = (TextView) convertView;
134             view.setText(sClusterItems[position].spinnerTitle);
135             return convertView;
136         }
137     }
138 
139     private class AlbumModeAdapter extends BaseAdapter {
140         @Override
getCount()141         public int getCount() {
142             return mAlbumModes.length;
143         }
144 
145         @Override
getItem(int position)146         public Object getItem(int position) {
147             return mAlbumModes[position];
148         }
149 
150         @Override
getItemId(int position)151         public long getItemId(int position) {
152             return position;
153         }
154 
155         @Override
getView(int position, View convertView, ViewGroup parent)156         public View getView(int position, View convertView, ViewGroup parent) {
157             if (convertView == null) {
158                 convertView = mInflater.inflate(R.layout.action_bar_two_line_text,
159                         parent, false);
160             }
161             TwoLineListItem view = (TwoLineListItem) convertView;
162             view.getText1().setText(mActionBar.getTitle());
163             view.getText2().setText((CharSequence) getItem(position));
164             return convertView;
165         }
166 
167         @Override
getDropDownView(int position, View convertView, ViewGroup parent)168         public View getDropDownView(int position, View convertView, ViewGroup parent) {
169             if (convertView == null) {
170                 convertView = mInflater.inflate(R.layout.action_bar_text,
171                         parent, false);
172             }
173             TextView view = (TextView) convertView;
174             view.setText((CharSequence) getItem(position));
175             return convertView;
176         }
177     }
178 
getClusterByTypeString(Context context, int type)179     public static String getClusterByTypeString(Context context, int type) {
180         for (ActionItem item : sClusterItems) {
181             if (item.action == type) {
182                 return context.getString(item.clusterBy);
183             }
184         }
185         return null;
186     }
187 
GalleryActionBar(AbstractGalleryActivity activity)188     public GalleryActionBar(AbstractGalleryActivity activity) {
189         mActionBar = activity.getActionBar();
190         mContext = activity.getAndroidContext();
191         mActivity = activity;
192         mInflater = ((Activity) mActivity).getLayoutInflater();
193         mCurrentIndex = 0;
194     }
195 
createDialogData()196     private void createDialogData() {
197         ArrayList<CharSequence> titles = new ArrayList<CharSequence>();
198         mActions = new ArrayList<Integer>();
199         for (ActionItem item : sClusterItems) {
200             if (item.enabled && item.visible) {
201                 titles.add(mContext.getString(item.dialogTitle));
202                 mActions.add(item.action);
203             }
204         }
205         mTitles = new CharSequence[titles.size()];
206         titles.toArray(mTitles);
207     }
208 
getHeight()209     public int getHeight() {
210         return mActionBar != null ? mActionBar.getHeight() : 0;
211     }
212 
setClusterItemEnabled(int id, boolean enabled)213     public void setClusterItemEnabled(int id, boolean enabled) {
214         for (ActionItem item : sClusterItems) {
215             if (item.action == id) {
216                 item.enabled = enabled;
217                 return;
218             }
219         }
220     }
221 
setClusterItemVisibility(int id, boolean visible)222     public void setClusterItemVisibility(int id, boolean visible) {
223         for (ActionItem item : sClusterItems) {
224             if (item.action == id) {
225                 item.visible = visible;
226                 return;
227             }
228         }
229     }
230 
getClusterTypeAction()231     public int getClusterTypeAction() {
232         return sClusterItems[mCurrentIndex].action;
233     }
234 
enableClusterMenu(int action, ClusterRunner runner)235     public void enableClusterMenu(int action, ClusterRunner runner) {
236         if (mActionBar != null) {
237             // Don't set cluster runner until action bar is ready.
238             mClusterRunner = null;
239             mActionBar.setListNavigationCallbacks(mAdapter, this);
240             mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
241             setSelectedAction(action);
242             mClusterRunner = runner;
243         }
244     }
245 
246     // The only use case not to hideMenu in this method is to ensure
247     // all elements disappear at the same time when exiting gallery.
248     // hideMenu should always be true in all other cases.
disableClusterMenu(boolean hideMenu)249     public void disableClusterMenu(boolean hideMenu) {
250         if (mActionBar != null) {
251             mClusterRunner = null;
252             if (hideMenu) {
253                 mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
254             }
255         }
256     }
257 
onConfigurationChanged()258     public void onConfigurationChanged() {
259         if (mActionBar != null && mAlbumModeListener != null) {
260             OnAlbumModeSelectedListener listener = mAlbumModeListener;
261             enableAlbumModeMenu(mLastAlbumModeSelected, listener);
262         }
263     }
264 
enableAlbumModeMenu(int selected, OnAlbumModeSelectedListener listener)265     public void enableAlbumModeMenu(int selected, OnAlbumModeSelectedListener listener) {
266         if (mActionBar != null) {
267             if (mAlbumModeAdapter == null) {
268                 // Initialize the album mode options if they haven't been already
269                 Resources res = mActivity.getResources();
270                 mAlbumModes = new CharSequence[] {
271                         res.getString(R.string.switch_photo_filmstrip),
272                         res.getString(R.string.switch_photo_grid)};
273                 mAlbumModeAdapter = new AlbumModeAdapter();
274             }
275             mAlbumModeListener = null;
276             mLastAlbumModeSelected = selected;
277             mActionBar.setListNavigationCallbacks(mAlbumModeAdapter, this);
278             mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
279             mActionBar.setSelectedNavigationItem(selected);
280             mAlbumModeListener = listener;
281         }
282     }
283 
disableAlbumModeMenu(boolean hideMenu)284     public void disableAlbumModeMenu(boolean hideMenu) {
285         if (mActionBar != null) {
286             mAlbumModeListener = null;
287             if (hideMenu) {
288                 mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
289             }
290         }
291     }
292 
showClusterDialog(final ClusterRunner clusterRunner)293     public void showClusterDialog(final ClusterRunner clusterRunner) {
294         createDialogData();
295         final ArrayList<Integer> actions = mActions;
296         new AlertDialog.Builder(mContext).setTitle(R.string.group_by).setItems(
297                 mTitles, new DialogInterface.OnClickListener() {
298             @Override
299             public void onClick(DialogInterface dialog, int which) {
300                 // Need to lock rendering when operations invoked by system UI (main thread) are
301                 // modifying slot data used in GL thread for rendering.
302                 mActivity.getGLRoot().lockRenderThread();
303                 try {
304                     clusterRunner.doCluster(actions.get(which).intValue());
305                 } finally {
306                     mActivity.getGLRoot().unlockRenderThread();
307                 }
308             }
309         }).create().show();
310     }
311 
312     @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
setHomeButtonEnabled(boolean enabled)313     private void setHomeButtonEnabled(boolean enabled) {
314         if (mActionBar != null) mActionBar.setHomeButtonEnabled(enabled);
315     }
316 
setDisplayOptions(boolean displayHomeAsUp, boolean showTitle)317     public void setDisplayOptions(boolean displayHomeAsUp, boolean showTitle) {
318         if (mActionBar == null) return;
319         int options = 0;
320         if (displayHomeAsUp) options |= ActionBar.DISPLAY_HOME_AS_UP;
321         if (showTitle) options |= ActionBar.DISPLAY_SHOW_TITLE;
322 
323         mActionBar.setDisplayOptions(options,
324                 ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_TITLE);
325         mActionBar.setHomeButtonEnabled(displayHomeAsUp);
326     }
327 
setTitle(String title)328     public void setTitle(String title) {
329         if (mActionBar != null) mActionBar.setTitle(title);
330     }
331 
setTitle(int titleId)332     public void setTitle(int titleId) {
333         if (mActionBar != null) {
334             mActionBar.setTitle(mContext.getString(titleId));
335         }
336     }
337 
setSubtitle(String title)338     public void setSubtitle(String title) {
339         if (mActionBar != null) mActionBar.setSubtitle(title);
340     }
341 
show()342     public void show() {
343         if (mActionBar != null) mActionBar.show();
344     }
345 
hide()346     public void hide() {
347         if (mActionBar != null) mActionBar.hide();
348     }
349 
addOnMenuVisibilityListener(OnMenuVisibilityListener listener)350     public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
351         if (mActionBar != null) mActionBar.addOnMenuVisibilityListener(listener);
352     }
353 
removeOnMenuVisibilityListener(OnMenuVisibilityListener listener)354     public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
355         if (mActionBar != null) mActionBar.removeOnMenuVisibilityListener(listener);
356     }
357 
setSelectedAction(int type)358     public boolean setSelectedAction(int type) {
359         if (mActionBar == null) return false;
360 
361         for (int i = 0, n = sClusterItems.length; i < n; i++) {
362             ActionItem item = sClusterItems[i];
363             if (item.action == type) {
364                 mActionBar.setSelectedNavigationItem(i);
365                 mCurrentIndex = i;
366                 return true;
367             }
368         }
369         return false;
370     }
371 
372     @Override
onNavigationItemSelected(int itemPosition, long itemId)373     public boolean onNavigationItemSelected(int itemPosition, long itemId) {
374         if (itemPosition != mCurrentIndex && mClusterRunner != null
375                 || mAlbumModeListener != null) {
376             // Need to lock rendering when operations invoked by system UI (main thread) are
377             // modifying slot data used in GL thread for rendering.
378             mActivity.getGLRoot().lockRenderThread();
379             try {
380                 if (mAlbumModeListener != null) {
381                     mAlbumModeListener.onAlbumModeSelected(itemPosition);
382                 } else {
383                     mClusterRunner.doCluster(sClusterItems[itemPosition].action);
384                 }
385             } finally {
386                 mActivity.getGLRoot().unlockRenderThread();
387             }
388         }
389         return false;
390     }
391 
392     private Menu mActionBarMenu;
393     private ShareActionProvider mSharePanoramaActionProvider;
394     private ShareActionProvider mShareActionProvider;
395     private Intent mSharePanoramaIntent;
396     private Intent mShareIntent;
397 
createActionBarMenu(int menuRes, Menu menu)398     public void createActionBarMenu(int menuRes, Menu menu) {
399         mActivity.getMenuInflater().inflate(menuRes, menu);
400         mActionBarMenu = menu;
401 
402         MenuItem item = menu.findItem(R.id.action_share_panorama);
403         if (item != null) {
404             mSharePanoramaActionProvider = (ShareActionProvider)
405                 item.getActionProvider();
406             mSharePanoramaActionProvider
407                 .setShareHistoryFileName("panorama_share_history.xml");
408             mSharePanoramaActionProvider.setShareIntent(mSharePanoramaIntent);
409         }
410 
411         item = menu.findItem(R.id.action_share);
412         if (item != null) {
413             mShareActionProvider = (ShareActionProvider)
414                 item.getActionProvider();
415             mShareActionProvider
416                 .setShareHistoryFileName("share_history.xml");
417             mShareActionProvider.setShareIntent(mShareIntent);
418         }
419     }
420 
getMenu()421     public Menu getMenu() {
422         return mActionBarMenu;
423     }
424 
setShareIntents(Intent sharePanoramaIntent, Intent shareIntent, ShareActionProvider.OnShareTargetSelectedListener onShareListener)425     public void setShareIntents(Intent sharePanoramaIntent, Intent shareIntent,
426         ShareActionProvider.OnShareTargetSelectedListener onShareListener) {
427         mSharePanoramaIntent = sharePanoramaIntent;
428         if (mSharePanoramaActionProvider != null) {
429             mSharePanoramaActionProvider.setShareIntent(sharePanoramaIntent);
430         }
431         mShareIntent = shareIntent;
432         if (mShareActionProvider != null) {
433             mShareActionProvider.setShareIntent(shareIntent);
434             mShareActionProvider.setOnShareTargetSelectedListener(
435                 onShareListener);
436         }
437     }
438 }
439