development
Revisão | f4f345d0b75c96d92f15a9aba8d58d5d4bec27c6 (tree) |
---|---|
Hora | 2011-02-08 10:03:19 |
Autor | Roman Nurik <romannurik@goog...> |
Commiter | Roman Nurik |
Major update to HoneycombGallery
* Add action bar and icon theming
* Add contextual action bar and photo sharing
* Add notifications (with large icons too)
* Add fullscreening (lights-out mode)
* Add a picture frame
Change-Id: I07a1da435d5adc7bc76c7ac2cc087ff2efd74156
@@ -162,7 +162,7 @@ development/samples/ContactManager samples/${PLATFORM_NAME}/ContactMan | ||
162 | 162 | development/samples/CrossCompatibility samples/${PLATFORM_NAME}/CrossCompatibility |
163 | 163 | development/samples/CubeLiveWallpaper samples/${PLATFORM_NAME}/CubeLiveWallpaper |
164 | 164 | development/samples/Home samples/${PLATFORM_NAME}/Home |
165 | -development/samples/Honeycomb-Gallery samples/${PLATFORM_NAME}/Honeycomb-Gallery | |
165 | +development/samples/HoneycombGallery samples/${PLATFORM_NAME}/HoneycombGallery | |
166 | 166 | development/samples/JetBoy samples/${PLATFORM_NAME}/JetBoy |
167 | 167 | development/samples/LunarLander samples/${PLATFORM_NAME}/LunarLander |
168 | 168 | development/samples/MultiResolution samples/${PLATFORM_NAME}/MultiResolution |
@@ -6,7 +6,7 @@ LOCAL_MODULE_TAGS := samples | ||
6 | 6 | # Only compile source java files in this apk. |
7 | 7 | LOCAL_SRC_FILES := $(call all-java-files-under, src) |
8 | 8 | |
9 | -LOCAL_PACKAGE_NAME := Honeycomb-Gallery | |
9 | +LOCAL_PACKAGE_NAME := HoneycombGallery | |
10 | 10 | |
11 | 11 | LOCAL_SDK_VERSION := current |
12 | 12 |
@@ -19,20 +19,28 @@ | ||
19 | 19 | android:versionName="1.0"> |
20 | 20 | |
21 | 21 | <uses-sdk android:minSdkVersion="11" /> |
22 | + | |
22 | 23 | <uses-permission android:name="android.permission.CAMERA" /> |
24 | + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> | |
23 | 25 | |
24 | 26 | <application android:label="@string/app_name" |
25 | 27 | android:icon="@drawable/icon" |
26 | 28 | android:logo="@drawable/logo" |
27 | - android:theme="@android:style/Theme.Holo.Light" | |
29 | + android:theme="@style/AppTheme.Light" | |
28 | 30 | android:hardwareAccelerated="true" |
29 | 31 | android:debuggable="true"> |
30 | 32 | |
31 | - <activity android:name=".MainActivity" android:label="@string/app_name"> | |
33 | + <activity android:name=".MainActivity" | |
34 | + android:label="@string/app_name" | |
35 | + android:launchMode="singleTop"> | |
32 | 36 | <intent-filter> |
33 | 37 | <action android:name="android.intent.action.MAIN" /> |
34 | 38 | <category android:name="android.intent.category.LAUNCHER" /> |
35 | 39 | </intent-filter> |
40 | + <intent-filter> | |
41 | + <action android:name="com.example.android.hcgallery.action.DIALOG" /> | |
42 | + <category android:name="android.intent.category.DEFAULT" /> | |
43 | + </intent-filter> | |
36 | 44 | </activity> |
37 | 45 | |
38 | 46 | <!-- CameraSample --> |
@@ -1,13 +1,27 @@ | ||
1 | 1 | <p>This is a demo application highlighting how to use some of the new APIs in |
2 | -Honeycomb, including Fragments, the Action Bar, drag'n drop, transition | |
3 | -animations, and a stack widget. The image gallery shows how all these pieces | |
4 | -can work together in one application.</p> | |
2 | +Honeycomb, including:</p> | |
5 | 3 | |
6 | -<p>The application includes the following classes:<p> | |
4 | +<ul> | |
5 | + <li><a href="../../../guide/topics/fundamentals/fragments.html">Fragments</a></li> | |
6 | + <li>The <a href="../../../guide/topics/ui/actionbar.html">action bar</a> | |
7 | + and contextual action bar</li> | |
8 | + <li>Drag and drop</li> | |
9 | + <li>The new <a href="../../../reference/android/animation/package-summary.html"><code>android.animation</code></a> | |
10 | + framework</li> | |
11 | + <li>Custom notifications</li> | |
12 | + <li><a href="../../../reference/android/widget/StackView.html"><code>StackView</code></a> | |
13 | + and other adapter-based app widgets</li> | |
14 | +</ul> | |
15 | + | |
16 | +<p>The image gallery shows how all these pieces can work together in one application.</p> | |
17 | + | |
18 | +<p>The application includes the following key classes:<p> | |
7 | 19 | <ul> |
8 | 20 | <li><a href="src/com/example/android/hcgallery/ContentFragment.html">ContentFragment</a> |
9 | - A fragment responsible for containing the "content" of the application. | |
10 | - Displays images, receives drag/drop events from other fragments.</li> | |
21 | + A fragment responsible for containing the "content" of the application. | |
22 | + Displays images, receives drag/drop events from other fragments, and can | |
23 | + invoke the contextual action bar using | |
24 | + <a href="../../../reference/android/view/ActionMode.html">action modes</a>.</li> | |
11 | 25 | <li><a href="src/com/example/android/hcgallery/TitlesFragment.html">TitlesFragment</a> |
12 | 26 | Shows a ListView of photos to display in the ContentFragment. Photos can |
13 | 27 | be chosen either by tapping on the listview, or dragging them from the |
@@ -19,7 +33,7 @@ can work together in one application.</p> | ||
19 | 33 | ContentFragment. MainActivity is also responsible for keeping track of |
20 | 34 | the currently selected theme and currently selected photo when the |
21 | 35 | activity is recreated, such as when the screen is rotated or an intent to |
22 | - a seperate activity is fired (such as the included Camera sample). | |
36 | + a separate activity is fired (such as the included Camera sample). | |
23 | 37 | MainActivity also contains code demonstrating how to animate |
24 | 38 | showing/hiding fragments (in this case, the TitlesFragment) and the |
25 | 39 | ActionBar, demonstrating how to smoothly transition between states |
@@ -0,0 +1,20 @@ | ||
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<!-- | |
3 | + Copyright (C) 2011 The Android Open Source Project | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + --> | |
17 | +<selector xmlns:android="http://schemas.android.com/apk/res/android"> | |
18 | + <item android:state_pressed="true" android:drawable="@drawable/btn_notification_ic_example_pressed" /> | |
19 | + <item android:drawable="@drawable/btn_notification_ic_example_default" /> | |
20 | +</selector> |
@@ -0,0 +1,21 @@ | ||
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<!-- | |
3 | + Copyright (C) 2011 The Android Open Source Project | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + --> | |
17 | +<selector xmlns:android="http://schemas.android.com/apk/res/android"> | |
18 | + <item android:state_selected="true" android:drawable="@drawable/picture_frame_selected" /> | |
19 | + <item android:state_pressed="true" android:drawable="@drawable/picture_frame_pressed" /> | |
20 | + <item android:drawable="@drawable/picture_frame_default" /> | |
21 | +</selector> |
@@ -15,13 +15,16 @@ | ||
15 | 15 | limitations under the License. |
16 | 16 | --> |
17 | 17 | |
18 | -<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
18 | +<view xmlns:android="http://schemas.android.com/apk/res/android" | |
19 | + class="com.example.android.hcgallery.FitCenterFrameLayout" | |
19 | 20 | android:layout_width="match_parent" |
20 | 21 | android:layout_height="match_parent" |
21 | - android:padding="12dp"> | |
22 | + android:padding="24dp" | |
23 | + android:clickable="true"> | |
22 | 24 | <ImageView android:id="@+id/image" |
23 | - android:layout_width="match_parent" | |
24 | - android:layout_height="match_parent" | |
25 | - android:scaleType="fitCenter" | |
26 | - android:layout_gravity="center" /> | |
27 | -</FrameLayout> | |
25 | + android:background="@drawable/picture_frame" | |
26 | + android:layout_width="wrap_content" | |
27 | + android:layout_height="wrap_content" | |
28 | + android:layout_gravity="center" | |
29 | + android:duplicateParentState="true"/> | |
30 | +</view> |
@@ -0,0 +1,60 @@ | ||
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<!-- | |
3 | + Copyright (C) 2011 The Android Open Source Project | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + --> | |
17 | +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
18 | + android:id="@+id/notificationbg" | |
19 | + android:layout_width="match_parent" | |
20 | + android:layout_height="match_parent" | |
21 | + android:orientation="horizontal"> | |
22 | + | |
23 | + <LinearLayout | |
24 | + android:paddingLeft="16dip" | |
25 | + android:layout_width="0dip" | |
26 | + android:layout_height="wrap_content" | |
27 | + android:layout_weight="1" | |
28 | + android:layout_gravity="center_vertical" | |
29 | + android:orientation="vertical"> | |
30 | + | |
31 | + <TextView android:id="@+id/notification_title" | |
32 | + style="@android:style/TextAppearance.StatusBar.EventContent.Title" | |
33 | + android:focusable="true" | |
34 | + android:ellipsize="marquee" | |
35 | + android:singleLine="true" | |
36 | + android:layout_gravity="left" | |
37 | + android:layout_width="match_parent" | |
38 | + android:layout_height="wrap_content" /> | |
39 | + | |
40 | + <TextView android:id="@+id/notification_subtitle" | |
41 | + style="@android:style/TextAppearance.StatusBar.EventContent" | |
42 | + android:layout_gravity="left" | |
43 | + android:maxLines="2" | |
44 | + android:scrollHorizontally="true" | |
45 | + android:ellipsize="end" | |
46 | + android:layout_width="match_parent" | |
47 | + android:layout_height="wrap_content" | |
48 | + android:text="@string/notification_text" /> | |
49 | + | |
50 | + </LinearLayout> | |
51 | + | |
52 | + <ImageButton | |
53 | + android:id="@+id/notification_button" | |
54 | + android:src="@drawable/btn_notification_ic_example" | |
55 | + android:background="@null" | |
56 | + android:layout_weight="0" | |
57 | + android:layout_width="48dip" | |
58 | + android:layout_height="match_parent" /> | |
59 | + | |
60 | +</LinearLayout> |
@@ -18,16 +18,23 @@ | ||
18 | 18 | <menu xmlns:android="http://schemas.android.com/apk/res/android"> |
19 | 19 | <item android:id="@+id/camera" |
20 | 20 | android:title="Camera" |
21 | - android:icon="@drawable/ic_menu_camera" | |
21 | + android:icon="?attr/menuIconCamera" | |
22 | 22 | android:showAsAction="ifRoom" /> |
23 | 23 | <item android:id="@+id/toggleTitles" |
24 | - android:icon="@drawable/ic_menu_toggle" | |
24 | + android:icon="?attr/menuIconToggle" | |
25 | 25 | android:title="Toggle Titles" |
26 | 26 | android:showAsAction="ifRoom|withText" /> |
27 | + <!-- Example of items in the overflow menu --> | |
27 | 28 | <item android:id="@+id/toggleTheme" |
28 | 29 | android:title="Day/Night" |
29 | - android:showAsAction="ifRoom|withText" /> | |
30 | + android:showAsAction="never" /> | |
30 | 31 | <item android:id="@+id/showDialog" |
31 | - android:title="Show a dialog" | |
32 | - android:showAsAction="ifRoom|withText" /> | |
32 | + android:title="Show a dialog" | |
33 | + android:showAsAction="never" /> | |
34 | + <item android:id="@+id/showStandardNotification" | |
35 | + android:title="Show a basic notification" | |
36 | + android:showAsAction="never" /> | |
37 | + <item android:id="@+id/showCustomNotification" | |
38 | + android:title="Show a custom notification" | |
39 | + android:showAsAction="never" /> | |
33 | 40 | </menu> |
@@ -0,0 +1,23 @@ | ||
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<!-- | |
3 | + Copyright (C) 2011 The Android Open Source Project | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + --> | |
17 | + | |
18 | +<menu xmlns:android="http://schemas.android.com/apk/res/android"> | |
19 | + <item android:id="@+id/share" | |
20 | + android:title="Share" | |
21 | + android:icon="?attr/menuIconShare" | |
22 | + android:showAsAction="always|withText" /> | |
23 | +</menu> |
@@ -0,0 +1,24 @@ | ||
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<!-- | |
3 | + Copyright (C) 2011 The Android Open Source Project | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + --> | |
17 | +<resources> | |
18 | + <declare-styleable name="AppTheme"> | |
19 | + <attr name="listDragShadowBackground" format="reference" /> | |
20 | + <attr name="menuIconCamera" format="reference" /> | |
21 | + <attr name="menuIconToggle" format="reference" /> | |
22 | + <attr name="menuIconShare" format="reference" /> | |
23 | + </declare-styleable> | |
24 | +</resources> |
@@ -17,4 +17,5 @@ | ||
17 | 17 | <resources> |
18 | 18 | <color name="actionbar_background_light">#ccffffff</color> |
19 | 19 | <color name="actionbar_background_dark">#cc000000</color> |
20 | + <color name="drag_active_color">#80cccccc</color> | |
20 | 21 | </resources> |
@@ -15,10 +15,14 @@ | ||
15 | 15 | limitations under the License. |
16 | 16 | --> |
17 | 17 | <resources> |
18 | - <string name="app_name">Honeycomb Example</string> | |
18 | + <string name="app_name">Honeycomb Gallery</string> | |
19 | 19 | <string name="camera_sample">Camera Example</string> |
20 | 20 | <string name="clip_label">Clip Label</string> |
21 | 21 | |
22 | 22 | <string name="app_widget_name">Honeycomb Example Widget</string> |
23 | 23 | <string name="widget_empty_view_text">Touch to show data</string> |
24 | + | |
25 | + <string name="notification_text">Example notification text</string> | |
26 | + | |
27 | + <string name="photo_selection_cab_title">Photo selection</string> | |
24 | 28 | </resources> |
@@ -0,0 +1,45 @@ | ||
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<!-- | |
3 | + Copyright (C) 2011 The Android Open Source Project | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + --> | |
17 | +<resources> | |
18 | + <style name="ActionBar" parent="@android:style/Widget.Holo.ActionBar" /> | |
19 | + | |
20 | + <style name="ActionBar.Light" parent="@style/ActionBar"> | |
21 | + <item name="android:background">@color/actionbar_background_light</item> | |
22 | + </style> | |
23 | + | |
24 | + <style name="ActionBar.Dark" parent="@style/ActionBar"> | |
25 | + <item name="android:background">@color/actionbar_background_dark</item> | |
26 | + </style> | |
27 | + | |
28 | + <style name="AppTheme.Light" parent="@android:style/Theme.Holo.Light"> | |
29 | + <item name="android:actionBarStyle">@style/ActionBar.Light</item> | |
30 | + <item name="android:windowActionBarOverlay">true</item> | |
31 | + <item name="listDragShadowBackground">@android:color/background_light</item> | |
32 | + <item name="menuIconCamera">@drawable/ic_menu_camera_holo_light</item> | |
33 | + <item name="menuIconToggle">@drawable/ic_menu_toggle_holo_light</item> | |
34 | + <item name="menuIconShare">@drawable/ic_menu_share_holo_light</item> | |
35 | + </style> | |
36 | + | |
37 | + <style name="AppTheme.Dark" parent="@android:style/Theme.Holo"> | |
38 | + <item name="android:actionBarStyle">@style/ActionBar.Dark</item> | |
39 | + <item name="android:windowActionBarOverlay">true</item> | |
40 | + <item name="listDragShadowBackground">@android:color/background_dark</item> | |
41 | + <item name="menuIconCamera">@drawable/ic_menu_camera_holo_dark</item> | |
42 | + <item name="menuIconToggle">@drawable/ic_menu_toggle_holo_dark</item> | |
43 | + <item name="menuIconShare">@drawable/ic_menu_share_holo_dark</item> | |
44 | + </style> | |
45 | +</resources> |
@@ -16,29 +16,45 @@ | ||
16 | 16 | |
17 | 17 | package com.example.android.hcgallery; |
18 | 18 | |
19 | -import java.util.StringTokenizer; | |
20 | - | |
21 | 19 | import android.app.ActionBar; |
20 | +import android.app.Activity; | |
22 | 21 | import android.app.Fragment; |
23 | 22 | import android.content.ClipData; |
24 | -import android.content.ClipDescription; | |
25 | 23 | import android.content.ClipData.Item; |
24 | +import android.content.ClipDescription; | |
25 | +import android.content.Intent; | |
26 | 26 | import android.graphics.Bitmap; |
27 | 27 | import android.graphics.Color; |
28 | +import android.net.Uri; | |
29 | +import android.os.AsyncTask; | |
28 | 30 | import android.os.Bundle; |
31 | +import android.view.ActionMode; | |
29 | 32 | import android.view.DragEvent; |
30 | 33 | import android.view.LayoutInflater; |
34 | +import android.view.Menu; | |
35 | +import android.view.MenuInflater; | |
36 | +import android.view.MenuItem; | |
31 | 37 | import android.view.View; |
32 | -import android.view.ViewGroup; | |
33 | 38 | import android.view.View.OnClickListener; |
39 | +import android.view.ViewGroup; | |
34 | 40 | import android.widget.ImageView; |
35 | -import android.view.Window; | |
36 | -import android.view.WindowManager; | |
41 | +import android.widget.Toast; | |
42 | + | |
43 | +import java.io.File; | |
44 | +import java.io.FileNotFoundException; | |
45 | +import java.io.FileOutputStream; | |
46 | +import java.io.IOException; | |
47 | +import java.util.StringTokenizer; | |
37 | 48 | |
38 | 49 | public class ContentFragment extends Fragment { |
50 | + private View mContentView; | |
51 | + | |
39 | 52 | // The bitmap currently used by ImageView |
40 | 53 | private Bitmap mBitmap = null; |
41 | 54 | |
55 | + // Current action mode (contextual action bar, a.k.a. CAB) | |
56 | + private ActionMode mCurrentActionMode; | |
57 | + | |
42 | 58 | @Override |
43 | 59 | public void onActivityCreated(Bundle savedInstanceState) { |
44 | 60 | super.onActivityCreated(savedInstanceState); |
@@ -47,47 +63,86 @@ public class ContentFragment extends Fragment { | ||
47 | 63 | @Override |
48 | 64 | public View onCreateView(LayoutInflater inflater, ViewGroup container, |
49 | 65 | Bundle savedInstanceState) { |
50 | - final View view = inflater.inflate(R.layout.content_welcome, null); | |
51 | - final ImageView imageView = (ImageView) view.findViewById(R.id.image); | |
52 | - view.setDrawingCacheEnabled(false); | |
66 | + mContentView = inflater.inflate(R.layout.content_welcome, null); | |
67 | + final ImageView imageView = (ImageView) mContentView.findViewById(R.id.image); | |
68 | + mContentView.setDrawingCacheEnabled(false); | |
53 | 69 | |
54 | - view.setOnDragListener(new View.OnDragListener() { | |
70 | + mContentView.setOnDragListener(new View.OnDragListener() { | |
55 | 71 | public boolean onDrag(View v, DragEvent event) { |
56 | 72 | switch (event.getAction()) { |
57 | - case DragEvent.ACTION_DRAG_ENTERED: | |
58 | - view.setBackgroundColor(Color.LTGRAY); | |
59 | - break; | |
60 | - case DragEvent.ACTION_DRAG_EXITED: | |
61 | - view.setBackgroundColor(Color.TRANSPARENT); | |
62 | - break; | |
63 | - case DragEvent.ACTION_DRAG_STARTED: | |
64 | - return processDragStarted(event); | |
65 | - case DragEvent.ACTION_DROP: | |
66 | - view.setBackgroundColor(Color.TRANSPARENT); | |
67 | - return processDrop(event, imageView); | |
73 | + case DragEvent.ACTION_DRAG_ENTERED: | |
74 | + mContentView.setBackgroundColor( | |
75 | + getResources().getColor(R.color.drag_active_color)); | |
76 | + break; | |
77 | + | |
78 | + case DragEvent.ACTION_DRAG_EXITED: | |
79 | + mContentView.setBackgroundColor(Color.TRANSPARENT); | |
80 | + break; | |
81 | + | |
82 | + case DragEvent.ACTION_DRAG_STARTED: | |
83 | + return processDragStarted(event); | |
84 | + | |
85 | + case DragEvent.ACTION_DROP: | |
86 | + mContentView.setBackgroundColor(Color.TRANSPARENT); | |
87 | + return processDrop(event, imageView); | |
68 | 88 | } |
69 | 89 | return false; |
70 | 90 | } |
71 | 91 | }); |
72 | 92 | |
73 | - view.setOnClickListener(new OnClickListener() { | |
93 | + // Keep the action bar visibility in sync with the system status bar. That is, when entering | |
94 | + // 'lights out mode,' hide the action bar, and when exiting this mode, show the action bar. | |
95 | + | |
96 | + final Activity activity = getActivity(); | |
97 | + mContentView.setOnSystemUiVisibilityChangeListener( | |
98 | + new View.OnSystemUiVisibilityChangeListener() { | |
99 | + public void onSystemUiVisibilityChange(int visibility) { | |
100 | + ActionBar actionBar = activity.getActionBar(); | |
101 | + if (actionBar != null) { | |
102 | + mContentView.setSystemUiVisibility(visibility); | |
103 | + if (visibility == View.STATUS_BAR_VISIBLE) { | |
104 | + actionBar.show(); | |
105 | + } else { | |
106 | + actionBar.hide(); | |
107 | + } | |
108 | + } | |
109 | + } | |
110 | + }); | |
74 | 111 | |
112 | + // Show/hide the system status bar when single-clicking a photo. This is also called | |
113 | + // 'lights out mode.' Activating and deactivating this mode also invokes the listener | |
114 | + // defined above, which will show or hide the action bar accordingly. | |
75 | 115 | |
116 | + mContentView.setOnClickListener(new OnClickListener() { | |
76 | 117 | public void onClick(View v) { |
77 | - ActionBar bar = getActivity().getActionBar(); | |
78 | - if (bar != null) { | |
79 | - if (bar.isShowing()) { | |
80 | - bar.hide(); | |
81 | - } else { | |
82 | - bar.show(); | |
83 | - } | |
118 | + if (mContentView.getSystemUiVisibility() == View.STATUS_BAR_VISIBLE) { | |
119 | + mContentView.setSystemUiVisibility(View.STATUS_BAR_HIDDEN); | |
120 | + } else { | |
121 | + mContentView.setSystemUiVisibility(View.STATUS_BAR_VISIBLE); | |
84 | 122 | } |
85 | 123 | } |
86 | 124 | }); |
87 | - return view; | |
125 | + | |
126 | + // When long-pressing a photo, activate the action mode for selection, showing the | |
127 | + // contextual action bar (CAB). | |
128 | + | |
129 | + mContentView.setOnLongClickListener(new View.OnLongClickListener() { | |
130 | + public boolean onLongClick(View view) { | |
131 | + if (mCurrentActionMode != null) { | |
132 | + return false; | |
133 | + } | |
134 | + | |
135 | + mCurrentActionMode = getActivity().startActionMode( | |
136 | + mContentSelectionActionModeCallback); | |
137 | + mContentView.setSelected(true); | |
138 | + return true; | |
139 | + } | |
140 | + }); | |
141 | + | |
142 | + return mContentView; | |
88 | 143 | } |
89 | 144 | |
90 | - boolean processDragStarted(DragEvent event) { | |
145 | + boolean processDragStarted(DragEvent event) { | |
91 | 146 | // Determine whether to continue processing drag and drop based on the |
92 | 147 | // plain text mime type. |
93 | 148 | ClipDescription clipDesc = event.getClipDescription(); |
@@ -97,7 +152,7 @@ public class ContentFragment extends Fragment { | ||
97 | 152 | return false; |
98 | 153 | } |
99 | 154 | |
100 | - private boolean processDrop(DragEvent event, ImageView imageView) { | |
155 | + boolean processDrop(DragEvent event, ImageView imageView) { | |
101 | 156 | // Attempt to parse clip data with expected format: category||entry_id. |
102 | 157 | // Ignore event if data does not conform to this format. |
103 | 158 | ClipData data = event.getClipData(); |
@@ -130,16 +185,115 @@ public class ContentFragment extends Fragment { | ||
130 | 185 | return false; |
131 | 186 | } |
132 | 187 | |
133 | - public void updateContentAndRecycleBitmap(int category, int position) { | |
134 | - // Get the bitmap that needs to be drawn and update the ImageView | |
135 | - Bitmap next = Directory.getCategory(category).getEntry(position) | |
136 | - .getBitmap(getResources()); | |
137 | - ((ImageView) getView().findViewById(R.id.image)).setImageBitmap(next); | |
188 | + void updateContentAndRecycleBitmap(int category, int position) { | |
189 | + if (mCurrentActionMode != null) { | |
190 | + mCurrentActionMode.finish(); | |
191 | + } | |
192 | + | |
138 | 193 | if (mBitmap != null) { |
139 | 194 | // This is an advanced call and should be used if you |
140 | 195 | // are working with a lot of bitmaps. The bitmap is dead |
141 | 196 | // after this call. |
142 | 197 | mBitmap.recycle(); |
143 | 198 | } |
199 | + | |
200 | + // Get the bitmap that needs to be drawn and update the ImageView | |
201 | + mBitmap = Directory.getCategory(category).getEntry(position) | |
202 | + .getBitmap(getResources()); | |
203 | + ((ImageView) getView().findViewById(R.id.image)).setImageBitmap(mBitmap); | |
204 | + } | |
205 | + | |
206 | + void shareCurrentPhoto() { | |
207 | + File externalCacheDir = getActivity().getExternalCacheDir(); | |
208 | + if (externalCacheDir == null) { | |
209 | + Toast.makeText(getActivity(), "Error writing to USB/external storage.", | |
210 | + Toast.LENGTH_SHORT).show(); | |
211 | + return; | |
212 | + } | |
213 | + | |
214 | + // Prevent media scanning of the cache directory. | |
215 | + final File noMediaFile = new File(externalCacheDir, ".nomedia"); | |
216 | + try { | |
217 | + noMediaFile.createNewFile(); | |
218 | + } catch (IOException e) { | |
219 | + } | |
220 | + | |
221 | + // Write the bitmap to temporary storage in the external storage directory (e.g. SD card). | |
222 | + // We perform the actual disk write operations on a separate thread using the | |
223 | + // {@link AsyncTask} class, thus avoiding the possibility of stalling the main (UI) thread. | |
224 | + | |
225 | + final File tempFile = new File(externalCacheDir, "tempfile.jpg"); | |
226 | + | |
227 | + new AsyncTask<Void, Void, Boolean>() { | |
228 | + /** | |
229 | + * Compress and write the bitmap to disk on a separate thread. | |
230 | + * @return TRUE if the write was successful, FALSE otherwise. | |
231 | + */ | |
232 | + protected Boolean doInBackground(Void... voids) { | |
233 | + try { | |
234 | + FileOutputStream fo = new FileOutputStream(tempFile, false); | |
235 | + if (!mBitmap.compress(Bitmap.CompressFormat.JPEG, 60, fo)) { | |
236 | + Toast.makeText(getActivity(), "Error writing bitmap data.", | |
237 | + Toast.LENGTH_SHORT).show(); | |
238 | + return Boolean.FALSE; | |
239 | + } | |
240 | + return Boolean.TRUE; | |
241 | + | |
242 | + } catch (FileNotFoundException e) { | |
243 | + Toast.makeText(getActivity(), "Error writing to USB/external storage.", | |
244 | + Toast.LENGTH_SHORT).show(); | |
245 | + return Boolean.FALSE; | |
246 | + } | |
247 | + } | |
248 | + | |
249 | + /** | |
250 | + * After doInBackground completes (either successfully or in failure), we invoke an | |
251 | + * intent to share the photo. This code is run on the main (UI) thread. | |
252 | + */ | |
253 | + protected void onPostExecute(Boolean result) { | |
254 | + if (result != Boolean.TRUE) { | |
255 | + return; | |
256 | + } | |
257 | + | |
258 | + Intent shareIntent = new Intent(Intent.ACTION_SEND); | |
259 | + shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(tempFile)); | |
260 | + shareIntent.setType("image/jpeg"); | |
261 | + startActivity(Intent.createChooser(shareIntent, "Share photo")); | |
262 | + } | |
263 | + }.execute(); | |
144 | 264 | } |
265 | + | |
266 | + /** | |
267 | + * The callback for the 'photo selected' {@link ActionMode}. In this action mode, we can | |
268 | + * provide contextual actions for the selected photo. We currently only provide the 'share' | |
269 | + * action, but we could also add clipboard functions such as cut/copy/paste here as well. | |
270 | + */ | |
271 | + private ActionMode.Callback mContentSelectionActionModeCallback = new ActionMode.Callback() { | |
272 | + public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { | |
273 | + actionMode.setTitle(R.string.photo_selection_cab_title); | |
274 | + | |
275 | + MenuInflater inflater = getActivity().getMenuInflater(); | |
276 | + inflater.inflate(R.menu.photo_context_menu, menu); | |
277 | + return true; | |
278 | + } | |
279 | + | |
280 | + public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { | |
281 | + return false; | |
282 | + } | |
283 | + | |
284 | + public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) { | |
285 | + switch (menuItem.getItemId()) { | |
286 | + case R.id.share: | |
287 | + shareCurrentPhoto(); | |
288 | + actionMode.finish(); | |
289 | + return true; | |
290 | + } | |
291 | + return false; | |
292 | + } | |
293 | + | |
294 | + public void onDestroyActionMode(ActionMode actionMode) { | |
295 | + mContentView.setSelected(false); | |
296 | + mCurrentActionMode = null; | |
297 | + } | |
298 | + }; | |
145 | 299 | } |
@@ -0,0 +1,108 @@ | ||
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.example.android.hcgallery; | |
18 | + | |
19 | +import android.content.Context; | |
20 | +import android.util.AttributeSet; | |
21 | +import android.view.View; | |
22 | +import android.view.ViewGroup; | |
23 | + | |
24 | +/** | |
25 | + * A simple layout that fits and centers each child view, maintaining aspect ratio. | |
26 | + */ | |
27 | +public class FitCenterFrameLayout extends ViewGroup { | |
28 | + public FitCenterFrameLayout(Context context) { | |
29 | + super(context); | |
30 | + } | |
31 | + | |
32 | + public FitCenterFrameLayout(Context context, AttributeSet attrs) { | |
33 | + super(context, attrs); | |
34 | + } | |
35 | + | |
36 | + @Override | |
37 | + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | |
38 | + // We purposely disregard child measurements. | |
39 | + final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec); | |
40 | + final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec); | |
41 | + setMeasuredDimension(width, height); | |
42 | + | |
43 | + int childWidthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.UNSPECIFIED); | |
44 | + int childHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED); | |
45 | + | |
46 | + int childCount = getChildCount(); | |
47 | + for (int i = 0; i < childCount; i++) { | |
48 | + getChildAt(i).measure(childWidthSpec, childHeightSpec); | |
49 | + } | |
50 | + } | |
51 | + | |
52 | + @Override | |
53 | + protected void onLayout(boolean changed, int l, int t, int r, int b) { | |
54 | + final int childCount = getChildCount(); | |
55 | + | |
56 | + final int parentLeft = getPaddingLeft(); | |
57 | + final int parentTop = getPaddingTop(); | |
58 | + final int parentRight = r - l - getPaddingRight(); | |
59 | + final int parentBottom = b - t - getPaddingBottom(); | |
60 | + | |
61 | + final int parentWidth = parentRight - parentLeft; | |
62 | + final int parentHeight = parentBottom - parentTop; | |
63 | + | |
64 | + int unpaddedWidth, unpaddedHeight, parentUnpaddedWidth, parentUnpaddedHeight; | |
65 | + int childPaddingLeft, childPaddingTop, childPaddingRight, childPaddingBottom; | |
66 | + | |
67 | + for (int i = 0; i < childCount; i++) { | |
68 | + final View child = getChildAt(i); | |
69 | + if (child.getVisibility() == GONE) { | |
70 | + continue; | |
71 | + } | |
72 | + | |
73 | + // Fit and center the child within the parent. Make sure not to consider padding | |
74 | + // as part of the child's aspect ratio. | |
75 | + | |
76 | + childPaddingLeft = child.getPaddingLeft(); | |
77 | + childPaddingTop = child.getPaddingTop(); | |
78 | + childPaddingRight = child.getPaddingRight(); | |
79 | + childPaddingBottom = child.getPaddingBottom(); | |
80 | + | |
81 | + unpaddedWidth = child.getMeasuredWidth() - childPaddingLeft - childPaddingRight; | |
82 | + unpaddedHeight = child.getMeasuredHeight() - childPaddingTop - childPaddingBottom; | |
83 | + | |
84 | + parentUnpaddedWidth = parentWidth - childPaddingLeft - childPaddingRight; | |
85 | + parentUnpaddedHeight = parentHeight - childPaddingTop - childPaddingBottom; | |
86 | + | |
87 | + if (parentUnpaddedWidth * unpaddedHeight > parentUnpaddedHeight * unpaddedWidth) { | |
88 | + // The child view should be left/right letterboxed. | |
89 | + final int scaledChildWidth = unpaddedWidth * parentUnpaddedHeight | |
90 | + / unpaddedHeight + childPaddingLeft + childPaddingRight; | |
91 | + child.layout( | |
92 | + parentLeft + (parentWidth - scaledChildWidth) / 2, | |
93 | + parentTop, | |
94 | + parentRight - (parentWidth - scaledChildWidth) / 2, | |
95 | + parentBottom); | |
96 | + } else { | |
97 | + // The child view should be top/bottom letterboxed. | |
98 | + final int scaledChildHeight = unpaddedHeight * parentUnpaddedWidth | |
99 | + / unpaddedWidth + childPaddingTop + childPaddingBottom; | |
100 | + child.layout( | |
101 | + parentLeft, | |
102 | + parentTop + (parentHeight - scaledChildHeight) / 2, | |
103 | + parentRight, | |
104 | + parentTop + (parentHeight + scaledChildHeight) / 2); | |
105 | + } | |
106 | + } | |
107 | + } | |
108 | +} |
@@ -28,10 +28,15 @@ import android.app.Dialog; | ||
28 | 28 | import android.app.DialogFragment; |
29 | 29 | import android.app.FragmentManager; |
30 | 30 | import android.app.FragmentTransaction; |
31 | +import android.app.Notification; | |
32 | +import android.app.NotificationManager; | |
33 | +import android.app.PendingIntent; | |
31 | 34 | import android.content.DialogInterface; |
32 | 35 | import android.content.Intent; |
33 | 36 | import android.content.res.Configuration; |
34 | -import android.graphics.drawable.ColorDrawable; | |
37 | +import android.content.res.Resources; | |
38 | +import android.graphics.Bitmap; | |
39 | +import android.graphics.BitmapFactory; | |
35 | 40 | import android.os.Bundle; |
36 | 41 | import android.view.Menu; |
37 | 42 | import android.view.MenuInflater; |
@@ -39,9 +44,13 @@ import android.view.MenuItem; | ||
39 | 44 | import android.view.View; |
40 | 45 | import android.view.ViewGroup; |
41 | 46 | import android.view.Window; |
47 | +import android.widget.RemoteViews; | |
42 | 48 | |
43 | 49 | public class MainActivity extends Activity implements ActionBar.TabListener { |
44 | 50 | |
51 | + private static final int NOTIFICATION_DEFAULT = 1; | |
52 | + private static final String ACTION_DIALOG = "com.example.android.hcgallery.action.DIALOG"; | |
53 | + | |
45 | 54 | private View mActionBarView; |
46 | 55 | private Animator mCurrentTitlesAnimator; |
47 | 56 | private String[] mToggleLabels = {"Show Titles", "Hide Titles"}; |
@@ -51,26 +60,18 @@ public class MainActivity extends Activity implements ActionBar.TabListener { | ||
51 | 60 | @Override |
52 | 61 | public void onCreate(Bundle savedInstanceState) { |
53 | 62 | super.onCreate(savedInstanceState); |
63 | + | |
54 | 64 | if(savedInstanceState != null && savedInstanceState.getInt("theme", -1) != -1) { |
55 | 65 | mThemeId = savedInstanceState.getInt("theme"); |
56 | 66 | this.setTheme(mThemeId); |
57 | 67 | } |
58 | 68 | |
59 | - requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY); | |
60 | 69 | setContentView(R.layout.main); |
61 | 70 | |
62 | 71 | Directory.initializeDirectory(); |
63 | 72 | |
64 | 73 | ActionBar bar = getActionBar(); |
65 | 74 | |
66 | - if (mThemeId == android.R.style.Theme_Holo_Light || mThemeId == -1) { | |
67 | - bar.setBackgroundDrawable( | |
68 | - new ColorDrawable(getResources().getColor(R.color.actionbar_background_light))); | |
69 | - } else { | |
70 | - bar.setBackgroundDrawable( | |
71 | - new ColorDrawable(getResources().getColor(R.color.actionbar_background_dark))); | |
72 | - } | |
73 | - | |
74 | 75 | int i; |
75 | 76 | for (i = 0; i < Directory.getCategoryCount(); i++) { |
76 | 77 | bar.addTab(bar.newTab().setText(Directory.getCategory(i).getName()) |
@@ -122,21 +123,30 @@ public class MainActivity extends Activity implements ActionBar.TabListener { | ||
122 | 123 | intent.putExtra("theme", mThemeId); |
123 | 124 | startActivity(intent); |
124 | 125 | return true; |
126 | + | |
125 | 127 | case R.id.toggleTitles: |
126 | 128 | toggleVisibleTitles(); |
127 | 129 | return true; |
128 | 130 | |
129 | 131 | case R.id.toggleTheme: |
130 | - if (mThemeId == android.R.style.Theme_Holo) { | |
131 | - mThemeId = android.R.style.Theme_Holo_Light; | |
132 | + if (mThemeId == R.style.AppTheme_Dark) { | |
133 | + mThemeId = R.style.AppTheme_Light; | |
132 | 134 | } else { |
133 | - mThemeId = android.R.style.Theme_Holo; | |
135 | + mThemeId = R.style.AppTheme_Dark; | |
134 | 136 | } |
135 | 137 | this.recreate(); |
136 | 138 | return true; |
137 | 139 | |
138 | 140 | case R.id.showDialog: |
139 | - showDialog(); | |
141 | + showDialog("This is indeed an awesome dialog."); | |
142 | + return true; | |
143 | + | |
144 | + case R.id.showStandardNotification: | |
145 | + showNotification(false); | |
146 | + return true; | |
147 | + | |
148 | + case R.id.showCustomNotification: | |
149 | + showNotification(true); | |
140 | 150 | return true; |
141 | 151 | |
142 | 152 | default: |
@@ -225,21 +235,84 @@ public class MainActivity extends Activity implements ActionBar.TabListener { | ||
225 | 235 | mCurrentTitlesAnimator = objectAnimator; |
226 | 236 | |
227 | 237 | invalidateOptionsMenu(); |
238 | + | |
239 | + // Manually trigger onNewIntent to check for ACTION_DIALOG. | |
240 | + onNewIntent(getIntent()); | |
228 | 241 | } |
229 | 242 | |
230 | - void showDialog() { | |
243 | + @Override | |
244 | + protected void onNewIntent(Intent intent) { | |
245 | + if (ACTION_DIALOG.equals(intent.getAction())) { | |
246 | + showDialog(intent.getStringExtra(Intent.EXTRA_TEXT)); | |
247 | + } | |
248 | + } | |
231 | 249 | |
250 | + void showDialog(String text) { | |
232 | 251 | // DialogFragment.show() will take care of adding the fragment |
233 | 252 | // in a transaction. We also want to remove any currently showing |
234 | 253 | // dialog, so make our own transaction and take care of that here. |
235 | 254 | FragmentTransaction ft = getFragmentManager().beginTransaction(); |
236 | 255 | |
237 | - DialogFragment newFragment = MyDialogFragment.newInstance("The Dialog Of Awesome"); | |
256 | + DialogFragment newFragment = MyDialogFragment.newInstance(text); | |
238 | 257 | |
239 | - // Create and show the dialog. | |
258 | + // Show the dialog. | |
240 | 259 | newFragment.show(ft, "dialog"); |
241 | 260 | } |
242 | 261 | |
262 | + void showNotification(boolean custom) { | |
263 | + final Resources res = getResources(); | |
264 | + final NotificationManager notificationManager = (NotificationManager) getSystemService( | |
265 | + NOTIFICATION_SERVICE); | |
266 | + | |
267 | + Notification.Builder builder = new Notification.Builder(this) | |
268 | + .setSmallIcon(R.drawable.ic_stat_notify_example) | |
269 | + .setAutoCancel(true) | |
270 | + .setTicker(getString(R.string.notification_text)) | |
271 | + .setContentIntent(getDialogPendingIntent("Tapped the notification entry.")); | |
272 | + | |
273 | + if (custom) { | |
274 | + // Sets a custom content view for the notification, including an image button. | |
275 | + RemoteViews layout = new RemoteViews(getPackageName(), R.layout.notification); | |
276 | + layout.setTextViewText(R.id.notification_title, getString(R.string.app_name)); | |
277 | + layout.setOnClickPendingIntent(R.id.notification_button, | |
278 | + getDialogPendingIntent("Tapped the 'dialog' button in the notification.")); | |
279 | + builder.setContent(layout); | |
280 | + | |
281 | + // Notifications in Android 3.0 now have a standard mechanism for displaying large | |
282 | + // bitmaps such as contact avatars. Here, we load an example image and resize it to the | |
283 | + // appropriate size for large bitmaps in notifications. | |
284 | + Bitmap largeIconTemp = BitmapFactory.decodeResource(res, | |
285 | + R.drawable.notification_default_largeicon); | |
286 | + Bitmap largeIcon = Bitmap.createScaledBitmap( | |
287 | + largeIconTemp, | |
288 | + res.getDimensionPixelSize(android.R.dimen.notification_large_icon_width), | |
289 | + res.getDimensionPixelSize(android.R.dimen.notification_large_icon_height), | |
290 | + false); | |
291 | + largeIconTemp.recycle(); | |
292 | + | |
293 | + builder.setLargeIcon(largeIcon); | |
294 | + | |
295 | + } else { | |
296 | + builder | |
297 | + .setNumber(7) // An example number. | |
298 | + .setContentTitle(getString(R.string.app_name)) | |
299 | + .setContentText(getString(R.string.notification_text)); | |
300 | + } | |
301 | + | |
302 | + notificationManager.notify(NOTIFICATION_DEFAULT, builder.getNotification()); | |
303 | + } | |
304 | + | |
305 | + PendingIntent getDialogPendingIntent(String dialogText) { | |
306 | + return PendingIntent.getActivity( | |
307 | + this, | |
308 | + dialogText.hashCode(), // Otherwise previous PendingIntents with the same | |
309 | + // requestCode may be overwritten. | |
310 | + new Intent(ACTION_DIALOG) | |
311 | + .putExtra(Intent.EXTRA_TEXT, dialogText) | |
312 | + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), | |
313 | + 0); | |
314 | + } | |
315 | + | |
243 | 316 | @Override |
244 | 317 | public boolean onPrepareOptionsMenu(Menu menu) { |
245 | 318 | menu.getItem(1).setTitle(mToggleLabels[mLabelIndex]); |
@@ -261,24 +334,19 @@ public class MainActivity extends Activity implements ActionBar.TabListener { | ||
261 | 334 | public static MyDialogFragment newInstance(String title) { |
262 | 335 | MyDialogFragment frag = new MyDialogFragment(); |
263 | 336 | Bundle args = new Bundle(); |
264 | - args.putString("title", title); | |
337 | + args.putString("text", title); | |
265 | 338 | frag.setArguments(args); |
266 | 339 | return frag; |
267 | 340 | } |
268 | 341 | |
269 | 342 | @Override |
270 | 343 | public Dialog onCreateDialog(Bundle savedInstanceState) { |
271 | - String title = getArguments().getString("title"); | |
344 | + String text = getArguments().getString("text"); | |
272 | 345 | |
273 | 346 | return new AlertDialog.Builder(getActivity()) |
274 | - .setTitle(title) | |
275 | - .setPositiveButton("OK", | |
276 | - new DialogInterface.OnClickListener() { | |
277 | - public void onClick(DialogInterface dialog, int whichButton) { | |
278 | - } | |
279 | - } | |
280 | - ) | |
281 | - .setNegativeButton("Cancel", | |
347 | + .setTitle("A Dialog of Awesome") | |
348 | + .setMessage(text) | |
349 | + .setPositiveButton(android.R.string.ok, | |
282 | 350 | new DialogInterface.OnClickListener() { |
283 | 351 | public void onClick(DialogInterface dialog, int whichButton) { |
284 | 352 | } |
@@ -20,6 +20,8 @@ import android.app.Fragment; | ||
20 | 20 | import android.app.FragmentManager; |
21 | 21 | import android.app.ListFragment; |
22 | 22 | import android.content.ClipData; |
23 | +import android.content.res.Resources; | |
24 | +import android.content.res.TypedArray; | |
23 | 25 | import android.graphics.Canvas; |
24 | 26 | import android.graphics.Color; |
25 | 27 | import android.graphics.drawable.ColorDrawable; |
@@ -28,6 +30,7 @@ import android.graphics.Paint; | ||
28 | 30 | import android.graphics.Typeface; |
29 | 31 | import android.os.Bundle; |
30 | 32 | import android.text.TextPaint; |
33 | +import android.util.TypedValue; | |
31 | 34 | import android.view.View; |
32 | 35 | import android.widget.AdapterView; |
33 | 36 | import android.widget.ArrayAdapter; |
@@ -53,47 +56,40 @@ public class TitlesFragment extends ListFragment { | ||
53 | 56 | populateTitles(mCategory); |
54 | 57 | ListView lv = getListView(); |
55 | 58 | lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE); |
56 | - selectPosition(mCurPosition); | |
57 | - lv.setCacheColorHint(Color.WHITE); | |
59 | + lv.setCacheColorHint(Color.TRANSPARENT); | |
58 | 60 | lv.setOnItemLongClickListener(new OnItemLongClickListener() { |
59 | - | |
60 | - public boolean onItemLongClick(AdapterView<?> av, View v, int pos, | |
61 | - long id) { | |
61 | + public boolean onItemLongClick(AdapterView<?> av, View v, int pos, long id) { | |
62 | 62 | final String title = (String) ((TextView) v).getText(); |
63 | 63 | |
64 | 64 | // Set up clip data with the category||entry_id format. |
65 | 65 | final String textData = String.format("%d||%d", mCategory, pos); |
66 | 66 | ClipData data = ClipData.newPlainText(title, textData); |
67 | - | |
68 | - v.startDrag(data, new MyDragShadowBuilder(v, title), null, 0); | |
67 | + v.startDrag(data, new MyDragShadowBuilder(v), null, 0); | |
69 | 68 | return true; |
70 | 69 | } |
71 | 70 | }); |
71 | + | |
72 | + selectPosition(mCurPosition); | |
72 | 73 | } |
73 | 74 | |
74 | - private static class MyDragShadowBuilder extends View.DragShadowBuilder { | |
75 | - private static Drawable mShadow; | |
76 | - private static String mLabel; | |
77 | - private static int mViewHeight; | |
78 | - | |
79 | - public MyDragShadowBuilder(View v, String label) { | |
75 | + private class MyDragShadowBuilder extends View.DragShadowBuilder { | |
76 | + private Drawable mShadow; | |
77 | + | |
78 | + public MyDragShadowBuilder(View v) { | |
80 | 79 | super(v); |
81 | - mShadow = new ColorDrawable(Color.BLUE); | |
80 | + | |
81 | + final TypedArray a = v.getContext().obtainStyledAttributes(R.styleable.AppTheme); | |
82 | + mShadow = a.getDrawable(R.styleable.AppTheme_listDragShadowBackground); | |
83 | + mShadow.setCallback(v); | |
82 | 84 | mShadow.setBounds(0, 0, v.getWidth(), v.getHeight()); |
83 | - mLabel = label; | |
84 | - mViewHeight = v.getHeight(); | |
85 | + a.recycle(); | |
85 | 86 | } |
86 | 87 | |
87 | 88 | @Override |
88 | 89 | public void onDrawShadow(Canvas canvas) { |
89 | 90 | super.onDrawShadow(canvas); |
90 | 91 | mShadow.draw(canvas); |
91 | - Paint paint = new TextPaint(); | |
92 | - paint.setTextSize(20); | |
93 | - paint.setColor(Color.LTGRAY); | |
94 | - paint.setTypeface(Typeface.DEFAULT_BOLD); | |
95 | - paint.setAntiAlias(true); | |
96 | - canvas.drawText(mLabel, 20, (float) (mViewHeight * .6), paint); | |
92 | + getView().draw(canvas); | |
97 | 93 | } |
98 | 94 | } |
99 | 95 |
@@ -116,13 +112,13 @@ public class TitlesFragment extends ListFragment { | ||
116 | 112 | ContentFragment frag = (ContentFragment) getFragmentManager() |
117 | 113 | .findFragmentById(R.id.frag_content); |
118 | 114 | frag.updateContentAndRecycleBitmap(mCategory, position); |
115 | + mCurPosition = position; | |
119 | 116 | } |
120 | 117 | |
121 | 118 | public void selectPosition(int position) { |
122 | 119 | ListView lv = getListView(); |
123 | 120 | lv.setItemChecked(position, true); |
124 | 121 | updateImage(position); |
125 | - | |
126 | 122 | } |
127 | 123 | |
128 | 124 | @Override |