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