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 { 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