Merge "Added Honeycomb Gallery sample application." into honeycomb

This commit is contained in:
Alexander Lucas
2011-01-19 18:33:28 -08:00
committed by Android (Google) Code Review
54 changed files with 1701 additions and 0 deletions

View File

@@ -160,6 +160,7 @@ development/samples/ContactManager samples/${PLATFORM_NAME}/ContactMan
development/samples/CrossCompatibility samples/${PLATFORM_NAME}/CrossCompatibility
development/samples/CubeLiveWallpaper samples/${PLATFORM_NAME}/CubeLiveWallpaper
development/samples/Home samples/${PLATFORM_NAME}/Home
development/samples/Honeycomb-Gallery samples/${PLATFORM_NAME}/Honeycomb-Gallery
development/samples/JetBoy samples/${PLATFORM_NAME}/JetBoy
development/samples/LunarLander samples/${PLATFORM_NAME}/LunarLander
development/samples/MultiResolution samples/${PLATFORM_NAME}/MultiResolution

View File

@@ -0,0 +1,16 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := samples
# Only compile source java files in this apk.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := Honeycomb-Gallery
LOCAL_SDK_VERSION := current
include $(BUILD_PACKAGE)
# Use the following include to make our test apk.
include $(call all-makefiles-under,$(LOCAL_PATH))

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2011 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.hcgallery" android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="Honeycomb" />
<uses-permission android:name="android.permission.CAMERA" />
<application android:label="@string/app_name"
android:icon="@drawable/icon"
android:logo="@drawable/logo"
android:theme="@android:style/Theme.Holo.Light"
android:hardwareAccelerated="true"
android:debuggable="true">
<activity android:name=".MainActivity" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- CameraSample -->
<activity android:name=".CameraSample"
android:label="@string/camera_sample"
android:screenOrientation="landscape" />
<!-- StackView widget sample code -->
<receiver android:name=".widget.WidgetProvider"
android:label="@string/app_widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/widget_info" />
</receiver>
<service android:name=".widget.WidgetService"
android:exported="true"
android:permission="android.permission.BIND_REMOTEVIEWS" />
</application>
</manifest>

View File

@@ -0,0 +1,37 @@
<p>This is a demo application highlighting how to use some of the new APIs in
Honeycomb, including Fragments, the Action Bar, drag'n drop, transition
animations, and a stack widget. The image gallery shows how all these pieces
can work together in one application.</p>
<p>The application includes the following classes:<p>
<ul>
<li><a href="src/com/example/android/hcgallery/ContentFragment.html">ContentFragment</a>
A fragment responsible for containing the "content" of the application.
Displays images, receives drag/drop events from other fragments.</li>
<li><a href="src/com/example/android/hcgallery/TitlesFragment.html">TitlesFragment</a>
Shows a ListView of photos to display in the ContentFragment. Photos can
be chosen either by tapping on the listview, or dragging them from the
list to the content area. The list of photos displayed depends on the
category selected in the ActionBar.</li>
<li><a href="src/com/example/android/hcgallery/MainActivity.html">MainActivity</a>
This is the main entry point of the application. MainActivity is
responsible for initialization of the ActionBar, TitlesFragment, and
ContentFragment. MainActivity is also responsible for keeping track of
the currently selected theme and currently selected photo when the
activity is recreated, such as when the screen is rotated or an intent to
a seperate activity is fired (such as the included Camera sample).
MainActivity also contains code demonstrating how to animate
showing/hiding fragments (in this case, the TitlesFragment) and the
ActionBar, demonstrating how to smoothly transition between states
in your application.</li>
<li><a href="src/com/example/android/hcgallery/widget/WidgetProvider.html">WidgetProvider</a>
The WidgetProvider class is an implementation of the AppWidgetProvider
class, which is a view that can be embedded in other applications.
This class is responsible for handling when the instance of this widget
is enabled, disabled, created, deleted, or updated.</li>
<li><a href="src/com/example/android/hcgallery/widget/WidgetService.html">WidgetService</a>
The WidgetService is an implementation of the RemoteViewsService class,
which is used to populate the collection view (in this case, a stack
widget)</li> </ul>
<img alt="Screenshot" src="../images/hcgallery.png" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2011 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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<gradient android:startColor="#ff666666" android:endColor="#ff333333" android:angle="270" />
</shape>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2011 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/frags">
<fragment class="com.example.android.hcgallery.TitlesFragment"
android:id="@+id/frag_title"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="@dimen/titles_size"/>
<fragment class="com.example.android.hcgallery.ContentFragment"
android:id="@+id/frag_content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

