1 /* 2 * Copyright (C) 2010 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.Activity; 21 import android.app.AlertDialog; 22 import android.content.BroadcastReceiver; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.content.DialogInterface; 26 import android.content.DialogInterface.OnCancelListener; 27 import android.content.DialogInterface.OnClickListener; 28 import android.content.Intent; 29 import android.content.IntentFilter; 30 import android.content.ServiceConnection; 31 import android.content.res.Configuration; 32 import android.os.Bundle; 33 import android.os.IBinder; 34 import android.view.Menu; 35 import android.view.MenuItem; 36 import android.view.Window; 37 import android.view.WindowManager; 38 39 import com.android.gallery3d.R; 40 import com.android.gallery3d.common.ApiHelper; 41 import com.android.gallery3d.data.DataManager; 42 import com.android.gallery3d.data.MediaItem; 43 import com.android.gallery3d.ui.GLRoot; 44 import com.android.gallery3d.ui.GLRootView; 45 import com.android.gallery3d.util.LightCycleHelper.PanoramaViewHelper; 46 import com.android.gallery3d.util.ThreadPool; 47 import com.android.photos.data.GalleryBitmapPool; 48 49 public class AbstractGalleryActivity extends Activity implements GalleryContext { 50 @SuppressWarnings("unused") 51 private static final String TAG = "AbstractGalleryActivity"; 52 private GLRootView mGLRootView; 53 private StateManager mStateManager; 54 private GalleryActionBar mActionBar; 55 private OrientationManager mOrientationManager; 56 private TransitionStore mTransitionStore = new TransitionStore(); 57 private boolean mDisableToggleStatusBar; 58 private PanoramaViewHelper mPanoramaViewHelper; 59 60 private AlertDialog mAlertDialog = null; 61 private BroadcastReceiver mMountReceiver = new BroadcastReceiver() { 62 @Override 63 public void onReceive(Context context, Intent intent) { 64 if (getExternalCacheDir() != null) onStorageReady(); 65 } 66 }; 67 private IntentFilter mMountFilter = new IntentFilter(Intent.ACTION_MEDIA_MOUNTED); 68 69 @Override 70 protected void onCreate(Bundle savedInstanceState) { 71 super.onCreate(savedInstanceState); 72 mOrientationManager = new OrientationManager(this); 73 toggleStatusBarByOrientation(); 74 getWindow().setBackgroundDrawable(null); 75 mPanoramaViewHelper = new PanoramaViewHelper(this); 76 mPanoramaViewHelper.onCreate(); 77 doBindBatchService(); 78 } 79 80 @Override 81 protected void onSaveInstanceState(Bundle outState) { 82 mGLRootView.lockRenderThread(); 83 try { 84 super.onSaveInstanceState(outState); 85 getStateManager().saveState(outState); 86 } finally { 87 mGLRootView.unlockRenderThread(); 88 } 89 } 90 91 @Override 92 public void onConfigurationChanged(Configuration config) { 93 super.onConfigurationChanged(config); 94 mStateManager.onConfigurationChange(config); 95 getGalleryActionBar().onConfigurationChanged(); 96 invalidateOptionsMenu(); 97 toggleStatusBarByOrientation(); 98 } 99 100 @Override 101 public boolean onCreateOptionsMenu(Menu menu) { 102 super.onCreateOptionsMenu(menu); 103 return getStateManager().createOptionsMenu(menu); 104 } 105 106 @Override 107 public Context getAndroidContext() { 108 return this; 109 } 110 111 @Override 112 public DataManager getDataManager() { 113 return ((GalleryApp) getApplication()).getDataManager(); 114 } 115 116 @Override 117 public ThreadPool getThreadPool() { 118 return ((GalleryApp) getApplication()).getThreadPool(); 119 } 120 121 public synchronized StateManager getStateManager() { 122 if (mStateManager == null) { 123 mStateManager = new StateManager(this); 124 } 125 return mStateManager; 126 } 127 128 public GLRoot getGLRoot() { 129 return mGLRootView; 130 } 131 132 public OrientationManager getOrientationManager() { 133 return mOrientationManager; 134 } 135 136 @Override 137 public void setContentView(int resId) { 138 super.setContentView(resId); 139 mGLRootView = (GLRootView) findViewById(R.id.gl_root_view); 140 } 141 142 protected void onStorageReady() { 143 if (mAlertDialog != null) { 144 mAlertDialog.dismiss(); 145 mAlertDialog = null; 146 unregisterReceiver(mMountReceiver); 147 } 148 } 149 150 @Override 151 protected void onStart() { 152 super.onStart(); 153 if (getExternalCacheDir() == null) { 154 OnCancelListener onCancel = new OnCancelListener() { 155 @Override 156 public void onCancel(DialogInterface dialog) { 157 finish(); 158 } 159 }; 160 OnClickListener onClick = new OnClickListener() { 161 @Override 162 public void onClick(DialogInterface dialog, int which) { 163 dialog.cancel(); 164 } 165 }; 166 AlertDialog.Builder builder = new AlertDialog.Builder(this) 167 .setTitle(R.string.no_external_storage_title) 168 .setMessage(R.string.no_external_storage) 169 .setNegativeButton(android.R.string.cancel, onClick) 170 .setOnCancelListener(onCancel); 171 if (ApiHelper.HAS_SET_ICON_ATTRIBUTE) { 172 setAlertDialogIconAttribute(builder); 173 } else { 174 builder.setIcon(android.R.drawable.ic_dialog_alert); 175 } 176 mAlertDialog = builder.show(); 177 registerReceiver(mMountReceiver, mMountFilter); 178 } 179 mPanoramaViewHelper.onStart(); 180 } 181 182 @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB) 183 private static void setAlertDialogIconAttribute( 184 AlertDialog.Builder builder) { 185 builder.setIconAttribute(android.R.attr.alertDialogIcon); 186 } 187 188 @Override 189 protected void onStop() { 190 super.onStop(); 191 if (mAlertDialog != null) { 192 unregisterReceiver(mMountReceiver); 193 mAlertDialog.dismiss(); 194 mAlertDialog = null; 195 } 196 mPanoramaViewHelper.onStop(); 197 } 198 199 @Override 200 protected void onResume() { 201 super.onResume(); 202 mGLRootView.lockRenderThread(); 203 try { 204 getStateManager().resume(); 205 getDataManager().resume(); 206 } finally { 207 mGLRootView.unlockRenderThread(); 208 } 209 mGLRootView.onResume(); 210 mOrientationManager.resume(); 211 } 212 213 @Override 214 protected void onPause() { 215 super.onPause(); 216 mOrientationManager.pause(); 217 mGLRootView.onPause(); 218 mGLRootView.lockRenderThread(); 219 try { 220 getStateManager().pause(); 221 getDataManager().pause(); 222 } finally { 223 mGLRootView.unlockRenderThread(); 224 } 225 GalleryBitmapPool.getInstance().clear(); 226 MediaItem.getBytesBufferPool().clear(); 227 } 228 229 @Override 230 protected void onDestroy() { 231 super.onDestroy(); 232 mGLRootView.lockRenderThread(); 233 try { 234 getStateManager().destroy(); 235 } finally { 236 mGLRootView.unlockRenderThread(); 237 } 238 doUnbindBatchService(); 239 } 240 241 @Override 242 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 243 mGLRootView.lockRenderThread(); 244 try { 245 getStateManager().notifyActivityResult( 246 requestCode, resultCode, data); 247 } finally { 248 mGLRootView.unlockRenderThread(); 249 } 250 } 251 252 @Override 253 public void onBackPressed() { 254 // send the back event to the top sub-state 255 GLRoot root = getGLRoot(); 256 root.lockRenderThread(); 257 try { 258 getStateManager().onBackPressed(); 259 } finally { 260 root.unlockRenderThread(); 261 } 262 } 263 264 public GalleryActionBar getGalleryActionBar() { 265 if (mActionBar == null) { 266 mActionBar = new GalleryActionBar(this); 267 } 268 return mActionBar; 269 } 270 271 @Override 272 public boolean onOptionsItemSelected(MenuItem item) { 273 GLRoot root = getGLRoot(); 274 root.lockRenderThread(); 275 try { 276 return getStateManager().itemSelected(item); 277 } finally { 278 root.unlockRenderThread(); 279 } 280 } 281 282 protected void disableToggleStatusBar() { 283 mDisableToggleStatusBar = true; 284 } 285 286 // Shows status bar in portrait view, hide in landscape view 287 private void toggleStatusBarByOrientation() { 288 if (mDisableToggleStatusBar) return; 289 290 Window win = getWindow(); 291 if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { 292 win.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); 293 } else { 294 win.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); 295 } 296 } 297 298 public TransitionStore getTransitionStore() { 299 return mTransitionStore; 300 } 301 302 public PanoramaViewHelper getPanoramaViewHelper() { 303 return mPanoramaViewHelper; 304 } 305 306 protected boolean isFullscreen() { 307 return (getWindow().getAttributes().flags 308 & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0; 309 } 310 311 private BatchService mBatchService; 312 private boolean mBatchServiceIsBound = false; 313 private ServiceConnection mBatchServiceConnection = new ServiceConnection() { 314 public void onServiceConnected(ComponentName className, IBinder service) { 315 mBatchService = ((BatchService.LocalBinder)service).getService(); 316 } 317 318 public void onServiceDisconnected(ComponentName className) { 319 mBatchService = null; 320 } 321 }; 322 323 private void doBindBatchService() { 324 bindService(new Intent(this, BatchService.class), mBatchServiceConnection, Context.BIND_AUTO_CREATE); 325 mBatchServiceIsBound = true; 326 } 327 328 private void doUnbindBatchService() { 329 if (mBatchServiceIsBound) { 330 // Detach our existing connection. 331 unbindService(mBatchServiceConnection); 332 mBatchServiceIsBound = false; 333 } 334 } 335 336 public ThreadPool getBatchServiceThreadPoolIfAvailable() { 337 if (mBatchServiceIsBound && mBatchService != null) { 338 return mBatchService.getThreadPool(); 339 } else { 340 throw new RuntimeException("Batch service unavailable"); 341 } 342 } 343 } 344