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 androidx.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
onCreate(Bundle savedInstanceState)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
onSaveInstanceState(Bundle outState)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
onConfigurationChanged(Configuration config)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
onCreateOptionsMenu(Menu menu)105     public boolean onCreateOptionsMenu(Menu menu) {
106         super.onCreateOptionsMenu(menu);
107         return getStateManager().createOptionsMenu(menu);
108     }
109 
110     @Override
getAndroidContext()111     public Context getAndroidContext() {
112         return this;
113     }
114 
115     @Override
getDataManager()116     public DataManager getDataManager() {
117         return ((GalleryApp) getApplication()).getDataManager();
118     }
119 
120     @Override
getThreadPool()121     public ThreadPool getThreadPool() {
122         return ((GalleryApp) getApplication()).getThreadPool();
123     }
124 
getStateManager()125     public synchronized StateManager getStateManager() {
126         if (mStateManager == null) {
127             mStateManager = new StateManager(this);
128         }
129         return mStateManager;
130     }
131 
getGLRoot()132     public GLRoot getGLRoot() {
133         return mGLRootView;
134     }
135 
getOrientationManager()136     public OrientationManager getOrientationManager() {
137         return mOrientationManager;
138     }
139 
140     @Override
setContentView(int resId)141     public void setContentView(int resId) {
142         super.setContentView(resId);
143         mGLRootView = (GLRootView) findViewById(R.id.gl_root_view);
144     }
145 
onStorageReady()146     protected void onStorageReady() {
147         if (mAlertDialog != null) {
148             mAlertDialog.dismiss();
149             mAlertDialog = null;
150             unregisterReceiver(mMountReceiver);
151         }
152     }
153 
154     @Override
onStart()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)
setAlertDialogIconAttribute( AlertDialog.Builder builder)187     private static void setAlertDialogIconAttribute(
188             AlertDialog.Builder builder) {
189         builder.setIconAttribute(android.R.attr.alertDialogIcon);
190     }
191 
192     @Override
onStop()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
onResume()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
onPause()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
onDestroy()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
onActivityResult(int requestCode, int resultCode, Intent data)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
onBackPressed()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 
getGalleryActionBar()268     public GalleryActionBar getGalleryActionBar() {
269         if (mActionBar == null) {
270             mActionBar = new GalleryActionBar(this);
271         }
272         return mActionBar;
273     }
274 
275     @Override
onOptionsItemSelected(MenuItem item)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 
disableToggleStatusBar()286     protected void disableToggleStatusBar() {
287         mDisableToggleStatusBar = true;
288     }
289 
290     // Shows status bar in portrait view, hide in landscape view
toggleStatusBarByOrientation()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 
getTransitionStore()302     public TransitionStore getTransitionStore() {
303         return mTransitionStore;
304     }
305 
getPanoramaViewHelper()306     public PanoramaViewHelper getPanoramaViewHelper() {
307         return mPanoramaViewHelper;
308     }
309 
isFullscreen()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 
doBindBatchService()329     private void doBindBatchService() {
330         bindService(new Intent(this, BatchService.class), mBatchServiceConnection, Context.BIND_AUTO_CREATE);
331         mBatchServiceIsBound = true;
332     }
333 
doUnbindBatchService()334     private void doUnbindBatchService() {
335         if (mBatchServiceIsBound) {
336             // Detach our existing connection.
337             unbindService(mBatchServiceConnection);
338             mBatchServiceIsBound = false;
339         }
340     }
341 
getBatchServiceThreadPoolIfAvailable()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 
printSelectedImage(Uri uri)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