View File

@@ -0,0 +1,24 @@
<!--
Copyright (C) 2011 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent">Hello Action Bar</TextView>
</LinearLayout>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2011 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.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment android:name="com.example.android.hcgallery.CameraFragment"
android:id="@+id/camera_frag"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2011 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.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="12dp">
<ImageView android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitCenter"
android:layout_gravity="center" />
</FrameLayout>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2011 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/frags">
<fragment class="com.example.android.hcgallery.TitlesFragment"
android:id="@+id/frag_title"
android:visibility="gone"
android:layout_width="@dimen/titles_size"
android:layout_height="match_parent" />
<fragment class="com.example.android.hcgallery.ContentFragment"
android:id="@+id/frag_content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2011 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.
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
android:gravity="bottom"
android:textAppearance="?android:attr/textAppearanceMedium"
android:background="?android:attr/activatedBackgroundIndicator" >
</TextView>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2011 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.
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/widget_item"
android:layout_width="120dp"
android:layout_height="120dp"
android:gravity="center"
android:background="@drawable/widget_item_background"
android:textColor="#ffffff"
android:textStyle="bold"
android:textSize="44sp" />

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2011 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.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<StackView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/stack_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:loopViews="true" />
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/empty_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="@drawable/widget_item_background"
android:textColor="#ffffff"
android:textStyle="bold"
android:text="@string/widget_empty_view_text"
android:textSize="20sp" />
</FrameLayout>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2011 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.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/switch_cam" android:title="Switch Camera" />
</menu>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2011 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.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/camera"
android:title="Camera"
android:icon="@drawable/ic_menu_camera"
android:showAsAction="ifRoom" />
<item android:id="@+id/toggleTitles"
android:icon="@drawable/ic_menu_toggle"
android:title="Toggle Titles"
android:showAsAction="ifRoom|withText" />
<item android:id="@+id/toggleTheme"
android:title="Day/Night"
android:showAsAction="ifRoom|withText" />
</menu>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2011 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.
-->
<resources>
<dimen name="titles_size">200dp</dimen>
</resources>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2011 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.
-->
<resources>
<dimen name="titles_size">300dp</dimen>
</resources>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2010 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.
-->
<resources>
<string name="app_name">Honeycomb Example</string>
<string name="camera_sample">Camera Example</string>
<string name="clip_label">Clip Label</string>
<string name="app_widget_name">Honeycomb Example Widget</string>
<string name="widget_empty_view_text">Touch to show data</string>
</resources>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2011 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.
-->
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="150dp"
android:minHeight="150dp"
android:updatePeriodMillis="3600000"
android:initialLayout="@layout/widget_layout"
android:previewImage="@drawable/widget_preview"
android:autoAdvanceViewId="@id/stack_view" />

View File

