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.gallery3d.app;
18
19import android.annotation.TargetApi;
20import android.app.ActionBar;
21import android.app.ActionBar.OnMenuVisibilityListener;
22import android.app.ActionBar.OnNavigationListener;
23import android.app.Activity;
24import android.app.AlertDialog;
25import android.content.Context;
26import android.content.DialogInterface;
27import android.content.Intent;
28import android.content.res.Resources;
29import android.view.LayoutInflater;
30import android.view.Menu;
31import android.view.MenuItem;
32import android.view.View;
33import android.view.ViewGroup;
34import android.widget.BaseAdapter;
35import android.widget.ShareActionProvider;
36import android.widget.TextView;
37import android.widget.TwoLineListItem;
38
39import com.android.gallery3d.R;
40import com.android.gallery3d.common.ApiHelper;
41
42import java.util.ArrayList;
43
44public 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 {
66        public void doCluster(int id);
67    }
68
69    public interface OnAlbumModeSelectedListener {
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
81        public ActionItem(int action, boolean applied, boolean enabled, int title,
82                int clusterBy) {
83            this(action, applied, enabled, title, title, clusterBy);
84        }
85
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
113        public int getCount() {
114            return sClusterItems.length;
115        }
116
117        @Override
118        public Object getItem(int position) {
119            return sClusterItems[position];
120        }
121
122        @Override
123        public long getItemId(int position) {
124            return sClusterItems[position].action;
125        }
126
127        @Override
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
141        public int getCount() {
142            return mAlbumModes.length;
143        }
144
145        @Override
146        public Object getItem(int position) {
147            return mAlbumModes[position];
148        }
149
150        @Override
151        public long getItemId(int position) {
152            return position;
153        }
154
155        @Override
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
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
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
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
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
209    public int getHeight() {
210        return mActionBar != null ? mActionBar.getHeight() : 0;
211    }
212
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
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
231    public int getClusterTypeAction() {
232        return sClusterItems[mCurrentIndex].action;
233    }
234
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.
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
258    public void onConfigurationChanged() {
259        if (mActionBar != null && mAlbumModeListener != null) {
260            OnAlbumModeSelectedListener listener = mAlbumModeListener;
261            enableAlbumModeMenu(mLastAlbumModeSelected, listener);
262        }
263    }
264
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
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
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)
313    private void setHomeButtonEnabled(boolean enabled) {
314        if (mActionBar != null) mActionBar.setHomeButtonEnabled(enabled);
315    }
316
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
328    public void setTitle(String title) {
329        if (mActionBar != null) mActionBar.setTitle(title);
330    }
331
332    public void setTitle(int titleId) {
333        if (mActionBar != null) {
334            mActionBar.setTitle(mContext.getString(titleId));
335        }
336    }
337
338    public void setSubtitle(String title) {
339        if (mActionBar != null) mActionBar.setSubtitle(title);
340    }
341
342    public void show() {
343        if (mActionBar != null) mActionBar.show();
344    }
345
346    public void hide() {
347        if (mActionBar != null) mActionBar.hide();
348    }
349
350    public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
351        if (mActionBar != null) mActionBar.addOnMenuVisibilityListener(listener);
352    }
353
354    public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
355        if (mActionBar != null) mActionBar.removeOnMenuVisibilityListener(listener);
356    }
357
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
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
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
421    public Menu getMenu() {
422        return mActionBarMenu;
423    }
424
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