diff options
| author | John Reck <jreck@google.com> | 2013-02-15 14:32:08 -0800 |
|---|---|---|
| committer | John Reck <jreck@google.com> | 2013-02-22 15:09:35 -0800 |
| commit | 5f30b98d6ac98c6aa863d48f47e9b8e2b77a1820 (patch) | |
| tree | b2494b57af472736cdc3805771177a9772f9c3dd | |
| parent | e77198985fc22ed2cf24f5d497309742165bc69f (diff) | |
| download | android_packages_apps_Gallery2-5f30b98d6ac98c6aa863d48f47e9b8e2b77a1820.tar.gz android_packages_apps_Gallery2-5f30b98d6ac98c6aa863d48f47e9b8e2b77a1820.tar.bz2 android_packages_apps_Gallery2-5f30b98d6ac98c6aa863d48f47e9b8e2b77a1820.zip | |
Start of photos
Change-Id: Id53dd96d8873e0fe6c2685e07cd7bdc0cde7ea75
| -rw-r--r-- | AndroidManifest.xml | 18 | ||||
| -rw-r--r-- | res/layout/photo_set.xml | 22 | ||||
| -rw-r--r-- | res/menu/gallery.xml | 23 | ||||
| -rw-r--r-- | res/values-v14/styles.xml | 2 | ||||
| -rw-r--r-- | res/values/strings.xml | 8 | ||||
| -rw-r--r-- | src/com/android/gallery3d/data/DataManager.java | 7 | ||||
| -rw-r--r-- | src/com/android/photos/AlbumSetFragment.java | 24 | ||||
| -rw-r--r-- | src/com/android/photos/GalleryActivity.java | 125 | ||||
| -rw-r--r-- | src/com/android/photos/PhotoFragment.java | 25 | ||||
| -rw-r--r-- | src/com/android/photos/PhotoSetFragment.java | 82 | ||||
| -rw-r--r-- | src/com/android/photos/data/MediaSetLoader.java | 89 | ||||
| -rw-r--r-- | src/com/android/photos/data/PhotoSetLoader.java | 70 |
12 files changed, 481 insertions, 14 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 508aefe9f..3cd30cbac 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -88,8 +88,11 @@ </intent-filter> </activity> - <activity android:name="com.android.gallery3d.app.Gallery" android:label="@string/app_name" - android:configChanges="keyboardHidden|orientation|screenSize"> + <activity android:name="com.android.photos.GalleryActivity" + android:label="@string/app_name" + android:configChanges="keyboardHidden|orientation|screenSize" + android:theme="@style/Theme.Photos.Gallery" + android:uiOptions="splitActionBarWhenNarrow"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.DEFAULT" /> @@ -164,17 +167,6 @@ </intent-filter> </activity> - <!-- we add this activity-alias for shortcut backward compatibility --> - <!-- Note: The alias must put after the target activity --> - <activity-alias android:name="com.cooliris.media.Gallery" - android:targetActivity="com.android.gallery3d.app.Gallery" - android:configChanges="keyboardHidden|orientation|screenSize" - android:label="@string/app_name"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - </intent-filter> - </activity-alias> - <!-- This activity receives USB_DEVICE_ATTACHED intents and allows importing media from attached MTP devices, like cameras and camera phones --> <activity android:launchMode="singleInstance" diff --git a/res/layout/photo_set.xml b/res/layout/photo_set.xml new file mode 100644 index 000000000..2bb97bbac --- /dev/null +++ b/res/layout/photo_set.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingLeft="8dp" + android:paddingRight="8dp" > + + <ListView + android:id="@id/android:list" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_weight="1" + android:drawSelectorOnTop="true" /> + + <TextView + android:id="@id/android:empty" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:text="@string/empty_album" /> + +</FrameLayout>
\ No newline at end of file diff --git a/res/menu/gallery.xml b/res/menu/gallery.xml new file mode 100644 index 000000000..dc36787c8 --- /dev/null +++ b/res/menu/gallery.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android" > + <item + android:id="@+id/menu_camera" + android:icon="@android:drawable/ic_menu_camera" + android:showAsAction="ifRoom" + android:title="@string/menu_camera"/> + <item + android:id="@+id/menu_search" + android:icon="@android:drawable/ic_menu_search" + android:showAsAction="ifRoom" + android:title="@string/menu_search"/> + <item + android:id="@+id/menu_settings" + android:icon="@android:drawable/ic_menu_preferences" + android:showAsAction="never" + android:title="@string/settings"/> + <item + android:id="@+id/menu_help" + android:icon="@android:drawable/ic_menu_help" + android:showAsAction="never" + android:title="@string/help"/> +</menu>
\ No newline at end of file diff --git a/res/values-v14/styles.xml b/res/values-v14/styles.xml index 18f3440f3..18610cbfc 100644 --- a/res/values-v14/styles.xml +++ b/res/values-v14/styles.xml @@ -22,4 +22,6 @@ <style name="ActionBarTwoLineItem"> <item name="android:background">?android:attr/activatedBackgroundIndicator</item> </style> + <style name="Theme.Photos.Gallery" parent="android:Theme.Holo.Light"> + </style> </resources> diff --git a/res/values/strings.xml b/res/values/strings.xml index fae3466cc..263b8b15b 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1002,4 +1002,12 @@ CHAR LIMIT = NONE] --> <!-- Positive answer for first run dialog asking if the user wants to remember photo locations [CHAR LIMIT = 20] --> <string name="remember_location_yes">Yes</string> + <!-- Menu item to launch the camera app [CHAR LIMIT=25] --> + <string name="menu_camera">Camera</string> + <!-- Menu item to search for photos [CHAR LIMIT=25] --> + <string name="menu_search">Search</string> + <!-- Title for the all photos tab [CHAR LIMIT=25] --> + <string name="tab_photos">Photos</string> + <!-- Title for the albums tab [CHAR LIMIT=25] --> + <string name="tab_albums">Albums</string> </resources> diff --git a/src/com/android/gallery3d/data/DataManager.java b/src/com/android/gallery3d/data/DataManager.java index 8fcf4008a..38865e9f1 100644 --- a/src/com/android/gallery3d/data/DataManager.java +++ b/src/com/android/gallery3d/data/DataManager.java @@ -16,13 +16,13 @@ package com.android.gallery3d.data; +import android.content.Context; import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; import com.android.gallery3d.app.GalleryApp; import com.android.gallery3d.app.StitchingChangeListener; -import com.android.gallery3d.common.ApiHelper; import com.android.gallery3d.common.Utils; import com.android.gallery3d.data.MediaObject.PanoramaSupportCallback; import com.android.gallery3d.data.MediaSet.ItemConsumer; @@ -65,6 +65,11 @@ public class DataManager implements StitchingChangeListener { // to prevent concurrency issue. public static final Object LOCK = new Object(); + public static DataManager from(Context context) { + GalleryApp app = (GalleryApp) context.getApplicationContext(); + return app.getDataManager(); + } + private static final String TAG = "DataManager"; // This is the path for the media set seen by the user at top level. diff --git a/src/com/android/photos/AlbumSetFragment.java b/src/com/android/photos/AlbumSetFragment.java new file mode 100644 index 000000000..2d348c248 --- /dev/null +++ b/src/com/android/photos/AlbumSetFragment.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.photos; + +import android.app.Fragment; + + +public class AlbumSetFragment extends Fragment { + +} diff --git a/src/com/android/photos/GalleryActivity.java b/src/com/android/photos/GalleryActivity.java new file mode 100644 index 000000000..46b5140fb --- /dev/null +++ b/src/com/android/photos/GalleryActivity.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.photos; + +import android.app.ActionBar; +import android.app.ActionBar.Tab; +import android.app.Activity; +import android.app.Fragment; +import android.app.FragmentTransaction; +import android.content.Intent; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; + +import com.android.camera.CameraActivity; +import com.android.gallery3d.R; + +public class GalleryActivity extends Activity { + + private final String FTAG_PHOTOSET = "PhotoSet"; + private final String FTAG_ALBUMSET = "AlbumSet"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setupActionBar(); + } + + private void setupActionBar() { + ActionBar ab = getActionBar(); + ab.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); + ab.setDisplayShowHomeEnabled(false); + ab.setDisplayShowTitleEnabled(false); + Tab tab = ab.newTab(); + tab.setText(R.string.tab_photos); + tab.setTabListener(new TabListener<PhotoSetFragment>(this, + FTAG_PHOTOSET, PhotoSetFragment.class)); + ab.addTab(tab, true); + tab = ab.newTab(); + tab.setText(R.string.tab_albums); + tab.setTabListener(new TabListener<AlbumSetFragment>(this, + FTAG_ALBUMSET, AlbumSetFragment.class)); + ab.addTab(tab); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.gallery, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.menu_camera: + Intent intent = new Intent(this, CameraActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + private static class TabListener<T extends Fragment> implements ActionBar.TabListener { + private Fragment mFragment; + private final Activity mActivity; + private final String mTag; + private final Class<T> mClass; + + /** Constructor used each time a new tab is created. + * @param activity The host Activity, used to instantiate the fragment + * @param tag The identifier tag for the fragment + * @param clz The fragment's Class, used to instantiate the fragment + */ + public TabListener(Activity activity, String tag, Class<T> clz) { + mActivity = activity; + mTag = tag; + mClass = clz; + } + + /* The following are each of the ActionBar.TabListener callbacks */ + + @Override + public void onTabSelected(Tab tab, FragmentTransaction ft) { + // Check if the fragment is already initialized + if (mFragment == null) { + // If not, instantiate and add it to the activity + mFragment = Fragment.instantiate(mActivity, mClass.getName()); + ft.add(android.R.id.content, mFragment, mTag); + } else { + // If it exists, simply attach it in order to show it + ft.attach(mFragment); + } + } + + @Override + public void onTabUnselected(Tab tab, FragmentTransaction ft) { + if (mFragment != null) { + // Detach the fragment, because another one is being attached + ft.detach(mFragment); + } + } + + @Override + public void onTabReselected(Tab tab, FragmentTransaction ft) { + // User selected the already selected tab. Usually do nothing. + } + } +} diff --git a/src/com/android/photos/PhotoFragment.java b/src/com/android/photos/PhotoFragment.java new file mode 100644 index 000000000..3be6313f2 --- /dev/null +++ b/src/com/android/photos/PhotoFragment.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package com.android.photos; + +import android.app.Fragment; + + +public class PhotoFragment extends Fragment { + +} diff --git a/src/com/android/photos/PhotoSetFragment.java b/src/com/android/photos/PhotoSetFragment.java new file mode 100644 index 000000000..e9bfce56f --- /dev/null +++ b/src/com/android/photos/PhotoSetFragment.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.photos; + +import android.app.Fragment; +import android.app.LoaderManager.LoaderCallbacks; +import android.content.Loader; +import android.database.Cursor; +import android.os.Bundle; +import android.provider.MediaStore.Files.FileColumns; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CursorAdapter; +import android.widget.ListView; +import android.widget.SimpleCursorAdapter; + +import com.android.gallery3d.R; +import com.android.photos.data.PhotoSetLoader; + + +public class PhotoSetFragment extends Fragment implements LoaderCallbacks<Cursor> { + + private static final int LOADER_PHOTOSET = 1; + + private ListView mPhotoSetView; + private View mEmptyView; + private CursorAdapter mAdapter; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View root = inflater.inflate(R.layout.photo_set, container, false); + mPhotoSetView = (ListView) root.findViewById(android.R.id.list); + mEmptyView = root.findViewById(android.R.id.empty); + mEmptyView.setVisibility(View.GONE); + mAdapter = new SimpleCursorAdapter(getActivity(), + android.R.layout.simple_list_item_1, null, + new String[] { FileColumns.DATA }, + new int[] { android.R.id.text1 }, 0); + mPhotoSetView.setAdapter(mAdapter); + getLoaderManager().initLoader(LOADER_PHOTOSET, null, this); + updateEmptyStatus(); + return root; + } + + private void updateEmptyStatus() { + boolean empty = (mAdapter == null || mAdapter.getCount() == 0); + mPhotoSetView.setVisibility(empty ? View.GONE : View.VISIBLE); + mEmptyView.setVisibility(empty ? View.VISIBLE : View.GONE); + } + + @Override + public Loader<Cursor> onCreateLoader(int id, Bundle args) { + return new PhotoSetLoader(getActivity()); + } + + @Override + public void onLoadFinished(Loader<Cursor> loader, + Cursor data) { + mAdapter.swapCursor(data); + updateEmptyStatus(); + } + + @Override + public void onLoaderReset(Loader<Cursor> loader) { + } +} diff --git a/src/com/android/photos/data/MediaSetLoader.java b/src/com/android/photos/data/MediaSetLoader.java new file mode 100644 index 000000000..4afb7d922 --- /dev/null +++ b/src/com/android/photos/data/MediaSetLoader.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.photos.data; + +import android.content.AsyncTaskLoader; +import android.content.Context; + +import com.android.gallery3d.data.ContentListener; +import com.android.gallery3d.data.DataManager; +import com.android.gallery3d.data.MediaSet; +import com.android.gallery3d.data.MediaSet.SyncListener; +import com.android.gallery3d.util.Future; + +/** + * Proof of concept, don't use + */ +public class MediaSetLoader extends AsyncTaskLoader<MediaSet> { + + private static final SyncListener sNullListener = new SyncListener() { + @Override + public void onSyncDone(MediaSet mediaSet, int resultCode) { + } + }; + + private MediaSet mMediaSet; + private Future<Integer> mSyncTask = null; + private ContentListener mObserver = new ContentListener() { + @Override + public void onContentDirty() { + onContentChanged(); + } + }; + + public MediaSetLoader(Context context, String path) { + super(context); + mMediaSet = DataManager.from(getContext()).getMediaSet(path); + } + + @Override + protected void onStartLoading() { + super.onStartLoading(); + mMediaSet.addContentListener(mObserver); + mSyncTask = mMediaSet.requestSync(sNullListener); + forceLoad(); + } + + @Override + protected boolean onCancelLoad() { + if (mSyncTask != null) { + mSyncTask.cancel(); + mSyncTask = null; + } + return super.onCancelLoad(); + } + + @Override + protected void onStopLoading() { + super.onStopLoading(); + cancelLoad(); + mMediaSet.removeContentListener(mObserver); + } + + @Override + protected void onReset() { + super.onReset(); + onStopLoading(); + } + + @Override + public MediaSet loadInBackground() { + mMediaSet.loadIfDirty(); + return mMediaSet; + } + +} diff --git a/src/com/android/photos/data/PhotoSetLoader.java b/src/com/android/photos/data/PhotoSetLoader.java new file mode 100644 index 000000000..8c511a525 --- /dev/null +++ b/src/com/android/photos/data/PhotoSetLoader.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.photos.data; + +import android.content.Context; +import android.content.CursorLoader; +import android.database.ContentObserver; +import android.net.Uri; +import android.provider.MediaStore; +import android.provider.MediaStore.Files; +import android.provider.MediaStore.Files.FileColumns; + +public class PhotoSetLoader extends CursorLoader { + + private static final Uri CONTENT_URI = Files.getContentUri("external"); + private static final String[] PROJECTION = new String[] { + FileColumns._ID, + FileColumns.DATA, + FileColumns.WIDTH, + FileColumns.HEIGHT, + FileColumns.DATE_ADDED, + FileColumns.MEDIA_TYPE, + }; + private static final String SORT_ORDER = FileColumns.DATE_ADDED + " DESC"; + private static final String SELECTION = + FileColumns.MEDIA_TYPE + " == " + FileColumns.MEDIA_TYPE_IMAGE + + " OR " + + FileColumns.MEDIA_TYPE + " == " + FileColumns.MEDIA_TYPE_VIDEO; + + public static final int INDEX_ID = 0; + public static final int INDEX_DATA = 1; + public static final int INDEX_WIDTH = 2; + public static final int INDEX_HEIGHT = 3; + public static final int INDEX_DATE_ADDED = 4; + public static final int INDEX_MEDIA_TYPE = 5; + + private static final Uri GLOBAL_CONTENT_URI = Uri.parse("content://" + MediaStore.AUTHORITY + "/external/"); + private final ContentObserver mGlobalObserver = new ForceLoadContentObserver(); + + public PhotoSetLoader(Context context) { + super(context, CONTENT_URI, PROJECTION, SELECTION, null, SORT_ORDER); + } + + @Override + protected void onStartLoading() { + super.onStartLoading(); + getContext().getContentResolver().registerContentObserver(GLOBAL_CONTENT_URI, + true, mGlobalObserver); + } + + @Override + protected void onReset() { + super.onReset(); + getContext().getContentResolver().unregisterContentObserver(mGlobalObserver); + } +} |