@@ -0,0 +1,318 @@
/*
* Copyright (C) 2011 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.example.android.hcgallery;
import java.io.IOException;
import java.util.List;
import android.app.Fragment;
import android.app.Activity;
import android.app.ActionBar;
import android.content.Context;
import android.content.Intent;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Size;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
public class CameraFragment extends Fragment {
private Preview mPreview;
Camera mCamera;
int mNumberOfCameras;
int cameraCurrentlyLocked;
// The first rear facing camera
int defaultCameraId;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Add an up arrow to the "home" button, indicating that the button will go "up"
// one activity in the app's Activity heirarchy.
Activity activity = this.getActivity();
ActionBar actionBar = activity.getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
// Create a RelativeLayout container that will hold a SurfaceView,
// and set it as the content of our activity.
mPreview = new Preview(this.getActivity());
// Find the total number of cameras available
mNumberOfCameras = Camera.getNumberOfCameras();
// Find the ID of the default camera
CameraInfo cameraInfo = new CameraInfo();
for (int i = 0; i < mNumberOfCameras; i++) {
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
defaultCameraId = i;
}
}
setHasOptionsMenu(mNumberOfCameras > 1);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return mPreview;
}
@Override
public void onResume() {
super.onResume();
// Open the default i.e. the first rear facing camera.
mCamera = Camera.open(defaultCameraId);
cameraCurrentlyLocked = defaultCameraId;
mPreview.setCamera(mCamera);
}
@Override
public void onPause() {
super.onPause();
// Because the Camera object is a shared resource, it's very
// important to release it when the activity is paused.
if (mCamera != null) {
mPreview.setCamera(null);
mCamera.release();
mCamera = null;
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (mNumberOfCameras > 1) {
// Inflate our menu which can gather user input for switching camera
inflater.inflate(R.menu.camera_menu, menu);
} else {
super.onCreateOptionsMenu(menu, inflater);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.switch_cam:
// Release this camera -> cameraCurrentlyLocked
if (mCamera != null) {
mCamera.stopPreview();
mPreview.setCamera(null);
mCamera.release();
mCamera = null;
}
// Acquire the next camera and request Preview to reconfigure
// parameters.
mCamera = Camera
.open((cameraCurrentlyLocked + 1) % mNumberOfCameras);
cameraCurrentlyLocked = (cameraCurrentlyLocked + 1)
% mNumberOfCameras;
mPreview.switchCamera(mCamera);
// Start the preview
mCamera.startPreview();
return true;
case android.R.id.home:
Intent intent = new Intent(this.getActivity(), MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
default:
return super.onOptionsItemSelected(item);
}
}
}
// ----------------------------------------------------------------------
/**
* A simple wrapper around a Camera and a SurfaceView that renders a centered
* preview of the Camera to the surface. We need to center the SurfaceView
* because not all devices have cameras that support preview sizes at the same
* aspect ratio as the device's display.
*/
class Preview extends ViewGroup implements SurfaceHolder.Callback {
private final String TAG = "Preview";
SurfaceView mSurfaceView;
SurfaceHolder mHolder;
Size mPreviewSize;
List<Size> mSupportedPreviewSizes;
Camera mCamera;
Preview(Context context) {
super(context);
mSurfaceView = new SurfaceView(context);
addView(mSurfaceView);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters()
.getSupportedPreviewSizes();
requestLayout();
}
}
public void switchCamera(Camera camera) {
setCamera(camera);
try {
camera.setPreviewDisplay(mHolder);
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
camera.setParameters(parameters);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// We purposely disregard child measurements because act as a
// wrapper to a SurfaceView that centers the camera preview instead
// of stretching it.
final int width = resolveSize(getSuggestedMinimumWidth(),
widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(),
heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width,
height);
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed && getChildCount() > 0) {
final View child = getChildAt(0);
final int width = r - l;
final int height = b - t;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null) {
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
}
// Center the child SurfaceView within the parent.
if (width * previewHeight > height * previewWidth) {
final int scaledChildWidth = previewWidth * height
/ previewHeight;
child.layout((width - scaledChildWidth) / 2, 0,
(width + scaledChildWidth) / 2, height);
} else {
final int scaledChildHeight = previewHeight * width
/ previewWidth;
child.layout(0, (height - scaledChildHeight) / 2, width,
(height + scaledChildHeight) / 2);
}
}
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the camera and tell it where
// to draw.
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(holder);
}
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
if (mCamera != null) {
mCamera.stopPreview();
}
}
private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) w / h;
if (sizes == null)
return null;
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Try to find an size match aspect ratio and size
for (Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
// Cannot find the one match the aspect ratio, ignore the requirement
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// Now that the size is known, set up the camera parameters and begin
// the preview.
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
mCamera.setParameters(parameters);
mCamera.startPreview();
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2011 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.example.android.hcgallery;
import android.app.Activity;
import android.os.Bundle;
public class CameraSample extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
int themeId = this.getIntent().getExtras().getInt("theme");
this.setTheme(themeId);
super.onCreate(savedInstanceState);
setContentView(R.layout.camera_sample);
}
}

View File

@@ -0,0 +1,119 @@
/*
* Copyright (C) 2011 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.example.android.hcgallery;
import java.util.StringTokenizer;
import android.app.ActionBar;
import android.app.Fragment;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.ClipData.Item;
import android.os.Bundle;
import android.view.DragEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.ImageView;
public class ContentFragment extends Fragment {
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.content_welcome, null);
final ImageView imageView = (ImageView) view.findViewById(R.id.image);
view.setDrawingCacheEnabled(false);
view.setOnDragListener(new View.OnDragListener() {
public boolean onDrag(View v, DragEvent event) {
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
return processDragStarted(event);
case DragEvent.ACTION_DROP:
return processDrop(event, imageView);
}
return false;
}
});
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
ActionBar bar = ContentFragment.this.getActivity()
.getActionBar();
if (bar != null) {
if (bar.isShowing()) {
bar.hide();
} else {
bar.show();
}
}
}
});
return view;
}
boolean processDragStarted(DragEvent event) {
// Determine whether to continue processing drag and drop based on the
// plain text mime type.
ClipDescription clipDesc = event.getClipDescription();
if (clipDesc != null) {
return clipDesc.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN);
}
return false;
}
boolean processDrop(DragEvent event, ImageView imageView) {
// Attempt to parse clip data with expected format: category||entry_id.
// Ignore event if data does not conform to this format.
ClipData data = event.getClipData();
if (data != null) {
if (data.getItemCount() > 0) {
Item item = data.getItemAt(0);
String textData = (String) item.getText();
if (textData != null) {
StringTokenizer tokenizer = new StringTokenizer(textData, "||");
if (tokenizer.countTokens() != 2) {
return false;
}
int category = -1;
int entryId = -1;
try {
category = Integer.parseInt(tokenizer.nextToken());
entryId = Integer.parseInt(tokenizer.nextToken());
} catch (NumberFormatException exception) {
return false;
}
imageView.setImageBitmap(
Directory.getCategory(category)
.getEntry(entryId)
.getBitmap(getResources()));
return true;
}
}
}
return false;
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2011 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.example.android.hcgallery;
public class Directory {
private static DirectoryCategory[] categories;
public static void initializeDirectory() {
categories = new DirectoryCategory[] {
new DirectoryCategory("Balloons", new DirectoryEntry[] {
new DirectoryEntry("Green Balloon", R.drawable.green_balloon),
new DirectoryEntry("Red Balloon", R.drawable.red_balloon),
new DirectoryEntry("Blue Balloon", R.drawable.blue_balloon)}),
new DirectoryCategory("Bikes", new DirectoryEntry[] {
new DirectoryEntry("Old school huffy", R.drawable.blue_bike),
new DirectoryEntry("New Bikes", R.drawable.rainbow_bike),
new DirectoryEntry("Chrome Fast", R.drawable.chrome_wheel)}),
new DirectoryCategory("Androids", new DirectoryEntry[] {
new DirectoryEntry("Steampunk Android", R.drawable.punk_droid),
new DirectoryEntry("Stargazing Android", R.drawable.stargazer_droid),
new DirectoryEntry("Big Android", R.drawable.big_droid) }),
new DirectoryCategory("Pastries", new DirectoryEntry[] {
new DirectoryEntry("Cupcake", R.drawable.cupcake),
new DirectoryEntry("Donut", R.drawable.donut),
new DirectoryEntry("Eclair", R.drawable.eclair),
new DirectoryEntry("Froyo", R.drawable.froyo), }), };
}
public static int getCategoryCount() {
return categories.length;
}
public static DirectoryCategory getCategory(int i) {
return categories[i];
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2011 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.example.android.hcgallery;
public class DirectoryCategory {
private String name;
private DirectoryEntry[] entries;
public DirectoryCategory(String name, DirectoryEntry[] entries) {
this.name = name;
this.entries = entries;
}
public String getName() {
return name;
}
public int getEntryCount() {
return entries.length;
}
public DirectoryEntry getEntry(int i) {
return entries[i];
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (C) 2011 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.example.android.hcgallery;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
public class DirectoryEntry {
private String name;
private int resID;
public DirectoryEntry(String name, int resID) {
this.name = name;
this.resID = resID;
}
public String getName() {
return name;
}
public Drawable getDrawable(Resources res) {
return res.getDrawable(resID);
}
public Bitmap getBitmap(Resources res) {
return BitmapFactory.decodeResource(res, resID);
}
}

View File

@@ -0,0 +1,220 @@
/*
* Copyright (C) 2011 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.example.android.hcgallery;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.app.ActionBar;
import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
public class MainActivity extends Activity implements ActionBar.TabListener {
private View mActionBarView;
private Animator mCurrentTitlesAnimator;
private String[] mToggleLabels = {"Show Titles", "Hide Titles"};
private int mLabelIndex = 1;
private int mThemeId = -1;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState != null && savedInstanceState.getInt("theme", -1) != -1) {
mThemeId = savedInstanceState.getInt("theme");
this.setTheme(mThemeId);
}
setContentView(R.layout.main);
Directory.initializeDirectory();
ActionBar bar = getActionBar();
int i;
for (i = 0; i < Directory.getCategoryCount(); i++)
bar.addTab(bar.newTab().setText(Directory.getCategory(i).getName())
.setTabListener(this));
mActionBarView = getLayoutInflater().inflate(
R.layout.action_bar_custom, null);
bar.setCustomView(mActionBarView);
bar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_USE_LOGO);
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayShowHomeEnabled(true);
// If category is not saved to the savedInstanceState,
// 0 is returned by default.
if(savedInstanceState != null) {
int category = savedInstanceState.getInt("category");
bar.selectTab(bar.getTabAt(category));
}
}
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
TitlesFragment titleFrag = (TitlesFragment) getFragmentManager()
.findFragmentById(R.id.frag_title);
titleFrag.populateTitles(tab.getPosition());
titleFrag.selectPosition(0);
}
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
}
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.camera:
Intent intent = new Intent(this, CameraSample.class);
intent.putExtra("theme", mThemeId);
startActivity(intent);
return true;
case R.id.toggleTitles:
toggleVisibleTitles();
return true;
case R.id.toggleTheme:
if (mThemeId == android.R.style.Theme_Holo) {
mThemeId = android.R.style.Theme_Holo_Light;
} else {
mThemeId = android.R.style.Theme_Holo;
}
this.recreate();
default:
return super.onOptionsItemSelected(item);
}
}
public void toggleVisibleTitles() {
// Use these for custom animations.
final FragmentManager fm = getFragmentManager();
final TitlesFragment f = (TitlesFragment) fm
.findFragmentById(R.id.frag_title);
final View titlesView = f.getView();
mLabelIndex = 1 - mLabelIndex;
// Determine if we're in portrait, and whether we're showing or hiding the titles
// with this toggle.
final boolean isPortrait = getResources().getConfiguration().orientation ==
Configuration.ORIENTATION_PORTRAIT;
final boolean shouldShow = f.isHidden() || mCurrentTitlesAnimator != null;
// Cancel the current titles animation if there is one.
if (mCurrentTitlesAnimator != null)
mCurrentTitlesAnimator.cancel();
// Begin setting up the object animator. We'll animate the bottom or right edge of the
// titles view, as well as its alpha for a fade effect.
ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(
titlesView,
PropertyValuesHolder.ofInt(
isPortrait ? "bottom" : "right",
shouldShow ? getResources().getDimensionPixelSize(R.dimen.titles_size)
: 0),
PropertyValuesHolder.ofFloat("alpha", shouldShow ? 1 : 0)
);
// At each step of the animation, we'll perform layout by calling setLayoutParams.
final ViewGroup.LayoutParams lp = titlesView.getLayoutParams();
objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator valueAnimator) {
// *** WARNING ***: triggering layout at each animation frame highly impacts
// performance so you should only do this for simple layouts. More complicated
// layouts can be better served with individual animations on child views to
// avoid the performance penalty of layout.
if (isPortrait) {
lp.height = (Integer) valueAnimator.getAnimatedValue();
} else {
lp.width = (Integer) valueAnimator.getAnimatedValue();
}
titlesView.setLayoutParams(lp);
}
});
if (shouldShow) {
fm.beginTransaction().show(f).commit();
objectAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animator) {
mCurrentTitlesAnimator = null;
}
});
} else {
objectAnimator.addListener(new AnimatorListenerAdapter() {
boolean canceled;
@Override
public void onAnimationCancel(Animator animation) {
canceled = true;
super.onAnimationCancel(animation);
}
@Override
public void onAnimationEnd(Animator animator) {
if (canceled)
return;
mCurrentTitlesAnimator = null;
fm.beginTransaction().hide(f).commit();
}
});
}
// Start the animation.
objectAnimator.start();
mCurrentTitlesAnimator = objectAnimator;
invalidateOptionsMenu();
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
menu.getItem(1).setTitle(mToggleLabels[mLabelIndex]);
return true;
}
@Override
public void onSaveInstanceState (Bundle outState) {
super.onSaveInstanceState(outState);
ActionBar bar = getActionBar();
int category = bar.getSelectedTab().getPosition();
outState.putInt("category", category);
outState.putInt("theme", mThemeId);
}
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright (C) 2011 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.example.android.hcgallery;
import android.app.ListFragment;
import android.content.ClipData;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AdapterView.OnItemLongClickListener;
public class TitlesFragment extends ListFragment {
private int mCategory = 0;
private int mCurPosition = 0;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//Current position should survive screen rotations.
if (savedInstanceState != null) {
mCategory = savedInstanceState.getInt("category");
mCurPosition = savedInstanceState.getInt("listPosition");
}
populateTitles(mCategory);
ListView lv = getListView();
lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
selectPosition(mCurPosition);
lv.setCacheColorHint(Color.WHITE);
lv.setOnItemLongClickListener(new OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> av, View v, int pos,
long id) {
final String title = (String) ((TextView) v).getText();
// Set up clip data with the category||entry_id format.
final String textData = String.format("%d||%d", mCategory, pos);
ClipData data = ClipData.newPlainText(title, textData);
v.startDrag(data, new MyDragShadowBuilder(v), null, 0);
return true;
}
});
}
private static class MyDragShadowBuilder extends View.DragShadowBuilder {
private static Drawable shadow;
public MyDragShadowBuilder(View v) {
super(v);
shadow = new ColorDrawable(Color.BLUE);
shadow.setBounds(0, 0, v.getWidth(), v.getHeight());
}
@Override
public void onDrawShadow(Canvas canvas) {
shadow.draw(canvas);
}
}
public void populateTitles(int category) {
DirectoryCategory cat = Directory.getCategory(category);
String[] items = new String[cat.getEntryCount()];
for (int i = 0; i < cat.getEntryCount(); i++)
items[i] = cat.getEntry(i).getName();
setListAdapter(new ArrayAdapter<String>(getActivity(),
R.layout.title_list_item, items));
mCategory = category;
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
updateImage(position);
}
private void updateImage(int position) {
ImageView iv = (ImageView) getFragmentManager().findFragmentById(
R.id.frag_content).getView().findViewById(R.id.image);
iv.setImageDrawable(Directory.getCategory(mCategory).getEntry(position)
.getDrawable(getResources()));
mCurPosition = position;
}
public void selectPosition(int position) {
ListView lv = getListView();
lv.setItemChecked(position, true);
updateImage(position);
}
@Override
public void onSaveInstanceState (Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("listPosition", mCurPosition);
outState.putInt("category", mCategory);
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2011 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.example.android.hcgallery.widget;
public class WidgetItem {
public String text;
public WidgetItem(String text) {
this.text = text;
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright (C) 2007 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.example.android.hcgallery.widget;
import com.example.android.hcgallery.R;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.widget.RemoteViews;
import android.widget.Toast;
public class WidgetProvider extends AppWidgetProvider {
public static String TOAST_ACTION = "com.example.android.widget.action.TOAST";
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
super.onDeleted(context, appWidgetIds);
}
@Override
public void onDisabled(Context context) {
super.onDisabled(context);
}
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
}
@Override
public void onReceive(Context context, Intent intent) {
AppWidgetManager mgr = AppWidgetManager.getInstance(context);
if (intent.getAction().equals(TOAST_ACTION)) {
int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
int viewIndex = intent.getIntExtra("numberToToast", 0);
Toast.makeText(context, "Touched view " + viewIndex, Toast.LENGTH_SHORT).show();
}
super.onReceive(context, intent);
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// update each of the widgets with the remote adapter
for (int i = 0; i < appWidgetIds.length; ++i) {
// Here we setup the intent which points to the StackViewService which will
// provide the views for this collection.
Intent intent = new Intent(context, WidgetService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
// When intents are compared, the extras are ignored, so we need to embed the extras
// into the data so that the extras will not be ignored.
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
rv.setRemoteAdapter(appWidgetIds[i], R.id.stack_view, intent);
// The empty view is displayed when the collection has no items. It should be a sibling
// of the collection view.
rv.setEmptyView(R.id.stack_view, R.id.empty_view);
// Here we setup the a pending intent template. Individuals items of a collection
// cannot setup their own pending intents, instead, the collection as a whole can
// setup a pending intent template, and the individual items can set a fillInIntent
// to create unique before on an item to item basis.
Intent toastIntent = new Intent(context, WidgetProvider.class);
toastIntent.setAction(WidgetProvider.TOAST_ACTION);
toastIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
toastIntent.setData(Uri.parse("widgetid" + appWidgetIds[i]));
PendingIntent toastPendingIntent = PendingIntent.getBroadcast(context, 0, toastIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
rv.setPendingIntentTemplate(R.id.stack_view, toastPendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
}

View File

@@ -0,0 +1,136 @@
/*
* Copyright (C) 2007 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.example.android.hcgallery.widget;
import com.example.android.hcgallery.R;
import java.util.ArrayList;
import java.util.List;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.RemoteViewsService;
public class WidgetService extends RemoteViewsService {
private class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
private static final int mCount = 10;
private List<WidgetItem> mWidgetItems = new ArrayList<WidgetItem>();
private Context mContext;
private int mAppWidgetId;
public StackRemoteViewsFactory(Context context, Intent intent) {
mContext = context;
mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
}
public void onCreate() {
// In onCreate() you setup any connections / cursors to your data source. Heavy lifting,
// for example downloading or creating content etc, should be deferred to getViewAt() or
// onDataSetChanged(). Taking more than 20 seconds in this call will result in an ANR.
for (int i = 0; i < mCount; i++) {
mWidgetItems.add(new WidgetItem(i + "!"));
}
// We sleep for 3 seconds here to show how the empty view appears in the interim.
// The empty view is set in the WidgetProvider and should be a sibling of the
// collection view.
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void onDestroy() {
// In onDestroy() you should tear down anything that was setup for your data source,
// eg. cursors, connections, etc.
mWidgetItems.clear();
}
public int getCount() {
return mCount;
}
public RemoteViews getViewAt(int position) {
// position will always range from 0 to getCount() - 1.
// We construct a remote views item based on our widget item xml file, and set the
// text based on the position.
RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_item);
rv.setTextViewText(R.id.widget_item, mWidgetItems.get(position).text);
// Next, we set an intent so that clicking on this view will result in a toast message
Bundle extras = new Bundle();
extras.putInt(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
extras.putInt("numberToToast", position);
Intent fillInIntent = new Intent();
fillInIntent.putExtras(extras);
rv.setOnClickFillInIntent(R.id.widget_item, fillInIntent);
// You can do heaving lifting in here, synchronously. For example, if you need to
// process an image, fetch something from the network, etc., it is ok to do it here,
// synchronously. A loading view will show up in lieu of the actual contents in the
// interim.
try {
Log.d("WidgetService/getViewAt", "Loading view " + position);
// Simulating a time-consuming operation. NO NEED to include this call in your app!
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Return our remote views object.
return rv;
}
public RemoteViews getLoadingView() {
// You can create a custom loading view (for instance when getViewAt() is slow. If you
// return null here, you will get the default loading view.
return null;
}
public int getViewTypeCount() {
return 1;
}
public long getItemId(int position) {
return position;
}
public boolean hasStableIds() {
return true;
}
public void onDataSetChanged() {
// This is triggered when you call AppWidgetManager notifyAppWidgetViewDataChanged
// on the collection view corresponding to this factory. You can do heaving lifting in
// here, synchronously. For example, if you need to process an image, fetch something
// from the network, etc., it is ok to do it here, synchronously. The widget will remain
// in its current state while work is being done here, so you don't need to worry about
// locking up the widget.
}
}
public RemoteViewsFactory onGetViewFactory(Intent intent) {
return new StackRemoteViewsFactory(this.getApplicationContext(), intent);
}
}