Add browseable samples for L SDK release
Change-Id: I71c6ff9a90b7734042d68af7f01e6d61118cc508
diff --git a/samples/browseable/ActivitySceneTransitionBasic/AndroidManifest.xml b/samples/browseable/ActivitySceneTransitionBasic/AndroidManifest.xml
new file mode 100644
index 0000000..ae64d6f
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/AndroidManifest.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.activityscenetransitionbasic"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
+ <application android:allowBackup="true"
+ android:label="@string/app_name"
+ android:icon="@drawable/ic_launcher"
+ android:theme="@style/AppTheme">
+
+ <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>
+
+ <activity android:name=".DetailActivity" />
+
+ </application>
+
+ <uses-permission android:name="android.permission.INTERNET" />
+
+</manifest>
diff --git a/samples/browseable/ActivitySceneTransitionBasic/_index.jd b/samples/browseable/ActivitySceneTransitionBasic/_index.jd
new file mode 100644
index 0000000..1053a7d
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/_index.jd
@@ -0,0 +1,12 @@
+page.tags="ActivitySceneTransitionBasic"
+sample.group=UI
+@jd:body
+
+<p>
+
+ Demonstrates how to the use Activity scene transitions when transitions
+ from one Activity to another. Uses a combination of moveImage and changeBounds
+ to nicely transition a grid of images to an Activity with a large image and detail
+ text.
+
+ </p>
diff --git a/samples/browseable/ActivitySceneTransitionBasic/res/drawable-hdpi/ic_launcher.png b/samples/browseable/ActivitySceneTransitionBasic/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a598447
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ActivitySceneTransitionBasic/res/drawable-hdpi/tile.9.png b/samples/browseable/ActivitySceneTransitionBasic/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/ActivitySceneTransitionBasic/res/drawable-mdpi/ic_launcher.png b/samples/browseable/ActivitySceneTransitionBasic/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..8aaa6c9
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ActivitySceneTransitionBasic/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/ActivitySceneTransitionBasic/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..3667baa
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ActivitySceneTransitionBasic/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/ActivitySceneTransitionBasic/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..e3c4a32
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ActivitySceneTransitionBasic/res/layout/activity_main.xml b/samples/browseable/ActivitySceneTransitionBasic/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/horizontal_page_margin"
+ android:layout_marginRight="@dimen/horizontal_page_margin"
+ android:layout_marginTop="@dimen/vertical_page_margin"
+ android:layout_marginBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/ActivitySceneTransitionBasic/res/layout/details.xml b/samples/browseable/ActivitySceneTransitionBasic/res/layout/details.xml
new file mode 100644
index 0000000..e61212e
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/res/layout/details.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <com.example.android.activityscenetransitionbasic.SquareFrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <com.android.volley.toolbox.NetworkImageView
+ android:id="@+id/imageview_header"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="centerCrop" />
+
+ </com.example.android.activityscenetransitionbasic.SquareFrameLayout>
+
+ <TextView
+ android:id="@+id/textview_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/colorPrimary"
+ android:theme="@android:style/Theme.Material"
+ android:textAppearance="@android:style/TextAppearance.Material.Title"
+ android:maxLines="2"
+ android:padding="16dp" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="16dp"
+ android:text="@string/bacon_ipsum"
+ android:textAppearance="@android:style/TextAppearance.Material.Body1" />
+
+ </LinearLayout>
+
+</ScrollView>
\ No newline at end of file
diff --git a/samples/browseable/ActivitySceneTransitionBasic/res/layout/grid.xml b/samples/browseable/ActivitySceneTransitionBasic/res/layout/grid.xml
new file mode 100644
index 0000000..4dded95
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/res/layout/grid.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<GridView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/grid"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipToPadding="false"
+ android:columnWidth="120dp"
+ android:drawSelectorOnTop="true"
+ android:horizontalSpacing="@dimen/grid_spacing"
+ android:numColumns="auto_fit"
+ android:padding="@dimen/grid_spacing"
+ android:verticalSpacing="@dimen/grid_spacing" />
diff --git a/samples/browseable/ActivitySceneTransitionBasic/res/layout/grid_item.xml b/samples/browseable/ActivitySceneTransitionBasic/res/layout/grid_item.xml
new file mode 100644
index 0000000..1d28dba
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/res/layout/grid_item.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <com.example.android.activityscenetransitionbasic.SquareFrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <com.android.volley.toolbox.NetworkImageView
+ android:id="@+id/imageview_item"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="centerCrop" />
+
+ </com.example.android.activityscenetransitionbasic.SquareFrameLayout>
+
+ <TextView
+ android:id="@+id/textview_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/colorPrimary"
+ android:theme="@android:style/Theme.Material"
+ android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+ android:maxLines="1"
+ android:padding="16dp" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/browseable/ActivitySceneTransitionBasic/res/transition/grid_detail_transition.xml b/samples/browseable/ActivitySceneTransitionBasic/res/transition/grid_detail_transition.xml
new file mode 100644
index 0000000..40be3d4
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/res/transition/grid_detail_transition.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<!--
+ The transitions which us used for the entrance and exit of shared elements. Here we declare
+ two different transitions which are targeting to specific views.
+-->
+<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <!-- changeBounds is used for the TextViews which are shared -->
+ <changeBounds>
+ <!--
+ Set this transitions target IDs to be those which point to the TextViews in both the
+ starting and result Activities
+ -->
+ <targets>
+ <target android:targetId="@id/textview_name" />
+ <target android:targetId="@id/textview_title" />
+ </targets>
+ </changeBounds>
+
+ <!-- moveImage is used for the ImageViews which are shared -->
+ <moveImage>
+ <!--
+ Set this transitions target IDs to be those which point to the ImageViews in both the
+ starting and result Activities
+ -->
+ <targets>
+ <target android:targetId="@id/imageview_header" />
+ <target android:targetId="@id/imageview_item" />
+ </targets>
+ </moveImage>
+
+</transitionSet>
+
+
diff --git a/samples/browseable/ActivitySceneTransitionBasic/res/values-sw600dp/template-dimens.xml b/samples/browseable/ActivitySceneTransitionBasic/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/ActivitySceneTransitionBasic/res/values-sw600dp/template-styles.xml b/samples/browseable/ActivitySceneTransitionBasic/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/ActivitySceneTransitionBasic/res/values-v11/template-styles.xml b/samples/browseable/ActivitySceneTransitionBasic/res/values-v11/template-styles.xml
new file mode 100644
index 0000000..8c1ea66
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/res/values-v11/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/samples/browseable/ActivitySceneTransitionBasic/res/values-v21/styles.xml b/samples/browseable/ActivitySceneTransitionBasic/res/values-v21/styles.xml
new file mode 100644
index 0000000..fd212b3
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/res/values-v21/styles.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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>
+
+ <style name="Theme.Sample" parent="Theme.Base">
+ <!-- Set the windowContentTransitions flag to enable Activity scene transitions -->
+ <item name="android:windowContentTransitions">true</item>
+
+ <!-- Set the transitions which are used for the entrance and exit of shared elements -->
+ <item name="android:windowSharedElementEnterTransition">
+ @transition/grid_detail_transition
+ </item>
+ <item name="android:windowSharedElementExitTransition">
+ @transition/grid_detail_transition
+ </item>
+ </style>
+
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/ActivitySceneTransitionBasic/res/values-v21/template-styles.xml b/samples/browseable/ActivitySceneTransitionBasic/res/values-v21/template-styles.xml
new file mode 100644
index 0000000..134fcd9
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/res/values-v21/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2014 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>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Material.Light" />
+
+</resources>
diff --git a/samples/browseable/ActivitySceneTransitionBasic/res/values/base-strings.xml b/samples/browseable/ActivitySceneTransitionBasic/res/values/base-strings.xml
new file mode 100644
index 0000000..989fe00
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/res/values/base-strings.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">ActivitySceneTransitionBasic</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ Demonstrates how to the use Activity scene transitions when transitions
+ from one Activity to another. Uses a combination of moveImage and changeBounds
+ to nicely transition a grid of images to an Activity with a large image and detail
+ text.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/ActivitySceneTransitionBasic/res/values/dimens.xml b/samples/browseable/ActivitySceneTransitionBasic/res/values/dimens.xml
new file mode 100644
index 0000000..b8e2e56
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/res/values/dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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="grid_spacing">4dp</dimen>
+
+</resources>
diff --git a/samples/browseable/ActivitySceneTransitionBasic/res/values/strings.xml b/samples/browseable/ActivitySceneTransitionBasic/res/values/strings.xml
new file mode 100644
index 0000000..2aa0d3b
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/res/values/strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="bacon_ipsum">
+ Bacon ipsum dolor sit amet venison shankle pork chop meatball tri-tip beef ribs turducken.
+ Strip steak ball tip boudin shank, turducken leberkas pork chop beef ribs ham hock sausage
+ frankfurter prosciutto doner ham. Bacon landjaeger ball tip, andouille chuck beef ribs jowl
+ kevin tri-tip turkey biltong frankfurter sausage. Boudin pork belly meatloaf chicken cow
+ tri-tip kielbasa shoulder. Pork loin pig boudin hamburger pastrami short ribs. Sirloin
+ tongue pork loin chicken spare ribs bresaola pastrami.\n\n
+ Tenderloin turducken pork chop, pork belly beef ribs brisket ham. Turducken landjaeger short
+ loin capicola pancetta pork chop strip steak rump meatloaf brisket kevin doner short ribs
+ salami. Beef prosciutto flank leberkas landjaeger swine. Fatback prosciutto sausage, jerky
+ tail tongue hamburger jowl biltong shank pork belly swine filet mignon chicken ground round.
+ Pork chop porchetta ground round tri-tip tail t-bone.\n\n
+ Landjaeger rump bacon salami sausage pork loin pig brisket strip steak corned beef. Biltong
+ sirloin meatloaf ribeye, bresaola cow chicken t-bone frankfurter andouille strip steak jerky
+ capicola. Ribeye porchetta strip steak boudin. Kielbasa cow brisket pastrami ball tip
+ tenderloin bresaola ham. Biltong andouille chuck ham hock jerky beef chicken, flank shankle
+ ball tip venison porchetta kevin fatback kielbasa. Boudin tongue ground round, turkey pork
+ belly salami corned beef pork tri-tip meatloaf sausage andouille strip steak pig. Spare ribs
+ beef meatloaf rump sausage doner frankfurter.\n\n
+ Fatback porchetta pork loin meatball, turducken pork chop drumstick boudin. Kevin tri-tip
+ ground round corned beef, ribeye swine filet mignon salami pork spare ribs pork chop
+ brisket. Filet mignon shankle t-bone bacon. Turducken capicola turkey porchetta kielbasa
+ shank pork loin jerky venison tenderloin boudin ham hock ground round.</string>
+
+ <string name="image_header">%1$s by %2$s</string>
+
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/ActivitySceneTransitionBasic/res/values/template-dimens.xml b/samples/browseable/ActivitySceneTransitionBasic/res/values/template-dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/ActivitySceneTransitionBasic/res/values/template-styles.xml b/samples/browseable/ActivitySceneTransitionBasic/res/values/template-styles.xml
new file mode 100644
index 0000000..6e7d593
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.activityscenetransitionbasic/DetailActivity.java b/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.activityscenetransitionbasic/DetailActivity.java
new file mode 100644
index 0000000..741cd26
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.activityscenetransitionbasic/DetailActivity.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2014 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.activityscenetransitionbasic;
+
+import com.android.volley.toolbox.ImageLoader;
+import com.android.volley.toolbox.NetworkImageView;
+import com.android.volley.toolbox.Volley;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.widget.TextView;
+
+/**
+ * Our secondary Activity which is launched from {@link MainActivity}. Has a simple detail UI
+ * which has a large banner image, title and body text.
+ */
+public class DetailActivity extends Activity {
+
+ // Extra name for the ID parameter
+ public static final String EXTRA_PARAM_ID = "detail:_id";
+
+ // View name of the header image. Used for activity scene transitions
+ public static final String VIEW_NAME_HEADER_IMAGE = "detail:header:image";
+
+ // View name of the header title. Used for activity scene transitions
+ public static final String VIEW_NAME_HEADER_TITLE = "detail:header:title";
+
+ private NetworkImageView mHeaderImageView;
+ private TextView mHeaderTitle;
+
+ private ImageLoader mImageLoader;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.details);
+
+ // Construct an ImageLoader instance so that we can load images from the network
+ mImageLoader = new ImageLoader(Volley.newRequestQueue(this), ImageMemoryCache.INSTANCE);
+
+ // Retrieve the correct Item instance, using the ID provided in the Intent
+ Item item = Item.getItem(getIntent().getIntExtra(EXTRA_PARAM_ID, 0));
+
+ mHeaderImageView = (NetworkImageView) findViewById(R.id.imageview_header);
+ mHeaderTitle = (TextView) findViewById(R.id.textview_title);
+
+ // BEGIN_INCLUDE(detail_set_view_name)
+ /**
+ * Set the name of the view's which will be transition to, using the static values above.
+ * This could be done in the layout XML, but exposing it via static variables allows easy
+ * querying from other Activities
+ */
+ mHeaderImageView.setViewName(VIEW_NAME_HEADER_IMAGE);
+ mHeaderTitle.setViewName(VIEW_NAME_HEADER_TITLE);
+ // END_INCLUDE(detail_set_view_name)
+
+ loadItem(item);
+ }
+
+ private void loadItem(Item item) {
+ // Set the title TextView to the item's name and author
+ mHeaderTitle.setText(getString(R.string.image_header, item.getName(), item.getAuthor()));
+
+ final ImageMemoryCache cache = ImageMemoryCache.INSTANCE;
+ Bitmap thumbnailImage = cache.getBitmapFromUrl(item.getThumbnailUrl());
+
+ // Check to see if we already have the thumbnail sized image in the cache. If so, start
+ // loading the full size image and display the thumbnail as a placeholder.
+ if (thumbnailImage != null) {
+ mHeaderImageView.setImageUrl(item.getPhotoUrl(), mImageLoader);
+ mHeaderImageView.setImageBitmap(thumbnailImage);
+ return;
+ }
+
+ // If we get here then we do not have either the full size or the thumbnail in the cache.
+ // Here we just load the full size and make do.
+ mHeaderImageView.setImageUrl(item.getPhotoUrl(), mImageLoader);
+ }
+
+}
diff --git a/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.activityscenetransitionbasic/ImageMemoryCache.java b/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.activityscenetransitionbasic/ImageMemoryCache.java
new file mode 100644
index 0000000..53d47ba
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.activityscenetransitionbasic/ImageMemoryCache.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 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.activityscenetransitionbasic;
+
+import com.android.volley.toolbox.ImageLoader;
+
+import android.graphics.Bitmap;
+import android.util.LruCache;
+
+import java.util.Map;
+
+/**
+ * An image memory cache implementation for Volley which allows the retrieval of entires via a URL.
+ * Volley internally inserts items with a key which is a combination of a the size of the image,
+ * and the url.
+ *
+ * This class provide the method {@link #getBitmapFromUrl(String)} which allows the retrieval of
+ * a bitmap solely on the URL.
+ */
+public class ImageMemoryCache extends LruCache<String, Bitmap> implements ImageLoader.ImageCache {
+
+ /**
+ * Singleton instance which has it's maximum size set to be 1/8th of the allowed memory size.
+ */
+ public static final ImageMemoryCache INSTANCE = new ImageMemoryCache(
+ (int) (Runtime.getRuntime().maxMemory() / 8));
+
+ // Cache the last created snapshot
+ private Map<String, Bitmap> mLastSnapshot;
+
+ private ImageMemoryCache(int maxSize) {
+ super(maxSize);
+ }
+
+ public Bitmap getBitmapFromUrl(String url) {
+ // If we do not have a snapshot to use, generate one
+ if (mLastSnapshot == null) {
+ mLastSnapshot = snapshot();
+ }
+
+ // Iterate through the snapshot to find any entries which match our url
+ for (Map.Entry<String, Bitmap> entry : mLastSnapshot.entrySet()) {
+ if (url.equals(extractUrl(entry.getKey()))) {
+ // We've found an entry with the same url, return the bitmap
+ return entry.getValue();
+ }
+ }
+
+ // We didn't find an entry, so return null
+ return null;
+ }
+
+ @Override
+ public Bitmap getBitmap(String key) {
+ return get(key);
+ }
+
+ @Override
+ public void putBitmap(String key, Bitmap bitmap) {
+ put(key, bitmap);
+
+ // An entry has been added, so invalidate the snapshot
+ mLastSnapshot = null;
+ }
+
+ @Override
+ protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
+ super.entryRemoved(evicted, key, oldValue, newValue);
+
+ // An entry has been removed, so invalidate the snapshot
+ mLastSnapshot = null;
+ }
+
+ private static String extractUrl(String key) {
+ return key.substring(key.indexOf("http"));
+ }
+
+ @Override
+ protected int sizeOf(String key, Bitmap value) {
+ return value.getAllocationByteCount();
+ }
+}
diff --git a/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.activityscenetransitionbasic/Item.java b/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.activityscenetransitionbasic/Item.java
new file mode 100644
index 0000000..e211886
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.activityscenetransitionbasic/Item.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 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.activityscenetransitionbasic;
+
+/**
+ * Represents an Item in our application. Each item has a name, id, full size image url and
+ * thumbnail url.
+ */
+public class Item {
+
+ private static final String LARGE_BASE_URL = "http://storage.googleapis.com/androiddevelopers/sample_data/activity_transition/large/";
+ private static final String THUMB_BASE_URL = "http://storage.googleapis.com/androiddevelopers/sample_data/activity_transition/thumbs/";
+
+ public static Item[] ITEMS = new Item[] {
+ new Item("Flying in the Light", "Romain Guy", "flying_in_the_light.jpg"),
+ new Item("Caterpillar", "Romain Guy", "caterpillar.jpg"),
+ new Item("Look Me in the Eye", "Romain Guy", "look_me_in_the_eye.jpg"),
+ new Item("Flamingo", "Romain Guy", "flamingo.jpg"),
+ new Item("Rainbow", "Romain Guy", "rainbow.jpg"),
+ new Item("Over there", "Romain Guy", "over_there.jpg"),
+ new Item("Jelly Fish 2", "Romain Guy", "jelly_fish_2.jpg"),
+ new Item("Lone Pine Sunset", "Romain Guy", "lone_pine_sunset.jpg"),
+ };
+
+ public static Item getItem(int id) {
+ for (Item item : ITEMS) {
+ if (item.getId() == id) {
+ return item;
+ }
+ }
+ return null;
+ }
+
+ private final String mName;
+ private final String mAuthor;
+ private final String mFileName;
+
+ Item (String name, String author, String fileName) {
+ mName = name;
+ mAuthor = author;
+ mFileName = fileName;
+ }
+
+ public int getId() {
+ return mName.hashCode() + mFileName.hashCode();
+ }
+
+ public String getAuthor() {
+ return mAuthor;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public String getPhotoUrl() {
+ return LARGE_BASE_URL + mFileName;
+ }
+
+ public String getThumbnailUrl() {
+ return THUMB_BASE_URL + mFileName;
+ }
+
+}
diff --git a/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.activityscenetransitionbasic/MainActivity.java b/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.activityscenetransitionbasic/MainActivity.java
new file mode 100644
index 0000000..3630990
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.activityscenetransitionbasic/MainActivity.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2014 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.activityscenetransitionbasic;
+
+import com.android.volley.toolbox.ImageLoader;
+import com.android.volley.toolbox.NetworkImageView;
+import com.android.volley.toolbox.Volley;
+
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Pair;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.GridView;
+import android.widget.TextView;
+
+/**
+ * Our main Activity in this sample. Displays a grid of items which an image and title. When the
+ * user clicks on an item, {@link DetailActivity} is launched, using the Activity Scene Transitions
+ * framework to animatedly do so.
+ */
+public class MainActivity extends Activity implements AdapterView.OnItemClickListener {
+
+ private GridView mGridView;
+ private GridAdapter mAdapter;
+
+ private ImageLoader mImageLoader;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.grid);
+
+ // Retrieve the ImageLoader we are going to use for NetworkImageView
+ mImageLoader = new ImageLoader(Volley.newRequestQueue(this), ImageMemoryCache.INSTANCE);
+
+ // Setup the GridView and set the adapter
+ mGridView = (GridView) findViewById(R.id.grid);
+ mGridView.setOnItemClickListener(this);
+ mAdapter = new GridAdapter();
+ mGridView.setAdapter(mAdapter);
+ }
+
+ /**
+ * Called when an item in the {@link android.widget.GridView} is clicked. Here will launch the
+ * {@link DetailActivity}, using the Scene Transition animation functionality.
+ */
+ @Override
+ public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
+ Item item = (Item) adapterView.getItemAtPosition(position);
+
+ // Construct an Intent as normal
+ Intent intent = new Intent(this, DetailActivity.class);
+ intent.putExtra(DetailActivity.EXTRA_PARAM_ID, item.getId());
+
+ // BEGIN_INCLUDE(start_activity)
+ /**
+ * Now create an {@link android.app.ActivityOptions} instance using the
+ * {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.app.Activity, android.util.Pair[])} factory method.
+ */
+ ActivityOptions activityOptions = ActivityOptions.makeSceneTransitionAnimation(
+ this,
+
+ // Now we provide a list of Pair items which contain the view we can transitioning
+ // from, and the name of the view it is transitioning to, in the launched activity
+ new Pair<View, String>(
+ view.findViewById(R.id.imageview_item),
+ DetailActivity.VIEW_NAME_HEADER_IMAGE),
+ new Pair<View, String>(
+ view.findViewById(R.id.textview_name),
+ DetailActivity.VIEW_NAME_HEADER_TITLE)
+ );
+
+ // Now we can start the Activity, providing the activity options as a bundle
+ startActivity(intent, activityOptions.toBundle());
+ // END_INCLUDE(start_activity)
+ }
+
+ /**
+ * {@link android.widget.BaseAdapter} which displays items.
+ */
+ private class GridAdapter extends BaseAdapter {
+
+ @Override
+ public int getCount() {
+ return Item.ITEMS.length;
+ }
+
+ @Override
+ public Item getItem(int position) {
+ return Item.ITEMS[position];
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return getItem(position).getId();
+ }
+
+ @Override
+ public View getView(int position, View view, ViewGroup viewGroup) {
+ if (view == null) {
+ view = getLayoutInflater().inflate(R.layout.grid_item, viewGroup, false);
+ }
+
+ final Item item = getItem(position);
+
+ // Load the thumbnail image
+ NetworkImageView image = (NetworkImageView) view.findViewById(R.id.imageview_item);
+ image.setImageUrl(item.getThumbnailUrl(), mImageLoader);
+
+ // Set the TextView's contents
+ TextView name = (TextView) view.findViewById(R.id.textview_name);
+ name.setText(item.getName());
+
+ // BEGIN_INCLUDE(grid_set_view_name)
+ /**
+ * As we're in an adapter we need to set each view's name dynamically, using the
+ * item's ID so that the names are unique.
+ */
+ image.setViewName("grid:image:" + item.getId());
+ name.setViewName("grid:name:" + item.getId());
+ // END_INCLUDE(grid_set_view_name)
+
+ return view;
+ }
+ }
+}
diff --git a/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.activityscenetransitionbasic/SquareFrameLayout.java b/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.activityscenetransitionbasic/SquareFrameLayout.java
new file mode 100644
index 0000000..eece73e
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.activityscenetransitionbasic/SquareFrameLayout.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 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.activityscenetransitionbasic;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+/**
+ * {@link android.widget.FrameLayout} which forces itself to be laid out as square.
+ */
+public class SquareFrameLayout extends FrameLayout {
+
+ public SquareFrameLayout(Context context) {
+ super(context);
+ }
+
+ public SquareFrameLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public SquareFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public SquareFrameLayout(Context context, AttributeSet attrs,
+ int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+ final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+
+ if (widthSize == 0 && heightSize == 0) {
+ // If there are no constraints on size, let FrameLayout measure
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ // Now use the smallest of the measured dimensions for both dimensions
+ final int minSize = Math.min(getMeasuredWidth(), getMeasuredHeight());
+ setMeasuredDimension(minSize, minSize);
+ return;
+ }
+
+ final int size;
+ if (widthSize == 0 || heightSize == 0) {
+ // If one of the dimensions has no restriction on size, set both dimensions to be the
+ // on that does
+ size = Math.max(widthSize, heightSize);
+ } else {
+ // Both dimensions have restrictions on size, set both dimensions to be the
+ // smallest of the two
+ size = Math.min(widthSize, heightSize);
+ }
+
+ final int newMeasureSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
+ super.onMeasure(newMeasureSpec, newMeasureSpec);
+ }
+}
diff --git a/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.common.logger/Log.java b/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.common.logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.common.logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+ // Grabbing the native values from Android's native logging facilities,
+ // to make for easy migration and interop.
+ public static final int NONE = -1;
+ public static final int VERBOSE = android.util.Log.VERBOSE;
+ public static final int DEBUG = android.util.Log.DEBUG;
+ public static final int INFO = android.util.Log.INFO;
+ public static final int WARN = android.util.Log.WARN;
+ public static final int ERROR = android.util.Log.ERROR;
+ public static final int ASSERT = android.util.Log.ASSERT;
+
+ // Stores the beginning of the LogNode topology.
+ private static LogNode mLogNode;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public static LogNode getLogNode() {
+ return mLogNode;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to.
+ */
+ public static void setLogNode(LogNode node) {
+ mLogNode = node;
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void println(int priority, String tag, String msg, Throwable tr) {
+ if (mLogNode != null) {
+ mLogNode.println(priority, tag, msg, tr);
+ }
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ */
+ public static void println(int priority, String tag, String msg) {
+ println(priority, tag, msg, null);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void v(String tag, String msg, Throwable tr) {
+ println(VERBOSE, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void v(String tag, String msg) {
+ v(tag, msg, null);
+ }
+
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void d(String tag, String msg, Throwable tr) {
+ println(DEBUG, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void d(String tag, String msg) {
+ d(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void i(String tag, String msg, Throwable tr) {
+ println(INFO, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void i(String tag, String msg) {
+ i(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, String msg, Throwable tr) {
+ println(WARN, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void w(String tag, String msg) {
+ w(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, Throwable tr) {
+ w(tag, null, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void e(String tag, String msg, Throwable tr) {
+ println(ERROR, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void e(String tag, String msg) {
+ e(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, String msg, Throwable tr) {
+ println(ASSERT, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void wtf(String tag, String msg) {
+ wtf(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, Throwable tr) {
+ wtf(tag, null, tr);
+ }
+}
diff --git a/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.common.logger/LogFragment.java b/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.common.logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.common.logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+ private LogView mLogView;
+ private ScrollView mScrollView;
+
+ public LogFragment() {}
+
+ public View inflateViews() {
+ mScrollView = new ScrollView(getActivity());
+ ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ mScrollView.setLayoutParams(scrollParams);
+
+ mLogView = new LogView(getActivity());
+ ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+ logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ mLogView.setLayoutParams(logParams);
+ mLogView.setClickable(true);
+ mLogView.setFocusable(true);
+ mLogView.setTypeface(Typeface.MONOSPACE);
+
+ // Want to set padding as 16 dips, setPadding takes pixels. Hooray math!
+ int paddingDips = 16;
+ double scale = getResources().getDisplayMetrics().density;
+ int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+ mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+ mLogView.setCompoundDrawablePadding(paddingPixels);
+
+ mLogView.setGravity(Gravity.BOTTOM);
+ mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+ mScrollView.addView(mLogView);
+ return mScrollView;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ View result = inflateViews();
+
+ mLogView.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+ }
+ });
+ return result;
+ }
+
+ public LogView getLogView() {
+ return mLogView;
+ }
+}
\ No newline at end of file
diff --git a/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.common.logger/LogNode.java b/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.common.logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.common.logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 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.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+ /**
+ * Instructs first LogNode in the list to print the log data provided.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.common.logger/LogView.java b/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.common.logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.common.logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+ public LogView(Context context) {
+ super(context);
+ }
+
+ public LogView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public LogView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * Formats the log data and prints it out to the LogView.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+
+
+ String priorityStr = null;
+
+ // For the purposes of this View, we want to print the priority as readable text.
+ switch(priority) {
+ case android.util.Log.VERBOSE:
+ priorityStr = "VERBOSE";
+ break;
+ case android.util.Log.DEBUG:
+ priorityStr = "DEBUG";
+ break;
+ case android.util.Log.INFO:
+ priorityStr = "INFO";
+ break;
+ case android.util.Log.WARN:
+ priorityStr = "WARN";
+ break;
+ case android.util.Log.ERROR:
+ priorityStr = "ERROR";
+ break;
+ case android.util.Log.ASSERT:
+ priorityStr = "ASSERT";
+ break;
+ default:
+ break;
+ }
+
+ // Handily, the Log class has a facility for converting a stack trace into a usable string.
+ String exceptionStr = null;
+ if (tr != null) {
+ exceptionStr = android.util.Log.getStackTraceString(tr);
+ }
+
+ // Take the priority, tag, message, and exception, and concatenate as necessary
+ // into one usable line of text.
+ final StringBuilder outputBuilder = new StringBuilder();
+
+ String delimiter = "\t";
+ appendIfNotNull(outputBuilder, priorityStr, delimiter);
+ appendIfNotNull(outputBuilder, tag, delimiter);
+ appendIfNotNull(outputBuilder, msg, delimiter);
+ appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+ // In case this was originally called from an AsyncTask or some other off-UI thread,
+ // make sure the update occurs within the UI thread.
+ ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+ @Override
+ public void run() {
+ // Display the text we just generated within the LogView.
+ appendToLog(outputBuilder.toString());
+ }
+ })));
+
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+ * the logger takes so many arguments that might be null, this method helps cut out some of the
+ * agonizing tedium of writing the same 3 lines over and over.
+ * @param source StringBuilder containing the text to append to.
+ * @param addStr The String to append
+ * @param delimiter The String to separate the source and appended strings. A tab or comma,
+ * for instance.
+ * @return The fully concatenated String as a StringBuilder
+ */
+ private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+ if (addStr != null) {
+ if (addStr.length() == 0) {
+ delimiter = "";
+ }
+
+ return source.append(addStr).append(delimiter);
+ }
+ return source;
+ }
+
+ // The next LogNode in the chain.
+ LogNode mNext;
+
+ /** Outputs the string as a new line of log data in the LogView. */
+ public void appendToLog(String s) {
+ append("\n" + s);
+ }
+
+
+}
diff --git a/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.common.logger/LogWrapper.java b/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.common.logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.common.logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 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.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface. This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+ // For piping: The next node to receive Log data after this one has done its work.
+ private LogNode mNext;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /**
+ * Prints data out to the console using Android's native log mechanism.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ // There actually are log methods that don't take a msg parameter. For now,
+ // if that's the case, just convert null to the empty string and move on.
+ String useMsg = msg;
+ if (useMsg == null) {
+ useMsg = "";
+ }
+
+ // If an exeption was provided, convert that exception to a usable string and attach
+ // it to the end of the msg method.
+ if (tr != null) {
+ msg += "\n" + Log.getStackTraceString(tr);
+ }
+
+ // This is functionally identical to Log.x(tag, useMsg);
+ // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+ Log.println(priority, tag, useMsg);
+
+ // If this isn't the last node in the chain, move things along.
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+}
diff --git a/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.common.logger/MessageOnlyLogFilter.java b/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.common.logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/ActivitySceneTransitionBasic/src/com.example.android.common.logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+ LogNode mNext;
+
+ /**
+ * Takes the "next" LogNode as a parameter, to simplify chaining.
+ *
+ * @param next The next LogNode in the pipeline.
+ */
+ public MessageOnlyLogFilter(LogNode next) {
+ mNext = next;
+ }
+
+ public MessageOnlyLogFilter() {
+ }
+
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ if (mNext != null) {
+ getNext().println(Log.NONE, null, msg, null);
+ }
+ }
+
+ /**
+ * Returns the next LogNode in the chain.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+}
diff --git a/samples/browseable/AppRestrictionEnforcer/AndroidManifest.xml b/samples/browseable/AppRestrictionEnforcer/AndroidManifest.xml
new file mode 100644
index 0000000..c66b4b3
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/AndroidManifest.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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.apprestrictionenforcer"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <application
+ android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme">
+
+ <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>
+
+ <activity
+ android:name=".EnableProfileActivity"
+ android:label="@string/app_name" />
+
+ <receiver
+ android:name=".EnforcerDeviceAdminReceiver"
+ android:description="@string/app_name"
+ android:label="@string/app_name"
+ android:permission="android.permission.BIND_DEVICE_ADMIN">
+ <meta-data
+ android:name="android.app.device_admin"
+ android:resource="@xml/enforcer_device_admin_receiver"/>
+ <intent-filter>
+ <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
+ </intent-filter>
+ </receiver>
+
+ </application>
+
+
+</manifest>
diff --git a/samples/browseable/AppRestrictionEnforcer/_index.jd b/samples/browseable/AppRestrictionEnforcer/_index.jd
new file mode 100644
index 0000000..f25084a
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/_index.jd
@@ -0,0 +1,10 @@
+page.tags="AppRestrictionEnforcer"
+sample.group=Admin
+@jd:body
+
+<p>
+
+ This sample demonstrates how to set restrictions to other apps as a profile owner.
+ Use AppRestrictionSchema sample as a app with available restrictions.
+
+ </p>
diff --git a/samples/browseable/AppRestrictionEnforcer/res/drawable-hdpi/ic_launcher.png b/samples/browseable/AppRestrictionEnforcer/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..e7bd161
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictionEnforcer/res/drawable-hdpi/tile.9.png b/samples/browseable/AppRestrictionEnforcer/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/AppRestrictionEnforcer/res/drawable-mdpi/ic_launcher.png b/samples/browseable/AppRestrictionEnforcer/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..4c42c9c
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictionEnforcer/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/AppRestrictionEnforcer/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..3ec3368
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictionEnforcer/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/AppRestrictionEnforcer/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..730f80c
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictionEnforcer/res/layout/activity_main.xml b/samples/browseable/AppRestrictionEnforcer/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/horizontal_page_margin"
+ android:layout_marginRight="@dimen/horizontal_page_margin"
+ android:layout_marginTop="@dimen/vertical_page_margin"
+ android:layout_marginBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/AppRestrictionEnforcer/res/layout/activity_main_real.xml b/samples/browseable/AppRestrictionEnforcer/res/layout/activity_main_real.xml
new file mode 100644
index 0000000..d36c2b6
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/res/layout/activity_main_real.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <FrameLayout
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/vertical_page_margin"
+ android:layout_marginLeft="@dimen/horizontal_page_margin"
+ android:layout_marginRight="@dimen/horizontal_page_margin"
+ android:layout_marginTop="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/browseable/AppRestrictionEnforcer/res/layout/fragment_app_restriction_enforcer.xml b/samples/browseable/AppRestrictionEnforcer/res/layout/fragment_app_restriction_enforcer.xml
new file mode 100644
index 0000000..e6c50a2
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/res/layout/fragment_app_restriction_enforcer.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/vertical_page_margin"
+ android:paddingLeft="@dimen/horizontal_page_margin"
+ android:paddingRight="@dimen/horizontal_page_margin"
+ android:paddingTop="@dimen/vertical_page_margin">
+
+ <TextView
+ android:id="@+id/status"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/status_not_installed" />
+
+ <Button
+ android:id="@+id/unhide"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/unhide" />
+
+ <Switch
+ android:id="@+id/say_hello"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/allow_saying_hello" />
+
+</LinearLayout>
diff --git a/samples/browseable/AppRestrictionEnforcer/res/layout/fragment_setup_profile.xml b/samples/browseable/AppRestrictionEnforcer/res/layout/fragment_setup_profile.xml
new file mode 100644
index 0000000..e9e9fe8
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/res/layout/fragment_setup_profile.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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.
+-->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context="com.example.android.basicmanagedprofile.MainActivity.MainFragment">
+
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/vertical_page_margin"
+ android:paddingLeft="@dimen/horizontal_page_margin"
+ android:paddingRight="@dimen/horizontal_page_margin"
+ android:paddingTop="@dimen/vertical_page_margin">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/setup_profile_message" />
+
+ <Button
+ android:id="@+id/set_up_profile"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/set_up_profile" />
+
+ </LinearLayout>
+
+</ScrollView>
diff --git a/samples/browseable/AppRestrictionEnforcer/res/values-sw600dp/template-dimens.xml b/samples/browseable/AppRestrictionEnforcer/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/AppRestrictionEnforcer/res/values-sw600dp/template-styles.xml b/samples/browseable/AppRestrictionEnforcer/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/AppRestrictionEnforcer/res/values-v11/template-styles.xml b/samples/browseable/AppRestrictionEnforcer/res/values-v11/template-styles.xml
new file mode 100644
index 0000000..8c1ea66
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/res/values-v11/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/samples/browseable/AppRestrictionEnforcer/res/values-v21/template-styles.xml b/samples/browseable/AppRestrictionEnforcer/res/values-v21/template-styles.xml
new file mode 100644
index 0000000..134fcd9
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/res/values-v21/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2014 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>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Material.Light" />
+
+</resources>
diff --git a/samples/browseable/AppRestrictionEnforcer/res/values/base-strings.xml b/samples/browseable/AppRestrictionEnforcer/res/values/base-strings.xml
new file mode 100644
index 0000000..1dc6cf9
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/res/values/base-strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">AppRestrictionEnforcer</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ This sample demonstrates how to set restrictions to other apps as a profile owner.
+ Use AppRestrictionSchema sample as a app with available restrictions.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/AppRestrictionEnforcer/res/values/strings.xml b/samples/browseable/AppRestrictionEnforcer/res/values/strings.xml
new file mode 100644
index 0000000..3029e04
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/res/values/strings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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="setup_profile_message">This app is currently not a profile owner.</string>
+ <string name="set_up_profile">Set up profile</string>
+ <string name="status_not_installed">AppRestrictionsSchema is not installed.</string>
+ <string name="status_not_activated">AppRestrictionsSchema is installed, but not activated in this profile.</string>
+ <string name="status_need_reinstall">AppRestrictionSchema needs reinstalling.</string>
+ <string name="unhide">Activate AppRestrictionSchema</string>
+ <string name="allow_saying_hello">Allow AppRestrictionSchema to say hello: </string>
+ <string name="allowed">Allowed</string>
+ <string name="disallowed">Disallowed</string>
+ <string name="profile_name">AppRestrictionEnforcer </string>
+</resources>
diff --git a/samples/browseable/AppRestrictionEnforcer/res/values/template-dimens.xml b/samples/browseable/AppRestrictionEnforcer/res/values/template-dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/AppRestrictionEnforcer/res/values/template-styles.xml b/samples/browseable/AppRestrictionEnforcer/res/values/template-styles.xml
new file mode 100644
index 0000000..6e7d593
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/AppRestrictionEnforcer/res/xml/enforcer_device_admin_receiver.xml b/samples/browseable/AppRestrictionEnforcer/res/xml/enforcer_device_admin_receiver.xml
new file mode 100644
index 0000000..5e084c6
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/res/xml/enforcer_device_admin_receiver.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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.
+-->
+<device-admin>
+ <uses-policies>
+ <limit-password />
+ <watch-login />
+ <reset-password />
+ <force-lock />
+ <wipe-data />
+ <expire-password />
+ <encrypted-storage />
+ </uses-policies>
+</device-admin>
diff --git a/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/AppRestrictionEnforcerFragment.java b/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/AppRestrictionEnforcerFragment.java
new file mode 100644
index 0000000..6db54f6
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/AppRestrictionEnforcerFragment.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2014 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.apprestrictionenforcer;
+
+import android.app.Activity;
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.content.RestrictionEntry;
+import android.content.RestrictionsManager;
+import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.CompoundButton;
+import android.widget.Switch;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.util.List;
+
+/**
+ * This fragment provides UI and functionality to set restrictions on the AppRestrictionSchema
+ * sample.
+ */
+public class AppRestrictionEnforcerFragment extends Fragment implements View.OnClickListener,
+ CompoundButton.OnCheckedChangeListener {
+
+ /**
+ * Package name of the AppRestrictionSchema sample.
+ */
+ private static final String PACKAGE_NAME_APP_RESTRICTION_SCHEMA
+ = "com.example.android.apprestrictionschema";
+
+ /**
+ * Key for {@link SharedPreferences}
+ */
+ private static final String PREFS_KEY = "AppRestrictionEnforcerFragment";
+
+ /**
+ * Key for the boolean restriction in AppRestrictionSchema.
+ */
+ private static final String RESTRICTION_KEY_SAY_HELLO = "can_say_hello";
+
+ /**
+ * Default boolean value for "can_say_hello" restriction. The actual value is loaded in
+ * {@link #loadRestrictions(android.app.Activity)}.
+ */
+ private boolean mDefaultValueRestrictionSayHello;
+
+ // UI Components
+ private TextView mTextStatus;
+ private Button mButtonUnhide;
+ private Switch mSwitchSayHello;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_app_restriction_enforcer, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ mTextStatus = (TextView) view.findViewById(R.id.status);
+ mButtonUnhide = (Button) view.findViewById(R.id.unhide);
+ mSwitchSayHello = (Switch) view.findViewById(R.id.say_hello);
+ mButtonUnhide.setOnClickListener(this);
+ mSwitchSayHello.setOnCheckedChangeListener(this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ updateUi(getActivity());
+ }
+
+ @Override
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.unhide: {
+ unhideApp(getActivity());
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
+ switch (compoundButton.getId()) {
+ case R.id.say_hello: {
+ allowSayHello(getActivity(), checked);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Updates the UI components according to the current status of AppRestrictionSchema and its
+ * restriction.
+ *
+ * @param activity The activity
+ */
+ private void updateUi(Activity activity) {
+ PackageManager packageManager = activity.getPackageManager();
+ try {
+ ApplicationInfo info = packageManager.getApplicationInfo(
+ PACKAGE_NAME_APP_RESTRICTION_SCHEMA, PackageManager.GET_UNINSTALLED_PACKAGES);
+ DevicePolicyManager devicePolicyManager =
+ (DevicePolicyManager) activity.getSystemService(Activity.DEVICE_POLICY_SERVICE);
+ if (0 < (info.flags & ApplicationInfo.FLAG_INSTALLED)) {
+ if (!devicePolicyManager.isApplicationHidden(
+ EnforcerDeviceAdminReceiver.getComponentName(activity),
+ PACKAGE_NAME_APP_RESTRICTION_SCHEMA)) {
+ // The app is ready
+ loadRestrictions(activity);
+ mTextStatus.setVisibility(View.GONE);
+ mButtonUnhide.setVisibility(View.GONE);
+ mSwitchSayHello.setVisibility(View.VISIBLE);
+ mSwitchSayHello.setOnCheckedChangeListener(null);
+ mSwitchSayHello.setChecked(canSayHello(activity));
+ mSwitchSayHello.setOnCheckedChangeListener(this);
+ } else {
+ // The app is installed but hidden in this profile
+ mTextStatus.setText(R.string.status_not_activated);
+ mTextStatus.setVisibility(View.VISIBLE);
+ mButtonUnhide.setVisibility(View.VISIBLE);
+ mSwitchSayHello.setVisibility(View.GONE);
+ }
+ } else {
+ // Need to reinstall the sample app
+ mTextStatus.setText(R.string.status_need_reinstall);
+ mTextStatus.setVisibility(View.VISIBLE);
+ mButtonUnhide.setVisibility(View.GONE);
+ mSwitchSayHello.setVisibility(View.GONE);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ mTextStatus.setText(R.string.status_not_installed);
+ mTextStatus.setVisibility(View.VISIBLE);
+ mButtonUnhide.setVisibility(View.GONE);
+ mSwitchSayHello.setVisibility(View.GONE);
+ }
+ }
+
+ /**
+ * Unhides the AppRestrictionSchema sample in case it is hidden in this profile.
+ *
+ * @param activity The activity
+ */
+ private void unhideApp(Activity activity) {
+ DevicePolicyManager devicePolicyManager =
+ (DevicePolicyManager) activity.getSystemService(Activity.DEVICE_POLICY_SERVICE);
+ devicePolicyManager.setApplicationHidden(
+ EnforcerDeviceAdminReceiver.getComponentName(activity),
+ PACKAGE_NAME_APP_RESTRICTION_SCHEMA, false);
+ Toast.makeText(activity, "Enabled the app", Toast.LENGTH_SHORT).show();
+ updateUi(activity);
+ }
+
+ /**
+ * Loads the restrictions for the AppRestrictionSchema sample. In this implementation, we just
+ * read the default value for the "can_say_hello" restriction.
+ *
+ * @param activity The activity
+ */
+ private void loadRestrictions(Activity activity) {
+ RestrictionsManager restrictionsManager =
+ (RestrictionsManager) activity.getSystemService(Context.RESTRICTIONS_SERVICE);
+ List<RestrictionEntry> restrictions =
+ restrictionsManager.getManifestRestrictions(PACKAGE_NAME_APP_RESTRICTION_SCHEMA);
+ for (RestrictionEntry restriction : restrictions) {
+ if (RESTRICTION_KEY_SAY_HELLO.equals(restriction.getKey())) {
+ mDefaultValueRestrictionSayHello = restriction.getSelectedState();
+ }
+ }
+ }
+
+ /**
+ * Returns whether the AppRestrictionSchema is currently allowed to say hello to its user. Note
+ * that a profile/device owner needs to remember each restriction value on its own.
+ *
+ * @param activity The activity
+ * @return True if the AppRestrictionSchema is allowed to say hello
+ */
+ private boolean canSayHello(Activity activity) {
+ SharedPreferences prefs = activity.getSharedPreferences(PREFS_KEY, Context.MODE_PRIVATE);
+ return prefs.getBoolean(RESTRICTION_KEY_SAY_HELLO, mDefaultValueRestrictionSayHello);
+ }
+
+ /**
+ * Sets the value for the "cay_say_hello" restriction of AppRestrictionSchema.
+ *
+ * @param activity The activity
+ * @param allow The value to be set for the restriction.
+ */
+ private void allowSayHello(Activity activity, boolean allow) {
+ DevicePolicyManager devicePolicyManager
+ = (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ Bundle restrictions = new Bundle();
+ restrictions.putBoolean(RESTRICTION_KEY_SAY_HELLO, allow);
+ devicePolicyManager.setApplicationRestrictions(
+ EnforcerDeviceAdminReceiver.getComponentName(activity),
+ PACKAGE_NAME_APP_RESTRICTION_SCHEMA, restrictions);
+ // The profile/device owner needs to remember the current state of restrictions on its own
+ activity.getSharedPreferences(PREFS_KEY, Context.MODE_PRIVATE)
+ .edit()
+ .putBoolean(RESTRICTION_KEY_SAY_HELLO, allow)
+ .apply();
+ Toast.makeText(activity, allow ? R.string.allowed : R.string.disallowed,
+ Toast.LENGTH_SHORT).show();
+ }
+
+}
diff --git a/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/EnableProfileActivity.java b/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/EnableProfileActivity.java
new file mode 100644
index 0000000..323ee99
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/EnableProfileActivity.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 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.apprestrictionenforcer;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+/**
+ * This activity is started after the provisioning is complete in
+ * {@link EnforcerDeviceAdminReceiver}.
+ */
+public class EnableProfileActivity extends FragmentActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (null == savedInstanceState) {
+ // Enable the newly created profile
+ DevicePolicyManager manager =
+ (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
+ ComponentName componentName = EnforcerDeviceAdminReceiver.getComponentName(this);
+ manager.setProfileName(componentName, getString(R.string.profile_name));
+ manager.setProfileEnabled(componentName);
+ }
+ // Open the main screen
+ startActivity(new Intent(this, MainActivity.class));
+ finish();
+ }
+
+}
diff --git a/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/EnforcerDeviceAdminReceiver.java b/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/EnforcerDeviceAdminReceiver.java
new file mode 100644
index 0000000..09d9e98
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/EnforcerDeviceAdminReceiver.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 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.apprestrictionenforcer;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * Handles events related to managed profile.
+ */
+public class EnforcerDeviceAdminReceiver extends DeviceAdminReceiver {
+
+ /**
+ * Called on the new profile when managed profile provisioning has completed. Managed profile
+ * provisioning is the process of setting up the device so that it has a separate profile which
+ * is managed by the mobile device management(mdm) application that triggered the provisioning.
+ * Note that the managed profile is not fully visible until it is enabled.
+ */
+ @Override
+ public void onProfileProvisioningComplete(Context context, Intent intent) {
+ // EnableProfileActivity is launched with the newly set up profile.
+ Intent launch = new Intent(context, EnableProfileActivity.class);
+ launch.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ context.startActivity(launch);
+ }
+
+ /**
+ * Generates a {@link ComponentName} that is used throughout the app.
+ * @return a {@link ComponentName}
+ */
+ public static ComponentName getComponentName(Context context) {
+ return new ComponentName(context.getApplicationContext(),
+ EnforcerDeviceAdminReceiver.class);
+ }
+
+}
diff --git a/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/MainActivity.java b/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/MainActivity.java
new file mode 100644
index 0000000..72224e1
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/MainActivity.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2014 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.apprestrictionenforcer;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+public class MainActivity extends FragmentActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main_real);
+ if (null == savedInstanceState) {
+ DevicePolicyManager manager = (DevicePolicyManager)
+ getSystemService(Context.DEVICE_POLICY_SERVICE);
+ if (manager.isProfileOwnerApp(getApplicationContext().getPackageName())) {
+ // If the managed profile is already set up, we show the main screen.
+ showMainFragment();
+ } else {
+ // If not, we show the set up screen.
+ showSetupProfile();
+ }
+ }
+ }
+
+ private void showSetupProfile() {
+ getSupportFragmentManager().beginTransaction()
+ .replace(R.id.container, new SetupProfileFragment())
+ .commit();
+ }
+
+ private void showMainFragment() {
+ getSupportFragmentManager().beginTransaction()
+ .replace(R.id.container, new AppRestrictionEnforcerFragment())
+ .commit();
+ }
+
+}
diff --git a/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/SetupProfileFragment.java b/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/SetupProfileFragment.java
new file mode 100644
index 0000000..4dbd930
--- /dev/null
+++ b/samples/browseable/AppRestrictionEnforcer/src/com.example.android.apprestrictionenforcer/SetupProfileFragment.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2014 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.apprestrictionenforcer;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Toast;
+
+import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
+import static android.app.admin.DevicePolicyManager.EXTRA_DEVICE_ADMIN;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME;
+
+/**
+ * This {@link Fragment} handles initiation of managed profile provisioning.
+ */
+public class SetupProfileFragment extends Fragment implements View.OnClickListener {
+
+ private static final int REQUEST_PROVISION_MANAGED_PROFILE = 1;
+
+ public static SetupProfileFragment newInstance() {
+ return new SetupProfileFragment();
+ }
+
+ public SetupProfileFragment() {
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_setup_profile, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ view.findViewById(R.id.set_up_profile).setOnClickListener(this);
+ }
+
+ @Override
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.set_up_profile: {
+ provisionManagedProfile();
+ break;
+ }
+ }
+ }
+
+ /**
+ * Initiates the managed profile provisioning. If we already have a managed profile set up on
+ * this device, we will get an error dialog in the following provisioning phase.
+ */
+ private void provisionManagedProfile() {
+ Activity activity = getActivity();
+ if (null == activity) {
+ return;
+ }
+ Intent intent = new Intent(ACTION_PROVISION_MANAGED_PROFILE);
+ intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME,
+ activity.getApplicationContext().getPackageName());
+ intent.putExtra(EXTRA_DEVICE_ADMIN, EnforcerDeviceAdminReceiver.getComponentName(activity));
+ if (intent.resolveActivity(activity.getPackageManager()) != null) {
+ startActivityForResult(intent, REQUEST_PROVISION_MANAGED_PROFILE);
+ activity.finish();
+ } else {
+ Toast.makeText(activity, "Device provisioning is not enabled. Stopping.",
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_PROVISION_MANAGED_PROFILE) {
+ if (resultCode == Activity.RESULT_OK) {
+ Toast.makeText(getActivity(), "Provisioning done.", Toast.LENGTH_SHORT).show();
+ } else {
+ Toast.makeText(getActivity(), "Provisioning failed.", Toast.LENGTH_SHORT).show();
+ }
+ return;
+ }
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+
+}
diff --git a/samples/browseable/AppRestrictionSchema/AndroidManifest.xml b/samples/browseable/AppRestrictionSchema/AndroidManifest.xml
new file mode 100644
index 0000000..f8bbccc
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/AndroidManifest.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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.apprestrictionschema"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" /-->
+
+ <application
+ android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme">
+
+ <meta-data
+ android:name="android.content.APP_RESTRICTIONS"
+ android:resource="@xml/app_restrictions" />
+
+ <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>
+ </application>
+
+
+</manifest>
diff --git a/samples/browseable/AppRestrictionSchema/_index.jd b/samples/browseable/AppRestrictionSchema/_index.jd
new file mode 100644
index 0000000..9378c1a
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/_index.jd
@@ -0,0 +1,12 @@
+page.tags="AppRestrictionSchema"
+sample.group=Admin
+@jd:body
+
+<p>
+
+ This sample shows how to use app restrictions. This application has one boolean
+ restriction with a key \"can_say_hello\" that defines whether the only feature of this
+ app (press the button to show \"Hello\" message) is enabled or disabled. Use
+ AppRestrictionEnforcer sample to toggle the restriction.
+
+ </p>
diff --git a/samples/browseable/AppRestrictionSchema/res/drawable-hdpi/ic_launcher.png b/samples/browseable/AppRestrictionSchema/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..74344d7
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictionSchema/res/drawable-hdpi/tile.9.png b/samples/browseable/AppRestrictionSchema/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/AppRestrictionSchema/res/drawable-mdpi/ic_launcher.png b/samples/browseable/AppRestrictionSchema/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..a01dbd7
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictionSchema/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/AppRestrictionSchema/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..19bb139
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictionSchema/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/AppRestrictionSchema/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..9922ae6
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AppRestrictionSchema/res/layout-w720dp/activity_main.xml b/samples/browseable/AppRestrictionSchema/res/layout-w720dp/activity_main.xml
new file mode 100755
index 0000000..c9a52f6
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/layout-w720dp/activity_main.xml
@@ -0,0 +1,73 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<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/sample_main_layout">
+
+ <LinearLayout
+ android:id="@+id/sample_output"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <FrameLayout
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/margin_medium"
+ android:paddingRight="@dimen/margin_medium"
+ android:paddingTop="@dimen/margin_large"
+ android:paddingBottom="@dimen/margin_large"
+ android:text="@string/intro_message" />
+ </FrameLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1" />
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="0px"
+ android:layout_height="match_parent" />
+
+</LinearLayout>
+
+
diff --git a/samples/browseable/AppRestrictionSchema/res/layout/activity_main.xml b/samples/browseable/AppRestrictionSchema/res/layout/activity_main.xml
new file mode 100755
index 0000000..1ae4f98
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/layout/activity_main.xml
@@ -0,0 +1,65 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<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/sample_main_layout">
+
+ <ViewAnimator
+ android:id="@+id/sample_output"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1">
+
+ <ScrollView
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/horizontal_page_margin"
+ android:paddingRight="@dimen/horizontal_page_margin"
+ android:paddingTop="@dimen/vertical_page_margin"
+ android:paddingBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </ScrollView>
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ </ViewAnimator>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="match_parent"
+ android:layout_height="0px" />
+
+</LinearLayout>
+
diff --git a/samples/browseable/AppRestrictionSchema/res/layout/activity_main_real.xml b/samples/browseable/AppRestrictionSchema/res/layout/activity_main_real.xml
new file mode 100644
index 0000000..8aa1c8b
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/layout/activity_main_real.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2014 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:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <FrameLayout style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/horizontal_page_margin"
+ android:layout_marginRight="@dimen/horizontal_page_margin"
+ android:layout_marginTop="@dimen/vertical_page_margin"
+ android:layout_marginBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/browseable/AppRestrictionSchema/res/layout/fragment_app_restriction_schema.xml b/samples/browseable/AppRestrictionSchema/res/layout/fragment_app_restriction_schema.xml
new file mode 100644
index 0000000..fc5e23d
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/layout/fragment_app_restriction_schema.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2014 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:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:padding="@dimen/margin_medium">
+
+ <TextView
+ android:id="@+id/say_hello_explanation"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/explanation_can_say_hello_true"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <Button
+ android:id="@+id/say_hello"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/margin_medium"
+ android:text="@string/action_can_say_hello" />
+
+</LinearLayout>
diff --git a/samples/browseable/AppRestrictionSchema/res/menu/main.xml b/samples/browseable/AppRestrictionSchema/res/menu/main.xml
new file mode 100644
index 0000000..b49c2c5
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/menu/main.xml
@@ -0,0 +1,21 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/menu_toggle_log"
+ android:showAsAction="always"
+ android:title="@string/sample_show_log" />
+</menu>
diff --git a/samples/browseable/AppRestrictionSchema/res/values-sw600dp/template-dimens.xml b/samples/browseable/AppRestrictionSchema/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/AppRestrictionSchema/res/values-sw600dp/template-styles.xml b/samples/browseable/AppRestrictionSchema/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/AppRestrictionSchema/res/values-v11/template-styles.xml b/samples/browseable/AppRestrictionSchema/res/values-v11/template-styles.xml
new file mode 100644
index 0000000..8c1ea66
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/values-v11/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/samples/browseable/AppRestrictionSchema/res/values-v21/template-styles.xml b/samples/browseable/AppRestrictionSchema/res/values-v21/template-styles.xml
new file mode 100644
index 0000000..134fcd9
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/values-v21/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2014 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>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Material.Light" />
+
+</resources>
diff --git a/samples/browseable/AppRestrictionSchema/res/values/base-strings.xml b/samples/browseable/AppRestrictionSchema/res/values/base-strings.xml
new file mode 100644
index 0000000..78a3966
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/values/base-strings.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">AppRestrictionSchema</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ This sample shows how to use app restrictions. This application has one boolean
+ restriction with a key \"can_say_hello\" that defines whether the only feature of this
+ app (press the button to show \"Hello\" message) is enabled or disabled. Use
+ AppRestrictionEnforcer sample to toggle the restriction.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/AppRestrictionSchema/res/values/fragmentview_strings.xml b/samples/browseable/AppRestrictionSchema/res/values/fragmentview_strings.xml
new file mode 100755
index 0000000..7b9d9ec
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/values/fragmentview_strings.xml
@@ -0,0 +1,19 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="sample_show_log">Show Log</string>
+ <string name="sample_hide_log">Hide Log</string>
+</resources>
diff --git a/samples/browseable/AppRestrictionSchema/res/values/strings.xml b/samples/browseable/AppRestrictionSchema/res/values/strings.xml
new file mode 100644
index 0000000..b8ef110
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/values/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2014 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="title_can_say_hello">Can say hello</string>
+ <string name="description_can_say_hello">Whether the app can say hello to the user</string>
+ <string name="explanation_can_say_hello_true">I can say hello to you.</string>
+ <string name="explanation_can_say_hello_false">I am restricted from saying hello to you.</string>
+ <string name="action_can_say_hello">Say hello</string>
+ <string name="message_hello">Hello!</string>
+
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/AppRestrictionSchema/res/values/template-dimens.xml b/samples/browseable/AppRestrictionSchema/res/values/template-dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/AppRestrictionSchema/res/values/template-styles.xml b/samples/browseable/AppRestrictionSchema/res/values/template-styles.xml
new file mode 100644
index 0000000..6e7d593
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/AppRestrictionSchema/res/xml/app_restrictions.xml b/samples/browseable/AppRestrictionSchema/res/xml/app_restrictions.xml
new file mode 100644
index 0000000..409527f
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/res/xml/app_restrictions.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2014 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.
+-->
+<restrictions xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <restriction
+ android:defaultValue="false"
+ android:description="@string/description_can_say_hello"
+ android:key="can_say_hello"
+ android:restrictionType="bool"
+ android:title="@string/title_can_say_hello" />
+
+</restrictions>
diff --git a/samples/browseable/AppRestrictionSchema/src/com.example.android.apprestrictionschema/AppRestrictionSchemaFragment.java b/samples/browseable/AppRestrictionSchema/src/com.example.android.apprestrictionschema/AppRestrictionSchemaFragment.java
new file mode 100644
index 0000000..76f024f
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/src/com.example.android.apprestrictionschema/AppRestrictionSchemaFragment.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2014 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.apprestrictionschema;
+
+import android.content.Context;
+import android.content.RestrictionsManager;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.example.android.common.logger.Log;
+
+/**
+ * Pressing the button on this fragment pops up a simple Toast message. The button is enabled or
+ * disabled according to the restrictions set by device/profile owner. You can use the
+ * AppRestrictionEnforcer sample as a profile owner for this.
+ */
+public class AppRestrictionSchemaFragment extends Fragment implements View.OnClickListener {
+
+ // Tag for the logger
+ private static final String TAG = "AppRestrictionSchemaFragment";
+
+ // UI Components
+ private TextView mTextSayHello;
+ private Button mButtonSayHello;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_app_restriction_schema, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ mTextSayHello = (TextView) view.findViewById(R.id.say_hello_explanation);
+ mButtonSayHello = (Button) view.findViewById(R.id.say_hello);
+ mButtonSayHello.setOnClickListener(this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ // Update the UI according to the configured restrictions
+ RestrictionsManager restrictionsManager =
+ (RestrictionsManager) getActivity().getSystemService(Context.RESTRICTIONS_SERVICE);
+ Bundle restrictions = restrictionsManager.getApplicationRestrictions();
+ updateUI(restrictions);
+ }
+
+ private void updateUI(Bundle restrictions) {
+ if (canSayHello(restrictions)) {
+ mTextSayHello.setText(R.string.explanation_can_say_hello_true);
+ mButtonSayHello.setEnabled(true);
+ } else {
+ mTextSayHello.setText(R.string.explanation_can_say_hello_false);
+ mButtonSayHello.setEnabled(false);
+ }
+ }
+
+ /**
+ * Returns the current status of the restriction.
+ *
+ * @param restrictions The application restrictions
+ * @return True if the app is allowed to say hello
+ */
+ private boolean canSayHello(Bundle restrictions) {
+ final boolean defaultValue = false;
+ boolean canSayHello = restrictions == null ? defaultValue :
+ restrictions.getBoolean("can_say_hello", defaultValue);
+ Log.d(TAG, "canSayHello: " + canSayHello);
+ return canSayHello;
+ }
+
+ @Override
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.say_hello: {
+ Toast.makeText(getActivity(), R.string.message_hello, Toast.LENGTH_SHORT).show();
+ break;
+ }
+ }
+ }
+
+}
diff --git a/samples/browseable/AppRestrictionSchema/src/com.example.android.apprestrictionschema/MainActivity.java b/samples/browseable/AppRestrictionSchema/src/com.example.android.apprestrictionschema/MainActivity.java
new file mode 100644
index 0000000..be04a62
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/src/com.example.android.apprestrictionschema/MainActivity.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.apprestrictionschema;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ViewAnimator;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description, sample log and a custom
+ * {@link android.support.v4.app.Fragment} which can display a view.
+ * <p>
+ * For devices with displays with a width of 720dp or greater, the sample log is always visible,
+ * on other devices it's visibility is controlled by an item on the Action Bar.
+ */
+public class MainActivity extends SampleActivityBase {
+
+ public static final String TAG = "MainActivity";
+
+ // Whether the Log Fragment is currently shown
+ private boolean mLogShown;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ if (savedInstanceState == null) {
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ AppRestrictionSchemaFragment fragment = new AppRestrictionSchemaFragment();
+ transaction.replace(R.id.sample_content_fragment, fragment);
+ transaction.commit();
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
+ logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
+ logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);
+
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch(item.getItemId()) {
+ case R.id.menu_toggle_log:
+ mLogShown = !mLogShown;
+ ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);
+ if (mLogShown) {
+ output.setDisplayedChild(1);
+ } else {
+ output.setDisplayedChild(0);
+ }
+ supportInvalidateOptionsMenu();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ /** Create a chain of targets that will receive log data */
+ @Override
+ public void initializeLogging() {
+ // Wraps Android's native log framework.
+ LogWrapper logWrapper = new LogWrapper();
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ Log.setLogNode(logWrapper);
+
+ // Filter strips out everything except the message text.
+ MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+ logWrapper.setNext(msgFilter);
+
+ // On screen logging via a fragment with a TextView.
+ LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+ .findFragmentById(R.id.log_fragment);
+ msgFilter.setNext(logFragment.getLogView());
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/AppRestrictionSchema/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/AppRestrictionSchema/src/com.example.android.common/activities/SampleActivityBase.java
new file mode 100644
index 0000000..3228927
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/src/com.example.android.common/activities/SampleActivityBase.java
@@ -0,0 +1,52 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.common.activities;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogWrapper;
+
+/**
+ * Base launcher activity, to handle most of the common plumbing for samples.
+ */
+public class SampleActivityBase extends FragmentActivity {
+
+ public static final String TAG = "SampleActivityBase";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ initializeLogging();
+ }
+
+ /** Set up targets to receive log data */
+ public void initializeLogging() {
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ // Wraps Android's native log framework
+ LogWrapper logWrapper = new LogWrapper();
+ Log.setLogNode(logWrapper);
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/AppRestrictionSchema/src/com.example.android.common/logger/Log.java b/samples/browseable/AppRestrictionSchema/src/com.example.android.common/logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+ // Grabbing the native values from Android's native logging facilities,
+ // to make for easy migration and interop.
+ public static final int NONE = -1;
+ public static final int VERBOSE = android.util.Log.VERBOSE;
+ public static final int DEBUG = android.util.Log.DEBUG;
+ public static final int INFO = android.util.Log.INFO;
+ public static final int WARN = android.util.Log.WARN;
+ public static final int ERROR = android.util.Log.ERROR;
+ public static final int ASSERT = android.util.Log.ASSERT;
+
+ // Stores the beginning of the LogNode topology.
+ private static LogNode mLogNode;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public static LogNode getLogNode() {
+ return mLogNode;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to.
+ */
+ public static void setLogNode(LogNode node) {
+ mLogNode = node;
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void println(int priority, String tag, String msg, Throwable tr) {
+ if (mLogNode != null) {
+ mLogNode.println(priority, tag, msg, tr);
+ }
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ */
+ public static void println(int priority, String tag, String msg) {
+ println(priority, tag, msg, null);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void v(String tag, String msg, Throwable tr) {
+ println(VERBOSE, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void v(String tag, String msg) {
+ v(tag, msg, null);
+ }
+
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void d(String tag, String msg, Throwable tr) {
+ println(DEBUG, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void d(String tag, String msg) {
+ d(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void i(String tag, String msg, Throwable tr) {
+ println(INFO, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void i(String tag, String msg) {
+ i(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, String msg, Throwable tr) {
+ println(WARN, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void w(String tag, String msg) {
+ w(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, Throwable tr) {
+ w(tag, null, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void e(String tag, String msg, Throwable tr) {
+ println(ERROR, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void e(String tag, String msg) {
+ e(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, String msg, Throwable tr) {
+ println(ASSERT, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void wtf(String tag, String msg) {
+ wtf(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, Throwable tr) {
+ wtf(tag, null, tr);
+ }
+}
diff --git a/samples/browseable/AppRestrictionSchema/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/AppRestrictionSchema/src/com.example.android.common/logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/src/com.example.android.common/logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+ private LogView mLogView;
+ private ScrollView mScrollView;
+
+ public LogFragment() {}
+
+ public View inflateViews() {
+ mScrollView = new ScrollView(getActivity());
+ ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ mScrollView.setLayoutParams(scrollParams);
+
+ mLogView = new LogView(getActivity());
+ ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+ logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ mLogView.setLayoutParams(logParams);
+ mLogView.setClickable(true);
+ mLogView.setFocusable(true);
+ mLogView.setTypeface(Typeface.MONOSPACE);
+
+ // Want to set padding as 16 dips, setPadding takes pixels. Hooray math!
+ int paddingDips = 16;
+ double scale = getResources().getDisplayMetrics().density;
+ int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+ mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+ mLogView.setCompoundDrawablePadding(paddingPixels);
+
+ mLogView.setGravity(Gravity.BOTTOM);
+ mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+ mScrollView.addView(mLogView);
+ return mScrollView;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ View result = inflateViews();
+
+ mLogView.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+ }
+ });
+ return result;
+ }
+
+ public LogView getLogView() {
+ return mLogView;
+ }
+}
\ No newline at end of file
diff --git a/samples/browseable/AppRestrictionSchema/src/com.example.android.common/logger/LogNode.java b/samples/browseable/AppRestrictionSchema/src/com.example.android.common/logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/src/com.example.android.common/logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 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.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+ /**
+ * Instructs first LogNode in the list to print the log data provided.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/AppRestrictionSchema/src/com.example.android.common/logger/LogView.java b/samples/browseable/AppRestrictionSchema/src/com.example.android.common/logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/src/com.example.android.common/logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+ public LogView(Context context) {
+ super(context);
+ }
+
+ public LogView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public LogView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * Formats the log data and prints it out to the LogView.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+
+
+ String priorityStr = null;
+
+ // For the purposes of this View, we want to print the priority as readable text.
+ switch(priority) {
+ case android.util.Log.VERBOSE:
+ priorityStr = "VERBOSE";
+ break;
+ case android.util.Log.DEBUG:
+ priorityStr = "DEBUG";
+ break;
+ case android.util.Log.INFO:
+ priorityStr = "INFO";
+ break;
+ case android.util.Log.WARN:
+ priorityStr = "WARN";
+ break;
+ case android.util.Log.ERROR:
+ priorityStr = "ERROR";
+ break;
+ case android.util.Log.ASSERT:
+ priorityStr = "ASSERT";
+ break;
+ default:
+ break;
+ }
+
+ // Handily, the Log class has a facility for converting a stack trace into a usable string.
+ String exceptionStr = null;
+ if (tr != null) {
+ exceptionStr = android.util.Log.getStackTraceString(tr);
+ }
+
+ // Take the priority, tag, message, and exception, and concatenate as necessary
+ // into one usable line of text.
+ final StringBuilder outputBuilder = new StringBuilder();
+
+ String delimiter = "\t";
+ appendIfNotNull(outputBuilder, priorityStr, delimiter);
+ appendIfNotNull(outputBuilder, tag, delimiter);
+ appendIfNotNull(outputBuilder, msg, delimiter);
+ appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+ // In case this was originally called from an AsyncTask or some other off-UI thread,
+ // make sure the update occurs within the UI thread.
+ ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+ @Override
+ public void run() {
+ // Display the text we just generated within the LogView.
+ appendToLog(outputBuilder.toString());
+ }
+ })));
+
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+ * the logger takes so many arguments that might be null, this method helps cut out some of the
+ * agonizing tedium of writing the same 3 lines over and over.
+ * @param source StringBuilder containing the text to append to.
+ * @param addStr The String to append
+ * @param delimiter The String to separate the source and appended strings. A tab or comma,
+ * for instance.
+ * @return The fully concatenated String as a StringBuilder
+ */
+ private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+ if (addStr != null) {
+ if (addStr.length() == 0) {
+ delimiter = "";
+ }
+
+ return source.append(addStr).append(delimiter);
+ }
+ return source;
+ }
+
+ // The next LogNode in the chain.
+ LogNode mNext;
+
+ /** Outputs the string as a new line of log data in the LogView. */
+ public void appendToLog(String s) {
+ append("\n" + s);
+ }
+
+
+}
diff --git a/samples/browseable/AppRestrictionSchema/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/AppRestrictionSchema/src/com.example.android.common/logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/src/com.example.android.common/logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 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.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface. This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+ // For piping: The next node to receive Log data after this one has done its work.
+ private LogNode mNext;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /**
+ * Prints data out to the console using Android's native log mechanism.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ // There actually are log methods that don't take a msg parameter. For now,
+ // if that's the case, just convert null to the empty string and move on.
+ String useMsg = msg;
+ if (useMsg == null) {
+ useMsg = "";
+ }
+
+ // If an exeption was provided, convert that exception to a usable string and attach
+ // it to the end of the msg method.
+ if (tr != null) {
+ msg += "\n" + Log.getStackTraceString(tr);
+ }
+
+ // This is functionally identical to Log.x(tag, useMsg);
+ // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+ Log.println(priority, tag, useMsg);
+
+ // If this isn't the last node in the chain, move things along.
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+}
diff --git a/samples/browseable/AppRestrictionSchema/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/AppRestrictionSchema/src/com.example.android.common/logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/AppRestrictionSchema/src/com.example.android.common/logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+ LogNode mNext;
+
+ /**
+ * Takes the "next" LogNode as a parameter, to simplify chaining.
+ *
+ * @param next The next LogNode in the pipeline.
+ */
+ public MessageOnlyLogFilter(LogNode next) {
+ mNext = next;
+ }
+
+ public MessageOnlyLogFilter() {
+ }
+
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ if (mNext != null) {
+ getNext().println(Log.NONE, null, msg, null);
+ }
+ }
+
+ /**
+ * Returns the next LogNode in the chain.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+}
diff --git a/samples/browseable/BasicManagedProfile/AndroidManifest.xml b/samples/browseable/BasicManagedProfile/AndroidManifest.xml
new file mode 100644
index 0000000..29020c3
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/AndroidManifest.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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
+ package="com.example.android.basicmanagedprofile"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <uses-sdk
+ android:minSdkVersion="21"
+ android:targetSdkVersion="21"/>
+
+ <application
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme">
+
+ <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>
+
+ <activity
+ android:name=".EnableProfileActivity"
+ android:label="@string/app_name"/>
+
+ <receiver
+ android:name=".BasicDeviceAdminReceiver"
+ android:description="@string/app_name"
+ android:label="@string/app_name"
+ android:permission="android.permission.BIND_DEVICE_ADMIN">
+ <meta-data
+ android:name="android.app.device_admin"
+ android:resource="@xml/basic_device_admin_receiver"/>
+ <intent-filter>
+ <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
+ </intent-filter>
+ </receiver>
+
+ </application>
+
+
+</manifest>
diff --git a/samples/browseable/BasicManagedProfile/_index.jd b/samples/browseable/BasicManagedProfile/_index.jd
new file mode 100644
index 0000000..0aa07ea
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/_index.jd
@@ -0,0 +1,13 @@
+page.tags="BasicManagedProfile"
+sample.group=Admin
+@jd:body
+
+<p>
+
+ This sample demonstrates how to create a managed profile. You can also learn how to
+ enable or disable other apps and how to set restrictions to them. Intents can be
+ configured to be forwarded between primary account and managed profile. Finally, you can
+ wipe all the data associated with the profile.
+ Note that there can only be one managed profile on a device.
+
+ </p>
diff --git a/samples/browseable/BasicManagedProfile/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicManagedProfile/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..c8feb76
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicManagedProfile/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicManagedProfile/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/BasicManagedProfile/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicManagedProfile/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..4bf549e
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicManagedProfile/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicManagedProfile/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..33afaaa
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicManagedProfile/res/drawable-xxhdpi/badge.png b/samples/browseable/BasicManagedProfile/res/drawable-xxhdpi/badge.png
new file mode 100644
index 0000000..77a88cf
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/res/drawable-xxhdpi/badge.png
Binary files differ
diff --git a/samples/browseable/BasicManagedProfile/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicManagedProfile/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..d6f927a
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicManagedProfile/res/drawable/ic_launcher_badged.xml b/samples/browseable/BasicManagedProfile/res/drawable/ic_launcher_badged.xml
new file mode 100644
index 0000000..b91b9bd
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/res/drawable/ic_launcher_badged.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/ic_launcher"/>
+ <item
+ android:top="56dp"
+ android:left="56dp"
+ android:right="8dp"
+ android:bottom="8dp"
+ android:drawable="@drawable/badge"/>
+</layer-list>
diff --git a/samples/browseable/BasicManagedProfile/res/layout/activity_main.xml b/samples/browseable/BasicManagedProfile/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/horizontal_page_margin"
+ android:layout_marginRight="@dimen/horizontal_page_margin"
+ android:layout_marginTop="@dimen/vertical_page_margin"
+ android:layout_marginBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/BasicManagedProfile/res/layout/activity_main_real.xml b/samples/browseable/BasicManagedProfile/res/layout/activity_main_real.xml
new file mode 100644
index 0000000..e09df9e
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/res/layout/activity_main_real.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context="com.example.android.basicmanagedprofile.MainActivity"
+ tools:ignore="MergeRootFrame" />
diff --git a/samples/browseable/BasicManagedProfile/res/layout/activity_setup.xml b/samples/browseable/BasicManagedProfile/res/layout/activity_setup.xml
new file mode 100644
index 0000000..c52f15d
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/res/layout/activity_setup.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:paddingTop="@dimen/activity_vertical_margin"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin">
+
+ <TextView
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/all_done"/>
+
+ <TextView
+ android:padding="8dp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/all_done_explanation"/>
+
+ <ImageButton
+ android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_launcher_badged"
+ android:contentDescription="@string/icon"/>
+
+</LinearLayout>
diff --git a/samples/browseable/BasicManagedProfile/res/layout/fragment_main.xml b/samples/browseable/BasicManagedProfile/res/layout/fragment_main.xml
new file mode 100644
index 0000000..a5ba580
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/res/layout/fragment_main.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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.
+-->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context="com.example.android.basicmanagedprofile.MainActivity.MainFragment">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/activity_vertical_margin"
+ android:text="@string/main_message" />
+
+ <!-- Calculator -->
+
+ <Switch
+ android:id="@+id/toggle_calculator"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="8dp"
+ android:text="@string/toggle_calculator" />
+
+ <!-- Chrome (App restrictions) -->
+
+ <Switch
+ android:id="@+id/toggle_chrome"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="24dp"
+ android:padding="8dp"
+ android:text="@string/toggle_chrome" />
+
+ <Button
+ android:id="@+id/set_chrome_restrictions"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/set_chrome_restrictions" />
+
+ <Button
+ android:id="@+id/clear_chrome_restrictions"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/clear_chrome_restrictions" />
+
+ <!-- Intent Forwarding -->
+
+ <Button
+ android:id="@+id/enable_forwarding"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="24dp"
+ android:text="@string/enable_forwarding" />
+
+ <Button
+ android:id="@+id/disable_forwarding"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/disable_forwarding" />
+
+ <Button
+ android:id="@+id/send_intent"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/send_intent_text" />
+
+ <!-- Remove profile -->
+
+ <Button
+ android:id="@+id/remove_profile"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="24dp"
+ android:text="@string/remove_profile" />
+
+ </LinearLayout>
+
+</ScrollView>
+
diff --git a/samples/browseable/BasicManagedProfile/res/layout/fragment_setup_profile.xml b/samples/browseable/BasicManagedProfile/res/layout/fragment_setup_profile.xml
new file mode 100644
index 0000000..2aaaa93
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/res/layout/fragment_setup_profile.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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.
+-->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context="com.example.android.basicmanagedprofile.MainActivity.MainFragment">
+
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/setup_profile_message" />
+
+ <Button
+ android:id="@+id/set_up_profile"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/set_up_profile" />
+
+ </LinearLayout>
+
+</ScrollView>
diff --git a/samples/browseable/BasicManagedProfile/res/values-sw600dp/template-dimens.xml b/samples/browseable/BasicManagedProfile/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicManagedProfile/res/values-sw600dp/template-styles.xml b/samples/browseable/BasicManagedProfile/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/BasicManagedProfile/res/values-v11/template-styles.xml b/samples/browseable/BasicManagedProfile/res/values-v11/template-styles.xml
new file mode 100644
index 0000000..8c1ea66
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/res/values-v11/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/samples/browseable/BasicManagedProfile/res/values-v21/template-styles.xml b/samples/browseable/BasicManagedProfile/res/values-v21/template-styles.xml
new file mode 100644
index 0000000..134fcd9
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/res/values-v21/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2014 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>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Material.Light" />
+
+</resources>
diff --git a/samples/browseable/BasicManagedProfile/res/values-w820dp/dimens.xml b/samples/browseable/BasicManagedProfile/res/values-w820dp/dimens.xml
new file mode 100644
index 0000000..146c0e1
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/res/values-w820dp/dimens.xml
@@ -0,0 +1,3 @@
+<resources>
+ <dimen name="activity_horizontal_margin">64dp</dimen>
+</resources>
diff --git a/samples/browseable/BasicManagedProfile/res/values/base-strings.xml b/samples/browseable/BasicManagedProfile/res/values/base-strings.xml
new file mode 100644
index 0000000..f66ab5a
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/res/values/base-strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">BasicManagedProfile</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ This sample demonstrates how to create a managed profile. You can also learn how to
+ enable or disable other apps and how to set restrictions to them. Intents can be
+ configured to be forwarded between primary account and managed profile. Finally, you can
+ wipe all the data associated with the profile.
+ Note that there can only be one managed profile on a device.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/BasicManagedProfile/res/values/dimens.xml b/samples/browseable/BasicManagedProfile/res/values/dimens.xml
new file mode 100644
index 0000000..71c0df5
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/res/values/dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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>
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+</resources>
diff --git a/samples/browseable/BasicManagedProfile/res/values/strings.xml b/samples/browseable/BasicManagedProfile/res/values/strings.xml
new file mode 100644
index 0000000..240c7ab
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/res/values/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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="set_up_profile">Set up profile</string>
+ <string name="enable_forwarding">Enable forwarding of Share Intent</string>
+ <string name="send_intent_text">Send a sample share Intent</string>
+ <string name="disable_forwarding">Disable forwarding</string>
+ <string name="setup_profile_message">This app is currently not a profile owner.</string>
+ <string name="main_message">The app is ready to control the managed profile.</string>
+ <string name="remove_profile">Remove managed profile</string>
+ <string name="all_done">Setup all done</string>
+ <string name="all_done_explanation">To manage the configuration in your managed profile, visit the badged version of this application.</string>
+ <string name="toggle_calculator">Calculator in this profile: </string>
+ <string name="toggle_chrome">Chrome in this profile:</string>
+ <string name="set_chrome_restrictions">Set Chrome restrictions</string>
+ <string name="clear_chrome_restrictions">Clear Chrome restrictions</string>
+ <string name="icon">Icon</string>
+ <string name="profile_name">Sample Managed Profile</string>
+ <string name="enabled">Enabled</string>
+ <string name="disabled">Disabled</string>
+ <string name="restrictions_set">Restrictions set.</string>
+ <string name="activity_not_found">No app can handle this intent.</string>
+ <string name="cleared">Cleared.</string>
+
+</resources>
diff --git a/samples/browseable/BasicManagedProfile/res/values/styles.xml b/samples/browseable/BasicManagedProfile/res/values/styles.xml
new file mode 100644
index 0000000..fbf538d
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/res/values/styles.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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>
+ <style name="MaterialTheme" parent="android:Theme.Material.Light.DarkActionBar">
+ </style>
+</resources>
diff --git a/samples/browseable/BasicManagedProfile/res/values/template-dimens.xml b/samples/browseable/BasicManagedProfile/res/values/template-dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/BasicManagedProfile/res/values/template-styles.xml b/samples/browseable/BasicManagedProfile/res/values/template-styles.xml
new file mode 100644
index 0000000..6e7d593
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/BasicManagedProfile/res/xml/basic_device_admin_receiver.xml b/samples/browseable/BasicManagedProfile/res/xml/basic_device_admin_receiver.xml
new file mode 100644
index 0000000..5b876dd
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/res/xml/basic_device_admin_receiver.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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.
+-->
+<device-admin>
+ <uses-policies>
+ <limit-password/>
+ <watch-login/>
+ <reset-password/>
+ <force-lock/>
+ <wipe-data/>
+ <expire-password/>
+ <encrypted-storage/>
+ <disable-camera/>
+ <disable-keyguard-features/>
+ </uses-policies>
+</device-admin>
diff --git a/samples/browseable/BasicManagedProfile/src/com.example.android.basicmanagedprofile/BasicDeviceAdminReceiver.java b/samples/browseable/BasicManagedProfile/src/com.example.android.basicmanagedprofile/BasicDeviceAdminReceiver.java
new file mode 100644
index 0000000..54eee84
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/src/com.example.android.basicmanagedprofile/BasicDeviceAdminReceiver.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 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.basicmanagedprofile;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * Handles events related to managed profile.
+ */
+public class BasicDeviceAdminReceiver extends DeviceAdminReceiver {
+
+ /**
+ * Called on the new profile when managed profile provisioning has completed. Managed profile
+ * provisioning is the process of setting up the device so that it has a separate profile which
+ * is managed by the mobile device management(mdm) application that triggered the provisioning.
+ * Note that the managed profile is not fully visible until it is enabled.
+ */
+ @Override
+ public void onProfileProvisioningComplete(Context context, Intent intent) {
+ // EnableProfileActivity is launched with the newly set up profile.
+ Intent launch = new Intent(context, EnableProfileActivity.class);
+ launch.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ context.startActivity(launch);
+ }
+
+ /**
+ * Generates a {@link ComponentName} that is used throughout the app.
+ * @return a {@link ComponentName}
+ */
+ public static ComponentName getComponentName(Context context) {
+ return new ComponentName(context.getApplicationContext(), BasicDeviceAdminReceiver.class);
+ }
+
+}
diff --git a/samples/browseable/BasicManagedProfile/src/com.example.android.basicmanagedprofile/BasicManagedProfileFragment.java b/samples/browseable/BasicManagedProfile/src/com.example.android.basicmanagedprofile/BasicManagedProfileFragment.java
new file mode 100644
index 0000000..beb8d4a
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/src/com.example.android.basicmanagedprofile/BasicManagedProfileFragment.java
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2014 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.basicmanagedprofile;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Fragment;
+import android.app.admin.DevicePolicyManager;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.CompoundButton;
+import android.widget.ScrollView;
+import android.widget.Switch;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import static android.app.admin.DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT;
+import static android.app.admin.DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED;
+
+/**
+ * Provides several functions that are available in a managed profile. This includes
+ * enabling/disabling other apps, setting app restrictions, enabling/disabling intent forwarding,
+ * and wiping out all the data in the profile.
+ */
+public class BasicManagedProfileFragment extends Fragment
+ implements View.OnClickListener,
+ CompoundButton.OnCheckedChangeListener {
+
+ /**
+ * Tag for logging.
+ */
+ private static final String TAG = "BasicManagedProfileFragment";
+
+ /**
+ * Package name of calculator
+ */
+ private static final String PACKAGE_NAME_CALCULATOR = "com.android.calculator2";
+
+ /**
+ * Package name of Chrome
+ */
+ private static final String PACKAGE_NAME_CHROME = "com.android.chrome";
+
+ /**
+ * {@link Button} to remove this managed profile.
+ */
+ private Button mButtonRemoveProfile;
+
+ /**
+ * Whether the calculator app is enabled in this profile
+ */
+ private boolean mCalculatorEnabled;
+
+ /**
+ * Whether Chrome is enabled in this profile
+ */
+ private boolean mChromeEnabled;
+
+ public BasicManagedProfileFragment() {
+ }
+
+ public static BasicManagedProfileFragment newInstance() {
+ return new BasicManagedProfileFragment();
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_main, container, false);
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ // Retrieves whether the calculator app is enabled in this profile
+ mCalculatorEnabled = isApplicationEnabled(PACKAGE_NAME_CALCULATOR);
+ // Retrieves whether Chrome is enabled in this profile
+ mChromeEnabled = isApplicationEnabled(PACKAGE_NAME_CHROME);
+ }
+
+ /**
+ * Checks if the application is available in this profile.
+ *
+ * @param packageName The package name
+ * @return True if the application is available in this profile.
+ */
+ private boolean isApplicationEnabled(String packageName) {
+ Activity activity = getActivity();
+ PackageManager packageManager = activity.getPackageManager();
+ try {
+ ApplicationInfo applicationInfo = packageManager.getApplicationInfo(
+ packageName, PackageManager.GET_UNINSTALLED_PACKAGES);
+ // Return false if the app is not installed in this profile
+ if (0 == (applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)) {
+ return false;
+ }
+ // Check if the app is not hidden in this profile
+ DevicePolicyManager devicePolicyManager =
+ (DevicePolicyManager) activity.getSystemService(Activity.DEVICE_POLICY_SERVICE);
+ return !devicePolicyManager.isApplicationHidden(
+ BasicDeviceAdminReceiver.getComponentName(activity), packageName);
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ // Bind event listeners and initial states
+ view.findViewById(R.id.set_chrome_restrictions).setOnClickListener(this);
+ view.findViewById(R.id.clear_chrome_restrictions).setOnClickListener(this);
+ view.findViewById(R.id.enable_forwarding).setOnClickListener(this);
+ view.findViewById(R.id.disable_forwarding).setOnClickListener(this);
+ view.findViewById(R.id.send_intent).setOnClickListener(this);
+ mButtonRemoveProfile = (Button) view.findViewById(R.id.remove_profile);
+ mButtonRemoveProfile.setOnClickListener(this);
+ Switch toggleCalculator = (Switch) view.findViewById(R.id.toggle_calculator);
+ toggleCalculator.setChecked(mCalculatorEnabled);
+ toggleCalculator.setOnCheckedChangeListener(this);
+ Switch toggleChrome = (Switch) view.findViewById(R.id.toggle_chrome);
+ toggleChrome.setChecked(mChromeEnabled);
+ toggleChrome.setOnCheckedChangeListener(this);
+ }
+
+ @Override
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.set_chrome_restrictions: {
+ setChromeRestrictions();
+ break;
+ }
+ case R.id.clear_chrome_restrictions: {
+ clearChromeRestrictions();
+ break;
+ }
+ case R.id.enable_forwarding: {
+ enableForwarding();
+ break;
+ }
+ case R.id.disable_forwarding: {
+ disableForwarding();
+ break;
+ }
+ case R.id.send_intent: {
+ sendIntent();
+ break;
+ }
+ case R.id.remove_profile: {
+ mButtonRemoveProfile.setEnabled(false);
+ removeProfile();
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
+ switch (compoundButton.getId()) {
+ case R.id.toggle_calculator: {
+ setAppEnabled(PACKAGE_NAME_CALCULATOR, checked);
+ mCalculatorEnabled = checked;
+ break;
+ }
+ case R.id.toggle_chrome: {
+ setAppEnabled(PACKAGE_NAME_CHROME, checked);
+ mChromeEnabled = checked;
+ break;
+ }
+ }
+ }
+
+ /**
+ * Enables or disables the specified app in this profile.
+ *
+ * @param packageName The package name of the target app.
+ * @param enabled Pass true to enable the app.
+ */
+ private void setAppEnabled(String packageName, boolean enabled) {
+ Activity activity = getActivity();
+ if (null == activity) {
+ return;
+ }
+ PackageManager packageManager = activity.getPackageManager();
+ DevicePolicyManager devicePolicyManager =
+ (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ try {
+ ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName,
+ PackageManager.GET_UNINSTALLED_PACKAGES);
+ // Here, we check the ApplicationInfo of the target app, and see if the flags have
+ // ApplicationInfo.FLAG_INSTALLED turned on using bitwise operation.
+ if (0 == (applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)) {
+ // If the app is not installed in this profile, we can enable it by
+ // DPM.enableSystemApp
+ if (enabled) {
+ devicePolicyManager.enableSystemApp(
+ BasicDeviceAdminReceiver.getComponentName(activity), packageName);
+ } else {
+ // But we cannot disable the app since it is already disabled
+ Log.e(TAG, "Cannot disable this app: " + packageName);
+ return;
+ }
+ } else {
+ // If the app is already installed, we can enable or disable it by
+ // DPM.setApplicationHidden
+ devicePolicyManager.setApplicationHidden(
+ BasicDeviceAdminReceiver.getComponentName(activity), packageName, !enabled);
+ }
+ Toast.makeText(activity, enabled ? R.string.enabled : R.string.disabled,
+ Toast.LENGTH_SHORT).show();
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "The app cannot be found: " + packageName, e);
+ }
+ }
+
+ /**
+ * Sets restrictions to Chrome
+ */
+ private void setChromeRestrictions() {
+ final Activity activity = getActivity();
+ if (null == activity) {
+ return;
+ }
+ final DevicePolicyManager manager =
+ (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ final Bundle settings = new Bundle();
+ settings.putString("EditBookmarksEnabled", "false");
+ settings.putString("IncognitoModeAvailability", "1");
+ settings.putString("ManagedBookmarks",
+ "[{\"name\": \"Chromium\", \"url\": \"http://chromium.org\"}, " +
+ "{\"name\": \"Google\", \"url\": \"https://www.google.com\"}]");
+ settings.putString("DefaultSearchProviderEnabled", "true");
+ settings.putString("DefaultSearchProviderName", "\"LMGTFY\"");
+ settings.putString("DefaultSearchProviderSearchURL",
+ "\"http://lmgtfy.com/?q={searchTerms}\"");
+ settings.putString("URLBlacklist", "[\"example.com\", \"example.org\"]");
+ StringBuilder message = new StringBuilder("Setting Chrome restrictions:");
+ for (String key : settings.keySet()) {
+ message.append("\n");
+ message.append(key);
+ message.append(": ");
+ message.append(settings.getString(key));
+ }
+ ScrollView view = new ScrollView(activity);
+ TextView text = new TextView(activity);
+ text.setText(message);
+ int size = (int) activity.getResources().getDimension(R.dimen.activity_horizontal_margin);
+ view.setPadding(size, size, size, size);
+ view.addView(text);
+ new AlertDialog.Builder(activity)
+ .setView(view)
+ .setNegativeButton(android.R.string.cancel, null)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ // This is how you can set restrictions to an app.
+ // The format for settings in Bundle differs from app to app.
+ manager.setApplicationRestrictions
+ (BasicDeviceAdminReceiver.getComponentName(activity),
+ PACKAGE_NAME_CHROME, settings);
+ Toast.makeText(activity, R.string.restrictions_set,
+ Toast.LENGTH_SHORT).show();
+ }
+ })
+ .show();
+ }
+
+ /**
+ * Clears restrictions to Chrome
+ */
+ private void clearChromeRestrictions() {
+ final Activity activity = getActivity();
+ if (null == activity) {
+ return;
+ }
+ final DevicePolicyManager manager =
+ (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ // In order to clear restrictions, pass null as the restriction Bundle for
+ // setApplicationRestrictions
+ manager.setApplicationRestrictions
+ (BasicDeviceAdminReceiver.getComponentName(activity),
+ PACKAGE_NAME_CHROME, null);
+ Toast.makeText(activity, R.string.cleared, Toast.LENGTH_SHORT).show();
+ }
+
+ /**
+ * Enables forwarding of share intent between private account and managed profile.
+ */
+ private void enableForwarding() {
+ Activity activity = getActivity();
+ if (null == activity || activity.isFinishing()) {
+ return;
+ }
+ DevicePolicyManager manager =
+ (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ try {
+ IntentFilter filter = new IntentFilter(Intent.ACTION_SEND);
+ filter.addDataType("text/plain");
+ filter.addDataType("image/jpeg");
+ // This is how you can register an IntentFilter as allowed pattern of Intent forwarding
+ manager.addCrossProfileIntentFilter(BasicDeviceAdminReceiver.getComponentName(activity),
+ filter, FLAG_MANAGED_CAN_ACCESS_PARENT | FLAG_PARENT_CAN_ACCESS_MANAGED);
+ } catch (IntentFilter.MalformedMimeTypeException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Disables forwarding of all intents.
+ */
+ private void disableForwarding() {
+ Activity activity = getActivity();
+ if (null == activity || activity.isFinishing()) {
+ return;
+ }
+ DevicePolicyManager manager =
+ (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ manager.clearCrossProfileIntentFilters(BasicDeviceAdminReceiver.getComponentName(activity));
+ }
+
+ /**
+ * Sends a sample intent of a plain text message. This is just a utility function to see how
+ * the intent forwarding works.
+ */
+ private void sendIntent() {
+ Activity activity = getActivity();
+ if (null == activity || activity.isFinishing()) {
+ return;
+ }
+ DevicePolicyManager manager =
+ (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.setType("text/plain");
+ intent.putExtra(Intent.EXTRA_TEXT,
+ manager.isProfileOwnerApp(activity.getApplicationContext().getPackageName())
+ ? "From the managed account" : "From the primary account");
+ try {
+ startActivity(intent);
+ Log.d(TAG, "A sample intent was sent.");
+ } catch (ActivityNotFoundException e) {
+ Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ /**
+ * Wipes out all the data related to this managed profile.
+ */
+ private void removeProfile() {
+ Activity activity = getActivity();
+ if (null == activity || activity.isFinishing()) {
+ return;
+ }
+ DevicePolicyManager manager =
+ (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ manager.wipeData(0);
+ // The screen turns off here
+ }
+
+}
diff --git a/samples/browseable/BasicManagedProfile/src/com.example.android.basicmanagedprofile/EnableProfileActivity.java b/samples/browseable/BasicManagedProfile/src/com.example.android.basicmanagedprofile/EnableProfileActivity.java
new file mode 100644
index 0000000..deed2f6
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/src/com.example.android.basicmanagedprofile/EnableProfileActivity.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2014 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.basicmanagedprofile;
+
+import android.app.Activity;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+
+/**
+ * This activity is started after the provisioning is complete in {@link BasicDeviceAdminReceiver}.
+ */
+public class EnableProfileActivity extends Activity implements View.OnClickListener {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (null == savedInstanceState) {
+ // Important: After the profile has been created, the MDM must enable it for corporate
+ // apps to become visible in the launcher.
+ enableProfile();
+ }
+ // This is just a friendly shortcut to the main screen.
+ setContentView(R.layout.activity_setup);
+ findViewById(R.id.icon).setOnClickListener(this);
+ }
+
+ private void enableProfile() {
+ DevicePolicyManager manager =
+ (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
+ ComponentName componentName = BasicDeviceAdminReceiver.getComponentName(this);
+ // This is the name for the newly created managed profile.
+ manager.setProfileName(componentName, getString(R.string.profile_name));
+ // We enable the profile here.
+ manager.setProfileEnabled(componentName);
+ }
+
+ @Override
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.icon: {
+ // Opens up the main screen
+ startActivity(new Intent(this, MainActivity.class));
+ finish();
+ break;
+ }
+ }
+ }
+
+}
diff --git a/samples/browseable/BasicManagedProfile/src/com.example.android.basicmanagedprofile/MainActivity.java b/samples/browseable/BasicManagedProfile/src/com.example.android.basicmanagedprofile/MainActivity.java
new file mode 100644
index 0000000..3847fee
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/src/com.example.android.basicmanagedprofile/MainActivity.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2014 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.basicmanagedprofile;
+
+import android.app.Activity;
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.os.Bundle;
+
+public class MainActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main_real);
+ if (savedInstanceState == null) {
+ DevicePolicyManager manager = (DevicePolicyManager)
+ getSystemService(Context.DEVICE_POLICY_SERVICE);
+ if (manager.isProfileOwnerApp(getApplicationContext().getPackageName())) {
+ // If the managed profile is already set up, we show the main screen.
+ showMainFragment();
+ } else {
+ // If not, we show the set up screen.
+ showSetupProfile();
+ }
+ }
+ }
+
+ private void showSetupProfile() {
+ getFragmentManager().beginTransaction()
+ .replace(R.id.container, SetupProfileFragment.newInstance())
+ .commit();
+ }
+
+ private void showMainFragment() {
+ getFragmentManager().beginTransaction()
+ .add(R.id.container, BasicManagedProfileFragment.newInstance())
+ .commit();
+ }
+
+}
diff --git a/samples/browseable/BasicManagedProfile/src/com.example.android.basicmanagedprofile/SetupProfileFragment.java b/samples/browseable/BasicManagedProfile/src/com.example.android.basicmanagedprofile/SetupProfileFragment.java
new file mode 100644
index 0000000..7da6e02
--- /dev/null
+++ b/samples/browseable/BasicManagedProfile/src/com.example.android.basicmanagedprofile/SetupProfileFragment.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2014 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.basicmanagedprofile;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Toast;
+
+import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME;
+
+/**
+ * This {@link Fragment} handles initiation of managed profile provisioning.
+ */
+public class SetupProfileFragment extends Fragment implements View.OnClickListener {
+
+ private static final int REQUEST_PROVISION_MANAGED_PROFILE = 1;
+
+ public static SetupProfileFragment newInstance() {
+ return new SetupProfileFragment();
+ }
+
+ public SetupProfileFragment() {
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_setup_profile, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ view.findViewById(R.id.set_up_profile).setOnClickListener(this);
+ }
+
+ @Override
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.set_up_profile: {
+ provisionManagedProfile();
+ break;
+ }
+ }
+ }
+
+ /**
+ * Initiates the managed profile provisioning. If we already have a managed profile set up on
+ * this device, we will get an error dialog in the following provisioning phase.
+ */
+ private void provisionManagedProfile() {
+ Activity activity = getActivity();
+ if (null == activity) {
+ return;
+ }
+ Intent intent = new Intent(ACTION_PROVISION_MANAGED_PROFILE);
+ intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME,
+ activity.getApplicationContext().getPackageName());
+ if (intent.resolveActivity(activity.getPackageManager()) != null) {
+ startActivityForResult(intent, REQUEST_PROVISION_MANAGED_PROFILE);
+ activity.finish();
+ } else {
+ Toast.makeText(activity, "Device provisioning is not enabled. Stopping.",
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_PROVISION_MANAGED_PROFILE) {
+ if (resultCode == Activity.RESULT_OK) {
+ Toast.makeText(getActivity(), "Provisioning done.", Toast.LENGTH_SHORT).show();
+ } else {
+ Toast.makeText(getActivity(), "Provisioning failed.", Toast.LENGTH_SHORT).show();
+ }
+ return;
+ }
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+
+}
diff --git a/samples/browseable/Camera2Basic/AndroidManifest.xml b/samples/browseable/Camera2Basic/AndroidManifest.xml
new file mode 100644
index 0000000..87d9af1
--- /dev/null
+++ b/samples/browseable/Camera2Basic/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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.camera2basic"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+ <uses-permission android:name="android.permission.CAMERA" />
+
+ <application android:allowBackup="true"
+ android:label="@string/app_name"
+ android:icon="@drawable/ic_launcher"
+ android:theme="@style/MaterialTheme">
+
+ <activity android:name=".CameraActivity"
+ android:label="@string/app_name">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
diff --git a/samples/browseable/Camera2Basic/_index.jd b/samples/browseable/Camera2Basic/_index.jd
new file mode 100644
index 0000000..ba27fff
--- /dev/null
+++ b/samples/browseable/Camera2Basic/_index.jd
@@ -0,0 +1,10 @@
+page.tags="Camera2Basic"
+sample.group=Media
+@jd:body
+
+<p>
+
+ This sample demonstrates the basic use of Camera2 API. Check the source code to see how
+ you can display camera preview and take pictures.
+
+ </p>
diff --git a/samples/browseable/Camera2Basic/res/drawable-hdpi/ic_action_info.png b/samples/browseable/Camera2Basic/res/drawable-hdpi/ic_action_info.png
new file mode 100644
index 0000000..32bd1aa
--- /dev/null
+++ b/samples/browseable/Camera2Basic/res/drawable-hdpi/ic_action_info.png
Binary files differ
diff --git a/samples/browseable/Camera2Basic/res/drawable-hdpi/ic_launcher.png b/samples/browseable/Camera2Basic/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..ac6cf27
--- /dev/null
+++ b/samples/browseable/Camera2Basic/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Camera2Basic/res/drawable-hdpi/tile.9.png b/samples/browseable/Camera2Basic/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/Camera2Basic/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/Camera2Basic/res/drawable-mdpi/ic_action_info.png b/samples/browseable/Camera2Basic/res/drawable-mdpi/ic_action_info.png
new file mode 100644
index 0000000..8efbbf8
--- /dev/null
+++ b/samples/browseable/Camera2Basic/res/drawable-mdpi/ic_action_info.png
Binary files differ
diff --git a/samples/browseable/Camera2Basic/res/drawable-mdpi/ic_launcher.png b/samples/browseable/Camera2Basic/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..65f92a5
--- /dev/null
+++ b/samples/browseable/Camera2Basic/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Camera2Basic/res/drawable-xhdpi/ic_action_info.png b/samples/browseable/Camera2Basic/res/drawable-xhdpi/ic_action_info.png
new file mode 100644
index 0000000..ba143ea
--- /dev/null
+++ b/samples/browseable/Camera2Basic/res/drawable-xhdpi/ic_action_info.png
Binary files differ
diff --git a/samples/browseable/Camera2Basic/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/Camera2Basic/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..6fd1318
--- /dev/null
+++ b/samples/browseable/Camera2Basic/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Camera2Basic/res/drawable-xxhdpi/ic_action_info.png b/samples/browseable/Camera2Basic/res/drawable-xxhdpi/ic_action_info.png
new file mode 100644
index 0000000..394eb7e
--- /dev/null
+++ b/samples/browseable/Camera2Basic/res/drawable-xxhdpi/ic_action_info.png
Binary files differ
diff --git a/samples/browseable/Camera2Basic/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/Camera2Basic/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..4513cf2
--- /dev/null
+++ b/samples/browseable/Camera2Basic/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Camera2Basic/res/layout-land/fragment_camera2_basic.xml b/samples/browseable/Camera2Basic/res/layout-land/fragment_camera2_basic.xml
new file mode 100644
index 0000000..3a3e2ff
--- /dev/null
+++ b/samples/browseable/Camera2Basic/res/layout-land/fragment_camera2_basic.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2014 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <com.example.android.camera2basic.AutoFitTextureView
+ android:id="@+id/texture"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentStart="true"
+ android:layout_alignParentTop="true" />
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentTop="true"
+ android:layout_below="@id/texture"
+ android:layout_toRightOf="@id/texture"
+ android:background="#4285f4"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/picture"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="@string/picture" />
+
+ <ImageButton
+ android:id="@+id/info"
+ style="@android:style/Widget.Material.Light.Button.Borderless"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal|bottom"
+ android:contentDescription="@string/description_info"
+ android:padding="20dp"
+ android:src="@drawable/ic_action_info" />
+
+
+ </FrameLayout>
+
+</RelativeLayout>
diff --git a/samples/browseable/Camera2Basic/res/layout/activity_camera.xml b/samples/browseable/Camera2Basic/res/layout/activity_camera.xml
new file mode 100644
index 0000000..a86d220
--- /dev/null
+++ b/samples/browseable/Camera2Basic/res/layout/activity_camera.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2014 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"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#000"
+ tools:context="com.example.android.camera2basic.CameraActivity" />
diff --git a/samples/browseable/Camera2Basic/res/layout/activity_main.xml b/samples/browseable/Camera2Basic/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/Camera2Basic/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/horizontal_page_margin"
+ android:layout_marginRight="@dimen/horizontal_page_margin"
+ android:layout_marginTop="@dimen/vertical_page_margin"
+ android:layout_marginBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/Camera2Basic/res/layout/fragment_camera2_basic.xml b/samples/browseable/Camera2Basic/res/layout/fragment_camera2_basic.xml
new file mode 100644
index 0000000..7d05ab3
--- /dev/null
+++ b/samples/browseable/Camera2Basic/res/layout/fragment_camera2_basic.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2014 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <com.example.android.camera2basic.AutoFitTextureView
+ android:id="@+id/texture"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentStart="true"
+ android:layout_alignParentTop="true" />
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentStart="true"
+ android:layout_below="@id/texture"
+ android:background="#4285f4">
+
+ <Button
+ android:id="@+id/picture"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="@string/picture" />
+
+ <ImageButton
+ android:id="@+id/info"
+ android:contentDescription="@string/description_info"
+ style="@android:style/Widget.Material.Light.Button.Borderless"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical|right"
+ android:padding="20dp"
+ android:src="@drawable/ic_action_info" />
+
+ </FrameLayout>
+
+</RelativeLayout>
diff --git a/samples/browseable/Camera2Basic/res/values-sw600dp/template-dimens.xml b/samples/browseable/Camera2Basic/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/Camera2Basic/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/Camera2Basic/res/values-sw600dp/template-styles.xml b/samples/browseable/Camera2Basic/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/Camera2Basic/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/Camera2Basic/res/values-v11/template-styles.xml b/samples/browseable/Camera2Basic/res/values-v11/template-styles.xml
new file mode 100644
index 0000000..8c1ea66
--- /dev/null
+++ b/samples/browseable/Camera2Basic/res/values-v11/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/samples/browseable/Camera2Basic/res/values-v21/template-styles.xml b/samples/browseable/Camera2Basic/res/values-v21/template-styles.xml
new file mode 100644
index 0000000..134fcd9
--- /dev/null
+++ b/samples/browseable/Camera2Basic/res/values-v21/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2014 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>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Material.Light" />
+
+</resources>
diff --git a/samples/browseable/Camera2Basic/res/values/base-strings.xml b/samples/browseable/Camera2Basic/res/values/base-strings.xml
new file mode 100644
index 0000000..9a7579e
--- /dev/null
+++ b/samples/browseable/Camera2Basic/res/values/base-strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">Camera2Basic</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ This sample demonstrates the basic use of Camera2 API. Check the source code to see how
+ you can display camera preview and take pictures.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/Camera2Basic/res/values/strings.xml b/samples/browseable/Camera2Basic/res/values/strings.xml
new file mode 100644
index 0000000..66f1000
--- /dev/null
+++ b/samples/browseable/Camera2Basic/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2014 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="picture">Picture</string>
+ <string name="description_info">Info</string>
+</resources>
diff --git a/samples/browseable/Camera2Basic/res/values/styles.xml b/samples/browseable/Camera2Basic/res/values/styles.xml
new file mode 100644
index 0000000..3f3bdfb
--- /dev/null
+++ b/samples/browseable/Camera2Basic/res/values/styles.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2014 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>
+ <style name="MaterialTheme" parent="android:Theme.Material.Light.NoActionBar.Fullscreen" />
+</resources>
diff --git a/samples/browseable/Camera2Basic/res/values/template-dimens.xml b/samples/browseable/Camera2Basic/res/values/template-dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/Camera2Basic/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/Camera2Basic/res/values/template-styles.xml b/samples/browseable/Camera2Basic/res/values/template-styles.xml
new file mode 100644
index 0000000..6e7d593
--- /dev/null
+++ b/samples/browseable/Camera2Basic/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/Camera2Basic/src/com.example.android.camera2basic/AutoFitTextureView.java b/samples/browseable/Camera2Basic/src/com.example.android.camera2basic/AutoFitTextureView.java
new file mode 100644
index 0000000..f4903e1
--- /dev/null
+++ b/samples/browseable/Camera2Basic/src/com.example.android.camera2basic/AutoFitTextureView.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2014 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.camera2basic;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.TextureView;
+
+/**
+ * A {@link TextureView} that can be adjusted to a specified aspect ratio.
+ */
+public class AutoFitTextureView extends TextureView {
+
+ private int mRatioWidth = 0;
+ private int mRatioHeight = 0;
+
+ public AutoFitTextureView(Context context) {
+ this(context, null);
+ }
+
+ public AutoFitTextureView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio
+ * calculated from the parameters. Note that the actual sizes of parameters don't matter, that
+ * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result.
+ *
+ * @param width Relative horizontal size
+ * @param height Relative vertical size
+ */
+ public void setAspectRatio(int width, int height) {
+ if (width < 0 || height < 0) {
+ throw new IllegalArgumentException("Size cannot be negative.");
+ }
+ mRatioWidth = width;
+ mRatioHeight = height;
+ requestLayout();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ int width = MeasureSpec.getSize(widthMeasureSpec);
+ int height = MeasureSpec.getSize(heightMeasureSpec);
+ if (0 == mRatioWidth || 0 == mRatioHeight) {
+ setMeasuredDimension(width, height);
+ } else {
+ if (width < height * mRatioWidth / mRatioHeight) {
+ setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
+ } else {
+ setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
+ }
+ }
+ }
+
+}
diff --git a/samples/browseable/Camera2Basic/src/com.example.android.camera2basic/Camera2BasicFragment.java b/samples/browseable/Camera2Basic/src/com.example.android.camera2basic/Camera2BasicFragment.java
new file mode 100644
index 0000000..f4bf220
--- /dev/null
+++ b/samples/browseable/Camera2Basic/src/com.example.android.camera2basic/Camera2BasicFragment.java
@@ -0,0 +1,819 @@
+/*
+ * Copyright 2014 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.camera2basic;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.res.Configuration;
+import android.graphics.ImageFormat;
+import android.graphics.Matrix;
+import android.graphics.RectF;
+import android.graphics.SurfaceTexture;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.media.Image;
+import android.media.ImageReader;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.util.Log;
+import android.util.Size;
+import android.util.SparseIntArray;
+import android.view.LayoutInflater;
+import android.view.Surface;
+import android.view.TextureView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Toast;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+public class Camera2BasicFragment extends Fragment implements View.OnClickListener {
+
+ /**
+ * Conversion from screen rotation to JPEG orientation.
+ */
+ private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
+
+ static {
+ ORIENTATIONS.append(Surface.ROTATION_0, 90);
+ ORIENTATIONS.append(Surface.ROTATION_90, 0);
+ ORIENTATIONS.append(Surface.ROTATION_180, 270);
+ ORIENTATIONS.append(Surface.ROTATION_270, 180);
+ }
+
+ /**
+ * Tag for the {@link Log}.
+ */
+ private static final String TAG = "Camera2BasicFragment";
+
+ /**
+ * Camera state: Showing camera preview.
+ */
+ private static final int STATE_PREVIEW = 0;
+
+ /**
+ * Camera state: Waiting for the focus to be locked.
+ */
+ private static final int STATE_WAITING_LOCK = 1;
+ /**
+ * Camera state: Waiting for the exposure to be precapture state.
+ */
+ private static final int STATE_WAITING_PRECAPTURE = 2;
+ /**
+ * Camera state: Waiting for the exposure state to be something other than precapture.
+ */
+ private static final int STATE_WAITING_NON_PRECAPTURE = 3;
+ /**
+ * Camera state: Picture was taken.
+ */
+ private static final int STATE_PICTURE_TAKEN = 4;
+
+ /**
+ * {@link TextureView.SurfaceTextureListener} handles several lifecycle events on a
+ * {@link TextureView}.
+ */
+ private final TextureView.SurfaceTextureListener mSurfaceTextureListener
+ = new TextureView.SurfaceTextureListener() {
+
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
+ openCamera(width, height);
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
+ configureTransform(width, height);
+ }
+
+ @Override
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
+ return true;
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(SurfaceTexture texture) {
+ }
+
+ };
+
+ /**
+ * ID of the current {@link CameraDevice}.
+ */
+ private String mCameraId;
+
+ /**
+ * An {@link AutoFitTextureView} for camera preview.
+ */
+ private AutoFitTextureView mTextureView;
+
+ /**
+ * A {@link CameraCaptureSession } for camera preview.
+ */
+
+ private CameraCaptureSession mCaptureSession;
+ /**
+ * A reference to the opened {@link CameraDevice}.
+ */
+
+ private CameraDevice mCameraDevice;
+ /**
+ * The {@link android.util.Size} of camera preview.
+ */
+
+ private Size mPreviewSize;
+
+ /**
+ * {@link CameraDevice.StateCallback} is called when {@link CameraDevice} changes its state.
+ */
+ private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
+
+ @Override
+ public void onOpened(CameraDevice cameraDevice) {
+ // This method is called when the camera is opened. We start camera preview here.
+ mCameraOpenCloseLock.release();
+ mCameraDevice = cameraDevice;
+ createCameraPreviewSession();
+ }
+
+ @Override
+ public void onDisconnected(CameraDevice cameraDevice) {
+ mCameraOpenCloseLock.release();
+ cameraDevice.close();
+ mCameraDevice = null;
+ }
+
+ @Override
+ public void onError(CameraDevice cameraDevice, int error) {
+ mCameraOpenCloseLock.release();
+ cameraDevice.close();
+ mCameraDevice = null;
+ Activity activity = getActivity();
+ if (null != activity) {
+ activity.finish();
+ }
+ }
+
+ };
+
+ /**
+ * An additional thread for running tasks that shouldn't block the UI.
+ */
+ private HandlerThread mBackgroundThread;
+
+ /**
+ * A {@link Handler} for running tasks in the background.
+ */
+ private Handler mBackgroundHandler;
+
+ /**
+ * An {@link ImageReader} that handles still image capture.
+ */
+ private ImageReader mImageReader;
+
+ /**
+ * This is the output file for our picture.
+ */
+ private File mFile;
+
+ /**
+ * This a callback object for the {@link ImageReader}. "onImageAvailable" will be called when a
+ * still image is ready to be saved.
+ */
+ private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
+ = new ImageReader.OnImageAvailableListener() {
+
+ @Override
+ public void onImageAvailable(ImageReader reader) {
+ mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), mFile));
+ }
+
+ };
+
+ /**
+ * {@link CaptureRequest.Builder} for the camera preview
+ */
+ private CaptureRequest.Builder mPreviewRequestBuilder;
+
+ /**
+ * {@link CaptureRequest} generated by {@link #mPreviewRequestBuilder}
+ */
+ private CaptureRequest mPreviewRequest;
+
+ /**
+ * The current state of camera state for taking pictures.
+ *
+ * @see #mCaptureCallback
+ */
+ private int mState = STATE_PREVIEW;
+
+ /**
+ * A {@link Semaphore} to prevent the app from exiting before closing the camera.
+ */
+ private Semaphore mCameraOpenCloseLock = new Semaphore(1);
+
+ /**
+ * A {@link CameraCaptureSession.CaptureCallback} that handles events related to JPEG capture.
+ */
+ private CameraCaptureSession.CaptureCallback mCaptureCallback
+ = new CameraCaptureSession.CaptureCallback() {
+
+ private void process(CaptureResult result) {
+ switch (mState) {
+ case STATE_PREVIEW: {
+ // We have nothing to do when the camera preview is working normally.
+ break;
+ }
+ case STATE_WAITING_LOCK: {
+ int afState = result.get(CaptureResult.CONTROL_AF_STATE);
+ if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
+ CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
+ int aeState = result.get(CaptureResult.CONTROL_AE_STATE);
+ if (aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
+ mState = STATE_WAITING_NON_PRECAPTURE;
+ captureStillPicture();
+ } else {
+ runPrecaptureSequence();
+ }
+ }
+ break;
+ }
+ case STATE_WAITING_PRECAPTURE: {
+ int aeState = result.get(CaptureResult.CONTROL_AE_STATE);
+ if (CaptureResult.CONTROL_AE_STATE_PRECAPTURE == aeState) {
+ mState = STATE_WAITING_NON_PRECAPTURE;
+ } else if (CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED == aeState) {
+ mState = STATE_WAITING_NON_PRECAPTURE;
+ }
+ break;
+ }
+ case STATE_WAITING_NON_PRECAPTURE: {
+ int aeState = result.get(CaptureResult.CONTROL_AE_STATE);
+ if (CaptureResult.CONTROL_AE_STATE_PRECAPTURE != aeState) {
+ mState = STATE_PICTURE_TAKEN;
+ captureStillPicture();
+ }
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request,
+ CaptureResult partialResult) {
+ process(partialResult);
+ }
+
+ @Override
+ public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
+ TotalCaptureResult result) {
+ process(result);
+ }
+
+ };
+
+ /**
+ * Given {@code choices} of {@code Size}s supported by a camera, chooses the smallest one whose
+ * width and height are at least as large as the respective requested values, and whose aspect
+ * ratio matches with the specified value.
+ *
+ * @param choices The list of sizes that the camera supports for the intended output class
+ * @param width The minimum desired width
+ * @param height The minimum desired height
+ * @param aspectRatio The aspect ratio
+ * @return The optimal {@code Size}, or an arbitrary one if none were big enough
+ */
+ private static Size chooseOptimalSize(Size[] choices, int width, int height, Size aspectRatio) {
+ // Collect the supported resolutions that are at least as big as the preview Surface
+ List<Size> bigEnough = new ArrayList<Size>();
+ int w = aspectRatio.getWidth();
+ int h = aspectRatio.getHeight();
+ for (Size option : choices) {
+ if (option.getHeight() == option.getWidth() * h / w &&
+ option.getWidth() >= width && option.getHeight() >= height) {
+ bigEnough.add(option);
+ }
+ }
+
+ // Pick the smallest of those, assuming we found any
+ if (bigEnough.size() > 0) {
+ return Collections.min(bigEnough, new CompareSizesByArea());
+ } else {
+ Log.e(TAG, "Couldn't find any suitable preview size");
+ return choices[0];
+ }
+ }
+
+ public static Camera2BasicFragment newInstance() {
+ Camera2BasicFragment fragment = new Camera2BasicFragment();
+ fragment.setRetainInstance(true);
+ return fragment;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_camera2_basic, container, false);
+ }
+
+ @Override
+ public void onViewCreated(final View view, Bundle savedInstanceState) {
+ view.findViewById(R.id.picture).setOnClickListener(this);
+ view.findViewById(R.id.info).setOnClickListener(this);
+ mTextureView = (AutoFitTextureView) view.findViewById(R.id.texture);
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ mFile = new File(getActivity().getExternalFilesDir(null), "pic.jpg");
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ startBackgroundThread();
+
+ // When the screen is turned off and turned back on, the SurfaceTexture is already
+ // available, and "onSurfaceTextureAvailable" will not be called. In that case, we can open
+ // a camera and start preview from here (otherwise, we wait until the surface is ready in
+ // the SurfaceTextureListener).
+ if (mTextureView.isAvailable()) {
+ openCamera(mTextureView.getWidth(), mTextureView.getHeight());
+ } else {
+ mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
+ }
+ }
+
+ @Override
+ public void onPause() {
+ closeCamera();
+ stopBackgroundThread();
+ super.onPause();
+ }
+
+ /**
+ * Sets up member variables related to camera.
+ *
+ * @param width The width of available size for camera preview
+ * @param height The height of available size for camera preview
+ */
+ private void setUpCameraOutputs(int width, int height) {
+ Activity activity = getActivity();
+ CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
+ try {
+ for (String cameraId : manager.getCameraIdList()) {
+ CameraCharacteristics characteristics
+ = manager.getCameraCharacteristics(cameraId);
+
+ // We don't use a front facing camera in this sample.
+ if (characteristics.get(CameraCharacteristics.LENS_FACING)
+ == CameraCharacteristics.LENS_FACING_FRONT) {
+ continue;
+ }
+
+ StreamConfigurationMap map = characteristics.get(
+ CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+
+ // For still image captures, we use the largest available size.
+ Size largest = Collections.max(
+ Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),
+ new CompareSizesByArea());
+ mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),
+ ImageFormat.JPEG, /*maxImages*/2);
+ mImageReader.setOnImageAvailableListener(
+ mOnImageAvailableListener, mBackgroundHandler);
+
+ // Danger, W.R.! Attempting to use too large a preview size could exceed the camera
+ // bus' bandwidth limitation, resulting in gorgeous previews but the storage of
+ // garbage capture data.
+ mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
+ width, height, largest);
+
+ // We fit the aspect ratio of TextureView to the size of preview we picked.
+ int orientation = getResources().getConfiguration().orientation;
+ if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ mTextureView.setAspectRatio(
+ mPreviewSize.getWidth(), mPreviewSize.getHeight());
+ } else {
+ mTextureView.setAspectRatio(
+ mPreviewSize.getHeight(), mPreviewSize.getWidth());
+ }
+
+ mCameraId = cameraId;
+ return;
+ }
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ } catch (NullPointerException e) {
+ // Currently an NPE is thrown when the Camera2API is used but not supported on the
+ // device this code runs.
+ new ErrorDialog().show(getFragmentManager(), "dialog");
+ }
+ }
+
+ /**
+ * Opens the camera specified by {@link Camera2BasicFragment#mCameraId}.
+ */
+ private void openCamera(int width, int height) {
+ setUpCameraOutputs(width, height);
+ configureTransform(width, height);
+ Activity activity = getActivity();
+ CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
+ try {
+ if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
+ throw new RuntimeException("Time out waiting to lock camera opening.");
+ }
+ manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
+ }
+ }
+
+ /**
+ * Closes the current {@link CameraDevice}.
+ */
+ private void closeCamera() {
+ try {
+ mCameraOpenCloseLock.acquire();
+ if (null != mCaptureSession) {
+ mCaptureSession.close();
+ mCaptureSession = null;
+ }
+ if (null != mCameraDevice) {
+ mCameraDevice.close();
+ mCameraDevice = null;
+ }
+ if (null != mImageReader) {
+ mImageReader.close();
+ mImageReader = null;
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
+ } finally {
+ mCameraOpenCloseLock.release();
+ }
+ }
+
+ /**
+ * Starts a background thread and its {@link Handler}.
+ */
+ private void startBackgroundThread() {
+ mBackgroundThread = new HandlerThread("CameraBackground");
+ mBackgroundThread.start();
+ mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
+ }
+
+ /**
+ * Stops the background thread and its {@link Handler}.
+ */
+ private void stopBackgroundThread() {
+ mBackgroundThread.quitSafely();
+ try {
+ mBackgroundThread.join();
+ mBackgroundThread = null;
+ mBackgroundHandler = null;
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Creates a new {@link CameraCaptureSession} for camera preview.
+ */
+ private void createCameraPreviewSession() {
+ try {
+ SurfaceTexture texture = mTextureView.getSurfaceTexture();
+ assert texture != null;
+
+ // We configure the size of default buffer to be the size of camera preview we want.
+ texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
+
+ // This is the output Surface we need to start preview.
+ Surface surface = new Surface(texture);
+
+ // We set up a CaptureRequest.Builder with the output Surface.
+ mPreviewRequestBuilder
+ = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+ mPreviewRequestBuilder.addTarget(surface);
+
+ // Here, we create a CameraCaptureSession for camera preview.
+ mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
+ new CameraCaptureSession.StateCallback() {
+
+ @Override
+ public void onConfigured(CameraCaptureSession cameraCaptureSession) {
+ // The camera is already closed
+ if (null == mCameraDevice) {
+ return;
+ }
+
+ // When the session is ready, we start displaying the preview.
+ mCaptureSession = cameraCaptureSession;
+ try {
+ // Auto focus should be continuous for camera preview.
+ mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
+ CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
+ // Flash is automatically enabled when necessary.
+ mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
+ CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
+
+ // Finally, we start displaying the camera preview.
+ mPreviewRequest = mPreviewRequestBuilder.build();
+ mCaptureSession.setRepeatingRequest(mPreviewRequest,
+ mCaptureCallback, mBackgroundHandler);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
+ Activity activity = getActivity();
+ if (null != activity) {
+ Toast.makeText(activity, "Failed", Toast.LENGTH_SHORT).show();
+ }
+ }
+ }, null
+ );
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Configures the necessary {@link android.graphics.Matrix} transformation to `mTextureView`.
+ * This method should be called after the camera preview size is determined in
+ * setUpCameraOutputs and also the size of `mTextureView` is fixed.
+ *
+ * @param viewWidth The width of `mTextureView`
+ * @param viewHeight The height of `mTextureView`
+ */
+ private void configureTransform(int viewWidth, int viewHeight) {
+ Activity activity = getActivity();
+ if (null == mTextureView || null == mPreviewSize || null == activity) {
+ return;
+ }
+ int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
+ Matrix matrix = new Matrix();
+ RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
+ RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
+ float centerX = viewRect.centerX();
+ float centerY = viewRect.centerY();
+ if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
+ bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
+ matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
+ float scale = Math.max(
+ (float) viewHeight / mPreviewSize.getHeight(),
+ (float) viewWidth / mPreviewSize.getWidth());
+ matrix.postScale(scale, scale, centerX, centerY);
+ matrix.postRotate(90 * (rotation - 2), centerX, centerY);
+ }
+ mTextureView.setTransform(matrix);
+ }
+
+ /**
+ * Initiate a still image capture.
+ */
+ private void takePicture() {
+ lockFocus();
+ }
+
+ /**
+ * Lock the focus as the first step for a still image capture.
+ */
+ private void lockFocus() {
+ try {
+ // This is how to tell the camera to lock focus.
+ mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
+ CameraMetadata.CONTROL_AF_TRIGGER_START);
+ // Tell #mCaptureCallback to wait for the lock.
+ mState = STATE_WAITING_LOCK;
+ mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback,
+ mBackgroundHandler);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Run the precapture sequence for capturing a still image. This method should be called when we
+ * get a response in {@link #mCaptureCallback} from {@link #lockFocus()}.
+ */
+ private void runPrecaptureSequence() {
+ try {
+ // This is how to tell the camera to trigger.
+ mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
+ CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
+ // Tell #mCaptureCallback to wait for the precapture sequence to be set.
+ mState = STATE_WAITING_PRECAPTURE;
+ mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
+ mBackgroundHandler);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Capture a still picture. This method should be called when we get a response in
+ * {@link #mCaptureCallback} from both {@link #lockFocus()}.
+ */
+ private void captureStillPicture() {
+ try {
+ final Activity activity = getActivity();
+ if (null == activity || null == mCameraDevice) {
+ return;
+ }
+ // This is the CaptureRequest.Builder that we use to take a picture.
+ final CaptureRequest.Builder captureBuilder =
+ mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
+ captureBuilder.addTarget(mImageReader.getSurface());
+
+ // Use the same AE and AF modes as the preview.
+ captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
+ CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
+ captureBuilder.set(CaptureRequest.CONTROL_AE_MODE,
+ CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
+
+ // Orientation
+ int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
+ captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
+
+ CameraCaptureSession.CaptureCallback CaptureCallback
+ = new CameraCaptureSession.CaptureCallback() {
+
+ @Override
+ public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
+ TotalCaptureResult result) {
+ Toast.makeText(getActivity(), "Saved: " + mFile, Toast.LENGTH_SHORT).show();
+ unlockFocus();
+ }
+ };
+
+ mCaptureSession.stopRepeating();
+ mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Unlock the focus. This method should be called when still image capture sequence is finished.
+ */
+ private void unlockFocus() {
+ try {
+ // Reset the autofucos trigger
+ mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
+ CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
+ mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
+ CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
+ mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
+ mBackgroundHandler);
+ // After this, the camera will go back to the normal state of preview.
+ mState = STATE_PREVIEW;
+ mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback,
+ mBackgroundHandler);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.picture: {
+ takePicture();
+ break;
+ }
+ case R.id.info: {
+ Activity activity = getActivity();
+ if (null != activity) {
+ new AlertDialog.Builder(activity)
+ .setMessage(R.string.intro_message)
+ .setPositiveButton(android.R.string.ok, null)
+ .show();
+ }
+ break;
+ }
+ }
+ }
+
+ /**
+ * Saves a JPEG {@link Image} into the specified {@link File}.
+ */
+ private static class ImageSaver implements Runnable {
+
+ /**
+ * The JPEG image
+ */
+ private final Image mImage;
+ /**
+ * The file we save the image into.
+ */
+ private final File mFile;
+
+ public ImageSaver(Image image, File file) {
+ mImage = image;
+ mFile = file;
+ }
+
+ @Override
+ public void run() {
+ ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
+ byte[] bytes = new byte[buffer.remaining()];
+ buffer.get(bytes);
+ FileOutputStream output = null;
+ try {
+ output = new FileOutputStream(mFile);
+ output.write(bytes);
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ mImage.close();
+ if (null != output) {
+ try {
+ output.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Compares two {@code Size}s based on their areas.
+ */
+ static class CompareSizesByArea implements Comparator<Size> {
+
+ @Override
+ public int compare(Size lhs, Size rhs) {
+ // We cast here to ensure the multiplications won't overflow
+ return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
+ (long) rhs.getWidth() * rhs.getHeight());
+ }
+
+ }
+
+ public static class ErrorDialog extends DialogFragment {
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Activity activity = getActivity();
+ return new AlertDialog.Builder(activity)
+ .setMessage("This device doesn't support Camera2 API.")
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ activity.finish();
+ }
+ })
+ .create();
+ }
+
+ }
+
+}
diff --git a/samples/browseable/Camera2Basic/src/com.example.android.camera2basic/CameraActivity.java b/samples/browseable/Camera2Basic/src/com.example.android.camera2basic/CameraActivity.java
new file mode 100644
index 0000000..eb7f834
--- /dev/null
+++ b/samples/browseable/Camera2Basic/src/com.example.android.camera2basic/CameraActivity.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2014 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.camera2basic;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class CameraActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_camera);
+ if (null == savedInstanceState) {
+ getFragmentManager().beginTransaction()
+ .replace(R.id.container, Camera2BasicFragment.newInstance())
+ .commit();
+ }
+ }
+
+}
diff --git a/samples/browseable/Camera2Video/AndroidManifest.xml b/samples/browseable/Camera2Video/AndroidManifest.xml
new file mode 100644
index 0000000..5cb5428
--- /dev/null
+++ b/samples/browseable/Camera2Video/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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.camera2video"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
+ <uses-permission android:name="android.permission.CAMERA"/>
+ <uses-permission android:name="android.permission.RECORD_AUDIO"/>
+
+ <application android:allowBackup="true"
+ android:label="@string/app_name"
+ android:icon="@drawable/ic_launcher"
+ android:theme="@style/MaterialTheme">
+
+ <activity android:name=".CameraActivity"
+ android:label="@string/app_name">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ </application>
+
+</manifest>
diff --git a/samples/browseable/Camera2Video/_index.jd b/samples/browseable/Camera2Video/_index.jd
new file mode 100644
index 0000000..27ccc11
--- /dev/null
+++ b/samples/browseable/Camera2Video/_index.jd
@@ -0,0 +1,9 @@
+page.tags="Camera2Video"
+sample.group=Media
+@jd:body
+
+<p>
+
+ This sample demonstrates how to record video using Camera2 API.
+
+ </p>
diff --git a/samples/browseable/Camera2Video/res/drawable-hdpi/ic_action_info.png b/samples/browseable/Camera2Video/res/drawable-hdpi/ic_action_info.png
new file mode 100644
index 0000000..32bd1aa
--- /dev/null
+++ b/samples/browseable/Camera2Video/res/drawable-hdpi/ic_action_info.png
Binary files differ
diff --git a/samples/browseable/Camera2Video/res/drawable-hdpi/ic_launcher.png b/samples/browseable/Camera2Video/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..88bc107
--- /dev/null
+++ b/samples/browseable/Camera2Video/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Camera2Video/res/drawable-hdpi/tile.9.png b/samples/browseable/Camera2Video/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/Camera2Video/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/Camera2Video/res/drawable-mdpi/ic_action_info.png b/samples/browseable/Camera2Video/res/drawable-mdpi/ic_action_info.png
new file mode 100644
index 0000000..8efbbf8
--- /dev/null
+++ b/samples/browseable/Camera2Video/res/drawable-mdpi/ic_action_info.png
Binary files differ
diff --git a/samples/browseable/Camera2Video/res/drawable-mdpi/ic_launcher.png b/samples/browseable/Camera2Video/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..28a5a42
--- /dev/null
+++ b/samples/browseable/Camera2Video/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Camera2Video/res/drawable-xhdpi/ic_action_info.png b/samples/browseable/Camera2Video/res/drawable-xhdpi/ic_action_info.png
new file mode 100644
index 0000000..ba143ea
--- /dev/null
+++ b/samples/browseable/Camera2Video/res/drawable-xhdpi/ic_action_info.png
Binary files differ
diff --git a/samples/browseable/Camera2Video/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/Camera2Video/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..2811666
--- /dev/null
+++ b/samples/browseable/Camera2Video/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Camera2Video/res/drawable-xxhdpi/ic_action_info.png b/samples/browseable/Camera2Video/res/drawable-xxhdpi/ic_action_info.png
new file mode 100644
index 0000000..394eb7e
--- /dev/null
+++ b/samples/browseable/Camera2Video/res/drawable-xxhdpi/ic_action_info.png
Binary files differ
diff --git a/samples/browseable/Camera2Video/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/Camera2Video/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..0e8ab46
--- /dev/null
+++ b/samples/browseable/Camera2Video/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Camera2Video/res/layout-land/fragment_camera2_video.xml b/samples/browseable/Camera2Video/res/layout-land/fragment_camera2_video.xml
new file mode 100644
index 0000000..aa139a9
--- /dev/null
+++ b/samples/browseable/Camera2Video/res/layout-land/fragment_camera2_video.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2014 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <com.example.android.camera2video.AutoFitTextureView
+ android:id="@+id/texture"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentStart="true"
+ android:layout_alignParentTop="true" />
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentTop="true"
+ android:layout_below="@id/texture"
+ android:layout_toRightOf="@id/texture"
+ android:background="#4285f4"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/video"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="@string/record" />
+
+ <ImageButton
+ android:id="@+id/info"
+ style="@android:style/Widget.Material.Light.Button.Borderless"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal|bottom"
+ android:contentDescription="@string/description_info"
+ android:padding="20dp"
+ android:src="@drawable/ic_action_info" />
+
+ </FrameLayout>
+
+</RelativeLayout>
diff --git a/samples/browseable/Camera2Video/res/layout/activity_camera.xml b/samples/browseable/Camera2Video/res/layout/activity_camera.xml
new file mode 100644
index 0000000..a86d220
--- /dev/null
+++ b/samples/browseable/Camera2Video/res/layout/activity_camera.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2014 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"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#000"
+ tools:context="com.example.android.camera2basic.CameraActivity" />
diff --git a/samples/browseable/Camera2Video/res/layout/activity_main.xml b/samples/browseable/Camera2Video/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/Camera2Video/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/horizontal_page_margin"
+ android:layout_marginRight="@dimen/horizontal_page_margin"
+ android:layout_marginTop="@dimen/vertical_page_margin"
+ android:layout_marginBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/Camera2Video/res/layout/fragment_camera2_video.xml b/samples/browseable/Camera2Video/res/layout/fragment_camera2_video.xml
new file mode 100644
index 0000000..e30009d
--- /dev/null
+++ b/samples/browseable/Camera2Video/res/layout/fragment_camera2_video.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2014 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <com.example.android.camera2video.AutoFitTextureView
+ android:id="@+id/texture"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentStart="true"
+ android:layout_alignParentTop="true" />
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentStart="true"
+ android:layout_below="@id/texture"
+ android:background="#4285f4">
+
+ <Button
+ android:id="@+id/video"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="@string/record" />
+
+ <ImageButton
+ android:id="@+id/info"
+ android:contentDescription="@string/description_info"
+ style="@android:style/Widget.Material.Light.Button.Borderless"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical|right"
+ android:padding="20dp"
+ android:src="@drawable/ic_action_info" />
+
+ </FrameLayout>
+
+</RelativeLayout>
diff --git a/samples/browseable/Camera2Video/res/values-sw600dp/template-dimens.xml b/samples/browseable/Camera2Video/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/Camera2Video/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/Camera2Video/res/values-sw600dp/template-styles.xml b/samples/browseable/Camera2Video/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/Camera2Video/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/Camera2Video/res/values-v11/template-styles.xml b/samples/browseable/Camera2Video/res/values-v11/template-styles.xml
new file mode 100644
index 0000000..8c1ea66
--- /dev/null
+++ b/samples/browseable/Camera2Video/res/values-v11/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/samples/browseable/Camera2Video/res/values-v21/template-styles.xml b/samples/browseable/Camera2Video/res/values-v21/template-styles.xml
new file mode 100644
index 0000000..134fcd9
--- /dev/null
+++ b/samples/browseable/Camera2Video/res/values-v21/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2014 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>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Material.Light" />
+
+</resources>
diff --git a/samples/browseable/Camera2Video/res/values/base-strings.xml b/samples/browseable/Camera2Video/res/values/base-strings.xml
new file mode 100644
index 0000000..08388de
--- /dev/null
+++ b/samples/browseable/Camera2Video/res/values/base-strings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">Camera2Video</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ This sample demonstrates how to record video using Camera2 API.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/Camera2Video/res/values/strings.xml b/samples/browseable/Camera2Video/res/values/strings.xml
new file mode 100644
index 0000000..bf5e439
--- /dev/null
+++ b/samples/browseable/Camera2Video/res/values/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="record">Record</string>
+ <string name="stop">Stop</string>
+ <string name="description_info">Info</string>
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/Camera2Video/res/values/styles.xml b/samples/browseable/Camera2Video/res/values/styles.xml
new file mode 100644
index 0000000..841d8ce
--- /dev/null
+++ b/samples/browseable/Camera2Video/res/values/styles.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2014 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>
+
+ <style name="MaterialTheme" parent="android:Theme.Material.Light.NoActionBar.Fullscreen" />
+
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/Camera2Video/res/values/template-dimens.xml b/samples/browseable/Camera2Video/res/values/template-dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/Camera2Video/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/Camera2Video/res/values/template-styles.xml b/samples/browseable/Camera2Video/res/values/template-styles.xml
new file mode 100644
index 0000000..6e7d593
--- /dev/null
+++ b/samples/browseable/Camera2Video/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/Camera2Video/src/com.example.android.camera2video/AutoFitTextureView.java b/samples/browseable/Camera2Video/src/com.example.android.camera2video/AutoFitTextureView.java
new file mode 100644
index 0000000..090f81c
--- /dev/null
+++ b/samples/browseable/Camera2Video/src/com.example.android.camera2video/AutoFitTextureView.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2014 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.camera2video;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.TextureView;
+
+/**
+ * A {@link TextureView} that can be adjusted to a specified aspect ratio.
+ */
+public class AutoFitTextureView extends TextureView {
+
+ private int mRatioWidth = 0;
+ private int mRatioHeight = 0;
+
+ public AutoFitTextureView(Context context) {
+ this(context, null);
+ }
+
+ public AutoFitTextureView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio
+ * calculated from the parameters. Note that the actual sizes of parameters don't matter, that
+ * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result.
+ *
+ * @param width Relative horizontal size
+ * @param height Relative vertical size
+ */
+ public void setAspectRatio(int width, int height) {
+ if (width < 0 || height < 0) {
+ throw new IllegalArgumentException("Size cannot be negative.");
+ }
+ mRatioWidth = width;
+ mRatioHeight = height;
+ requestLayout();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ int width = MeasureSpec.getSize(widthMeasureSpec);
+ int height = MeasureSpec.getSize(heightMeasureSpec);
+ if (0 == mRatioWidth || 0 == mRatioHeight) {
+ setMeasuredDimension(width, height);
+ } else {
+ if (width < height * mRatioWidth / mRatioHeight) {
+ setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
+ } else {
+ setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
+ }
+ }
+ }
+
+}
diff --git a/samples/browseable/Camera2Video/src/com.example.android.camera2video/Camera2VideoFragment.java b/samples/browseable/Camera2Video/src/com.example.android.camera2video/Camera2VideoFragment.java
new file mode 100644
index 0000000..78e276a
--- /dev/null
+++ b/samples/browseable/Camera2Video/src/com.example.android.camera2video/Camera2VideoFragment.java
@@ -0,0 +1,578 @@
+/*
+ * Copyright 2014 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.camera2video;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.res.Configuration;
+import android.graphics.Matrix;
+import android.graphics.RectF;
+import android.graphics.SurfaceTexture;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.media.MediaRecorder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.util.Log;
+import android.util.Size;
+import android.util.SparseIntArray;
+import android.view.LayoutInflater;
+import android.view.Surface;
+import android.view.TextureView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.Toast;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+public class Camera2VideoFragment extends Fragment implements View.OnClickListener {
+
+ private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
+
+ private static final String TAG = "Camera2VideoFragment";
+
+ static {
+ ORIENTATIONS.append(Surface.ROTATION_0, 90);
+ ORIENTATIONS.append(Surface.ROTATION_90, 0);
+ ORIENTATIONS.append(Surface.ROTATION_180, 270);
+ ORIENTATIONS.append(Surface.ROTATION_270, 180);
+ }
+
+ /**
+ * An {@link AutoFitTextureView} for camera preview.
+ */
+ private AutoFitTextureView mTextureView;
+
+ /**
+ * Button to record video
+ */
+ private Button mButtonVideo;
+
+ /**
+ * A refernce to the opened {@link android.hardware.camera2.CameraDevice}.
+ */
+ private CameraDevice mCameraDevice;
+
+ /**
+ * A reference to the current {@link android.hardware.camera2.CameraCaptureSession} for preview.
+ */
+ private CameraCaptureSession mPreviewSession;
+
+ /**
+ * {@link TextureView.SurfaceTextureListener} handles several lifecycle events on a
+ * {@link TextureView}.
+ */
+ private TextureView.SurfaceTextureListener mSurfaceTextureListener
+ = new TextureView.SurfaceTextureListener() {
+
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture,
+ int width, int height) {
+ openCamera(width, height);
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture,
+ int width, int height) {
+ configureTransform(width, height);
+ }
+
+ @Override
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
+ return true;
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
+ }
+
+ };
+
+ /**
+ * The {@link android.util.Size} of camera preview.
+ */
+ private Size mPreviewSize;
+
+ /**
+ * The {@link android.util.Size} of video recording.
+ */
+ private Size mVideoSize;
+
+ /**
+ * Camera preview.
+ */
+ private CaptureRequest.Builder mPreviewBuilder;
+
+ /**
+ * MediaRecorder
+ */
+ private MediaRecorder mMediaRecorder;
+
+ /**
+ * Whether the app is recording video now
+ */
+ private boolean mIsRecordingVideo;
+
+ /**
+ * An additional thread for running tasks that shouldn't block the UI.
+ */
+ private HandlerThread mBackgroundThread;
+
+ /**
+ * A {@link Handler} for running tasks in the background.
+ */
+ private Handler mBackgroundHandler;
+
+ /**
+ * A {@link Semaphore} to prevent the app from exiting before closing the camera.
+ */
+ private Semaphore mCameraOpenCloseLock = new Semaphore(1);
+
+ /**
+ * {@link CameraDevice.StateCallback} is called when {@link CameraDevice} changes its status.
+ */
+ private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
+
+ @Override
+ public void onOpened(CameraDevice cameraDevice) {
+ mCameraDevice = cameraDevice;
+ startPreview();
+ mCameraOpenCloseLock.release();
+ if (null != mTextureView) {
+ configureTransform(mTextureView.getWidth(), mTextureView.getHeight());
+ }
+ }
+
+ @Override
+ public void onDisconnected(CameraDevice cameraDevice) {
+ mCameraOpenCloseLock.release();
+ cameraDevice.close();
+ mCameraDevice = null;
+ }
+
+ @Override
+ public void onError(CameraDevice cameraDevice, int error) {
+ mCameraOpenCloseLock.release();
+ cameraDevice.close();
+ mCameraDevice = null;
+ Activity activity = getActivity();
+ if (null != activity) {
+ activity.finish();
+ }
+ }
+
+ };
+
+ public static Camera2VideoFragment newInstance() {
+ Camera2VideoFragment fragment = new Camera2VideoFragment();
+ fragment.setRetainInstance(true);
+ return fragment;
+ }
+
+ /**
+ * In this sample, we choose a video size with 3x4 aspect ratio. Also, we don't use sizes larger
+ * than 1080p, since MediaRecorder cannot handle such a high-resolution video.
+ *
+ * @param choices The list of available sizes
+ * @return The video size
+ */
+ private static Size chooseVideoSize(Size[] choices) {
+ for (Size size : choices) {
+ if (size.getWidth() == size.getHeight() * 4 / 3 && size.getWidth() <= 1080) {
+ return size;
+ }
+ }
+ Log.e(TAG, "Couldn't find any suitable video size");
+ return choices[choices.length - 1];
+ }
+
+ /**
+ * Given {@code choices} of {@code Size}s supported by a camera, chooses the smallest one whose
+ * width and height are at least as large as the respective requested values, and whose aspect
+ * ratio matches with the specified value.
+ *
+ * @param choices The list of sizes that the camera supports for the intended output class
+ * @param width The minimum desired width
+ * @param height The minimum desired height
+ * @param aspectRatio The aspect ratio
+ * @return The optimal {@code Size}, or an arbitrary one if none were big enough
+ */
+ private static Size chooseOptimalSize(Size[] choices, int width, int height, Size aspectRatio) {
+ // Collect the supported resolutions that are at least as big as the preview Surface
+ List<Size> bigEnough = new ArrayList<Size>();
+ int w = aspectRatio.getWidth();
+ int h = aspectRatio.getHeight();
+ for (Size option : choices) {
+ if (option.getHeight() == option.getWidth() * h / w &&
+ option.getWidth() >= width && option.getHeight() >= height) {
+ bigEnough.add(option);
+ }
+ }
+
+ // Pick the smallest of those, assuming we found any
+ if (bigEnough.size() > 0) {
+ return Collections.min(bigEnough, new CompareSizesByArea());
+ } else {
+ Log.e(TAG, "Couldn't find any suitable preview size");
+ return choices[0];
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_camera2_video, container, false);
+ }
+
+ @Override
+ public void onViewCreated(final View view, Bundle savedInstanceState) {
+ mTextureView = (AutoFitTextureView) view.findViewById(R.id.texture);
+ mButtonVideo = (Button) view.findViewById(R.id.video);
+ mButtonVideo.setOnClickListener(this);
+ view.findViewById(R.id.info).setOnClickListener(this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ startBackgroundThread();
+ if (mTextureView.isAvailable()) {
+ openCamera(mTextureView.getWidth(), mTextureView.getHeight());
+ } else {
+ mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
+ }
+ }
+
+ @Override
+ public void onPause() {
+ closeCamera();
+ stopBackgroundThread();
+ super.onPause();
+ }
+
+ @Override
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.video: {
+ if (mIsRecordingVideo) {
+ stopRecordingVideo();
+ } else {
+ startRecordingVideo();
+ }
+ break;
+ }
+ case R.id.info: {
+ Activity activity = getActivity();
+ if (null != activity) {
+ new AlertDialog.Builder(activity)
+ .setMessage(R.string.intro_message)
+ .setPositiveButton(android.R.string.ok, null)
+ .show();
+ }
+ break;
+ }
+ }
+ }
+
+ /**
+ * Starts a background thread and its {@link Handler}.
+ */
+ private void startBackgroundThread() {
+ mBackgroundThread = new HandlerThread("CameraBackground");
+ mBackgroundThread.start();
+ mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
+ }
+
+ /**
+ * Stops the background thread and its {@link Handler}.
+ */
+ private void stopBackgroundThread() {
+ mBackgroundThread.quitSafely();
+ try {
+ mBackgroundThread.join();
+ mBackgroundThread = null;
+ mBackgroundHandler = null;
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Tries to open a {@link CameraDevice}. The result is listened by `mStateCallback`.
+ */
+ private void openCamera(int width, int height) {
+ final Activity activity = getActivity();
+ if (null == activity || activity.isFinishing()) {
+ return;
+ }
+ CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
+ try {
+ if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
+ throw new RuntimeException("Time out waiting to lock camera opening.");
+ }
+ String cameraId = manager.getCameraIdList()[0];
+
+ // Choose the sizes for camera preview and video recording
+ CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
+ StreamConfigurationMap map = characteristics
+ .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ mVideoSize = chooseVideoSize(map.getOutputSizes(MediaRecorder.class));
+ mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
+ width, height, mVideoSize);
+
+ int orientation = getResources().getConfiguration().orientation;
+ if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ mTextureView.setAspectRatio(mPreviewSize.getWidth(), mPreviewSize.getHeight());
+ } else {
+ mTextureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
+ }
+ configureTransform(width, height);
+ mMediaRecorder = new MediaRecorder();
+ manager.openCamera(cameraId, mStateCallback, null);
+ } catch (CameraAccessException e) {
+ Toast.makeText(activity, "Cannot access the camera.", Toast.LENGTH_SHORT).show();
+ activity.finish();
+ } catch (NullPointerException e) {
+ // Currently an NPE is thrown when the Camera2API is used but not supported on the
+ // device this code runs.
+ new ErrorDialog().show(getFragmentManager(), "dialog");
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted while trying to lock camera opening.");
+ }
+ }
+
+ private void closeCamera() {
+ try {
+ mCameraOpenCloseLock.acquire();
+ if (null != mCameraDevice) {
+ mCameraDevice.close();
+ mCameraDevice = null;
+ }
+ if (null != mMediaRecorder) {
+ mMediaRecorder.release();
+ mMediaRecorder = null;
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Interrupted while trying to lock camera closing.");
+ } finally {
+ mCameraOpenCloseLock.release();
+ }
+ }
+
+ /**
+ * Start the camera preview.
+ */
+ private void startPreview() {
+ if (null == mCameraDevice || !mTextureView.isAvailable() || null == mPreviewSize) {
+ return;
+ }
+ try {
+ setUpMediaRecorder();
+ SurfaceTexture texture = mTextureView.getSurfaceTexture();
+ assert texture != null;
+ texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
+ mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
+ List<Surface> surfaces = new ArrayList<Surface>();
+
+ Surface previewSurface = new Surface(texture);
+ surfaces.add(previewSurface);
+ mPreviewBuilder.addTarget(previewSurface);
+
+ Surface recorderSurface = mMediaRecorder.getSurface();
+ surfaces.add(recorderSurface);
+ mPreviewBuilder.addTarget(recorderSurface);
+
+ mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
+
+ @Override
+ public void onConfigured(CameraCaptureSession cameraCaptureSession) {
+ mPreviewSession = cameraCaptureSession;
+ updatePreview();
+ }
+
+ @Override
+ public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
+ Activity activity = getActivity();
+ if (null != activity) {
+ Toast.makeText(activity, "Failed", Toast.LENGTH_SHORT).show();
+ }
+ }
+ }, mBackgroundHandler);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Update the camera preview. {@link #startPreview()} needs to be called in advance.
+ */
+ private void updatePreview() {
+ if (null == mCameraDevice) {
+ return;
+ }
+ try {
+ setUpCaptureRequestBuilder(mPreviewBuilder);
+ HandlerThread thread = new HandlerThread("CameraPreview");
+ thread.start();
+ mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, mBackgroundHandler);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void setUpCaptureRequestBuilder(CaptureRequest.Builder builder) {
+ builder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
+ }
+
+ /**
+ * Configures the necessary {@link android.graphics.Matrix} transformation to `mTextureView`.
+ * This method should not to be called until the camera preview size is determined in
+ * openCamera, or until the size of `mTextureView` is fixed.
+ *
+ * @param viewWidth The width of `mTextureView`
+ * @param viewHeight The height of `mTextureView`
+ */
+ private void configureTransform(int viewWidth, int viewHeight) {
+ Activity activity = getActivity();
+ if (null == mTextureView || null == mPreviewSize || null == activity) {
+ return;
+ }
+ int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
+ Matrix matrix = new Matrix();
+ RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
+ RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
+ float centerX = viewRect.centerX();
+ float centerY = viewRect.centerY();
+ if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
+ bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
+ matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
+ float scale = Math.max(
+ (float) viewHeight / mPreviewSize.getHeight(),
+ (float) viewWidth / mPreviewSize.getWidth());
+ matrix.postScale(scale, scale, centerX, centerY);
+ matrix.postRotate(90 * (rotation - 2), centerX, centerY);
+ }
+ mTextureView.setTransform(matrix);
+ }
+
+ private void setUpMediaRecorder() throws IOException {
+ final Activity activity = getActivity();
+ if (null == activity) {
+ return;
+ }
+ mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
+ mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
+ mMediaRecorder.setOutputFile(getVideoFile(activity).getAbsolutePath());
+ mMediaRecorder.setVideoEncodingBitRate(10000000);
+ mMediaRecorder.setVideoFrameRate(30);
+ mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight());
+ mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
+ mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
+ int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
+ int orientation = ORIENTATIONS.get(rotation);
+ mMediaRecorder.setOrientationHint(orientation);
+ mMediaRecorder.prepare();
+ }
+
+ private File getVideoFile(Context context) {
+ return new File(context.getExternalFilesDir(null), "video.mp4");
+ }
+
+ private void startRecordingVideo() {
+ try {
+ // UI
+ mButtonVideo.setText(R.string.stop);
+ mIsRecordingVideo = true;
+
+ // Start recording
+ mMediaRecorder.start();
+ } catch (IllegalStateException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void stopRecordingVideo() {
+ // UI
+ mIsRecordingVideo = false;
+ mButtonVideo.setText(R.string.record);
+ // Stop recording
+ mMediaRecorder.stop();
+ mMediaRecorder.reset();
+ Activity activity = getActivity();
+ if (null != activity) {
+ Toast.makeText(activity, "Video saved: " + getVideoFile(activity),
+ Toast.LENGTH_SHORT).show();
+ }
+ startPreview();
+ }
+
+ /**
+ * Compares two {@code Size}s based on their areas.
+ */
+ static class CompareSizesByArea implements Comparator<Size> {
+
+ @Override
+ public int compare(Size lhs, Size rhs) {
+ // We cast here to ensure the multiplications won't overflow
+ return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
+ (long) rhs.getWidth() * rhs.getHeight());
+ }
+
+ }
+
+ public static class ErrorDialog extends DialogFragment {
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Activity activity = getActivity();
+ return new AlertDialog.Builder(activity)
+ .setMessage("This device doesn't support Camera2 API.")
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ activity.finish();
+ }
+ })
+ .create();
+ }
+
+ }
+
+}
diff --git a/samples/browseable/Camera2Video/src/com.example.android.camera2video/CameraActivity.java b/samples/browseable/Camera2Video/src/com.example.android.camera2video/CameraActivity.java
new file mode 100644
index 0000000..d90f227
--- /dev/null
+++ b/samples/browseable/Camera2Video/src/com.example.android.camera2video/CameraActivity.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2014 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.camera2video;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class CameraActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_camera);
+ if (null == savedInstanceState) {
+ getFragmentManager().beginTransaction()
+ .replace(R.id.container, Camera2VideoFragment.newInstance())
+ .commit();
+ }
+ }
+
+}
diff --git a/samples/browseable/CardView/AndroidManifest.xml b/samples/browseable/CardView/AndroidManifest.xml
new file mode 100644
index 0000000..6c4a9d9
--- /dev/null
+++ b/samples/browseable/CardView/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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.cardview"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk android:minSdkVersion="7"
+ android:targetSdkVersion="21" />
+
+ <application
+ android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme" >
+ <activity
+ android:name=".CardViewActivity"
+ android:label="@string/app_name" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
diff --git a/samples/browseable/CardView/_index.jd b/samples/browseable/CardView/_index.jd
new file mode 100644
index 0000000..28cbdc7
--- /dev/null
+++ b/samples/browseable/CardView/_index.jd
@@ -0,0 +1,10 @@
+page.tags="CardView Sample"
+sample.group=UI
+@jd:body
+
+<p>
+
+ This sample demonstrates how to use CardView introduced in the support library for the
+ Android L preview.
+
+ </p>
diff --git a/samples/browseable/CardView/res/drawable-hdpi/ic_launcher.png b/samples/browseable/CardView/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..36f4db5
--- /dev/null
+++ b/samples/browseable/CardView/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CardView/res/drawable-hdpi/tile.9.png b/samples/browseable/CardView/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/CardView/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/CardView/res/drawable-mdpi/ic_launcher.png b/samples/browseable/CardView/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f4ca065
--- /dev/null
+++ b/samples/browseable/CardView/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CardView/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/CardView/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..6464a93
--- /dev/null
+++ b/samples/browseable/CardView/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CardView/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/CardView/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..5a017ba
--- /dev/null
+++ b/samples/browseable/CardView/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CardView/res/layout/activity_card_view.xml b/samples/browseable/CardView/res/layout/activity_card_view.xml
new file mode 100644
index 0000000..e32b7a6
--- /dev/null
+++ b/samples/browseable/CardView/res/layout/activity_card_view.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ tools:context="com.example.android.cardview.CardViewActivity"
+ tools:ignore="MergeRootFrame" />
diff --git a/samples/browseable/CardView/res/layout/activity_main.xml b/samples/browseable/CardView/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/CardView/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/horizontal_page_margin"
+ android:layout_marginRight="@dimen/horizontal_page_margin"
+ android:layout_marginTop="@dimen/vertical_page_margin"
+ android:layout_marginBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/CardView/res/layout/fragment_card_view.xml b/samples/browseable/CardView/res/layout/fragment_card_view.xml
new file mode 100644
index 0000000..432c524
--- /dev/null
+++ b/samples/browseable/CardView/res/layout/fragment_card_view.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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.
+-->
+<ScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:card_view="http://schemas.android.com/apk/res-auto"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ >
+
+ <LinearLayout android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ android:paddingTop="@dimen/activity_vertical_margin"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ >
+ <android.support.v7.widget.CardView
+ android:id="@+id/cardview"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:elevation="100dp"
+ card_view:cardBackgroundColor="@color/cardview_initial_background"
+ card_view:cardCornerRadius="8dp"
+ android:layout_marginLeft="@dimen/margin_large"
+ android:layout_marginRight="@dimen/margin_large"
+ >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="@dimen/margin_medium"
+ android:text="@string/cardview_contents"
+ />
+ </android.support.v7.widget.CardView>
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/margin_large"
+ android:orientation="horizontal"
+ >
+ <TextView
+ android:layout_width="@dimen/seekbar_label_length"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:text="@string/cardview_radius_seekbar_text"
+ />
+ <SeekBar
+ android:id="@+id/cardview_radius_seekbar"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="@dimen/margin_medium"
+ />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ >
+ <TextView
+ android:layout_width="@dimen/seekbar_label_length"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:text="@string/cardview_elevation_seekbar_text"
+ />
+ <SeekBar
+ android:id="@+id/cardview_elevation_seekbar"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="@dimen/margin_medium"
+ />
+ </LinearLayout>
+ </LinearLayout>
+</ScrollView>
+
diff --git a/samples/browseable/CardView/res/values-sw600dp/template-dimens.xml b/samples/browseable/CardView/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/CardView/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/CardView/res/values-sw600dp/template-styles.xml b/samples/browseable/CardView/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/CardView/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/CardView/res/values-v11/template-styles.xml b/samples/browseable/CardView/res/values-v11/template-styles.xml
new file mode 100644
index 0000000..8c1ea66
--- /dev/null
+++ b/samples/browseable/CardView/res/values-v11/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/samples/browseable/CardView/res/values-v21/template-styles.xml b/samples/browseable/CardView/res/values-v21/template-styles.xml
new file mode 100644
index 0000000..134fcd9
--- /dev/null
+++ b/samples/browseable/CardView/res/values-v21/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2014 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>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Material.Light" />
+
+</resources>
diff --git a/samples/browseable/CardView/res/values/base-strings.xml b/samples/browseable/CardView/res/values/base-strings.xml
new file mode 100644
index 0000000..d39c396
--- /dev/null
+++ b/samples/browseable/CardView/res/values/base-strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">CardView Sample</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ This sample demonstrates how to use CardView introduced in the support library for the
+ Android L preview.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/CardView/res/values/colors.xml b/samples/browseable/CardView/res/values/colors.xml
new file mode 100644
index 0000000..71d15f7
--- /dev/null
+++ b/samples/browseable/CardView/res/values/colors.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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>
+ <color name="cardview_initial_background">#71C3DE</color>
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/CardView/res/values/dimens.xml b/samples/browseable/CardView/res/values/dimens.xml
new file mode 100644
index 0000000..9133662
--- /dev/null
+++ b/samples/browseable/CardView/res/values/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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>
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+ <dimen name="seekbar_label_length">70dp</dimen>
+</resources>
diff --git a/samples/browseable/CardView/res/values/strings.xml b/samples/browseable/CardView/res/values/strings.xml
new file mode 100644
index 0000000..c995595
--- /dev/null
+++ b/samples/browseable/CardView/res/values/strings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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="title_activity_card_view">CardViewActivity</string>
+ <string name="cardview_contents">This is a CardView widget. CardView widgets can have
+ shadows and rounded corners.
+ \n\nTo create a card with a shadow, use the <font fgcolor="#FFFFFFFF">android:elevation</font>
+ attribute.
+ \n\nTo set the corner radius in your layouts, use the <font
+ fgcolor="#FFFFFFFF">card_view:cardCornerRadius</font> attribute.
+ </string>
+ <string name="cardview_radius_seekbar_text">Radius</string>
+ <string name="cardview_elevation_seekbar_text">Elevation</string>
+</resources>
diff --git a/samples/browseable/CardView/res/values/template-dimens.xml b/samples/browseable/CardView/res/values/template-dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/CardView/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/CardView/res/values/template-styles.xml b/samples/browseable/CardView/res/values/template-styles.xml
new file mode 100644
index 0000000..6e7d593
--- /dev/null
+++ b/samples/browseable/CardView/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/CardView/src/com.example.android.cardview/CardViewActivity.java b/samples/browseable/CardView/src/com.example.android.cardview/CardViewActivity.java
new file mode 100644
index 0000000..0153f56
--- /dev/null
+++ b/samples/browseable/CardView/src/com.example.android.cardview/CardViewActivity.java
@@ -0,0 +1,37 @@
+/*
+* Copyright 2014 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.cardview;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Launcher Activity for the CardView sample app.
+ */
+public class CardViewActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_card_view);
+ if (savedInstanceState == null) {
+ getFragmentManager().beginTransaction()
+ .add(R.id.container, CardViewFragment.newInstance())
+ .commit();
+ }
+ }
+}
diff --git a/samples/browseable/CardView/src/com.example.android.cardview/CardViewFragment.java b/samples/browseable/CardView/src/com.example.android.cardview/CardViewFragment.java
new file mode 100644
index 0000000..46ba6b0
--- /dev/null
+++ b/samples/browseable/CardView/src/com.example.android.cardview/CardViewFragment.java
@@ -0,0 +1,120 @@
+/*
+* Copyright 2014 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.cardview;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.support.v7.widget.CardView;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.SeekBar;
+
+/**
+ * Fragment that demonstrates how to use CardView.
+ */
+public class CardViewFragment extends Fragment {
+
+ private static final String TAG = CardViewFragment.class.getSimpleName();
+
+ /** The CardView widget. */
+ //@VisibleForTesting
+ CardView mCardView;
+
+ /**
+ * SeekBar that changes the cornerRadius attribute for the {@link #mCardView} widget.
+ */
+ //@VisibleForTesting
+ SeekBar mRadiusSeekBar;
+
+ /**
+ * SeekBar that changes the Elevation attribute for the {@link #mCardView} widget.
+ */
+ //@VisibleForTesting
+ SeekBar mElevationSeekBar;
+
+ /**
+ * Use this factory method to create a new instance of
+ * this fragment using the provided parameters.
+ *
+ * @return A new instance of fragment NotificationFragment.
+ */
+ public static CardViewFragment newInstance() {
+ CardViewFragment fragment = new CardViewFragment();
+ fragment.setRetainInstance(true);
+ return fragment;
+ }
+
+ public CardViewFragment() {
+ // Required empty public constructor
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_card_view, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ mCardView = (CardView) view.findViewById(R.id.cardview);
+ mRadiusSeekBar = (SeekBar) view.findViewById(R.id.cardview_radius_seekbar);
+ mRadiusSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ Log.d(TAG, String.format("SeekBar Radius progress : %d", progress));
+ mCardView.setRadius(progress);
+ }
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ //Do nothing
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ //Do nothing
+ }
+ });
+
+ mElevationSeekBar = (SeekBar) view.findViewById(R.id.cardview_elevation_seekbar);
+ mElevationSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ Log.d(TAG, String.format("SeekBar Elevation progress : %d", progress));
+ mCardView.setElevation(progress);
+ }
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ //Do nothing
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ //Do nothing
+ }
+ });
+ }
+}
+
diff --git a/samples/browseable/ClippingBasic/AndroidManifest.xml b/samples/browseable/ClippingBasic/AndroidManifest.xml
new file mode 100644
index 0000000..282d089
--- /dev/null
+++ b/samples/browseable/ClippingBasic/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.clippingbasic"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <application android:allowBackup="true"
+ android:label="@string/app_name"
+ android:icon="@drawable/ic_launcher"
+ android:theme="@android:style/Theme.Material.Light">
+
+ <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>
+ </application>
+
+
+</manifest>
diff --git a/samples/browseable/ClippingBasic/_index.jd b/samples/browseable/ClippingBasic/_index.jd
new file mode 100644
index 0000000..6db7049
--- /dev/null
+++ b/samples/browseable/ClippingBasic/_index.jd
@@ -0,0 +1,9 @@
+page.tags="ClippingBasic"
+sample.group=UI
+@jd:body
+
+<p>
+
+ Basic sample to demonstrate clipping on a View.
+
+ </p>
diff --git a/samples/browseable/ClippingBasic/res/drawable-hdpi/ic_launcher.png b/samples/browseable/ClippingBasic/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..d79207b
--- /dev/null
+++ b/samples/browseable/ClippingBasic/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ClippingBasic/res/drawable-hdpi/tile.9.png b/samples/browseable/ClippingBasic/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/ClippingBasic/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/ClippingBasic/res/drawable-mdpi/ic_launcher.png b/samples/browseable/ClippingBasic/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..3ee83ad
--- /dev/null
+++ b/samples/browseable/ClippingBasic/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ClippingBasic/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/ClippingBasic/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..3b1ae0a
--- /dev/null
+++ b/samples/browseable/ClippingBasic/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ClippingBasic/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/ClippingBasic/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..64b728d
--- /dev/null
+++ b/samples/browseable/ClippingBasic/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ClippingBasic/res/drawable/gradient_drawable.xml b/samples/browseable/ClippingBasic/res/drawable/gradient_drawable.xml
new file mode 100644
index 0000000..c6377cc
--- /dev/null
+++ b/samples/browseable/ClippingBasic/res/drawable/gradient_drawable.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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="#95C7D8"
+ android:endColor="#607D8B"
+ android:angle="270"/>
+</shape>
\ No newline at end of file
diff --git a/samples/browseable/ClippingBasic/res/layout-w720dp/activity_main.xml b/samples/browseable/ClippingBasic/res/layout-w720dp/activity_main.xml
new file mode 100755
index 0000000..c9a52f6
--- /dev/null
+++ b/samples/browseable/ClippingBasic/res/layout-w720dp/activity_main.xml
@@ -0,0 +1,73 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<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/sample_main_layout">
+
+ <LinearLayout
+ android:id="@+id/sample_output"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <FrameLayout
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/margin_medium"
+ android:paddingRight="@dimen/margin_medium"
+ android:paddingTop="@dimen/margin_large"
+ android:paddingBottom="@dimen/margin_large"
+ android:text="@string/intro_message" />
+ </FrameLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1" />
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="0px"
+ android:layout_height="match_parent" />
+
+</LinearLayout>
+
+
diff --git a/samples/browseable/ClippingBasic/res/layout/activity_main.xml b/samples/browseable/ClippingBasic/res/layout/activity_main.xml
new file mode 100755
index 0000000..1ae4f98
--- /dev/null
+++ b/samples/browseable/ClippingBasic/res/layout/activity_main.xml
@@ -0,0 +1,65 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<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/sample_main_layout">
+
+ <ViewAnimator
+ android:id="@+id/sample_output"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1">
+
+ <ScrollView
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/horizontal_page_margin"
+ android:paddingRight="@dimen/horizontal_page_margin"
+ android:paddingTop="@dimen/vertical_page_margin"
+ android:paddingBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </ScrollView>
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ </ViewAnimator>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="match_parent"
+ android:layout_height="0px" />
+
+</LinearLayout>
+
diff --git a/samples/browseable/ClippingBasic/res/layout/clipping_basic_fragment.xml b/samples/browseable/ClippingBasic/res/layout/clipping_basic_fragment.xml
new file mode 100644
index 0000000..44efedc
--- /dev/null
+++ b/samples/browseable/ClippingBasic/res/layout/clipping_basic_fragment.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+
+ <FrameLayout
+ android:id="@+id/frame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/gradient_drawable"
+ android:foreground="?android:attr/selectableItemBackground"
+ android:addStatesFromChildren="true"
+ android:layout_above="@+id/button" >
+ <TextView
+ android:id="@+id/text_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:textSize="26sp"
+ android:textColor="@android:color/white"
+ android:layout_marginLeft="64dp"
+ android:layout_marginRight="64dp"
+ android:gravity="center" />
+ </FrameLayout>
+
+ <Button
+ android:id="@+id/button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/clip_button"
+ android:layout_alignParentBottom="true"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="8dp"
+ android:layout_marginTop="8dp"/>
+</RelativeLayout>
\ No newline at end of file
diff --git a/samples/browseable/ClippingBasic/res/menu/main.xml b/samples/browseable/ClippingBasic/res/menu/main.xml
new file mode 100644
index 0000000..b49c2c5
--- /dev/null
+++ b/samples/browseable/ClippingBasic/res/menu/main.xml
@@ -0,0 +1,21 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/menu_toggle_log"
+ android:showAsAction="always"
+ android:title="@string/sample_show_log" />
+</menu>
diff --git a/samples/browseable/ClippingBasic/res/values-sw600dp/template-dimens.xml b/samples/browseable/ClippingBasic/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/ClippingBasic/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/ClippingBasic/res/values-sw600dp/template-styles.xml b/samples/browseable/ClippingBasic/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/ClippingBasic/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/ClippingBasic/res/values-v11/template-styles.xml b/samples/browseable/ClippingBasic/res/values-v11/template-styles.xml
new file mode 100644
index 0000000..8c1ea66
--- /dev/null
+++ b/samples/browseable/ClippingBasic/res/values-v11/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/samples/browseable/ClippingBasic/res/values-v21/template-styles.xml b/samples/browseable/ClippingBasic/res/values-v21/template-styles.xml
new file mode 100644
index 0000000..134fcd9
--- /dev/null
+++ b/samples/browseable/ClippingBasic/res/values-v21/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2014 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>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Material.Light" />
+
+</resources>
diff --git a/samples/browseable/ClippingBasic/res/values/base-strings.xml b/samples/browseable/ClippingBasic/res/values/base-strings.xml
new file mode 100644
index 0000000..622c074
--- /dev/null
+++ b/samples/browseable/ClippingBasic/res/values/base-strings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">ClippingBasic</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ Basic sample to demonstrate clipping on a View.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/ClippingBasic/res/values/fragmentview_strings.xml b/samples/browseable/ClippingBasic/res/values/fragmentview_strings.xml
new file mode 100755
index 0000000..7b9d9ec
--- /dev/null
+++ b/samples/browseable/ClippingBasic/res/values/fragmentview_strings.xml
@@ -0,0 +1,19 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="sample_show_log">Show Log</string>
+ <string name="sample_hide_log">Hide Log</string>
+</resources>
diff --git a/samples/browseable/ClippingBasic/res/values/strings.xml b/samples/browseable/ClippingBasic/res/values/strings.xml
new file mode 100644
index 0000000..b01a168
--- /dev/null
+++ b/samples/browseable/ClippingBasic/res/values/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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-array name="sample_texts">
+ <item>Lorem ipsum dolor sit amet, duo numquam nominavi consectetuer at.</item>
+ <item>Vivendo philosophia mea et. Duo te idque appetere.</item>
+ <item>De finibus bonorum et malorum.</item>
+ </string-array>
+
+ <string name="clip_button">Enabled outline clipping</string>
+ <string name="unclip_button">Disable outline clipping</string>
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/ClippingBasic/res/values/template-dimens.xml b/samples/browseable/ClippingBasic/res/values/template-dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/ClippingBasic/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/ClippingBasic/res/values/template-styles.xml b/samples/browseable/ClippingBasic/res/values/template-styles.xml
new file mode 100644
index 0000000..6e7d593
--- /dev/null
+++ b/samples/browseable/ClippingBasic/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/ClippingBasic/src/com.example.android.clippingbasic/ClippingBasicFragment.java b/samples/browseable/ClippingBasic/src/com.example.android.clippingbasic/ClippingBasicFragment.java
new file mode 100644
index 0000000..295a474
--- /dev/null
+++ b/samples/browseable/ClippingBasic/src/com.example.android.clippingbasic/ClippingBasicFragment.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2014 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.clippingbasic;
+
+import com.example.android.common.logger.Log;
+
+import android.graphics.Outline;
+import android.support.v4.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
+import android.widget.Button;
+import android.widget.TextView;
+
+/**
+ * This sample shows how to clip a {@link View} using an {@link Outline}.
+ */
+public class ClippingBasicFragment extends Fragment {
+
+ private final static String TAG = "ClippingBasicFragment";
+
+ /* Store the click count so that we can show a different text on every click. */
+ private int mClickCount = 0;
+
+ /* The {@Link Outline} used to clip the image with. */
+ private ViewOutlineProvider mOutlineProvider;
+
+ /* An array of texts. */
+ private String[] mSampleTexts;
+
+ /* A reference to a {@Link TextView} that shows different text strings when clicked. */
+ private TextView mTextView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ mOutlineProvider = new ClipOutlineProvider();
+ mSampleTexts = getResources().getStringArray(R.array.sample_texts);
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.clipping_basic_fragment, container, false);
+ }
+
+ @Override
+ public void onViewCreated(final View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ /* Set the initial text for the TextView. */
+ mTextView = (TextView) view.findViewById(R.id.text_view);
+ changeText();
+
+
+ final View clippedView = view.findViewById(R.id.frame);
+
+ /* Sets the OutlineProvider for the View. */
+ clippedView.setOutlineProvider(mOutlineProvider);
+
+ /* When the button is clicked, the text is clipped or un-clipped. */
+ view.findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View bt) {
+ // Toggle whether the View is clipped to the outline
+ if (clippedView.getClipToOutline()) {
+ /* The Outline is set for the View, but disable clipping. */
+ clippedView.setClipToOutline(false);
+
+ Log.d(TAG, String.format("Clipping to outline is disabled"));
+ ((Button) bt).setText(R.string.clip_button);
+ } else {
+ /* Enables clipping on the View. */
+ clippedView.setClipToOutline(true);
+
+ Log.d(TAG, String.format("Clipping to outline is enabled"));
+ ((Button) bt).setText(R.string.unclip_button);
+ }
+ }
+ });
+
+ /* When the text is clicked, a new string is shown. */
+ view.findViewById(R.id.text_view).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ mClickCount++;
+
+ // Update the text in the TextView
+ changeText();
+
+ // Invalidate the outline just in case the TextView changed size
+ clippedView.invalidateOutline();
+ }
+ });
+ }
+
+ private void changeText() {
+ // Compute the position of the string in the array using the number of strings
+ // and the number of clicks.
+ String newText = mSampleTexts[mClickCount % mSampleTexts.length];
+
+ /* Once the text is selected, change the TextView */
+ mTextView.setText(newText);
+ Log.d(TAG, String.format("Text was changed."));
+
+
+ }
+
+ /**
+ * A {@link ViewOutlineProvider} which clips the view with a rounded rectangle which is inset
+ * by 10%
+ */
+ private class ClipOutlineProvider extends ViewOutlineProvider {
+
+ @Override
+ public void getOutline(View view, Outline outline) {
+ final int margin = Math.min(view.getWidth(), view.getHeight()) / 10;
+ outline.setRoundRect(margin, margin, view.getWidth() - margin,
+ view.getHeight() - margin, margin / 2);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/samples/browseable/ClippingBasic/src/com.example.android.clippingbasic/MainActivity.java b/samples/browseable/ClippingBasic/src/com.example.android.clippingbasic/MainActivity.java
new file mode 100644
index 0000000..fe290f9
--- /dev/null
+++ b/samples/browseable/ClippingBasic/src/com.example.android.clippingbasic/MainActivity.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.clippingbasic;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ViewAnimator;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description, sample log and a custom
+ * {@link android.support.v4.app.Fragment} which can display a view.
+ * <p>
+ * For devices with displays with a width of 720dp or greater, the sample log is always visible,
+ * on other devices it's visibility is controlled by an item on the Action Bar.
+ */
+public class MainActivity extends SampleActivityBase {
+
+ public static final String TAG = "MainActivity";
+
+ // Whether the Log Fragment is currently shown
+ private boolean mLogShown;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ if (savedInstanceState == null) {
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ ClippingBasicFragment fragment = new ClippingBasicFragment();
+ transaction.replace(R.id.sample_content_fragment, fragment);
+ transaction.commit();
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
+ logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
+ logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);
+
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch(item.getItemId()) {
+ case R.id.menu_toggle_log:
+ mLogShown = !mLogShown;
+ ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);
+ if (mLogShown) {
+ output.setDisplayedChild(1);
+ } else {
+ output.setDisplayedChild(0);
+ }
+ supportInvalidateOptionsMenu();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ /** Create a chain of targets that will receive log data */
+ @Override
+ public void initializeLogging() {
+ // Wraps Android's native log framework.
+ LogWrapper logWrapper = new LogWrapper();
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ Log.setLogNode(logWrapper);
+
+ // Filter strips out everything except the message text.
+ MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+ logWrapper.setNext(msgFilter);
+
+ // On screen logging via a fragment with a TextView.
+ LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+ .findFragmentById(R.id.log_fragment);
+ msgFilter.setNext(logFragment.getLogView());
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/ClippingBasic/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/ClippingBasic/src/com.example.android.common/activities/SampleActivityBase.java
new file mode 100644
index 0000000..3228927
--- /dev/null
+++ b/samples/browseable/ClippingBasic/src/com.example.android.common/activities/SampleActivityBase.java
@@ -0,0 +1,52 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.common.activities;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogWrapper;
+
+/**
+ * Base launcher activity, to handle most of the common plumbing for samples.
+ */
+public class SampleActivityBase extends FragmentActivity {
+
+ public static final String TAG = "SampleActivityBase";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ initializeLogging();
+ }
+
+ /** Set up targets to receive log data */
+ public void initializeLogging() {
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ // Wraps Android's native log framework
+ LogWrapper logWrapper = new LogWrapper();
+ Log.setLogNode(logWrapper);
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/ClippingBasic/src/com.example.android.common/logger/Log.java b/samples/browseable/ClippingBasic/src/com.example.android.common/logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/ClippingBasic/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+ // Grabbing the native values from Android's native logging facilities,
+ // to make for easy migration and interop.
+ public static final int NONE = -1;
+ public static final int VERBOSE = android.util.Log.VERBOSE;
+ public static final int DEBUG = android.util.Log.DEBUG;
+ public static final int INFO = android.util.Log.INFO;
+ public static final int WARN = android.util.Log.WARN;
+ public static final int ERROR = android.util.Log.ERROR;
+ public static final int ASSERT = android.util.Log.ASSERT;
+
+ // Stores the beginning of the LogNode topology.
+ private static LogNode mLogNode;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public static LogNode getLogNode() {
+ return mLogNode;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to.
+ */
+ public static void setLogNode(LogNode node) {
+ mLogNode = node;
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void println(int priority, String tag, String msg, Throwable tr) {
+ if (mLogNode != null) {
+ mLogNode.println(priority, tag, msg, tr);
+ }
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ */
+ public static void println(int priority, String tag, String msg) {
+ println(priority, tag, msg, null);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void v(String tag, String msg, Throwable tr) {
+ println(VERBOSE, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void v(String tag, String msg) {
+ v(tag, msg, null);
+ }
+
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void d(String tag, String msg, Throwable tr) {
+ println(DEBUG, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void d(String tag, String msg) {
+ d(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void i(String tag, String msg, Throwable tr) {
+ println(INFO, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void i(String tag, String msg) {
+ i(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, String msg, Throwable tr) {
+ println(WARN, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void w(String tag, String msg) {
+ w(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, Throwable tr) {
+ w(tag, null, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void e(String tag, String msg, Throwable tr) {
+ println(ERROR, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void e(String tag, String msg) {
+ e(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, String msg, Throwable tr) {
+ println(ASSERT, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void wtf(String tag, String msg) {
+ wtf(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, Throwable tr) {
+ wtf(tag, null, tr);
+ }
+}
diff --git a/samples/browseable/ClippingBasic/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/ClippingBasic/src/com.example.android.common/logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/ClippingBasic/src/com.example.android.common/logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+ private LogView mLogView;
+ private ScrollView mScrollView;
+
+ public LogFragment() {}
+
+ public View inflateViews() {
+ mScrollView = new ScrollView(getActivity());
+ ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ mScrollView.setLayoutParams(scrollParams);
+
+ mLogView = new LogView(getActivity());
+ ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+ logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ mLogView.setLayoutParams(logParams);
+ mLogView.setClickable(true);
+ mLogView.setFocusable(true);
+ mLogView.setTypeface(Typeface.MONOSPACE);
+
+ // Want to set padding as 16 dips, setPadding takes pixels. Hooray math!
+ int paddingDips = 16;
+ double scale = getResources().getDisplayMetrics().density;
+ int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+ mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+ mLogView.setCompoundDrawablePadding(paddingPixels);
+
+ mLogView.setGravity(Gravity.BOTTOM);
+ mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+ mScrollView.addView(mLogView);
+ return mScrollView;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ View result = inflateViews();
+
+ mLogView.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+ }
+ });
+ return result;
+ }
+
+ public LogView getLogView() {
+ return mLogView;
+ }
+}
\ No newline at end of file
diff --git a/samples/browseable/ClippingBasic/src/com.example.android.common/logger/LogNode.java b/samples/browseable/ClippingBasic/src/com.example.android.common/logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/ClippingBasic/src/com.example.android.common/logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 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.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+ /**
+ * Instructs first LogNode in the list to print the log data provided.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/ClippingBasic/src/com.example.android.common/logger/LogView.java b/samples/browseable/ClippingBasic/src/com.example.android.common/logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/ClippingBasic/src/com.example.android.common/logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+ public LogView(Context context) {
+ super(context);
+ }
+
+ public LogView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public LogView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * Formats the log data and prints it out to the LogView.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+
+
+ String priorityStr = null;
+
+ // For the purposes of this View, we want to print the priority as readable text.
+ switch(priority) {
+ case android.util.Log.VERBOSE:
+ priorityStr = "VERBOSE";
+ break;
+ case android.util.Log.DEBUG:
+ priorityStr = "DEBUG";
+ break;
+ case android.util.Log.INFO:
+ priorityStr = "INFO";
+ break;
+ case android.util.Log.WARN:
+ priorityStr = "WARN";
+ break;
+ case android.util.Log.ERROR:
+ priorityStr = "ERROR";
+ break;
+ case android.util.Log.ASSERT:
+ priorityStr = "ASSERT";
+ break;
+ default:
+ break;
+ }
+
+ // Handily, the Log class has a facility for converting a stack trace into a usable string.
+ String exceptionStr = null;
+ if (tr != null) {
+ exceptionStr = android.util.Log.getStackTraceString(tr);
+ }
+
+ // Take the priority, tag, message, and exception, and concatenate as necessary
+ // into one usable line of text.
+ final StringBuilder outputBuilder = new StringBuilder();
+
+ String delimiter = "\t";
+ appendIfNotNull(outputBuilder, priorityStr, delimiter);
+ appendIfNotNull(outputBuilder, tag, delimiter);
+ appendIfNotNull(outputBuilder, msg, delimiter);
+ appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+ // In case this was originally called from an AsyncTask or some other off-UI thread,
+ // make sure the update occurs within the UI thread.
+ ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+ @Override
+ public void run() {
+ // Display the text we just generated within the LogView.
+ appendToLog(outputBuilder.toString());
+ }
+ })));
+
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+ * the logger takes so many arguments that might be null, this method helps cut out some of the
+ * agonizing tedium of writing the same 3 lines over and over.
+ * @param source StringBuilder containing the text to append to.
+ * @param addStr The String to append
+ * @param delimiter The String to separate the source and appended strings. A tab or comma,
+ * for instance.
+ * @return The fully concatenated String as a StringBuilder
+ */
+ private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+ if (addStr != null) {
+ if (addStr.length() == 0) {
+ delimiter = "";
+ }
+
+ return source.append(addStr).append(delimiter);
+ }
+ return source;
+ }
+
+ // The next LogNode in the chain.
+ LogNode mNext;
+
+ /** Outputs the string as a new line of log data in the LogView. */
+ public void appendToLog(String s) {
+ append("\n" + s);
+ }
+
+
+}
diff --git a/samples/browseable/ClippingBasic/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/ClippingBasic/src/com.example.android.common/logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/ClippingBasic/src/com.example.android.common/logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 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.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface. This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+ // For piping: The next node to receive Log data after this one has done its work.
+ private LogNode mNext;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /**
+ * Prints data out to the console using Android's native log mechanism.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ // There actually are log methods that don't take a msg parameter. For now,
+ // if that's the case, just convert null to the empty string and move on.
+ String useMsg = msg;
+ if (useMsg == null) {
+ useMsg = "";
+ }
+
+ // If an exeption was provided, convert that exception to a usable string and attach
+ // it to the end of the msg method.
+ if (tr != null) {
+ msg += "\n" + Log.getStackTraceString(tr);
+ }
+
+ // This is functionally identical to Log.x(tag, useMsg);
+ // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+ Log.println(priority, tag, useMsg);
+
+ // If this isn't the last node in the chain, move things along.
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+}
diff --git a/samples/browseable/ClippingBasic/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/ClippingBasic/src/com.example.android.common/logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/ClippingBasic/src/com.example.android.common/logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+ LogNode mNext;
+
+ /**
+ * Takes the "next" LogNode as a parameter, to simplify chaining.
+ *
+ * @param next The next LogNode in the pipeline.
+ */
+ public MessageOnlyLogFilter(LogNode next) {
+ mNext = next;
+ }
+
+ public MessageOnlyLogFilter() {
+ }
+
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ if (mNext != null) {
+ getNext().println(Log.NONE, null, msg, null);
+ }
+ }
+
+ /**
+ * Returns the next LogNode in the chain.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+}
diff --git a/samples/browseable/DocumentCentricApps/AndroidManifest.xml b/samples/browseable/DocumentCentricApps/AndroidManifest.xml
new file mode 100644
index 0000000..a1378ef
--- /dev/null
+++ b/samples/browseable/DocumentCentricApps/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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.documentcentricapps"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <application android:allowBackup="true"
+ android:label="@string/app_name"
+ android:icon="@drawable/ic_launcher"
+ android:theme="@style/AppTheme">
+
+ <activity android:name="com.example.android.documentcentricapps.DocumentCentricActivity"
+ android:label="@string/app_name"
+ android:persistableMode="persistAcrossReboots">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name="com.example.android.documentcentricapps.NewDocumentActivity"
+ android:label="@string/activity_new_document_title" >
+ </activity>
+ </application>
+
+</manifest>
diff --git a/samples/browseable/DocumentCentricApps/_index.jd b/samples/browseable/DocumentCentricApps/_index.jd
new file mode 100644
index 0000000..9eb8b2f
--- /dev/null
+++ b/samples/browseable/DocumentCentricApps/_index.jd
@@ -0,0 +1,12 @@
+page.tags="DocumentCentricRecents"
+sample.group=UI
+@jd:body
+
+<p>
+
+ This sample shows the basic usage of the new \"Document Centric Apps\" API.
+ It let\'s you create new documents in the system overview menu and persists its
+ state through reboots. If \"Task per document\" is checked a new task will be
+ created for every new document in the overview menu.
+
+ </p>
diff --git a/samples/browseable/DocumentCentricApps/res/drawable-hdpi/ic_launcher.png b/samples/browseable/DocumentCentricApps/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..b1efaf4
--- /dev/null
+++ b/samples/browseable/DocumentCentricApps/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/DocumentCentricApps/res/drawable-hdpi/tile.9.png b/samples/browseable/DocumentCentricApps/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/DocumentCentricApps/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/DocumentCentricApps/res/drawable-mdpi/ic_launcher.png b/samples/browseable/DocumentCentricApps/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f5f9244
--- /dev/null
+++ b/samples/browseable/DocumentCentricApps/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/DocumentCentricApps/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/DocumentCentricApps/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..5d07b3f
--- /dev/null
+++ b/samples/browseable/DocumentCentricApps/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/DocumentCentricApps/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/DocumentCentricApps/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..6ef21e1
--- /dev/null
+++ b/samples/browseable/DocumentCentricApps/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/DocumentCentricApps/res/layout/activity_document_centric_main.xml b/samples/browseable/DocumentCentricApps/res/layout/activity_document_centric_main.xml
new file mode 100755
index 0000000..5f62415
--- /dev/null
+++ b/samples/browseable/DocumentCentricApps/res/layout/activity_document_centric_main.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/horizontal_page_margin"
+ android:layout_marginRight="@dimen/horizontal_page_margin"
+ android:layout_marginTop="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/margin_small"
+ android:layout_marginLeft="@dimen/margin_small"
+ android:orientation="vertical">
+
+ <Button
+ android:id="@+id/new_document_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="@dimen/margin_medium"
+ android:text="@string/new_document_button_text"
+ android:onClick="createNewDocument" />
+
+ <CheckBox
+ android:id="@+id/multiple_task_checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/margin_small"
+ android:text="@string/multiple_task_checkbox_label" />
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/samples/browseable/DocumentCentricApps/res/layout/activity_main.xml b/samples/browseable/DocumentCentricApps/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/DocumentCentricApps/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/horizontal_page_margin"
+ android:layout_marginRight="@dimen/horizontal_page_margin"
+ android:layout_marginTop="@dimen/vertical_page_margin"
+ android:layout_marginBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/DocumentCentricApps/res/layout/activity_new_document.xml b/samples/browseable/DocumentCentricApps/res/layout/activity_new_document.xml
new file mode 100644
index 0000000..2a6c58a
--- /dev/null
+++ b/samples/browseable/DocumentCentricApps/res/layout/activity_new_document.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ tools:context="com.example.android.basicdocumentcentric.DocumentActivity">
+
+ <TextView
+ android:id="@+id/hello_new_document_text_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/margin_small"
+ android:layout_marginLeft="@dimen/margin_small" />
+
+ <Button
+ android:id="@+id/remove_task_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/margin_small"
+ android:layout_marginLeft="@dimen/margin_small"
+ android:text="@string/remove_task_button_text"
+ android:onClick="onRemoveFromOverview" />
+
+</LinearLayout>
diff --git a/samples/browseable/DocumentCentricApps/res/values-sw600dp/template-dimens.xml b/samples/browseable/DocumentCentricApps/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/DocumentCentricApps/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/DocumentCentricApps/res/values-sw600dp/template-styles.xml b/samples/browseable/DocumentCentricApps/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/DocumentCentricApps/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/DocumentCentricApps/res/values-v11/template-styles.xml b/samples/browseable/DocumentCentricApps/res/values-v11/template-styles.xml
new file mode 100644
index 0000000..8c1ea66
--- /dev/null
+++ b/samples/browseable/DocumentCentricApps/res/values-v11/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/samples/browseable/DocumentCentricApps/res/values-v21/template-styles.xml b/samples/browseable/DocumentCentricApps/res/values-v21/template-styles.xml
new file mode 100644
index 0000000..134fcd9
--- /dev/null
+++ b/samples/browseable/DocumentCentricApps/res/values-v21/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2014 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>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Material.Light" />
+
+</resources>
diff --git a/samples/browseable/DocumentCentricApps/res/values/base-strings.xml b/samples/browseable/DocumentCentricApps/res/values/base-strings.xml
new file mode 100644
index 0000000..0ffbd45
--- /dev/null
+++ b/samples/browseable/DocumentCentricApps/res/values/base-strings.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">DocumentCentricRecents</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ This sample shows the basic usage of the new \"Document Centric Apps\" API.
+ It let\'s you create new documents in the system overview menu and persists its
+ state through reboots. If \"Task per document\" is checked a new task will be
+ created for every new document in the overview menu.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/DocumentCentricApps/res/values/dimens.xml b/samples/browseable/DocumentCentricApps/res/values/dimens.xml
new file mode 100644
index 0000000..061387a
--- /dev/null
+++ b/samples/browseable/DocumentCentricApps/res/values/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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>
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+</resources>
diff --git a/samples/browseable/DocumentCentricApps/res/values/strings.xml b/samples/browseable/DocumentCentricApps/res/values/strings.xml
new file mode 100644
index 0000000..5f0e3f0
--- /dev/null
+++ b/samples/browseable/DocumentCentricApps/res/values/strings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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="title_activity_main">MainActivity</string>
+ <string name="hello_new_document_counter">Hello Document %s!</string>
+ <string name="reusing_document_counter">Reusing Document %s!</string>
+ <string name="activity_new_document_title">DocumentActivity</string>
+ <string name="new_document_button_text">Create new document</string>
+ <string name="multiple_task_checkbox_label">Task per document</string>
+ <string name="remove_task_button_text">Remove from Overview</string>
+
+</resources>
diff --git a/samples/browseable/DocumentCentricApps/res/values/template-dimens.xml b/samples/browseable/DocumentCentricApps/res/values/template-dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/DocumentCentricApps/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/DocumentCentricApps/res/values/template-styles.xml b/samples/browseable/DocumentCentricApps/res/values/template-styles.xml
new file mode 100644
index 0000000..6e7d593
--- /dev/null
+++ b/samples/browseable/DocumentCentricApps/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/DocumentCentricApps/src/com.example.android.documentcentricapps/DocumentCentricActivity.java b/samples/browseable/DocumentCentricApps/src/com.example.android.documentcentricapps/DocumentCentricActivity.java
new file mode 100644
index 0000000..92b5b43
--- /dev/null
+++ b/samples/browseable/DocumentCentricApps/src/com.example.android.documentcentricapps/DocumentCentricActivity.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2014 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.documentcentricapps;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.PersistableBundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.CheckBox;
+
+/**
+ * DocumentCentricActivity shows the basic usage of the new Document-Centric Apps API. The new
+ * API modifies the meaning of the {@link Intent#FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET} flag, which is
+ * now deprecated. In versions before L it serves to define a boundary between the main task and a
+ * subtask. The subtask holds a different thumbnail and all activities in it are finished when the
+ * task is reset. In L this flag causes a full break with the task that launched it. As such it has
+ * been renamed to {@link Intent#FLAG_ACTIVITY_NEW_DOCUMENT}.
+ *
+ * This sample mainly uses Intent flags in code. But Activities can also specify in their manifests
+ * that they shall always be launched into a new task in the above manner using the new activity
+ * attribute documentLaunchMode which may take on one of three values, “intoExisting” equivalent to
+ * NEW_DOCUMENT, “always” equivalent to NEW_DOCUMENT | MULTIPLE_TASK, “none” the default, and
+ * “never” which will negate the effect of any attempt to launch the activity with NEW_DOCUMENT.
+ */
+public class DocumentCentricActivity extends Activity {
+
+ private final static String TAG = "DocumentCentricActivity";
+
+ public final static String KEY_EXTRA_NEW_DOCUMENT_COUNTER = "KEY_EXTRA_NEW_DOCUMENT_COUNTER";
+
+ private static int mDocumentCounter = 0;
+
+ private CheckBox mCheckbox;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_document_centric_main);
+ mCheckbox = (CheckBox) findViewById(R.id.multiple_task_checkbox);
+ }
+
+ @Override
+ public void onPostCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
+ super.onPostCreate(savedInstanceState, persistentState);
+ // Restore state from PersistableBundle
+ if (persistentState != null) {
+ mDocumentCounter = persistentState.getInt(KEY_EXTRA_NEW_DOCUMENT_COUNTER);
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
+ /*
+ To maintain activity state across reboots the system saves and restore critical information for
+ all tasks and their activities. Information known by the system includes the activity stack order,
+ each task’s thumbnails and each activity’s and task's Intents. For Information that cannot be retained
+ because they contain Bundles which can’t be persisted a new constrained version of Bundle,
+ PersistableBundle is added. PersistableBundle can store only basic data types. To use it
+ in your Activities you must declare the new activity:persistableMode attribute in the manifest.
+ */
+ outPersistentState.putInt(KEY_EXTRA_NEW_DOCUMENT_COUNTER, mDocumentCounter);
+ super.onSaveInstanceState(outState, outPersistentState);
+ }
+
+ public void createNewDocument(View view) {
+ boolean useMultipleTasks = mCheckbox.isChecked();
+ final Intent newDocumentIntent = newDocumentIntent();
+ if (useMultipleTasks) {
+ /*
+ When {@linkIntent#FLAG_ACTIVITY_NEW_DOCUMENT} is used with {@link Intent#FLAG_ACTIVITY_MULTIPLE_TASK}
+ the system will always create a new task with the target activity as the root. This allows the same
+ document to be opened in more than one task.
+ */
+ newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ }
+ startActivity(newDocumentIntent);
+ }
+
+
+ /**
+ * Returns an new {@link Intent} to start {@link NewDocumentActivity} as a new document in
+ * overview menu.
+ *
+ * To start a new document task {@link Intent#FLAG_ACTIVITY_NEW_DOCUMENT} must be used. The
+ * system will search through existing tasks for one whose Intent matches the Intent component
+ * name and the Intent data. If it finds one then that task will be brought to the front and the
+ * new Intent will be passed to onNewIntent().
+ *
+ * Activities launched with the NEW_DOCUMENT flag must be created with launchMode="standard".
+ */
+ private Intent newDocumentIntent() {
+ final Intent newDocumentIntent = new Intent(this, NewDocumentActivity.class);
+ newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+ newDocumentIntent.putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, incrementAndGet());
+ return newDocumentIntent;
+ }
+
+ private static int incrementAndGet() {
+ Log.d(TAG, "incrementAndGet(): " + mDocumentCounter);
+ return mDocumentCounter++;
+ }
+
+}
diff --git a/samples/browseable/DocumentCentricApps/src/com.example.android.documentcentricapps/NewDocumentActivity.java b/samples/browseable/DocumentCentricApps/src/com.example.android.documentcentricapps/NewDocumentActivity.java
new file mode 100644
index 0000000..ac5e4f3
--- /dev/null
+++ b/samples/browseable/DocumentCentricApps/src/com.example.android.documentcentricapps/NewDocumentActivity.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014 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.documentcentricapps;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * Represents a "document" in the new overview notion. This is just a placeholder.
+ * Real world examples of this could be:
+ *
+ * <ul>
+ * <li>Document Editing</li>
+ * <li>Browser tabs</li>
+ * <li>Message composition</li>
+ * <li>Sharing</li>
+ * <li>Shopping item details</li>
+ * </ul>
+ */
+public class NewDocumentActivity extends Activity {
+
+ private TextView mDocumentCounterTextView;
+ private int mDocumentCount;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_new_document);
+ mDocumentCount = getIntent()
+ .getIntExtra(DocumentCentricActivity.KEY_EXTRA_NEW_DOCUMENT_COUNTER, 0);
+ mDocumentCounterTextView = (TextView) findViewById(
+ R.id.hello_new_document_text_view);
+ setDocumentCounterText(R.string.hello_new_document_counter);
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ /* If {@link Intent#FLAG_ACTIVITY_MULTIPLE_TASK} has not been used this Activity
+ will be reused.
+ */
+ setDocumentCounterText(R.string.reusing_document_counter);
+ }
+
+ public void onRemoveFromOverview(View view) {
+ // It is good pratice to remove a document from the overview stack if not needed anymore.
+ finishAndRemoveTask();
+ }
+
+ public void setDocumentCounterText(int resId) {
+ mDocumentCounterTextView
+ .setText(String.format(getString(resId), String.valueOf(mDocumentCount)));
+ }
+
+}
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/AndroidManifest.xml b/samples/browseable/DocumentCentricRelinquishIdentity/AndroidManifest.xml
new file mode 100644
index 0000000..00cfd13
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/AndroidManifest.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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.documentcentricrelinquishidentity"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
+ <application
+ android:allowBackup="true"
+ android:label="@string/app_name"
+ android:icon="@drawable/ic_launcher"
+ android:theme="@style/AppTheme">
+
+ <activity
+ android:name=".RelinquishIdentityActivity"
+ android:label="@string/activity_relinquish_title"
+ android:relinquishTaskIdentity="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".NewDocumentActivity"
+ android:label="@string/activity_new_document" />
+ </application>
+
+
+</manifest>
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/_index.jd b/samples/browseable/DocumentCentricRelinquishIdentity/_index.jd
new file mode 100644
index 0000000..0a489af
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/_index.jd
@@ -0,0 +1,9 @@
+page.tags="DocumentCentricRelinquishIdentity"
+sample.group=UI
+@jd:body
+
+<p>
+
+ This sample shows how to relinquish identity to activities above it in the task stack.
+
+ </p>
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-hdpi/ic_launcher.png b/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..b1efaf4
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-hdpi/new_icon.png b/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-hdpi/new_icon.png
new file mode 100755
index 0000000..34767f3
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-hdpi/new_icon.png
Binary files differ
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-hdpi/tile.9.png b/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-mdpi/ic_launcher.png b/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f5f9244
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-mdpi/new_icon.png b/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-mdpi/new_icon.png
new file mode 100755
index 0000000..f1b91b9
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-mdpi/new_icon.png
Binary files differ
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..5d07b3f
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-xhdpi/new_icon.png b/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-xhdpi/new_icon.png
new file mode 100755
index 0000000..412a06d
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-xhdpi/new_icon.png
Binary files differ
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..6ef21e1
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-xxhdpi/new_icon.png b/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-xxhdpi/new_icon.png
new file mode 100755
index 0000000..a159b16
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/res/drawable-xxhdpi/new_icon.png
Binary files differ
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/res/layout/activity_document.xml b/samples/browseable/DocumentCentricRelinquishIdentity/res/layout/activity_document.xml
new file mode 100644
index 0000000..b9f6755
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/res/layout/activity_document.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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"
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/horizontal_page_margin"
+ android:layout_marginRight="@dimen/horizontal_page_margin"
+ android:layout_marginTop="@dimen/vertical_page_margin"
+ android:text="@string/go_to_recents_text" />
+
+</LinearLayout>
+
+
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/res/layout/activity_main.xml b/samples/browseable/DocumentCentricRelinquishIdentity/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/horizontal_page_margin"
+ android:layout_marginRight="@dimen/horizontal_page_margin"
+ android:layout_marginTop="@dimen/vertical_page_margin"
+ android:layout_marginBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/res/layout/activity_relinquish_identity.xml b/samples/browseable/DocumentCentricRelinquishIdentity/res/layout/activity_relinquish_identity.xml
new file mode 100755
index 0000000..7552eae
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/res/layout/activity_relinquish_identity.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+
+ <LinearLayout
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/horizontal_page_margin"
+ android:layout_marginRight="@dimen/horizontal_page_margin"
+ android:layout_marginTop="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </LinearLayout>
+
+ <Button
+ android:id="@+id/new_document_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/margin_small"
+ android:layout_marginLeft="@dimen/margin_small"
+ android:padding="@dimen/margin_medium"
+ android:text="@string/new_document_button_text"
+ android:onClick="createNewDocument" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/res/values-sw600dp/template-dimens.xml b/samples/browseable/DocumentCentricRelinquishIdentity/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/res/values-sw600dp/template-styles.xml b/samples/browseable/DocumentCentricRelinquishIdentity/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/res/values-v11/template-styles.xml b/samples/browseable/DocumentCentricRelinquishIdentity/res/values-v11/template-styles.xml
new file mode 100644
index 0000000..8c1ea66
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/res/values-v11/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/res/values-v21/template-styles.xml b/samples/browseable/DocumentCentricRelinquishIdentity/res/values-v21/template-styles.xml
new file mode 100644
index 0000000..134fcd9
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/res/values-v21/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2014 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>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Material.Light" />
+
+</resources>
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/res/values/base-strings.xml b/samples/browseable/DocumentCentricRelinquishIdentity/res/values/base-strings.xml
new file mode 100644
index 0000000..6073bba
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/res/values/base-strings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">DocumentCentricRelinquishIdentity</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ This sample shows how to relinquish identity to activities above it in the task stack.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/res/values/dimens.xml b/samples/browseable/DocumentCentricRelinquishIdentity/res/values/dimens.xml
new file mode 100644
index 0000000..061387a
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/res/values/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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>
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+</resources>
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/res/values/strings.xml b/samples/browseable/DocumentCentricRelinquishIdentity/res/values/strings.xml
new file mode 100644
index 0000000..4ddf4c7
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/res/values/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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="activity_relinquish_title">RelinquishIdentityActivity</string>
+ <string name="activity_new_document">NewDocumentActivity</string>
+ <string name="new_document_button_text">Create new document</string>
+ <string name="new_document_recents_label">New Label</string>
+ <string name="go_to_recents_text">Click on the Recents button in the navigation bar to see the label and icon change in the recents stack.</string>
+
+</resources>
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/res/values/template-dimens.xml b/samples/browseable/DocumentCentricRelinquishIdentity/res/values/template-dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/res/values/template-styles.xml b/samples/browseable/DocumentCentricRelinquishIdentity/res/values/template-styles.xml
new file mode 100644
index 0000000..6e7d593
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/src/com.example.android.documentcentricrelinquishidentity/NewDocumentActivity.java b/samples/browseable/DocumentCentricRelinquishIdentity/src/com.example.android.documentcentricrelinquishidentity/NewDocumentActivity.java
new file mode 100644
index 0000000..c3037d6
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/src/com.example.android.documentcentricrelinquishidentity/NewDocumentActivity.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2014 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.documentcentricrelinquishidentity;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+
+/**
+ * Activity that changes its task identifiers by setting a new {@link android.app.ActivityManager.TaskDescription}
+ */
+public class NewDocumentActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_document);
+ // Set a new task description to change label and icon
+ setTaskDescription(newTaskDescription());
+ }
+
+ /**
+ * Creates a new {@link android.app.ActivityManager.TaskDescription} with a new label and icon to change the
+ * appearance of this activity in the recents stack.
+ */
+ private ActivityManager.TaskDescription newTaskDescription() {
+ Bitmap newIcon = BitmapFactory.decodeResource(getResources(), R.drawable.new_icon);
+ String newDocumentRecentsLabel = getString(R.string.new_document_recents_label);
+ ActivityManager.TaskDescription newTaskDescription = new ActivityManager.TaskDescription(
+ newDocumentRecentsLabel, newIcon);
+ return newTaskDescription;
+ }
+
+}
diff --git a/samples/browseable/DocumentCentricRelinquishIdentity/src/com.example.android.documentcentricrelinquishidentity/RelinquishIdentityActivity.java b/samples/browseable/DocumentCentricRelinquishIdentity/src/com.example.android.documentcentricrelinquishidentity/RelinquishIdentityActivity.java
new file mode 100644
index 0000000..d2ce228
--- /dev/null
+++ b/samples/browseable/DocumentCentricRelinquishIdentity/src/com.example.android.documentcentricrelinquishidentity/RelinquishIdentityActivity.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 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.documentcentricrelinquishidentity;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+
+/**
+ * Activities that serve as the root of a task may give up certain task identifiers to activities
+ * above it in the task stack. These identifiers include the task base Intent, and the task name,
+ * color and icon used in the recent task list. The base @link{Intent} is used to match the task when
+ * relaunching based on an incoming Intent.
+ *
+ * <p>
+ * To relinquish its identity the base activity must have the activity attribute
+ * android:relinquishTaskIdentity=”true” in the manifest.
+ * </p>
+ */
+public class RelinquishIdentityActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_relinquish_identity);
+ }
+
+ public void createNewDocument(View view) {
+ final Intent intent = newDocumentIntent();
+ startActivity(intent);
+ }
+
+ /**
+ * Returns an new intent to start {@link NewDocumentActivity}
+ * as a new document in recents..
+ */
+ private Intent newDocumentIntent() {
+ final Intent newDocumentIntent = new Intent(this, NewDocumentActivity.class);
+ newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+ // Always launch in a new task.
+ newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ return newDocumentIntent;
+ }
+
+}
diff --git a/samples/browseable/DrawableTinting/AndroidManifest.xml b/samples/browseable/DrawableTinting/AndroidManifest.xml
new file mode 100644
index 0000000..9aa3976
--- /dev/null
+++ b/samples/browseable/DrawableTinting/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.drawabletinting"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
+ <application android:allowBackup="true"
+ android:label="@string/app_name"
+ android:icon="@drawable/ic_launcher"
+ android:theme="@style/AppTheme">
+
+ <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>
+ </application>
+
+
+</manifest>
diff --git a/samples/browseable/DrawableTinting/_index.jd b/samples/browseable/DrawableTinting/_index.jd
new file mode 100644
index 0000000..1b01114
--- /dev/null
+++ b/samples/browseable/DrawableTinting/_index.jd
@@ -0,0 +1,16 @@
+page.tags="DrawableTinting"
+sample.group=UI
+@jd:body
+
+<p>
+
+ Sample that shows applying tinting and color filters to Drawables both programmatically
+ and as Drawable resources in XML.
+ \n\nTinting is set on a nine-patch drawable through the "tint" and "tintMode" parameters.
+ A color state list is referenced as the tint color, which defines colors for different
+ states of a View (for example disabled/enabled, focused, pressed or selected).
+ \n\nProgrammatically, tinting is applied to a Drawable through its "setColorFilter" method,
+ with a reference to a color and a PorterDuff blend mode. The color and blend mode can be
+ changed from the UI to see the effect of different options.
+
+ </p>
diff --git a/samples/browseable/DrawableTinting/res/color/custom_tint.xml b/samples/browseable/DrawableTinting/res/color/custom_tint.xml
new file mode 100644
index 0000000..983880a
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/color/custom_tint.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2014 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.
+-->
+
+<!-- This color state list defines the color applied to the "buttonbackground" drawable.
+ A color is selected based on the state of its view.-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <!-- Pressed state -->
+ <item android:color="@color/red" android:state_pressed="true" />
+
+ <!-- Focused state -->
+ <item android:color="@color/light_purple" android:state_focused="true" />
+
+ <item android:color="@color/deep_purple" android:state_enabled="true" />
+
+ <!-- Disabled state -->
+ <item android:color="@color/light_blue" android:state_enabled="false" />
+
+ <!-- Default -->
+ <item android:color="@color/light_blue" />
+
+
+</selector>
\ No newline at end of file
diff --git a/samples/browseable/DrawableTinting/res/drawable-hdpi/btn_default_normal_holo.9.png b/samples/browseable/DrawableTinting/res/drawable-hdpi/btn_default_normal_holo.9.png
new file mode 100644
index 0000000..dbcede7
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/drawable-hdpi/btn_default_normal_holo.9.png
Binary files differ
diff --git a/samples/browseable/DrawableTinting/res/drawable-hdpi/ic_launcher.png b/samples/browseable/DrawableTinting/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a8cb237
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/DrawableTinting/res/drawable-hdpi/tile.9.png b/samples/browseable/DrawableTinting/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/DrawableTinting/res/drawable-mdpi/btn_default_normal_holo.9.png b/samples/browseable/DrawableTinting/res/drawable-mdpi/btn_default_normal_holo.9.png
new file mode 100644
index 0000000..0e0da34
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/drawable-mdpi/btn_default_normal_holo.9.png
Binary files differ
diff --git a/samples/browseable/DrawableTinting/res/drawable-mdpi/ic_launcher.png b/samples/browseable/DrawableTinting/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..9249aa2
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/DrawableTinting/res/drawable-xhdpi/btn_default_normal_holo.9.png b/samples/browseable/DrawableTinting/res/drawable-xhdpi/btn_default_normal_holo.9.png
new file mode 100644
index 0000000..92a49db
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/drawable-xhdpi/btn_default_normal_holo.9.png
Binary files differ
diff --git a/samples/browseable/DrawableTinting/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/DrawableTinting/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..5d57004
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/DrawableTinting/res/drawable-xxhdpi/btn_default_normal_holo.9.png b/samples/browseable/DrawableTinting/res/drawable-xxhdpi/btn_default_normal_holo.9.png
new file mode 100644
index 0000000..c1632c8
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/drawable-xxhdpi/btn_default_normal_holo.9.png
Binary files differ
diff --git a/samples/browseable/DrawableTinting/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/DrawableTinting/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..9ceea0e
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/DrawableTinting/res/drawable/buttonbackground.xml b/samples/browseable/DrawableTinting/res/drawable/buttonbackground.xml
new file mode 100644
index 0000000..060c5c7
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/drawable/buttonbackground.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2014 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.
+-->
+
+<!-- This nine patch definition refers to a drawable bitmap (btn_default_holo.png) to which
+a tint is applied. The tint is a color state list that changes color based on the state of the
+view it is applied to. Refer to its definition in "color/custom_tint.xml". -->
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/btn_default_normal_holo"
+ android:tint="@color/custom_tint"
+ android:tintMode="multiply" />
\ No newline at end of file
diff --git a/samples/browseable/DrawableTinting/res/layout-w720dp/activity_main.xml b/samples/browseable/DrawableTinting/res/layout-w720dp/activity_main.xml
new file mode 100755
index 0000000..c9a52f6
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/layout-w720dp/activity_main.xml
@@ -0,0 +1,73 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<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/sample_main_layout">
+
+ <LinearLayout
+ android:id="@+id/sample_output"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <FrameLayout
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/margin_medium"
+ android:paddingRight="@dimen/margin_medium"
+ android:paddingTop="@dimen/margin_large"
+ android:paddingBottom="@dimen/margin_large"
+ android:text="@string/intro_message" />
+ </FrameLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1" />
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="0px"
+ android:layout_height="match_parent" />
+
+</LinearLayout>
+
+
diff --git a/samples/browseable/DrawableTinting/res/layout/activity_main.xml b/samples/browseable/DrawableTinting/res/layout/activity_main.xml
new file mode 100755
index 0000000..1ae4f98
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/layout/activity_main.xml
@@ -0,0 +1,65 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<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/sample_main_layout">
+
+ <ViewAnimator
+ android:id="@+id/sample_output"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1">
+
+ <ScrollView
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/horizontal_page_margin"
+ android:paddingRight="@dimen/horizontal_page_margin"
+ android:paddingTop="@dimen/vertical_page_margin"
+ android:paddingBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </ScrollView>
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ </ViewAnimator>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="match_parent"
+ android:layout_height="0px" />
+
+</LinearLayout>
+
diff --git a/samples/browseable/DrawableTinting/res/layout/tinting_fragment.xml b/samples/browseable/DrawableTinting/res/layout/tinting_fragment.xml
new file mode 100644
index 0000000..0a3bfa7
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/layout/tinting_fragment.xml
@@ -0,0 +1,124 @@
+<!--
+ Copyright 2014 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.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginBottom="@dimen/vertical_page_margin"
+ android:layout_marginEnd="@dimen/horizontal_page_margin"
+ android:layout_marginStart="@dimen/horizontal_page_margin"
+ android:layout_marginTop="@dimen/vertical_page_margin"
+ android:orientation="vertical"
+ android:paddingBottom="@dimen/horizontal_page_margin">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/resource_tint_label" />
+
+ <!-- Button on which the background is set to a Drawable resource that references a
+ color state list to define its tint. The color varies based on the state of the View. -->
+ <Button
+ android:id="@+id/button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:background="@drawable/buttonbackground"
+ android:paddingEnd="7dp"
+ android:paddingStart="7dp"
+ android:text="@string/resource_tint_button" />
+
+ <!-- Image -->
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/prog_tint_label" />
+
+ <ImageView
+ android:id="@+id/image"
+ android:layout_width="200dp"
+ android:layout_height="50dp"
+ android:layout_gravity="center_horizontal"
+ android:scaleType="fitXY"
+ android:tint="#330000FF" />
+
+ <!-- Blend mode -->
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="0dp"
+ android:text="@string/blend_mode_label" />
+
+ <Spinner
+ android:id="@+id/blendSpinner"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <!-- Alpha -->
+ <TextView
+ android:id="@+id/alphaText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <SeekBar
+ android:id="@+id/alphaSeek"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:max="255"
+ android:progress="255" />
+
+ <!-- Red -->
+ <TextView
+ android:id="@+id/redText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <SeekBar
+ android:id="@+id/redSeek"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:max="255" />
+
+ <!-- Green -->
+ <TextView
+ android:id="@+id/greenText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <SeekBar
+ android:id="@+id/greenSeek"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:max="255" />
+
+ <!-- Blue -->
+ <TextView
+ android:id="@+id/blueText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <SeekBar
+ android:id="@+id/blueSeek"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:max="255" />
+
+ </LinearLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/samples/browseable/DrawableTinting/res/menu/main.xml b/samples/browseable/DrawableTinting/res/menu/main.xml
new file mode 100644
index 0000000..b49c2c5
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/menu/main.xml
@@ -0,0 +1,21 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/menu_toggle_log"
+ android:showAsAction="always"
+ android:title="@string/sample_show_log" />
+</menu>
diff --git a/samples/browseable/DrawableTinting/res/values-sw600dp/template-dimens.xml b/samples/browseable/DrawableTinting/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/DrawableTinting/res/values-sw600dp/template-styles.xml b/samples/browseable/DrawableTinting/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/DrawableTinting/res/values-v11/template-styles.xml b/samples/browseable/DrawableTinting/res/values-v11/template-styles.xml
new file mode 100644
index 0000000..8c1ea66
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/values-v11/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/samples/browseable/DrawableTinting/res/values-v21/template-styles.xml b/samples/browseable/DrawableTinting/res/values-v21/template-styles.xml
new file mode 100644
index 0000000..134fcd9
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/values-v21/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2014 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>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Material.Light" />
+
+</resources>
diff --git a/samples/browseable/DrawableTinting/res/values/base-strings.xml b/samples/browseable/DrawableTinting/res/values/base-strings.xml
new file mode 100644
index 0000000..1b3516a
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/values/base-strings.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">DrawableTinting</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ Sample that shows applying tinting and color filters to Drawables both programmatically
+ and as Drawable resources in XML.
+ \n\nTinting is set on a nine-patch drawable through the "tint" and "tintMode" parameters.
+ A color state list is referenced as the tint color, which defines colors for different
+ states of a View (for example disabled/enabled, focused, pressed or selected).
+ \n\nProgrammatically, tinting is applied to a Drawable through its "setColorFilter" method,
+ with a reference to a color and a PorterDuff blend mode. The color and blend mode can be
+ changed from the UI to see the effect of different options.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/DrawableTinting/res/values/color.xml b/samples/browseable/DrawableTinting/res/values/color.xml
new file mode 100644
index 0000000..86a2db7
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/values/color.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2014 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>
+
+ <color name="red">#e51c23</color>
+ <color name="light_purple">#e1bee7</color>
+ <color name="deep_purple">#673ab7</color>
+ <color name="light_blue">#e7e9fd</color>
+ <color name="green">#259b24</color>
+
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/DrawableTinting/res/values/fragmentview_strings.xml b/samples/browseable/DrawableTinting/res/values/fragmentview_strings.xml
new file mode 100755
index 0000000..7b9d9ec
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/values/fragmentview_strings.xml
@@ -0,0 +1,19 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="sample_show_log">Show Log</string>
+ <string name="sample_hide_log">Hide Log</string>
+</resources>
diff --git a/samples/browseable/DrawableTinting/res/values/strings.xml b/samples/browseable/DrawableTinting/res/values/strings.xml
new file mode 100644
index 0000000..4a517d1
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/values/strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2014 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="resource_tint_label">Button with tinting set by state color list as resource:</string>
+ <string name="resource_tint_button">Tinting set by StateDrawable</string>
+ <string name="prog_tint_label">View with tinting set programmatically:</string>
+ <string name="value_alpha">Alpha: %d\%</string>
+ <string name="value_red">Red: %d\%</string>
+ <string name="value_green">Green: %d\%</string>
+ <string name="value_blue">Blue: %d\%</string>
+ <string name="blend_mode_label">Blend Mode:</string>
+
+ <string-array name="blend_modes">
+ <item>Add</item>
+ <item>Clear</item>
+ <item>Darken</item>
+ <item>Destination (DST)</item>
+ <item>Destination atop (DST_ATOP)</item>
+ <item>Destination in (DST_IN)</item>
+ <item>Destination out (DST_OUT)</item>
+ <item>Destination over (DST_OVER)</item>
+ <item>Lighten</item>
+ <item>Multiply</item>
+ <item>Overlay</item>
+ <item>Screen</item>
+ <item>Source (SRC)</item>
+ <item>Source atop (SRC_ATOP)</item>
+ <item>Source in (SRC_IN)</item>
+ <item>Source out (SRC_OUT)</item>
+ <item>Source over (SRC_OVER)</item>
+ <item>XOR</item>
+ </string-array>
+
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/DrawableTinting/res/values/template-dimens.xml b/samples/browseable/DrawableTinting/res/values/template-dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/DrawableTinting/res/values/template-styles.xml b/samples/browseable/DrawableTinting/res/values/template-styles.xml
new file mode 100644
index 0000000..6e7d593
--- /dev/null
+++ b/samples/browseable/DrawableTinting/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/DrawableTinting/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/DrawableTinting/src/com.example.android.common/activities/SampleActivityBase.java
new file mode 100644
index 0000000..3228927
--- /dev/null
+++ b/samples/browseable/DrawableTinting/src/com.example.android.common/activities/SampleActivityBase.java
@@ -0,0 +1,52 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.common.activities;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogWrapper;
+
+/**
+ * Base launcher activity, to handle most of the common plumbing for samples.
+ */
+public class SampleActivityBase extends FragmentActivity {
+
+ public static final String TAG = "SampleActivityBase";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ initializeLogging();
+ }
+
+ /** Set up targets to receive log data */
+ public void initializeLogging() {
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ // Wraps Android's native log framework
+ LogWrapper logWrapper = new LogWrapper();
+ Log.setLogNode(logWrapper);
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/DrawableTinting/src/com.example.android.common/logger/Log.java b/samples/browseable/DrawableTinting/src/com.example.android.common/logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/DrawableTinting/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+ // Grabbing the native values from Android's native logging facilities,
+ // to make for easy migration and interop.
+ public static final int NONE = -1;
+ public static final int VERBOSE = android.util.Log.VERBOSE;
+ public static final int DEBUG = android.util.Log.DEBUG;
+ public static final int INFO = android.util.Log.INFO;
+ public static final int WARN = android.util.Log.WARN;
+ public static final int ERROR = android.util.Log.ERROR;
+ public static final int ASSERT = android.util.Log.ASSERT;
+
+ // Stores the beginning of the LogNode topology.
+ private static LogNode mLogNode;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public static LogNode getLogNode() {
+ return mLogNode;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to.
+ */
+ public static void setLogNode(LogNode node) {
+ mLogNode = node;
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void println(int priority, String tag, String msg, Throwable tr) {
+ if (mLogNode != null) {
+ mLogNode.println(priority, tag, msg, tr);
+ }
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ */
+ public static void println(int priority, String tag, String msg) {
+ println(priority, tag, msg, null);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void v(String tag, String msg, Throwable tr) {
+ println(VERBOSE, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void v(String tag, String msg) {
+ v(tag, msg, null);
+ }
+
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void d(String tag, String msg, Throwable tr) {
+ println(DEBUG, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void d(String tag, String msg) {
+ d(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void i(String tag, String msg, Throwable tr) {
+ println(INFO, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void i(String tag, String msg) {
+ i(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, String msg, Throwable tr) {
+ println(WARN, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void w(String tag, String msg) {
+ w(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, Throwable tr) {
+ w(tag, null, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void e(String tag, String msg, Throwable tr) {
+ println(ERROR, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void e(String tag, String msg) {
+ e(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, String msg, Throwable tr) {
+ println(ASSERT, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void wtf(String tag, String msg) {
+ wtf(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, Throwable tr) {
+ wtf(tag, null, tr);
+ }
+}
diff --git a/samples/browseable/DrawableTinting/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/DrawableTinting/src/com.example.android.common/logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/DrawableTinting/src/com.example.android.common/logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+ private LogView mLogView;
+ private ScrollView mScrollView;
+
+ public LogFragment() {}
+
+ public View inflateViews() {
+ mScrollView = new ScrollView(getActivity());
+ ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ mScrollView.setLayoutParams(scrollParams);
+
+ mLogView = new LogView(getActivity());
+ ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+ logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ mLogView.setLayoutParams(logParams);
+ mLogView.setClickable(true);
+ mLogView.setFocusable(true);
+ mLogView.setTypeface(Typeface.MONOSPACE);
+
+ // Want to set padding as 16 dips, setPadding takes pixels. Hooray math!
+ int paddingDips = 16;
+ double scale = getResources().getDisplayMetrics().density;
+ int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+ mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+ mLogView.setCompoundDrawablePadding(paddingPixels);
+
+ mLogView.setGravity(Gravity.BOTTOM);
+ mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+ mScrollView.addView(mLogView);
+ return mScrollView;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ View result = inflateViews();
+
+ mLogView.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+ }
+ });
+ return result;
+ }
+
+ public LogView getLogView() {
+ return mLogView;
+ }
+}
\ No newline at end of file
diff --git a/samples/browseable/DrawableTinting/src/com.example.android.common/logger/LogNode.java b/samples/browseable/DrawableTinting/src/com.example.android.common/logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/DrawableTinting/src/com.example.android.common/logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 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.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+ /**
+ * Instructs first LogNode in the list to print the log data provided.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/DrawableTinting/src/com.example.android.common/logger/LogView.java b/samples/browseable/DrawableTinting/src/com.example.android.common/logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/DrawableTinting/src/com.example.android.common/logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+ public LogView(Context context) {
+ super(context);
+ }
+
+ public LogView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public LogView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * Formats the log data and prints it out to the LogView.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+
+
+ String priorityStr = null;
+
+ // For the purposes of this View, we want to print the priority as readable text.
+ switch(priority) {
+ case android.util.Log.VERBOSE:
+ priorityStr = "VERBOSE";
+ break;
+ case android.util.Log.DEBUG:
+ priorityStr = "DEBUG";
+ break;
+ case android.util.Log.INFO:
+ priorityStr = "INFO";
+ break;
+ case android.util.Log.WARN:
+ priorityStr = "WARN";
+ break;
+ case android.util.Log.ERROR:
+ priorityStr = "ERROR";
+ break;
+ case android.util.Log.ASSERT:
+ priorityStr = "ASSERT";
+ break;
+ default:
+ break;
+ }
+
+ // Handily, the Log class has a facility for converting a stack trace into a usable string.
+ String exceptionStr = null;
+ if (tr != null) {
+ exceptionStr = android.util.Log.getStackTraceString(tr);
+ }
+
+ // Take the priority, tag, message, and exception, and concatenate as necessary
+ // into one usable line of text.
+ final StringBuilder outputBuilder = new StringBuilder();
+
+ String delimiter = "\t";
+ appendIfNotNull(outputBuilder, priorityStr, delimiter);
+ appendIfNotNull(outputBuilder, tag, delimiter);
+ appendIfNotNull(outputBuilder, msg, delimiter);
+ appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+ // In case this was originally called from an AsyncTask or some other off-UI thread,
+ // make sure the update occurs within the UI thread.
+ ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+ @Override
+ public void run() {
+ // Display the text we just generated within the LogView.
+ appendToLog(outputBuilder.toString());
+ }
+ })));
+
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+ * the logger takes so many arguments that might be null, this method helps cut out some of the
+ * agonizing tedium of writing the same 3 lines over and over.
+ * @param source StringBuilder containing the text to append to.
+ * @param addStr The String to append
+ * @param delimiter The String to separate the source and appended strings. A tab or comma,
+ * for instance.
+ * @return The fully concatenated String as a StringBuilder
+ */
+ private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+ if (addStr != null) {
+ if (addStr.length() == 0) {
+ delimiter = "";
+ }
+
+ return source.append(addStr).append(delimiter);
+ }
+ return source;
+ }
+
+ // The next LogNode in the chain.
+ LogNode mNext;
+
+ /** Outputs the string as a new line of log data in the LogView. */
+ public void appendToLog(String s) {
+ append("\n" + s);
+ }
+
+
+}
diff --git a/samples/browseable/DrawableTinting/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/DrawableTinting/src/com.example.android.common/logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/DrawableTinting/src/com.example.android.common/logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 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.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface. This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+ // For piping: The next node to receive Log data after this one has done its work.
+ private LogNode mNext;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /**
+ * Prints data out to the console using Android's native log mechanism.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ // There actually are log methods that don't take a msg parameter. For now,
+ // if that's the case, just convert null to the empty string and move on.
+ String useMsg = msg;
+ if (useMsg == null) {
+ useMsg = "";
+ }
+
+ // If an exeption was provided, convert that exception to a usable string and attach
+ // it to the end of the msg method.
+ if (tr != null) {
+ msg += "\n" + Log.getStackTraceString(tr);
+ }
+
+ // This is functionally identical to Log.x(tag, useMsg);
+ // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+ Log.println(priority, tag, useMsg);
+
+ // If this isn't the last node in the chain, move things along.
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+}
diff --git a/samples/browseable/DrawableTinting/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/DrawableTinting/src/com.example.android.common/logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/DrawableTinting/src/com.example.android.common/logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+ LogNode mNext;
+
+ /**
+ * Takes the "next" LogNode as a parameter, to simplify chaining.
+ *
+ * @param next The next LogNode in the pipeline.
+ */
+ public MessageOnlyLogFilter(LogNode next) {
+ mNext = next;
+ }
+
+ public MessageOnlyLogFilter() {
+ }
+
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ if (mNext != null) {
+ getNext().println(Log.NONE, null, msg, null);
+ }
+ }
+
+ /**
+ * Returns the next LogNode in the chain.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+}
diff --git a/samples/browseable/DrawableTinting/src/com.example.android.drawabletinting/DrawableTintingFragment.java b/samples/browseable/DrawableTinting/src/com.example.android.drawabletinting/DrawableTintingFragment.java
new file mode 100644
index 0000000..cd46fb9
--- /dev/null
+++ b/samples/browseable/DrawableTinting/src/com.example.android.drawabletinting/DrawableTintingFragment.java
@@ -0,0 +1,316 @@
+/*
+* Copyright 2014 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.drawabletinting;
+
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.SeekBar;
+import android.widget.Spinner;
+import android.widget.SpinnerAdapter;
+import android.widget.TextView;
+
+import com.example.android.common.logger.Log;
+
+/**
+ * Sample that shows tinting of Drawables programmatically and of Drawable resources in XML.
+ * Tinting is set on a nine-patch drawable through the "tint" and "tintMode" parameters.
+ * A color state list is referenced as the tint color, which defines colors for different
+ * states of a View (for example disabled/enabled, focused, pressed or selected).
+ * Programmatically, tinting is applied to a Drawable through its "setColorFilter" method, with
+ * a reference to a color and a PorterDuff blend mode. The color and blend mode can be
+ * changed from the UI.
+ *
+ * @see android.graphics.drawable.Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)
+ * @see android.graphics.drawable.Drawable#setTint(android.content.res.ColorStateList, android.graphics.PorterDuff.Mode)
+ */
+public class DrawableTintingFragment extends Fragment {
+
+ /**
+ * String that identifies logging output from this Fragment.
+ */
+ private static final String TAG = "DrawableTintingFragment";
+
+ /**
+ * Image that tinting is applied to programmatically.
+ */
+ private ImageView mImage;
+
+ /**
+ * Seekbar for alpha component of tinting color.
+ */
+ private SeekBar mAlphaBar;
+ /**
+ * Seekbar for red component of tinting color.
+ */
+ private SeekBar mRedBar;
+ /**
+ * Seekbar for green bar of tinting color.
+ */
+ private SeekBar mGreenBar;
+ /**
+ * Seekbar for blue bar of tinting color.
+ */
+ private SeekBar mBlueBar;
+
+ /**
+ * Text label for alpha component seekbar.
+ */
+ private TextView mAlphaText;
+ /**
+ * Text label for red component seekbar.
+ */
+ private TextView mRedText;
+ /**
+ * Text label for green component seekbar.
+ */
+ private TextView mGreenText;
+ /**
+ * Text label for blue component seekbar.
+ */
+ private TextView mBlueText;
+
+ /**
+ * Selector for blend type for color tinting.
+ */
+ private Spinner mBlendSpinner;
+
+ /**
+ * Computed color for tinting of drawable.
+ */
+ private int mHintColor;
+
+ /**
+ * Selected color tinting mode.
+ */
+ private PorterDuff.Mode mMode;
+
+ /**
+ * Identifier for state of blend mod spinner in state bundle.
+ */
+ private static final String STATE_BLEND = "DRAWABLETINTING_BLEND";
+ /**
+ * Identifier for state of alpha seek bar in state bundle.
+ */
+ private static final String STATE_ALPHA = "DRAWABLETINTING_ALPHA";
+ /**
+ * Identifier for state of red seek bar in state bundle.
+ */
+ private static final String STATE_RED = "DRAWABLETINTING_RED";
+ /**
+ * Identifier for state of green seek bar in state bundle.
+ */
+ private static final String STATE_GREEN = "DRAWABLETINTING_GREEN";
+ /**
+ * Identifier for state of blue seek bar in state bundle.
+ */
+ private static final String STATE_BLUE = "DRAWABLETINTING_BLUE";
+
+ /**
+ * Available tinting modes. Note that this array must be kept in sync with the
+ * <code>blend_modes</code> string array that provides labels for these modes.
+ */
+ private static final PorterDuff.Mode[] MODES = new PorterDuff.Mode[]{
+ PorterDuff.Mode.ADD,
+ PorterDuff.Mode.CLEAR,
+ PorterDuff.Mode.DARKEN,
+ PorterDuff.Mode.DST,
+ PorterDuff.Mode.DST_ATOP,
+ PorterDuff.Mode.DST_IN,
+ PorterDuff.Mode.DST_OUT,
+ PorterDuff.Mode.DST_OVER,
+ PorterDuff.Mode.LIGHTEN,
+ PorterDuff.Mode.MULTIPLY,
+ PorterDuff.Mode.OVERLAY,
+ PorterDuff.Mode.SCREEN,
+ PorterDuff.Mode.SRC,
+ PorterDuff.Mode.SRC_ATOP,
+ PorterDuff.Mode.SRC_IN,
+ PorterDuff.Mode.SRC_OUT,
+ PorterDuff.Mode.SRC_OVER,
+ PorterDuff.Mode.XOR
+ };
+
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.tinting_fragment, null);
+
+ // Set a drawable as the image to display
+ mImage = (ImageView) v.findViewById(R.id.image);
+ mImage.setImageResource(R.drawable.btn_default_normal_holo);
+
+ // Get text labels and seekbars for the four color components: ARGB
+ mAlphaBar = (SeekBar) v.findViewById(R.id.alphaSeek);
+ mAlphaText = (TextView) v.findViewById(R.id.alphaText);
+ mGreenBar = (SeekBar) v.findViewById(R.id.greenSeek);
+ mGreenText = (TextView) v.findViewById(R.id.greenText);
+ mRedBar = (SeekBar) v.findViewById(R.id.redSeek);
+ mRedText = (TextView) v.findViewById(R.id.redText);
+ mBlueText = (TextView) v.findViewById(R.id.blueText);
+ mBlueBar = (SeekBar) v.findViewById(R.id.blueSeek);
+
+ // Set a listener to update tinted image when selections have changed
+ mAlphaBar.setOnSeekBarChangeListener(mSeekBarListener);
+ mRedBar.setOnSeekBarChangeListener(mSeekBarListener);
+ mGreenBar.setOnSeekBarChangeListener(mSeekBarListener);
+ mBlueBar.setOnSeekBarChangeListener(mSeekBarListener);
+
+
+ // Set up the spinner for blend mode selection from a string array resource
+ mBlendSpinner = (Spinner) v.findViewById(R.id.blendSpinner);
+ SpinnerAdapter sa = ArrayAdapter.createFromResource(getActivity(),
+ R.array.blend_modes, android.R.layout.simple_spinner_dropdown_item);
+ mBlendSpinner.setAdapter(sa);
+ // Set a listener to update the tinted image when a blend mode is selected
+ mBlendSpinner.setOnItemSelectedListener(mBlendListener);
+ // Select the first item
+ mBlendSpinner.setSelection(0);
+ mMode = MODES[0];
+
+ if (savedInstanceState != null) {
+ // Restore the previous state if this fragment has been restored
+ mBlendSpinner.setSelection(savedInstanceState.getInt(STATE_BLEND));
+ mAlphaBar.setProgress(savedInstanceState.getInt(STATE_ALPHA));
+ mRedBar.setProgress(savedInstanceState.getInt(STATE_RED));
+ mGreenBar.setProgress(savedInstanceState.getInt(STATE_GREEN));
+ mBlueBar.setProgress(savedInstanceState.getInt(STATE_BLUE));
+ }
+
+ // Apply the default blend mode and color
+ updateTint(getColor(), getTintMode());
+
+ return v;
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ Log.d(TAG, "state saved.");
+ outState.putInt(STATE_BLEND, mBlendSpinner.getSelectedItemPosition());
+ outState.putInt(STATE_ALPHA, mAlphaBar.getProgress());
+ outState.putInt(STATE_RED, mRedBar.getProgress());
+ outState.putInt(STATE_GREEN, mGreenBar.getProgress());
+ outState.putInt(STATE_BLUE, mBlueBar.getProgress());
+ }
+
+ /**
+ * Computes the {@link Color} value from selection on ARGB sliders.
+ *
+ * @return color computed from selected ARGB values
+ */
+ public int getColor() {
+ final int alpha = mAlphaBar.getProgress();
+ final int red = mRedBar.getProgress();
+ final int green = mGreenBar.getProgress();
+ final int blue = mBlueBar.getProgress();
+
+ return Color.argb(alpha, red, green, blue);
+ }
+
+ /**
+ * Returns the {@link android.graphics.PorterDuff.Mode} for the selected tint mode option.
+ *
+ * @return selected tint mode
+ */
+ public PorterDuff.Mode getTintMode() {
+ return MODES[mBlendSpinner.getSelectedItemPosition()];
+ }
+
+ /**
+ * Update the tint of the image with the color set in the seekbars and selected blend mode.
+ * The seekbars are set to a maximum of 255, with one for each of the four components of the
+ * ARGB color. (Alpha, Red, Green, Blue.) Once a color has been computed using
+ * {@link Color#argb(int, int, int, int)}, it is set togethe with the blend mode on the background
+ * image using
+ * {@link android.widget.ImageView#setColorFilter(int, android.graphics.PorterDuff.Mode)}.
+ */
+ public void updateTint(int color, PorterDuff.Mode mode) {
+ // Set the color hint of the image: ARGB
+ mHintColor = color;
+
+ // Set the color tint mode based on the selection of the Spinner
+ mMode = mode;
+
+ // Log selection
+ Log.d(TAG, String.format("Updating tint with color [ARGB: %d,%d,%d,%d] and mode [%s]",
+ Color.alpha(color), Color.red(color), Color.green(color), Color.blue(color),
+ mode.toString()));
+
+ // Apply the color tint for the selected tint mode
+ mImage.setColorFilter(mHintColor, mMode);
+
+ // Update the text for each label with the value of each channel
+ mAlphaText.setText(getString(R.string.value_alpha, Color.alpha(color)));
+ mRedText.setText(getString(R.string.value_red, Color.red(color)));
+ mGreenText.setText(getString(R.string.value_green, Color.green(color)));
+ mBlueText.setText(getString(R.string.value_blue, Color.blue(color)));
+ }
+
+ /**
+ * Listener that updates the tint when a blend mode is selected.
+ */
+ private AdapterView.OnItemSelectedListener mBlendListener =
+ new AdapterView.OnItemSelectedListener() {
+
+ @Override
+ public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
+ // Selected a blend mode and update the tint of image
+ updateTint(getColor(), getTintMode());
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> adapterView) {
+
+ }
+
+ };
+
+ /**
+ * Seekbar listener that updates the tinted color when the progress bar has changed.
+ */
+ private SeekBar.OnSeekBarChangeListener mSeekBarListener =
+ new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
+ // Update the tinted color from all selections in the UI
+ updateTint(getColor(), getTintMode());
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+ };
+}
diff --git a/samples/browseable/DrawableTinting/src/com.example.android.drawabletinting/MainActivity.java b/samples/browseable/DrawableTinting/src/com.example.android.drawabletinting/MainActivity.java
new file mode 100644
index 0000000..d00bc37
--- /dev/null
+++ b/samples/browseable/DrawableTinting/src/com.example.android.drawabletinting/MainActivity.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.drawabletinting;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ViewAnimator;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description, sample log and a custom
+ * {@link android.support.v4.app.Fragment} which can display a view.
+ * <p>
+ * For devices with displays with a width of 720dp or greater, the sample log is always visible,
+ * on other devices it's visibility is controlled by an item on the Action Bar.
+ */
+public class MainActivity extends SampleActivityBase {
+
+ public static final String TAG = "MainActivity";
+
+ // Whether the Log Fragment is currently shown
+ private boolean mLogShown;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ if (savedInstanceState == null) {
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ DrawableTintingFragment fragment = new DrawableTintingFragment();
+ transaction.replace(R.id.sample_content_fragment, fragment);
+ transaction.commit();
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
+ logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
+ logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);
+
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch(item.getItemId()) {
+ case R.id.menu_toggle_log:
+ mLogShown = !mLogShown;
+ ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);
+ if (mLogShown) {
+ output.setDisplayedChild(1);
+ } else {
+ output.setDisplayedChild(0);
+ }
+ supportInvalidateOptionsMenu();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ /** Create a chain of targets that will receive log data */
+ @Override
+ public void initializeLogging() {
+ // Wraps Android's native log framework.
+ LogWrapper logWrapper = new LogWrapper();
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ Log.setLogNode(logWrapper);
+
+ // Filter strips out everything except the message text.
+ MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+ logWrapper.setNext(msgFilter);
+
+ // On screen logging via a fragment with a TextView.
+ LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+ .findFragmentById(R.id.log_fragment);
+ msgFilter.setNext(logFragment.getLogView());
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/ElevationBasic/AndroidManifest.xml b/samples/browseable/ElevationBasic/AndroidManifest.xml
new file mode 100644
index 0000000..a70cd85
--- /dev/null
+++ b/samples/browseable/ElevationBasic/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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.elevationbasic"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+
+ <application android:allowBackup="true"
+ android:label="@string/app_name"
+ android:icon="@drawable/ic_launcher"
+ android:theme="@android:style/Theme.Material.Light">
+
+ <activity android:name=".MainActivity"
+ android:label="@string/app_name"
+ android:uiOptions="splitActionBarWhenNarrow">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+
+</manifest>
diff --git a/samples/browseable/ElevationBasic/_index.jd b/samples/browseable/ElevationBasic/_index.jd
new file mode 100644
index 0000000..cf473d4
--- /dev/null
+++ b/samples/browseable/ElevationBasic/_index.jd
@@ -0,0 +1,11 @@
+page.tags="ElevationBasic"
+sample.group=UI
+@jd:body
+
+<p>
+
+ This sample demonstrates two alternative ways to move a view in the z-axis. The
+ first view has a fixed elevation using XML and the second one is raised when the user
+ taps on it, using setTranslationZ().
+
+ </p>
diff --git a/samples/browseable/ElevationBasic/res/drawable-hdpi/ic_launcher.png b/samples/browseable/ElevationBasic/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..c28e40d
--- /dev/null
+++ b/samples/browseable/ElevationBasic/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ElevationBasic/res/drawable-hdpi/tile.9.png b/samples/browseable/ElevationBasic/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/ElevationBasic/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/ElevationBasic/res/drawable-mdpi/ic_launcher.png b/samples/browseable/ElevationBasic/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..71738ff
--- /dev/null
+++ b/samples/browseable/ElevationBasic/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ElevationBasic/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/ElevationBasic/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..788ac1f
--- /dev/null
+++ b/samples/browseable/ElevationBasic/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ElevationBasic/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/ElevationBasic/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..72359c3
--- /dev/null
+++ b/samples/browseable/ElevationBasic/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ElevationBasic/res/drawable/shape.xml b/samples/browseable/ElevationBasic/res/drawable/shape.xml
new file mode 100644
index 0000000..22ffe05
--- /dev/null
+++ b/samples/browseable/ElevationBasic/res/drawable/shape.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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="oval">
+ <solid android:color="@color/color_1" />
+</shape>
\ No newline at end of file
diff --git a/samples/browseable/ElevationBasic/res/drawable/shape2.xml b/samples/browseable/ElevationBasic/res/drawable/shape2.xml
new file mode 100644
index 0000000..7060f58
--- /dev/null
+++ b/samples/browseable/ElevationBasic/res/drawable/shape2.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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">
+ <solid android:color="@color/color_2" />
+</shape>
\ No newline at end of file
diff --git a/samples/browseable/ElevationBasic/res/layout-w720dp/activity_main.xml b/samples/browseable/ElevationBasic/res/layout-w720dp/activity_main.xml
new file mode 100755
index 0000000..c9a52f6
--- /dev/null
+++ b/samples/browseable/ElevationBasic/res/layout-w720dp/activity_main.xml
@@ -0,0 +1,73 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<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/sample_main_layout">
+
+ <LinearLayout
+ android:id="@+id/sample_output"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <FrameLayout
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/margin_medium"
+ android:paddingRight="@dimen/margin_medium"
+ android:paddingTop="@dimen/margin_large"
+ android:paddingBottom="@dimen/margin_large"
+ android:text="@string/intro_message" />
+ </FrameLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1" />
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="0px"
+ android:layout_height="match_parent" />
+
+</LinearLayout>
+
+
diff --git a/samples/browseable/ElevationBasic/res/layout/activity_main.xml b/samples/browseable/ElevationBasic/res/layout/activity_main.xml
new file mode 100755
index 0000000..1ae4f98
--- /dev/null
+++ b/samples/browseable/ElevationBasic/res/layout/activity_main.xml
@@ -0,0 +1,65 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<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/sample_main_layout">
+
+ <ViewAnimator
+ android:id="@+id/sample_output"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1">
+
+ <ScrollView
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/horizontal_page_margin"
+ android:paddingRight="@dimen/horizontal_page_margin"
+ android:paddingTop="@dimen/vertical_page_margin"
+ android:paddingBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </ScrollView>
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ </ViewAnimator>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="match_parent"
+ android:layout_height="0px" />
+
+</LinearLayout>
+
diff --git a/samples/browseable/ElevationBasic/res/layout/elevation_basic.xml b/samples/browseable/ElevationBasic/res/layout/elevation_basic.xml
new file mode 100644
index 0000000..83ab1d2
--- /dev/null
+++ b/samples/browseable/ElevationBasic/res/layout/elevation_basic.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <View
+ android:id="@+id/floating_shape"
+ android:layout_width="80dp"
+ android:layout_height="80dp"
+ android:layout_marginRight="40dp"
+ android:background="@drawable/shape"
+ android:elevation="30dp"
+ android:layout_gravity="center"/>
+ <View
+ android:id="@+id/floating_shape_2"
+ android:layout_width="80dp"
+ android:layout_height="80dp"
+ android:layout_marginLeft="25dp"
+ android:background="@drawable/shape2"
+ android:layout_gravity="center"/>
+</FrameLayout>
+
diff --git a/samples/browseable/ElevationBasic/res/menu/main.xml b/samples/browseable/ElevationBasic/res/menu/main.xml
new file mode 100644
index 0000000..b49c2c5
--- /dev/null
+++ b/samples/browseable/ElevationBasic/res/menu/main.xml
@@ -0,0 +1,21 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/menu_toggle_log"
+ android:showAsAction="always"
+ android:title="@string/sample_show_log" />
+</menu>
diff --git a/samples/browseable/ElevationBasic/res/values-sw600dp/template-dimens.xml b/samples/browseable/ElevationBasic/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/ElevationBasic/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/ElevationBasic/res/values-sw600dp/template-styles.xml b/samples/browseable/ElevationBasic/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/ElevationBasic/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/ElevationBasic/res/values-v11/template-styles.xml b/samples/browseable/ElevationBasic/res/values-v11/template-styles.xml
new file mode 100644
index 0000000..8c1ea66
--- /dev/null
+++ b/samples/browseable/ElevationBasic/res/values-v11/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/samples/browseable/ElevationBasic/res/values-v21/template-styles.xml b/samples/browseable/ElevationBasic/res/values-v21/template-styles.xml
new file mode 100644
index 0000000..134fcd9
--- /dev/null
+++ b/samples/browseable/ElevationBasic/res/values-v21/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2014 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>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Material.Light" />
+
+</resources>
diff --git a/samples/browseable/ElevationBasic/res/values/base-strings.xml b/samples/browseable/ElevationBasic/res/values/base-strings.xml
new file mode 100644
index 0000000..9ae4843
--- /dev/null
+++ b/samples/browseable/ElevationBasic/res/values/base-strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">ElevationBasic</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ This sample demonstrates two alternative ways to move a view in the z-axis. The
+ first view has a fixed elevation using XML and the second one is raised when the user
+ taps on it, using setTranslationZ().
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/ElevationBasic/res/values/colors.xml b/samples/browseable/ElevationBasic/res/values/colors.xml
new file mode 100644
index 0000000..b5782df
--- /dev/null
+++ b/samples/browseable/ElevationBasic/res/values/colors.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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>
+ <color name="color_1">#E91E63</color>
+ <color name="color_2">#673AB7</color>
+</resources>
diff --git a/samples/browseable/ElevationBasic/res/values/fragmentview_strings.xml b/samples/browseable/ElevationBasic/res/values/fragmentview_strings.xml
new file mode 100755
index 0000000..7b9d9ec
--- /dev/null
+++ b/samples/browseable/ElevationBasic/res/values/fragmentview_strings.xml
@@ -0,0 +1,19 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="sample_show_log">Show Log</string>
+ <string name="sample_hide_log">Hide Log</string>
+</resources>
diff --git a/samples/browseable/ElevationBasic/res/values/template-dimens.xml b/samples/browseable/ElevationBasic/res/values/template-dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/ElevationBasic/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/ElevationBasic/res/values/template-styles.xml b/samples/browseable/ElevationBasic/res/values/template-styles.xml
new file mode 100644
index 0000000..6e7d593
--- /dev/null
+++ b/samples/browseable/ElevationBasic/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/ElevationBasic/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/ElevationBasic/src/com.example.android.common/activities/SampleActivityBase.java
new file mode 100644
index 0000000..3228927
--- /dev/null
+++ b/samples/browseable/ElevationBasic/src/com.example.android.common/activities/SampleActivityBase.java
@@ -0,0 +1,52 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.common.activities;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogWrapper;
+
+/**
+ * Base launcher activity, to handle most of the common plumbing for samples.
+ */
+public class SampleActivityBase extends FragmentActivity {
+
+ public static final String TAG = "SampleActivityBase";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ initializeLogging();
+ }
+
+ /** Set up targets to receive log data */
+ public void initializeLogging() {
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ // Wraps Android's native log framework
+ LogWrapper logWrapper = new LogWrapper();
+ Log.setLogNode(logWrapper);
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/ElevationBasic/src/com.example.android.common/logger/Log.java b/samples/browseable/ElevationBasic/src/com.example.android.common/logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/ElevationBasic/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+ // Grabbing the native values from Android's native logging facilities,
+ // to make for easy migration and interop.
+ public static final int NONE = -1;
+ public static final int VERBOSE = android.util.Log.VERBOSE;
+ public static final int DEBUG = android.util.Log.DEBUG;
+ public static final int INFO = android.util.Log.INFO;
+ public static final int WARN = android.util.Log.WARN;
+ public static final int ERROR = android.util.Log.ERROR;
+ public static final int ASSERT = android.util.Log.ASSERT;
+
+ // Stores the beginning of the LogNode topology.
+ private static LogNode mLogNode;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public static LogNode getLogNode() {
+ return mLogNode;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to.
+ */
+ public static void setLogNode(LogNode node) {
+ mLogNode = node;
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void println(int priority, String tag, String msg, Throwable tr) {
+ if (mLogNode != null) {
+ mLogNode.println(priority, tag, msg, tr);
+ }
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ */
+ public static void println(int priority, String tag, String msg) {
+ println(priority, tag, msg, null);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void v(String tag, String msg, Throwable tr) {
+ println(VERBOSE, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void v(String tag, String msg) {
+ v(tag, msg, null);
+ }
+
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void d(String tag, String msg, Throwable tr) {
+ println(DEBUG, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void d(String tag, String msg) {
+ d(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void i(String tag, String msg, Throwable tr) {
+ println(INFO, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void i(String tag, String msg) {
+ i(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, String msg, Throwable tr) {
+ println(WARN, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void w(String tag, String msg) {
+ w(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, Throwable tr) {
+ w(tag, null, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void e(String tag, String msg, Throwable tr) {
+ println(ERROR, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void e(String tag, String msg) {
+ e(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, String msg, Throwable tr) {
+ println(ASSERT, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void wtf(String tag, String msg) {
+ wtf(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, Throwable tr) {
+ wtf(tag, null, tr);
+ }
+}
diff --git a/samples/browseable/ElevationBasic/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/ElevationBasic/src/com.example.android.common/logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/ElevationBasic/src/com.example.android.common/logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+ private LogView mLogView;
+ private ScrollView mScrollView;
+
+ public LogFragment() {}
+
+ public View inflateViews() {
+ mScrollView = new ScrollView(getActivity());
+ ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ mScrollView.setLayoutParams(scrollParams);
+
+ mLogView = new LogView(getActivity());
+ ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+ logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ mLogView.setLayoutParams(logParams);
+ mLogView.setClickable(true);
+ mLogView.setFocusable(true);
+ mLogView.setTypeface(Typeface.MONOSPACE);
+
+ // Want to set padding as 16 dips, setPadding takes pixels. Hooray math!
+ int paddingDips = 16;
+ double scale = getResources().getDisplayMetrics().density;
+ int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+ mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+ mLogView.setCompoundDrawablePadding(paddingPixels);
+
+ mLogView.setGravity(Gravity.BOTTOM);
+ mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+ mScrollView.addView(mLogView);
+ return mScrollView;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ View result = inflateViews();
+
+ mLogView.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+ }
+ });
+ return result;
+ }
+
+ public LogView getLogView() {
+ return mLogView;
+ }
+}
\ No newline at end of file
diff --git a/samples/browseable/ElevationBasic/src/com.example.android.common/logger/LogNode.java b/samples/browseable/ElevationBasic/src/com.example.android.common/logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/ElevationBasic/src/com.example.android.common/logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 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.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+ /**
+ * Instructs first LogNode in the list to print the log data provided.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/ElevationBasic/src/com.example.android.common/logger/LogView.java b/samples/browseable/ElevationBasic/src/com.example.android.common/logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/ElevationBasic/src/com.example.android.common/logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+ public LogView(Context context) {
+ super(context);
+ }
+
+ public LogView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public LogView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * Formats the log data and prints it out to the LogView.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+
+
+ String priorityStr = null;
+
+ // For the purposes of this View, we want to print the priority as readable text.
+ switch(priority) {
+ case android.util.Log.VERBOSE:
+ priorityStr = "VERBOSE";
+ break;
+ case android.util.Log.DEBUG:
+ priorityStr = "DEBUG";
+ break;
+ case android.util.Log.INFO:
+ priorityStr = "INFO";
+ break;
+ case android.util.Log.WARN:
+ priorityStr = "WARN";
+ break;
+ case android.util.Log.ERROR:
+ priorityStr = "ERROR";
+ break;
+ case android.util.Log.ASSERT:
+ priorityStr = "ASSERT";
+ break;
+ default:
+ break;
+ }
+
+ // Handily, the Log class has a facility for converting a stack trace into a usable string.
+ String exceptionStr = null;
+ if (tr != null) {
+ exceptionStr = android.util.Log.getStackTraceString(tr);
+ }
+
+ // Take the priority, tag, message, and exception, and concatenate as necessary
+ // into one usable line of text.
+ final StringBuilder outputBuilder = new StringBuilder();
+
+ String delimiter = "\t";
+ appendIfNotNull(outputBuilder, priorityStr, delimiter);
+ appendIfNotNull(outputBuilder, tag, delimiter);
+ appendIfNotNull(outputBuilder, msg, delimiter);
+ appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+ // In case this was originally called from an AsyncTask or some other off-UI thread,
+ // make sure the update occurs within the UI thread.
+ ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+ @Override
+ public void run() {
+ // Display the text we just generated within the LogView.
+ appendToLog(outputBuilder.toString());
+ }
+ })));
+
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+ * the logger takes so many arguments that might be null, this method helps cut out some of the
+ * agonizing tedium of writing the same 3 lines over and over.
+ * @param source StringBuilder containing the text to append to.
+ * @param addStr The String to append
+ * @param delimiter The String to separate the source and appended strings. A tab or comma,
+ * for instance.
+ * @return The fully concatenated String as a StringBuilder
+ */
+ private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+ if (addStr != null) {
+ if (addStr.length() == 0) {
+ delimiter = "";
+ }
+
+ return source.append(addStr).append(delimiter);
+ }
+ return source;
+ }
+
+ // The next LogNode in the chain.
+ LogNode mNext;
+
+ /** Outputs the string as a new line of log data in the LogView. */
+ public void appendToLog(String s) {
+ append("\n" + s);
+ }
+
+
+}
diff --git a/samples/browseable/ElevationBasic/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/ElevationBasic/src/com.example.android.common/logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/ElevationBasic/src/com.example.android.common/logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 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.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface. This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+ // For piping: The next node to receive Log data after this one has done its work.
+ private LogNode mNext;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /**
+ * Prints data out to the console using Android's native log mechanism.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ // There actually are log methods that don't take a msg parameter. For now,
+ // if that's the case, just convert null to the empty string and move on.
+ String useMsg = msg;
+ if (useMsg == null) {
+ useMsg = "";
+ }
+
+ // If an exeption was provided, convert that exception to a usable string and attach
+ // it to the end of the msg method.
+ if (tr != null) {
+ msg += "\n" + Log.getStackTraceString(tr);
+ }
+
+ // This is functionally identical to Log.x(tag, useMsg);
+ // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+ Log.println(priority, tag, useMsg);
+
+ // If this isn't the last node in the chain, move things along.
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+}
diff --git a/samples/browseable/ElevationBasic/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/ElevationBasic/src/com.example.android.common/logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/ElevationBasic/src/com.example.android.common/logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+ LogNode mNext;
+
+ /**
+ * Takes the "next" LogNode as a parameter, to simplify chaining.
+ *
+ * @param next The next LogNode in the pipeline.
+ */
+ public MessageOnlyLogFilter(LogNode next) {
+ mNext = next;
+ }
+
+ public MessageOnlyLogFilter() {
+ }
+
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ if (mNext != null) {
+ getNext().println(Log.NONE, null, msg, null);
+ }
+ }
+
+ /**
+ * Returns the next LogNode in the chain.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+}
diff --git a/samples/browseable/ElevationBasic/src/com.example.android.elevationbasic/ElevationBasicFragment.java b/samples/browseable/ElevationBasic/src/com.example.android.elevationbasic/ElevationBasicFragment.java
new file mode 100644
index 0000000..71edea5
--- /dev/null
+++ b/samples/browseable/ElevationBasic/src/com.example.android.elevationbasic/ElevationBasicFragment.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2014 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.elevationbasic;
+
+import android.support.v4.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.example.android.common.logger.Log;
+
+public class ElevationBasicFragment extends Fragment {
+
+ private final static String TAG = "ElevationBasicFragment";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ /**
+ * Inflates an XML containing two shapes: the first has a fixed elevation
+ * and the second ones raises when tapped.
+ */
+ View rootView = inflater.inflate(R.layout.elevation_basic, container, false);
+
+ View shape2 = rootView.findViewById(R.id.floating_shape_2);
+
+ /**
+ * Sets a {@Link View.OnTouchListener} that responds to a touch event on shape2.
+ */
+ shape2.setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View view, MotionEvent motionEvent) {
+ int action = motionEvent.getActionMasked();
+ /* Raise view on ACTION_DOWN and lower it on ACTION_UP. */
+ switch (action) {
+ case MotionEvent.ACTION_DOWN:
+ Log.d(TAG, "ACTION_DOWN on view.");
+ view.setTranslationZ(120);
+ break;
+ case MotionEvent.ACTION_UP:
+ Log.d(TAG, "ACTION_UP on view.");
+ view.setTranslationZ(0);
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+ });
+ return rootView;
+ }
+}
\ No newline at end of file
diff --git a/samples/browseable/ElevationBasic/src/com.example.android.elevationbasic/MainActivity.java b/samples/browseable/ElevationBasic/src/com.example.android.elevationbasic/MainActivity.java
new file mode 100644
index 0000000..f4285d2
--- /dev/null
+++ b/samples/browseable/ElevationBasic/src/com.example.android.elevationbasic/MainActivity.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.elevationbasic;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ViewAnimator;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description, sample log and a custom
+ * {@link android.support.v4.app.Fragment} which can display a view.
+ * <p>
+ * For devices with displays with a width of 720dp or greater, the sample log is always visible,
+ * on other devices it's visibility is controlled by an item on the Action Bar.
+ */
+public class MainActivity extends SampleActivityBase {
+
+ public static final String TAG = "MainActivity";
+
+ // Whether the Log Fragment is currently shown
+ private boolean mLogShown;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ if (savedInstanceState == null) {
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ ElevationBasicFragment fragment = new ElevationBasicFragment();
+ transaction.replace(R.id.sample_content_fragment, fragment);
+ transaction.commit();
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
+ logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
+ logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);
+
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch(item.getItemId()) {
+ case R.id.menu_toggle_log:
+ mLogShown = !mLogShown;
+ ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);
+ if (mLogShown) {
+ output.setDisplayedChild(1);
+ } else {
+ output.setDisplayedChild(0);
+ }
+ supportInvalidateOptionsMenu();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ /** Create a chain of targets that will receive log data */
+ @Override
+ public void initializeLogging() {
+ // Wraps Android's native log framework.
+ LogWrapper logWrapper = new LogWrapper();
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ Log.setLogNode(logWrapper);
+
+ // Filter strips out everything except the message text.
+ MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+ logWrapper.setNext(msgFilter);
+
+ // On screen logging via a fragment with a TextView.
+ LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+ .findFragmentById(R.id.log_fragment);
+ msgFilter.setNext(logFragment.getLogView());
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/ElevationDrag/AndroidManifest.xml b/samples/browseable/ElevationDrag/AndroidManifest.xml
new file mode 100644
index 0000000..9fd7d53
--- /dev/null
+++ b/samples/browseable/ElevationDrag/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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.elevationdrag"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <application android:allowBackup="true"
+ android:label="@string/app_name"
+ android:icon="@drawable/ic_launcher"
+ android:theme="@android:style/Theme.Material.Light" >
+
+ <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>
+ </application>
+
+
+</manifest>
diff --git a/samples/browseable/ElevationDrag/_index.jd b/samples/browseable/ElevationDrag/_index.jd
new file mode 100644
index 0000000..f484613
--- /dev/null
+++ b/samples/browseable/ElevationDrag/_index.jd
@@ -0,0 +1,11 @@
+page.tags="ElevationDrag"
+sample.group=UI
+@jd:body
+
+<p>
+
+ This sample demonstrates a drag and drop action on different shapes. Elevation and
+ z-translation are used to render the shadows and the views are clipped using different
+ Outlines.
+
+ </p>
diff --git a/samples/browseable/ElevationDrag/res/drawable-hdpi/ic_launcher.png b/samples/browseable/ElevationDrag/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..8d34f6a
--- /dev/null
+++ b/samples/browseable/ElevationDrag/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ElevationDrag/res/drawable-hdpi/tile.9.png b/samples/browseable/ElevationDrag/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/ElevationDrag/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/ElevationDrag/res/drawable-mdpi/ic_launcher.png b/samples/browseable/ElevationDrag/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..8d9cd3e
--- /dev/null
+++ b/samples/browseable/ElevationDrag/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ElevationDrag/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/ElevationDrag/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..09e4c8d
--- /dev/null
+++ b/samples/browseable/ElevationDrag/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ElevationDrag/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/ElevationDrag/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..232dc77
--- /dev/null
+++ b/samples/browseable/ElevationDrag/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ElevationDrag/res/layout-w720dp/activity_main.xml b/samples/browseable/ElevationDrag/res/layout-w720dp/activity_main.xml
new file mode 100755
index 0000000..c9a52f6
--- /dev/null
+++ b/samples/browseable/ElevationDrag/res/layout-w720dp/activity_main.xml
@@ -0,0 +1,73 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<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/sample_main_layout">
+
+ <LinearLayout
+ android:id="@+id/sample_output"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <FrameLayout
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/margin_medium"
+ android:paddingRight="@dimen/margin_medium"
+ android:paddingTop="@dimen/margin_large"
+ android:paddingBottom="@dimen/margin_large"
+ android:text="@string/intro_message" />
+ </FrameLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1" />
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="0px"
+ android:layout_height="match_parent" />
+
+</LinearLayout>
+
+
diff --git a/samples/browseable/ElevationDrag/res/layout/activity_main.xml b/samples/browseable/ElevationDrag/res/layout/activity_main.xml
new file mode 100755
index 0000000..1ae4f98
--- /dev/null
+++ b/samples/browseable/ElevationDrag/res/layout/activity_main.xml
@@ -0,0 +1,65 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<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/sample_main_layout">
+
+ <ViewAnimator
+ android:id="@+id/sample_output"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1">
+
+ <ScrollView
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/horizontal_page_margin"
+ android:paddingRight="@dimen/horizontal_page_margin"
+ android:paddingTop="@dimen/vertical_page_margin"
+ android:paddingBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </ScrollView>
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ </ViewAnimator>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="match_parent"
+ android:layout_height="0px" />
+
+</LinearLayout>
+
diff --git a/samples/browseable/ElevationDrag/res/layout/ztranslation.xml b/samples/browseable/ElevationDrag/res/layout/ztranslation.xml
new file mode 100644
index 0000000..2ae3926
--- /dev/null
+++ b/samples/browseable/ElevationDrag/res/layout/ztranslation.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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.
+-->
+<com.example.android.elevationdrag.DragFrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/main_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".MainActivity">
+
+ <View
+ android:id="@+id/circle"
+ android:layout_width="@dimen/shape_size"
+ android:layout_height="@dimen/shape_size"
+ android:layout_gravity="center"
+ android:background="@color/color_1"/>
+
+ <LinearLayout
+ android:layout_margin="16dp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom">
+
+ <Button
+ android:id="@+id/raise_bt"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.5"
+ android:text="Z+"/>
+
+ <Button
+ android:id="@+id/lower_bt"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.5"
+ android:text="Z-"/>
+ </LinearLayout>
+</com.example.android.elevationdrag.DragFrameLayout>
\ No newline at end of file
diff --git a/samples/browseable/ElevationDrag/res/menu/main.xml b/samples/browseable/ElevationDrag/res/menu/main.xml
new file mode 100644
index 0000000..b49c2c5
--- /dev/null
+++ b/samples/browseable/ElevationDrag/res/menu/main.xml
@@ -0,0 +1,21 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/menu_toggle_log"
+ android:showAsAction="always"
+ android:title="@string/sample_show_log" />
+</menu>
diff --git a/samples/browseable/ElevationDrag/res/values-sw600dp/template-dimens.xml b/samples/browseable/ElevationDrag/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/ElevationDrag/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/ElevationDrag/res/values-sw600dp/template-styles.xml b/samples/browseable/ElevationDrag/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/ElevationDrag/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/ElevationDrag/res/values-v11/template-styles.xml b/samples/browseable/ElevationDrag/res/values-v11/template-styles.xml
new file mode 100644
index 0000000..8c1ea66
--- /dev/null
+++ b/samples/browseable/ElevationDrag/res/values-v11/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/samples/browseable/ElevationDrag/res/values-v21/template-styles.xml b/samples/browseable/ElevationDrag/res/values-v21/template-styles.xml
new file mode 100644
index 0000000..134fcd9
--- /dev/null
+++ b/samples/browseable/ElevationDrag/res/values-v21/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2014 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>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Material.Light" />
+
+</resources>
diff --git a/samples/browseable/ElevationDrag/res/values/base-strings.xml b/samples/browseable/ElevationDrag/res/values/base-strings.xml
new file mode 100644
index 0000000..133e1b3
--- /dev/null
+++ b/samples/browseable/ElevationDrag/res/values/base-strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">ElevationDrag</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ This sample demonstrates a drag and drop action on different shapes. Elevation and
+ z-translation are used to render the shadows and the views are clipped using different
+ Outlines.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/ElevationDrag/res/values/colors.xml b/samples/browseable/ElevationDrag/res/values/colors.xml
new file mode 100644
index 0000000..d563796
--- /dev/null
+++ b/samples/browseable/ElevationDrag/res/values/colors.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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>
+ <color name="color_1">#E91E63</color>
+</resources>
diff --git a/samples/browseable/ElevationDrag/res/values/dimens.xml b/samples/browseable/ElevationDrag/res/values/dimens.xml
new file mode 100644
index 0000000..778d8de
--- /dev/null
+++ b/samples/browseable/ElevationDrag/res/values/dimens.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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="shape_size">96dp</dimen>
+ <dimen name="elevation_step">8dp</dimen>
+</resources>
diff --git a/samples/browseable/ElevationDrag/res/values/fragmentview_strings.xml b/samples/browseable/ElevationDrag/res/values/fragmentview_strings.xml
new file mode 100755
index 0000000..7b9d9ec
--- /dev/null
+++ b/samples/browseable/ElevationDrag/res/values/fragmentview_strings.xml
@@ -0,0 +1,19 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="sample_show_log">Show Log</string>
+ <string name="sample_hide_log">Hide Log</string>
+</resources>
diff --git a/samples/browseable/ElevationDrag/res/values/template-dimens.xml b/samples/browseable/ElevationDrag/res/values/template-dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/ElevationDrag/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/ElevationDrag/res/values/template-styles.xml b/samples/browseable/ElevationDrag/res/values/template-styles.xml
new file mode 100644
index 0000000..6e7d593
--- /dev/null
+++ b/samples/browseable/ElevationDrag/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/ElevationDrag/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/ElevationDrag/src/com.example.android.common/activities/SampleActivityBase.java
new file mode 100644
index 0000000..3228927
--- /dev/null
+++ b/samples/browseable/ElevationDrag/src/com.example.android.common/activities/SampleActivityBase.java
@@ -0,0 +1,52 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.common.activities;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogWrapper;
+
+/**
+ * Base launcher activity, to handle most of the common plumbing for samples.
+ */
+public class SampleActivityBase extends FragmentActivity {
+
+ public static final String TAG = "SampleActivityBase";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ initializeLogging();
+ }
+
+ /** Set up targets to receive log data */
+ public void initializeLogging() {
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ // Wraps Android's native log framework
+ LogWrapper logWrapper = new LogWrapper();
+ Log.setLogNode(logWrapper);
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/ElevationDrag/src/com.example.android.common/logger/Log.java b/samples/browseable/ElevationDrag/src/com.example.android.common/logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/ElevationDrag/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+ // Grabbing the native values from Android's native logging facilities,
+ // to make for easy migration and interop.
+ public static final int NONE = -1;
+ public static final int VERBOSE = android.util.Log.VERBOSE;
+ public static final int DEBUG = android.util.Log.DEBUG;
+ public static final int INFO = android.util.Log.INFO;
+ public static final int WARN = android.util.Log.WARN;
+ public static final int ERROR = android.util.Log.ERROR;
+ public static final int ASSERT = android.util.Log.ASSERT;
+
+ // Stores the beginning of the LogNode topology.
+ private static LogNode mLogNode;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public static LogNode getLogNode() {
+ return mLogNode;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to.
+ */
+ public static void setLogNode(LogNode node) {
+ mLogNode = node;
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void println(int priority, String tag, String msg, Throwable tr) {
+ if (mLogNode != null) {
+ mLogNode.println(priority, tag, msg, tr);
+ }
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ */
+ public static void println(int priority, String tag, String msg) {
+ println(priority, tag, msg, null);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void v(String tag, String msg, Throwable tr) {
+ println(VERBOSE, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void v(String tag, String msg) {
+ v(tag, msg, null);
+ }
+
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void d(String tag, String msg, Throwable tr) {
+ println(DEBUG, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void d(String tag, String msg) {
+ d(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void i(String tag, String msg, Throwable tr) {
+ println(INFO, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void i(String tag, String msg) {
+ i(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, String msg, Throwable tr) {
+ println(WARN, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void w(String tag, String msg) {
+ w(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, Throwable tr) {
+ w(tag, null, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void e(String tag, String msg, Throwable tr) {
+ println(ERROR, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void e(String tag, String msg) {
+ e(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, String msg, Throwable tr) {
+ println(ASSERT, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void wtf(String tag, String msg) {
+ wtf(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, Throwable tr) {
+ wtf(tag, null, tr);
+ }
+}
diff --git a/samples/browseable/ElevationDrag/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/ElevationDrag/src/com.example.android.common/logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/ElevationDrag/src/com.example.android.common/logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+ private LogView mLogView;
+ private ScrollView mScrollView;
+
+ public LogFragment() {}
+
+ public View inflateViews() {
+ mScrollView = new ScrollView(getActivity());
+ ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ mScrollView.setLayoutParams(scrollParams);
+
+ mLogView = new LogView(getActivity());
+ ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+ logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ mLogView.setLayoutParams(logParams);
+ mLogView.setClickable(true);
+ mLogView.setFocusable(true);
+ mLogView.setTypeface(Typeface.MONOSPACE);
+
+ // Want to set padding as 16 dips, setPadding takes pixels. Hooray math!
+ int paddingDips = 16;
+ double scale = getResources().getDisplayMetrics().density;
+ int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+ mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+ mLogView.setCompoundDrawablePadding(paddingPixels);
+
+ mLogView.setGravity(Gravity.BOTTOM);
+ mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+ mScrollView.addView(mLogView);
+ return mScrollView;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ View result = inflateViews();
+
+ mLogView.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+ }
+ });
+ return result;
+ }
+
+ public LogView getLogView() {
+ return mLogView;
+ }
+}
\ No newline at end of file
diff --git a/samples/browseable/ElevationDrag/src/com.example.android.common/logger/LogNode.java b/samples/browseable/ElevationDrag/src/com.example.android.common/logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/ElevationDrag/src/com.example.android.common/logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 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.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+ /**
+ * Instructs first LogNode in the list to print the log data provided.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/ElevationDrag/src/com.example.android.common/logger/LogView.java b/samples/browseable/ElevationDrag/src/com.example.android.common/logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/ElevationDrag/src/com.example.android.common/logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+ public LogView(Context context) {
+ super(context);
+ }
+
+ public LogView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public LogView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * Formats the log data and prints it out to the LogView.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+
+
+ String priorityStr = null;
+
+ // For the purposes of this View, we want to print the priority as readable text.
+ switch(priority) {
+ case android.util.Log.VERBOSE:
+ priorityStr = "VERBOSE";
+ break;
+ case android.util.Log.DEBUG:
+ priorityStr = "DEBUG";
+ break;
+ case android.util.Log.INFO:
+ priorityStr = "INFO";
+ break;
+ case android.util.Log.WARN:
+ priorityStr = "WARN";
+ break;
+ case android.util.Log.ERROR:
+ priorityStr = "ERROR";
+ break;
+ case android.util.Log.ASSERT:
+ priorityStr = "ASSERT";
+ break;
+ default:
+ break;
+ }
+
+ // Handily, the Log class has a facility for converting a stack trace into a usable string.
+ String exceptionStr = null;
+ if (tr != null) {
+ exceptionStr = android.util.Log.getStackTraceString(tr);
+ }
+
+ // Take the priority, tag, message, and exception, and concatenate as necessary
+ // into one usable line of text.
+ final StringBuilder outputBuilder = new StringBuilder();
+
+ String delimiter = "\t";
+ appendIfNotNull(outputBuilder, priorityStr, delimiter);
+ appendIfNotNull(outputBuilder, tag, delimiter);
+ appendIfNotNull(outputBuilder, msg, delimiter);
+ appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+ // In case this was originally called from an AsyncTask or some other off-UI thread,
+ // make sure the update occurs within the UI thread.
+ ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+ @Override
+ public void run() {
+ // Display the text we just generated within the LogView.
+ appendToLog(outputBuilder.toString());
+ }
+ })));
+
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+ * the logger takes so many arguments that might be null, this method helps cut out some of the
+ * agonizing tedium of writing the same 3 lines over and over.
+ * @param source StringBuilder containing the text to append to.
+ * @param addStr The String to append
+ * @param delimiter The String to separate the source and appended strings. A tab or comma,
+ * for instance.
+ * @return The fully concatenated String as a StringBuilder
+ */
+ private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+ if (addStr != null) {
+ if (addStr.length() == 0) {
+ delimiter = "";
+ }
+
+ return source.append(addStr).append(delimiter);
+ }
+ return source;
+ }
+
+ // The next LogNode in the chain.
+ LogNode mNext;
+
+ /** Outputs the string as a new line of log data in the LogView. */
+ public void appendToLog(String s) {
+ append("\n" + s);
+ }
+
+
+}
diff --git a/samples/browseable/ElevationDrag/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/ElevationDrag/src/com.example.android.common/logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/ElevationDrag/src/com.example.android.common/logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 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.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface. This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+ // For piping: The next node to receive Log data after this one has done its work.
+ private LogNode mNext;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /**
+ * Prints data out to the console using Android's native log mechanism.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ // There actually are log methods that don't take a msg parameter. For now,
+ // if that's the case, just convert null to the empty string and move on.
+ String useMsg = msg;
+ if (useMsg == null) {
+ useMsg = "";
+ }
+
+ // If an exeption was provided, convert that exception to a usable string and attach
+ // it to the end of the msg method.
+ if (tr != null) {
+ msg += "\n" + Log.getStackTraceString(tr);
+ }
+
+ // This is functionally identical to Log.x(tag, useMsg);
+ // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+ Log.println(priority, tag, useMsg);
+
+ // If this isn't the last node in the chain, move things along.
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+}
diff --git a/samples/browseable/ElevationDrag/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/ElevationDrag/src/com.example.android.common/logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/ElevationDrag/src/com.example.android.common/logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+ LogNode mNext;
+
+ /**
+ * Takes the "next" LogNode as a parameter, to simplify chaining.
+ *
+ * @param next The next LogNode in the pipeline.
+ */
+ public MessageOnlyLogFilter(LogNode next) {
+ mNext = next;
+ }
+
+ public MessageOnlyLogFilter() {
+ }
+
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ if (mNext != null) {
+ getNext().println(Log.NONE, null, msg, null);
+ }
+ }
+
+ /**
+ * Returns the next LogNode in the chain.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+}
diff --git a/samples/browseable/ElevationDrag/src/com.example.android.elevationdrag/DragFrameLayout.java b/samples/browseable/ElevationDrag/src/com.example.android.elevationdrag/DragFrameLayout.java
new file mode 100644
index 0000000..0b2a8d2
--- /dev/null
+++ b/samples/browseable/ElevationDrag/src/com.example.android.elevationdrag/DragFrameLayout.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2014 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.elevationdrag;
+
+import android.content.Context;
+import android.support.v4.widget.ViewDragHelper;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A {@link FrameLayout} that allows the user to drag and reposition child views.
+ */
+public class DragFrameLayout extends FrameLayout {
+
+ /**
+ * The list of {@link View}s that will be draggable.
+ */
+ private List<View> mDragViews;
+
+ /**
+ * The {@link DragFrameLayoutController} that will be notify on drag.
+ */
+ private DragFrameLayoutController mDragFrameLayoutController;
+
+ private ViewDragHelper mDragHelper;
+
+ public DragFrameLayout(Context context) {
+ this(context, null, 0, 0);
+ }
+
+ public DragFrameLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0, 0);
+ }
+
+ public DragFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public DragFrameLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ mDragViews = new ArrayList<View>();
+
+ /**
+ * Create the {@link ViewDragHelper} and set its callback.
+ */
+ mDragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {
+ @Override
+ public boolean tryCaptureView(View child, int pointerId) {
+ return mDragViews.contains(child);
+ }
+
+ @Override
+ public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
+ super.onViewPositionChanged(changedView, left, top, dx, dy);
+ }
+
+ @Override
+ public int clampViewPositionHorizontal(View child, int left, int dx) {
+ return left;
+ }
+
+ @Override
+ public int clampViewPositionVertical(View child, int top, int dy) {
+ return top;
+ }
+
+ @Override
+ public void onViewCaptured(View capturedChild, int activePointerId) {
+ super.onViewCaptured(capturedChild, activePointerId);
+ if (mDragFrameLayoutController != null) {
+ mDragFrameLayoutController.onDragDrop(true);
+ }
+ }
+
+ @Override
+ public void onViewReleased(View releasedChild, float xvel, float yvel) {
+ super.onViewReleased(releasedChild, xvel, yvel);
+ if (mDragFrameLayoutController != null) {
+ mDragFrameLayoutController.onDragDrop(false);
+ }
+ }
+ });
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ final int action = ev.getActionMasked();
+ if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
+ mDragHelper.cancel();
+ return false;
+ }
+ return mDragHelper.shouldInterceptTouchEvent(ev);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ mDragHelper.processTouchEvent(ev);
+ return true;
+ }
+
+ /**
+ * Adds a new {@link View} to the list of views that are draggable within the container.
+ * @param dragView the {@link View} to make draggable
+ */
+ public void addDragView(View dragView) {
+ mDragViews.add(dragView);
+ }
+
+ /**
+ * Sets the {@link DragFrameLayoutController} that will receive the drag events.
+ * @param dragFrameLayoutController a {@link DragFrameLayoutController}
+ */
+ public void setDragFrameController(DragFrameLayoutController dragFrameLayoutController) {
+ mDragFrameLayoutController = dragFrameLayoutController;
+ }
+
+ /**
+ * A controller that will receive the drag events.
+ */
+ public interface DragFrameLayoutController {
+
+ public void onDragDrop(boolean captured);
+ }
+}
diff --git a/samples/browseable/ElevationDrag/src/com.example.android.elevationdrag/ElevationDragFragment.java b/samples/browseable/ElevationDrag/src/com.example.android.elevationdrag/ElevationDragFragment.java
new file mode 100644
index 0000000..9d14206
--- /dev/null
+++ b/samples/browseable/ElevationDrag/src/com.example.android.elevationdrag/ElevationDragFragment.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2014 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.elevationdrag;
+
+import com.example.android.common.logger.Log;
+
+import android.graphics.Outline;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
+
+public class ElevationDragFragment extends Fragment {
+
+ public static final String TAG = "ElevationDragFragment";
+
+ /* The circular outline provider */
+ private ViewOutlineProvider mOutlineProviderCircle;
+
+ /* The current elevation of the floating view. */
+ private float mElevation = 0;
+
+ /* The step in elevation when changing the Z value */
+ private int mElevationStep;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mOutlineProviderCircle = new CircleOutlineProvider();
+
+ mElevationStep = getResources().getDimensionPixelSize(R.dimen.elevation_step);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View rootView = inflater.inflate(R.layout.ztranslation, container, false);
+
+ /* Find the {@link View} to apply z-translation to. */
+ final View floatingShape = rootView.findViewById(R.id.circle);
+
+ /* Define the shape of the {@link View}'s shadow by setting one of the {@link Outline}s. */
+ floatingShape.setOutlineProvider(mOutlineProviderCircle);
+
+ /* Clip the {@link View} with its outline. */
+ floatingShape.setClipToOutline(true);
+
+ DragFrameLayout dragLayout = ((DragFrameLayout) rootView.findViewById(R.id.main_layout));
+
+ dragLayout.setDragFrameController(new DragFrameLayout.DragFrameLayoutController() {
+
+ @Override
+ public void onDragDrop(boolean captured) {
+ /* Animate the translation of the {@link View}. Note that the translation
+ is being modified, not the elevation. */
+ floatingShape.animate()
+ .translationZ(captured ? 50 : 0)
+ .setDuration(100);
+ Log.d(TAG, captured ? "Drag" : "Drop");
+ }
+ });
+
+ dragLayout.addDragView(floatingShape);
+
+ /* Raise the circle in z when the "z+" button is clicked. */
+ rootView.findViewById(R.id.raise_bt).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mElevation += mElevationStep;
+ Log.d(TAG, String.format("Elevation: %.1f", mElevation));
+ floatingShape.setElevation(mElevation);
+ }
+ });
+
+ /* Lower the circle in z when the "z-" button is clicked. */
+ rootView.findViewById(R.id.lower_bt).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mElevation -= mElevationStep;
+ // Don't allow for negative values of Z.
+ if (mElevation < 0) {
+ mElevation = 0;
+ }
+ Log.d(TAG, String.format("Elevation: %.1f", mElevation));
+ floatingShape.setElevation(mElevation);
+ }
+ });
+
+ return rootView;
+ }
+
+ /**
+ * ViewOutlineProvider which sets the outline to be an oval which fits the view bounds.
+ */
+ private class CircleOutlineProvider extends ViewOutlineProvider {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setOval(0, 0, view.getWidth(), view.getHeight());
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/samples/browseable/ElevationDrag/src/com.example.android.elevationdrag/MainActivity.java b/samples/browseable/ElevationDrag/src/com.example.android.elevationdrag/MainActivity.java
new file mode 100644
index 0000000..98579bf
--- /dev/null
+++ b/samples/browseable/ElevationDrag/src/com.example.android.elevationdrag/MainActivity.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.elevationdrag;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ViewAnimator;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description, sample log and a custom
+ * {@link android.support.v4.app.Fragment} which can display a view.
+ * <p>
+ * For devices with displays with a width of 720dp or greater, the sample log is always visible,
+ * on other devices it's visibility is controlled by an item on the Action Bar.
+ */
+public class MainActivity extends SampleActivityBase {
+
+ public static final String TAG = "MainActivity";
+
+ // Whether the Log Fragment is currently shown
+ private boolean mLogShown;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ if (savedInstanceState == null) {
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ ElevationDragFragment fragment = new ElevationDragFragment();
+ transaction.replace(R.id.sample_content_fragment, fragment);
+ transaction.commit();
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
+ logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
+ logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);
+
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch(item.getItemId()) {
+ case R.id.menu_toggle_log:
+ mLogShown = !mLogShown;
+ ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);
+ if (mLogShown) {
+ output.setDisplayedChild(1);
+ } else {
+ output.setDisplayedChild(0);
+ }
+ supportInvalidateOptionsMenu();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ /** Create a chain of targets that will receive log data */
+ @Override
+ public void initializeLogging() {
+ // Wraps Android's native log framework.
+ LogWrapper logWrapper = new LogWrapper();
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ Log.setLogNode(logWrapper);
+
+ // Filter strips out everything except the message text.
+ MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+ logWrapper.setNext(msgFilter);
+
+ // On screen logging via a fragment with a TextView.
+ LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+ .findFragmentById(R.id.log_fragment);
+ msgFilter.setNext(logFragment.getLogView());
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/FloatingActionButtonBasic/AndroidManifest.xml b/samples/browseable/FloatingActionButtonBasic/AndroidManifest.xml
new file mode 100644
index 0000000..8f26c99
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014, 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.floatingactionbuttonbasic"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <application android:allowBackup="true"
+ android:label="@string/app_name"
+ android:icon="@drawable/ic_launcher"
+ android:theme="@style/AppTheme">
+
+ <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>
+ </application>
+
+
+</manifest>
diff --git a/samples/browseable/FloatingActionButtonBasic/_index.jd b/samples/browseable/FloatingActionButtonBasic/_index.jd
new file mode 100644
index 0000000..48a11c2
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/_index.jd
@@ -0,0 +1,10 @@
+page.tags="FloatingActionButtonBasic"
+sample.group=UI
+@jd:body
+
+<p>
+
+ This sample shows the two sizes of Floating Action Buttons and how to interact with
+ them.
+
+ </p>
diff --git a/samples/browseable/FloatingActionButtonBasic/res/animator/fab_anim.xml b/samples/browseable/FloatingActionButtonBasic/res/animator/fab_anim.xml
new file mode 100644
index 0000000..dd83cd3
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/res/animator/fab_anim.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014, 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:state_enabled="true" android:state_pressed="true">
+ <objectAnimator
+ android:duration="@android:integer/config_shortAnimTime"
+ android:propertyName="translationZ"
+ android:valueTo="@dimen/fab_press_translation_z"
+ android:valueType="floatType" />
+ </item>
+
+ <item>
+ <objectAnimator
+ android:duration="@android:integer/config_shortAnimTime"
+ android:propertyName="translationZ"
+ android:valueTo="0"
+ android:valueType="floatType" />
+ </item>
+
+</selector>
\ No newline at end of file
diff --git a/samples/browseable/FloatingActionButtonBasic/res/drawable-hdpi/ic_launcher.png b/samples/browseable/FloatingActionButtonBasic/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..5832eda
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/FloatingActionButtonBasic/res/drawable-hdpi/tile.9.png b/samples/browseable/FloatingActionButtonBasic/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/FloatingActionButtonBasic/res/drawable-mdpi/ic_launcher.png b/samples/browseable/FloatingActionButtonBasic/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..08e272e
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/FloatingActionButtonBasic/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/FloatingActionButtonBasic/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..7803f2d
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/FloatingActionButtonBasic/res/drawable-xxhdpi/ic_add.png b/samples/browseable/FloatingActionButtonBasic/res/drawable-xxhdpi/ic_add.png
new file mode 100644
index 0000000..f3166df
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/res/drawable-xxhdpi/ic_add.png
Binary files differ
diff --git a/samples/browseable/FloatingActionButtonBasic/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/FloatingActionButtonBasic/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..a1f819c
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/FloatingActionButtonBasic/res/drawable-xxhdpi/ic_tick.png b/samples/browseable/FloatingActionButtonBasic/res/drawable-xxhdpi/ic_tick.png
new file mode 100644
index 0000000..56f0454
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/res/drawable-xxhdpi/ic_tick.png
Binary files differ
diff --git a/samples/browseable/FloatingActionButtonBasic/res/drawable/fab_background.xml b/samples/browseable/FloatingActionButtonBasic/res/drawable/fab_background.xml
new file mode 100644
index 0000000..e5e7dbc
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/res/drawable/fab_background.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:state_checked="true">
+ <ripple android:color="@color/fab_color_2_muted">
+ <item>
+ <shape>
+ <solid android:color="@color/fab_color_2" />
+ </shape>
+ </item>
+ </ripple>
+ </item>
+
+ <item>
+ <ripple android:color="@color/fab_color_1_muted">
+ <item>
+ <shape>
+ <solid android:color="@color/fab_color_1" />
+ </shape>
+ </item>
+ </ripple>
+ </item>
+
+</selector>
\ No newline at end of file
diff --git a/samples/browseable/FloatingActionButtonBasic/res/drawable/fab_icons.xml b/samples/browseable/FloatingActionButtonBasic/res/drawable/fab_icons.xml
new file mode 100644
index 0000000..daf1d24
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/res/drawable/fab_icons.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:enterFadeDuration="@android:integer/config_shortAnimTime">
+
+ <item android:state_checked="true">
+ <bitmap android:src="@drawable/ic_tick" android:tint="@android:color/white" />
+ </item>
+
+ <item>
+ <bitmap android:src="@drawable/ic_add" android:tint="@android:color/white" />
+ </item>
+
+</selector>
\ No newline at end of file
diff --git a/samples/browseable/FloatingActionButtonBasic/res/layout-w720dp/activity_main.xml b/samples/browseable/FloatingActionButtonBasic/res/layout-w720dp/activity_main.xml
new file mode 100755
index 0000000..c9a52f6
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/res/layout-w720dp/activity_main.xml
@@ -0,0 +1,73 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<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/sample_main_layout">
+
+ <LinearLayout
+ android:id="@+id/sample_output"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <FrameLayout
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/margin_medium"
+ android:paddingRight="@dimen/margin_medium"
+ android:paddingTop="@dimen/margin_large"
+ android:paddingBottom="@dimen/margin_large"
+ android:text="@string/intro_message" />
+ </FrameLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1" />
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="0px"
+ android:layout_height="match_parent" />
+
+</LinearLayout>
+
+
diff --git a/samples/browseable/FloatingActionButtonBasic/res/layout/activity_main.xml b/samples/browseable/FloatingActionButtonBasic/res/layout/activity_main.xml
new file mode 100755
index 0000000..1ae4f98
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/res/layout/activity_main.xml
@@ -0,0 +1,65 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<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/sample_main_layout">
+
+ <ViewAnimator
+ android:id="@+id/sample_output"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1">
+
+ <ScrollView
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/horizontal_page_margin"
+ android:paddingRight="@dimen/horizontal_page_margin"
+ android:paddingTop="@dimen/vertical_page_margin"
+ android:paddingBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </ScrollView>
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ </ViewAnimator>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="match_parent"
+ android:layout_height="0px" />
+
+</LinearLayout>
+
diff --git a/samples/browseable/FloatingActionButtonBasic/res/layout/fab_layout.xml b/samples/browseable/FloatingActionButtonBasic/res/layout/fab_layout.xml
new file mode 100644
index 0000000..ab8c7dc
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/res/layout/fab_layout.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014, 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 android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <com.example.android.floatingactionbuttonbasic.FloatingActionButton
+ android:id="@+id/fab_1"
+ android:layout_width="@dimen/fab_size"
+ android:layout_height="@dimen/fab_size"
+ android:layout_marginTop="16dp"
+ android:elevation="@dimen/fab_elevation"
+ android:background="@drawable/fab_background"
+ android:stateListAnimator="@animator/fab_anim"
+ android:layout_gravity="center_horizontal">
+
+ <ImageView
+ android:layout_width="@dimen/fab_icon_size"
+ android:layout_height="@dimen/fab_icon_size"
+ android:src="@drawable/fab_icons"
+ android:layout_gravity="center"
+ android:duplicateParentState="true"/>
+
+ </com.example.android.floatingactionbuttonbasic.FloatingActionButton>
+
+
+ <com.example.android.floatingactionbuttonbasic.FloatingActionButton
+ android:id="@+id/fab_2"
+ android:layout_width="@dimen/fab_size_small"
+ android:layout_height="@dimen/fab_size_small"
+ android:layout_marginTop="128dp"
+ android:elevation="@dimen/fab_elevation"
+ android:background="@drawable/fab_background"
+ android:stateListAnimator="@animator/fab_anim"
+ android:layout_gravity="center_horizontal">
+
+ <ImageView
+ android:layout_width="@dimen/fab_icon_size"
+ android:layout_height="@dimen/fab_icon_size"
+ android:src="@drawable/fab_icons"
+ android:layout_gravity="center"
+ android:duplicateParentState="true"/>
+
+ </com.example.android.floatingactionbuttonbasic.FloatingActionButton>
+</FrameLayout>
diff --git a/samples/browseable/FloatingActionButtonBasic/res/menu/main.xml b/samples/browseable/FloatingActionButtonBasic/res/menu/main.xml
new file mode 100644
index 0000000..b49c2c5
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/res/menu/main.xml
@@ -0,0 +1,21 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/menu_toggle_log"
+ android:showAsAction="always"
+ android:title="@string/sample_show_log" />
+</menu>
diff --git a/samples/browseable/FloatingActionButtonBasic/res/values-sw600dp/template-dimens.xml b/samples/browseable/FloatingActionButtonBasic/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/FloatingActionButtonBasic/res/values-sw600dp/template-styles.xml b/samples/browseable/FloatingActionButtonBasic/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/FloatingActionButtonBasic/res/values-v11/template-styles.xml b/samples/browseable/FloatingActionButtonBasic/res/values-v11/template-styles.xml
new file mode 100644
index 0000000..8c1ea66
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/res/values-v11/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/samples/browseable/FloatingActionButtonBasic/res/values-v21/template-styles.xml b/samples/browseable/FloatingActionButtonBasic/res/values-v21/template-styles.xml
new file mode 100644
index 0000000..134fcd9
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/res/values-v21/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2014 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>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Material.Light" />
+
+</resources>
diff --git a/samples/browseable/FloatingActionButtonBasic/res/values/base-strings.xml b/samples/browseable/FloatingActionButtonBasic/res/values/base-strings.xml
new file mode 100644
index 0000000..2eea10e
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/res/values/base-strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">FloatingActionButtonBasic</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ This sample shows the two sizes of Floating Action Buttons and how to interact with
+ them.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/FloatingActionButtonBasic/res/values/colors.xml b/samples/browseable/FloatingActionButtonBasic/res/values/colors.xml
new file mode 100644
index 0000000..141b1f5
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/res/values/colors.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014, 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>
+ <color name="fab_color_1">#ff5252</color>
+ <color name="fab_color_1_muted">#ff8080</color>
+ <color name="fab_color_2">#9c27b0</color>
+ <color name="fab_color_2_muted">#a56ab0</color>
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/FloatingActionButtonBasic/res/values/dimens.xml b/samples/browseable/FloatingActionButtonBasic/res/values/dimens.xml
new file mode 100644
index 0000000..f063937
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/res/values/dimens.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014, 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="fab_elevation">2dp</dimen>
+ <dimen name="fab_press_translation_z">2dp</dimen>
+ <dimen name="fab_size">56dp</dimen>
+ <dimen name="fab_size_small">40dp</dimen>
+ <dimen name="fab_icon_size">24dp</dimen>
+</resources>
diff --git a/samples/browseable/FloatingActionButtonBasic/res/values/fragmentview_strings.xml b/samples/browseable/FloatingActionButtonBasic/res/values/fragmentview_strings.xml
new file mode 100755
index 0000000..7b9d9ec
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/res/values/fragmentview_strings.xml
@@ -0,0 +1,19 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="sample_show_log">Show Log</string>
+ <string name="sample_hide_log">Hide Log</string>
+</resources>
diff --git a/samples/browseable/FloatingActionButtonBasic/res/values/template-dimens.xml b/samples/browseable/FloatingActionButtonBasic/res/values/template-dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/FloatingActionButtonBasic/res/values/template-styles.xml b/samples/browseable/FloatingActionButtonBasic/res/values/template-styles.xml
new file mode 100644
index 0000000..6e7d593
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/FloatingActionButtonBasic/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/FloatingActionButtonBasic/src/com.example.android.common/activities/SampleActivityBase.java
new file mode 100644
index 0000000..3228927
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/src/com.example.android.common/activities/SampleActivityBase.java
@@ -0,0 +1,52 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.common.activities;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogWrapper;
+
+/**
+ * Base launcher activity, to handle most of the common plumbing for samples.
+ */
+public class SampleActivityBase extends FragmentActivity {
+
+ public static final String TAG = "SampleActivityBase";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ initializeLogging();
+ }
+
+ /** Set up targets to receive log data */
+ public void initializeLogging() {
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ // Wraps Android's native log framework
+ LogWrapper logWrapper = new LogWrapper();
+ Log.setLogNode(logWrapper);
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/FloatingActionButtonBasic/src/com.example.android.common/logger/Log.java b/samples/browseable/FloatingActionButtonBasic/src/com.example.android.common/logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+ // Grabbing the native values from Android's native logging facilities,
+ // to make for easy migration and interop.
+ public static final int NONE = -1;
+ public static final int VERBOSE = android.util.Log.VERBOSE;
+ public static final int DEBUG = android.util.Log.DEBUG;
+ public static final int INFO = android.util.Log.INFO;
+ public static final int WARN = android.util.Log.WARN;
+ public static final int ERROR = android.util.Log.ERROR;
+ public static final int ASSERT = android.util.Log.ASSERT;
+
+ // Stores the beginning of the LogNode topology.
+ private static LogNode mLogNode;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public static LogNode getLogNode() {
+ return mLogNode;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to.
+ */
+ public static void setLogNode(LogNode node) {
+ mLogNode = node;
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void println(int priority, String tag, String msg, Throwable tr) {
+ if (mLogNode != null) {
+ mLogNode.println(priority, tag, msg, tr);
+ }
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ */
+ public static void println(int priority, String tag, String msg) {
+ println(priority, tag, msg, null);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void v(String tag, String msg, Throwable tr) {
+ println(VERBOSE, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void v(String tag, String msg) {
+ v(tag, msg, null);
+ }
+
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void d(String tag, String msg, Throwable tr) {
+ println(DEBUG, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void d(String tag, String msg) {
+ d(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void i(String tag, String msg, Throwable tr) {
+ println(INFO, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void i(String tag, String msg) {
+ i(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, String msg, Throwable tr) {
+ println(WARN, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void w(String tag, String msg) {
+ w(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, Throwable tr) {
+ w(tag, null, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void e(String tag, String msg, Throwable tr) {
+ println(ERROR, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void e(String tag, String msg) {
+ e(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, String msg, Throwable tr) {
+ println(ASSERT, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void wtf(String tag, String msg) {
+ wtf(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, Throwable tr) {
+ wtf(tag, null, tr);
+ }
+}
diff --git a/samples/browseable/FloatingActionButtonBasic/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/FloatingActionButtonBasic/src/com.example.android.common/logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/src/com.example.android.common/logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+ private LogView mLogView;
+ private ScrollView mScrollView;
+
+ public LogFragment() {}
+
+ public View inflateViews() {
+ mScrollView = new ScrollView(getActivity());
+ ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ mScrollView.setLayoutParams(scrollParams);
+
+ mLogView = new LogView(getActivity());
+ ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+ logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ mLogView.setLayoutParams(logParams);
+ mLogView.setClickable(true);
+ mLogView.setFocusable(true);
+ mLogView.setTypeface(Typeface.MONOSPACE);
+
+ // Want to set padding as 16 dips, setPadding takes pixels. Hooray math!
+ int paddingDips = 16;
+ double scale = getResources().getDisplayMetrics().density;
+ int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+ mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+ mLogView.setCompoundDrawablePadding(paddingPixels);
+
+ mLogView.setGravity(Gravity.BOTTOM);
+ mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+ mScrollView.addView(mLogView);
+ return mScrollView;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ View result = inflateViews();
+
+ mLogView.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+ }
+ });
+ return result;
+ }
+
+ public LogView getLogView() {
+ return mLogView;
+ }
+}
\ No newline at end of file
diff --git a/samples/browseable/FloatingActionButtonBasic/src/com.example.android.common/logger/LogNode.java b/samples/browseable/FloatingActionButtonBasic/src/com.example.android.common/logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/src/com.example.android.common/logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 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.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+ /**
+ * Instructs first LogNode in the list to print the log data provided.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/FloatingActionButtonBasic/src/com.example.android.common/logger/LogView.java b/samples/browseable/FloatingActionButtonBasic/src/com.example.android.common/logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/src/com.example.android.common/logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+ public LogView(Context context) {
+ super(context);
+ }
+
+ public LogView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public LogView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * Formats the log data and prints it out to the LogView.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+
+
+ String priorityStr = null;
+
+ // For the purposes of this View, we want to print the priority as readable text.
+ switch(priority) {
+ case android.util.Log.VERBOSE:
+ priorityStr = "VERBOSE";
+ break;
+ case android.util.Log.DEBUG:
+ priorityStr = "DEBUG";
+ break;
+ case android.util.Log.INFO:
+ priorityStr = "INFO";
+ break;
+ case android.util.Log.WARN:
+ priorityStr = "WARN";
+ break;
+ case android.util.Log.ERROR:
+ priorityStr = "ERROR";
+ break;
+ case android.util.Log.ASSERT:
+ priorityStr = "ASSERT";
+ break;
+ default:
+ break;
+ }
+
+ // Handily, the Log class has a facility for converting a stack trace into a usable string.
+ String exceptionStr = null;
+ if (tr != null) {
+ exceptionStr = android.util.Log.getStackTraceString(tr);
+ }
+
+ // Take the priority, tag, message, and exception, and concatenate as necessary
+ // into one usable line of text.
+ final StringBuilder outputBuilder = new StringBuilder();
+
+ String delimiter = "\t";
+ appendIfNotNull(outputBuilder, priorityStr, delimiter);
+ appendIfNotNull(outputBuilder, tag, delimiter);
+ appendIfNotNull(outputBuilder, msg, delimiter);
+ appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+ // In case this was originally called from an AsyncTask or some other off-UI thread,
+ // make sure the update occurs within the UI thread.
+ ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+ @Override
+ public void run() {
+ // Display the text we just generated within the LogView.
+ appendToLog(outputBuilder.toString());
+ }
+ })));
+
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+ * the logger takes so many arguments that might be null, this method helps cut out some of the
+ * agonizing tedium of writing the same 3 lines over and over.
+ * @param source StringBuilder containing the text to append to.
+ * @param addStr The String to append
+ * @param delimiter The String to separate the source and appended strings. A tab or comma,
+ * for instance.
+ * @return The fully concatenated String as a StringBuilder
+ */
+ private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+ if (addStr != null) {
+ if (addStr.length() == 0) {
+ delimiter = "";
+ }
+
+ return source.append(addStr).append(delimiter);
+ }
+ return source;
+ }
+
+ // The next LogNode in the chain.
+ LogNode mNext;
+
+ /** Outputs the string as a new line of log data in the LogView. */
+ public void appendToLog(String s) {
+ append("\n" + s);
+ }
+
+
+}
diff --git a/samples/browseable/FloatingActionButtonBasic/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/FloatingActionButtonBasic/src/com.example.android.common/logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/src/com.example.android.common/logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 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.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface. This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+ // For piping: The next node to receive Log data after this one has done its work.
+ private LogNode mNext;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /**
+ * Prints data out to the console using Android's native log mechanism.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ // There actually are log methods that don't take a msg parameter. For now,
+ // if that's the case, just convert null to the empty string and move on.
+ String useMsg = msg;
+ if (useMsg == null) {
+ useMsg = "";
+ }
+
+ // If an exeption was provided, convert that exception to a usable string and attach
+ // it to the end of the msg method.
+ if (tr != null) {
+ msg += "\n" + Log.getStackTraceString(tr);
+ }
+
+ // This is functionally identical to Log.x(tag, useMsg);
+ // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+ Log.println(priority, tag, useMsg);
+
+ // If this isn't the last node in the chain, move things along.
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+}
diff --git a/samples/browseable/FloatingActionButtonBasic/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/FloatingActionButtonBasic/src/com.example.android.common/logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/src/com.example.android.common/logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+ LogNode mNext;
+
+ /**
+ * Takes the "next" LogNode as a parameter, to simplify chaining.
+ *
+ * @param next The next LogNode in the pipeline.
+ */
+ public MessageOnlyLogFilter(LogNode next) {
+ mNext = next;
+ }
+
+ public MessageOnlyLogFilter() {
+ }
+
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ if (mNext != null) {
+ getNext().println(Log.NONE, null, msg, null);
+ }
+ }
+
+ /**
+ * Returns the next LogNode in the chain.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+}
diff --git a/samples/browseable/FloatingActionButtonBasic/src/com.example.android.floatingactionbuttonbasic/FloatingActionButton.java b/samples/browseable/FloatingActionButtonBasic/src/com.example.android.floatingactionbuttonbasic/FloatingActionButton.java
new file mode 100644
index 0000000..12fdd1c
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/src/com.example.android.floatingactionbuttonbasic/FloatingActionButton.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2014, 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.floatingactionbuttonbasic;
+
+import android.content.Context;
+import android.graphics.Outline;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+import android.widget.Checkable;
+import android.widget.FrameLayout;
+
+/**
+ * A Floating Action Button is a {@link android.widget.Checkable} view distinguished by a circled
+ * icon floating above the UI, with special motion behaviors.
+ */
+public class FloatingActionButton extends FrameLayout implements Checkable {
+
+ /**
+ * Interface definition for a callback to be invoked when the checked state
+ * of a compound button changes.
+ */
+ public static interface OnCheckedChangeListener {
+
+ /**
+ * Called when the checked state of a FAB has changed.
+ *
+ * @param fabView The FAB view whose state has changed.
+ * @param isChecked The new checked state of buttonView.
+ */
+ void onCheckedChanged(FloatingActionButton fabView, boolean isChecked);
+ }
+
+ /**
+ * An array of states.
+ */
+ private static final int[] CHECKED_STATE_SET = {
+ android.R.attr.state_checked
+ };
+
+ private static final String TAG = "FloatingActionButton";
+
+ // A boolean that tells if the FAB is checked or not.
+ private boolean mChecked;
+
+ // A listener to communicate that the FAB has changed it's state
+ private OnCheckedChangeListener mOnCheckedChangeListener;
+
+ public FloatingActionButton(Context context) {
+ this(context, null, 0, 0);
+ }
+
+ public FloatingActionButton(Context context, AttributeSet attrs) {
+ this(context, attrs, 0, 0);
+ }
+
+ public FloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public FloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr);
+
+ setClickable(true);
+
+ // Set the outline provider for this view. The provider is given the outline which it can
+ // then modify as needed. In this case we set the outline to be an oval fitting the height
+ // and width.
+ setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setOval(0, 0, getWidth(), getHeight());
+ }
+ });
+
+ // Finally, enable clipping to the outline, using the provider we set above
+ setClipToOutline(true);
+ }
+
+ /**
+ * Sets the checked/unchecked state of the FAB.
+ * @param checked
+ */
+ public void setChecked(boolean checked) {
+ // If trying to set the current state, ignore.
+ if (checked == mChecked) {
+ return;
+ }
+ mChecked = checked;
+
+ // Now refresh the drawable state (so the icon changes)
+ refreshDrawableState();
+
+ if (mOnCheckedChangeListener != null) {
+ mOnCheckedChangeListener.onCheckedChanged(this, checked);
+ }
+ }
+
+ /**
+ * Register a callback to be invoked when the checked state of this button
+ * changes.
+ *
+ * @param listener the callback to call on checked state change
+ */
+ public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
+ mOnCheckedChangeListener = listener;
+ }
+
+ @Override
+ public boolean isChecked() {
+ return mChecked;
+ }
+
+ @Override
+ public void toggle() {
+ setChecked(!mChecked);
+ }
+
+ /**
+ * Override performClick() so that we can toggle the checked state when the view is clicked
+ */
+ @Override
+ public boolean performClick() {
+ toggle();
+ return super.performClick();
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+
+ // As we have changed size, we should invalidate the outline so that is the the
+ // correct size
+ invalidateOutline();
+ }
+
+ @Override
+ protected int[] onCreateDrawableState(int extraSpace) {
+ final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
+ if (isChecked()) {
+ mergeDrawableStates(drawableState, CHECKED_STATE_SET);
+ }
+ return drawableState;
+ }
+}
diff --git a/samples/browseable/FloatingActionButtonBasic/src/com.example.android.floatingactionbuttonbasic/FloatingActionButtonBasicFragment.java b/samples/browseable/FloatingActionButtonBasic/src/com.example.android.floatingactionbuttonbasic/FloatingActionButtonBasicFragment.java
new file mode 100644
index 0000000..817cfb7
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/src/com.example.android.floatingactionbuttonbasic/FloatingActionButtonBasicFragment.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2014, 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.floatingactionbuttonbasic;
+
+import com.example.android.common.logger.Log;
+
+import android.app.Activity;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+
+/**
+ * This fragment inflates a layout with two Floating Action Buttons and acts as a listener to
+ * changes on them.
+ */
+public class FloatingActionButtonBasicFragment extends Fragment implements FloatingActionButton.OnCheckedChangeListener{
+
+ private final static String TAG = "FloatingActionButtonBasicFragment";
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ View rootView = inflater.inflate(R.layout.fab_layout, container, false);
+
+ // Make this {@link Fragment} listen for changes in both FABs.
+ FloatingActionButton fab1 = (FloatingActionButton) rootView.findViewById(R.id.fab_1);
+ fab1.setOnCheckedChangeListener(this);
+ FloatingActionButton fab2 = (FloatingActionButton) rootView.findViewById(R.id.fab_2);
+ fab2.setOnCheckedChangeListener(this);
+ return rootView;
+ }
+
+
+ @Override
+ public void onCheckedChanged(FloatingActionButton fabView, boolean isChecked) {
+ // When a FAB is toggled, log the action.
+ switch (fabView.getId()){
+ case R.id.fab_1:
+ Log.d(TAG, String.format("FAB 1 was %s.", isChecked ? "checked" : "unchecked"));
+ break;
+ case R.id.fab_2:
+ Log.d(TAG, String.format("FAB 2 was %s.", isChecked ? "checked" : "unchecked"));
+ break;
+ default:
+ break;
+ }
+ }
+}
diff --git a/samples/browseable/FloatingActionButtonBasic/src/com.example.android.floatingactionbuttonbasic/MainActivity.java b/samples/browseable/FloatingActionButtonBasic/src/com.example.android.floatingactionbuttonbasic/MainActivity.java
new file mode 100644
index 0000000..b88fc7a
--- /dev/null
+++ b/samples/browseable/FloatingActionButtonBasic/src/com.example.android.floatingactionbuttonbasic/MainActivity.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.floatingactionbuttonbasic;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ViewAnimator;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description, sample log and a custom
+ * {@link android.support.v4.app.Fragment} which can display a view.
+ * <p>
+ * For devices with displays with a width of 720dp or greater, the sample log is always visible,
+ * on other devices it's visibility is controlled by an item on the Action Bar.
+ */
+public class MainActivity extends SampleActivityBase {
+
+ public static final String TAG = "MainActivity";
+
+ // Whether the Log Fragment is currently shown
+ private boolean mLogShown;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ if (savedInstanceState == null) {
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ FloatingActionButtonBasicFragment fragment = new FloatingActionButtonBasicFragment();
+ transaction.replace(R.id.sample_content_fragment, fragment);
+ transaction.commit();
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
+ logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
+ logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);
+
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch(item.getItemId()) {
+ case R.id.menu_toggle_log:
+ mLogShown = !mLogShown;
+ ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);
+ if (mLogShown) {
+ output.setDisplayedChild(1);
+ } else {
+ output.setDisplayedChild(0);
+ }
+ supportInvalidateOptionsMenu();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ /** Create a chain of targets that will receive log data */
+ @Override
+ public void initializeLogging() {
+ // Wraps Android's native log framework.
+ LogWrapper logWrapper = new LogWrapper();
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ Log.setLogNode(logWrapper);
+
+ // Filter strips out everything except the message text.
+ MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+ logWrapper.setNext(msgFilter);
+
+ // On screen logging via a fragment with a TextView.
+ LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+ .findFragmentById(R.id.log_fragment);
+ msgFilter.setNext(logFragment.getLogView());
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/HdrViewfinder/AndroidManifest.xml b/samples/browseable/HdrViewfinder/AndroidManifest.xml
new file mode 100644
index 0000000..772b7df
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/AndroidManifest.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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
+ package="com.example.android.hdrviewfinder"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <uses-sdk
+ android:minSdkVersion="21"
+ android:targetSdkVersion="21"/>
+
+ <uses-feature android:name="android.hardware.camera"/>
+ <uses-feature
+ android:name="android.hardware.camera.front"
+ android:required="false"/>
+
+ <uses-permission android:name="android.permission.CAMERA"/>
+ <uses-permission android:name="android.permission.RECORD_AUDIO"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+
+ <application
+ android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme">
+
+ <activity
+ android:name=".HdrViewfinderActivity"
+ android:label="@string/app_name"
+ android:screenOrientation="landscape">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ </application>
+
+
+</manifest>
diff --git a/samples/browseable/HdrViewfinder/_index.jd b/samples/browseable/HdrViewfinder/_index.jd
new file mode 100644
index 0000000..3348a3f
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/_index.jd
@@ -0,0 +1,11 @@
+page.tags="HdrViewfinder"
+sample.group=Media
+@jd:body
+
+<p>
+
+ This demo implements a real-time high-dynamic-range camera viewfinder, by alternating
+ the sensor\'s exposure time between two exposure values on even and odd frames, and then
+ compositing together the latest two frames whenever a new frame is captured.
+
+ </p>
diff --git a/samples/browseable/HdrViewfinder/res/drawable-hdpi/ic_action_info.png b/samples/browseable/HdrViewfinder/res/drawable-hdpi/ic_action_info.png
new file mode 100644
index 0000000..32bd1aa
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/res/drawable-hdpi/ic_action_info.png
Binary files differ
diff --git a/samples/browseable/HdrViewfinder/res/drawable-hdpi/ic_launcher.png b/samples/browseable/HdrViewfinder/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..18f79c1
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/HdrViewfinder/res/drawable-hdpi/tile.9.png b/samples/browseable/HdrViewfinder/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/HdrViewfinder/res/drawable-mdpi/ic_action_info.png b/samples/browseable/HdrViewfinder/res/drawable-mdpi/ic_action_info.png
new file mode 100644
index 0000000..8efbbf8
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/res/drawable-mdpi/ic_action_info.png
Binary files differ
diff --git a/samples/browseable/HdrViewfinder/res/drawable-mdpi/ic_launcher.png b/samples/browseable/HdrViewfinder/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..e70a7dc
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/HdrViewfinder/res/drawable-xhdpi/ic_action_info.png b/samples/browseable/HdrViewfinder/res/drawable-xhdpi/ic_action_info.png
new file mode 100644
index 0000000..ba143ea
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/res/drawable-xhdpi/ic_action_info.png
Binary files differ
diff --git a/samples/browseable/HdrViewfinder/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/HdrViewfinder/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..ed25c5a
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/HdrViewfinder/res/drawable-xxhdpi/ic_action_info.png b/samples/browseable/HdrViewfinder/res/drawable-xxhdpi/ic_action_info.png
new file mode 100644
index 0000000..394eb7e
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/res/drawable-xxhdpi/ic_action_info.png
Binary files differ
diff --git a/samples/browseable/HdrViewfinder/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/HdrViewfinder/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..90867ff
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/HdrViewfinder/res/layout/activity_main.xml b/samples/browseable/HdrViewfinder/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/horizontal_page_margin"
+ android:layout_marginRight="@dimen/horizontal_page_margin"
+ android:layout_marginTop="@dimen/vertical_page_margin"
+ android:layout_marginBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/HdrViewfinder/res/layout/main.xml b/samples/browseable/HdrViewfinder/res/layout/main.xml
new file mode 100644
index 0000000..7507709
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/res/layout/main.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 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
+ android:id="@+id/panels"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:custom="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+
+ <com.example.android.hdrviewfinder.FixedAspectSurfaceView
+ android:id="@+id/preview"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="4"
+ custom:aspectRatio="1.333"/>
+
+ <LinearLayout
+ android:id="@+id/control_bar_contents"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <Button
+ android:id="@+id/help_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/help_button"/>
+
+ <TextView
+ android:id="@+id/mode_label"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textSize="16sp"
+ tools:text="MODE: HDR"/>
+
+ <TextView
+ android:id="@+id/auto_exposure_label"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/auto_exposure_label"/>
+
+ <TextView
+ android:id="@+id/auto_exposure"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:textSize="20sp"
+ tools:text="33.33 ms"/>
+
+ <TextView
+ android:id="@+id/even_exposure_label"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/even_exposure_label"/>
+
+ <TextView
+ android:id="@+id/even_exposure"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:textSize="20sp"
+ tools:text="30.30 ms"/>
+
+ <TextView
+ android:id="@+id/odd_exposure_label"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/odd_exposure_label"/>
+
+ <TextView
+ android:id="@+id/odd_exposure"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:textSize="20sp"
+ tools:text="30.30 ms"/>
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/samples/browseable/HdrViewfinder/res/menu/main.xml b/samples/browseable/HdrViewfinder/res/menu/main.xml
new file mode 100644
index 0000000..14b2ffa
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/res/menu/main.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:id="@+id/info"
+ android:icon="@drawable/ic_action_info"
+ android:showAsAction="always"
+ android:title="@string/info"/>
+
+</menu>
\ No newline at end of file
diff --git a/samples/browseable/HdrViewfinder/res/values-sw600dp/template-dimens.xml b/samples/browseable/HdrViewfinder/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/HdrViewfinder/res/values-sw600dp/template-styles.xml b/samples/browseable/HdrViewfinder/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/HdrViewfinder/res/values-v11/template-styles.xml b/samples/browseable/HdrViewfinder/res/values-v11/template-styles.xml
new file mode 100644
index 0000000..8c1ea66
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/res/values-v11/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/samples/browseable/HdrViewfinder/res/values-v21/template-styles.xml b/samples/browseable/HdrViewfinder/res/values-v21/template-styles.xml
new file mode 100644
index 0000000..134fcd9
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/res/values-v21/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2014 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>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Material.Light" />
+
+</resources>
diff --git a/samples/browseable/HdrViewfinder/res/values/attrs.xml b/samples/browseable/HdrViewfinder/res/values/attrs.xml
new file mode 100644
index 0000000..ec8a564
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/res/values/attrs.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2014 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>
+ <declare-styleable name="FixedAspectSurfaceView">
+ <attr name="aspectRatio" format="float"/>
+ </declare-styleable>
+</resources>
diff --git a/samples/browseable/HdrViewfinder/res/values/base-strings.xml b/samples/browseable/HdrViewfinder/res/values/base-strings.xml
new file mode 100644
index 0000000..64c518c
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/res/values/base-strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">HdrViewfinder</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ This demo implements a real-time high-dynamic-range camera viewfinder, by alternating
+ the sensor\'s exposure time between two exposure values on even and odd frames, and then
+ compositing together the latest two frames whenever a new frame is captured.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/HdrViewfinder/res/values/strings.xml b/samples/browseable/HdrViewfinder/res/values/strings.xml
new file mode 100644
index 0000000..21838d5
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/res/values/strings.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+
+ <string name="help_button">Help</string>
+
+ <string-array name="mode_label_array">
+ <!-- must be in same order as ViewfinderProcessor.MODE_ ints -->
+ <item>Mode: Normal</item>
+ <item>Mode: Split</item>
+ <item>Mode: HDR</item>
+ </string-array>
+
+ <string name="auto_exposure_label">Auto exp. time:</string>
+ <string name="even_exposure_label">Even exp. time:</string>
+ <string name="odd_exposure_label">Odd exp. time:</string>
+
+ <string name="help_text">
+ <b>HDR Viewfinder Demo:</b>\n\n
+
+ Tap viewfinder to switch modes.\n\n
+
+ <b>Normal:</b> Standard camera preview\n
+ <b>Split:</b> Manual exposure control\n
+ <b>HDR:</b> Fused HDR viewfinder\n\n
+
+ Swipe up/down in Split/HDR modes to change manual exposure
+ values.\n\n
+
+ The left half of the viewfinder controls exposure time for
+ even-numbered frames, and the right half of the viewfinder
+ controls exposure time for odd-numbered frames
+ </string>
+
+ <string name="info">Info</string>
+
+ <string name="camera_no_good">No back-facing sufficiently capable camera available!</string>
+ <string name="camera_disabled">Camera is disabled by device policy</string>
+ <string name="camera_disconnected">Camera was disconnected before it was opened</string>
+ <string name="camera_error">Camera service reported an error</string>
+ <string name="camera_unknown">Unknown camera error: %s</string>
+
+</resources>
diff --git a/samples/browseable/HdrViewfinder/res/values/template-dimens.xml b/samples/browseable/HdrViewfinder/res/values/template-dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/HdrViewfinder/res/values/template-styles.xml b/samples/browseable/HdrViewfinder/res/values/template-styles.xml
new file mode 100644
index 0000000..6e7d593
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/HdrViewfinder/src/com.example.android.hdrviewfinder/CameraOps.java b/samples/browseable/HdrViewfinder/src/com.example.android.hdrviewfinder/CameraOps.java
new file mode 100644
index 0000000..5769760
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/src/com.example.android.hdrviewfinder/CameraOps.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2014 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.hdrviewfinder;
+
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CaptureRequest;
+import android.os.ConditionVariable;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.util.Log;
+import android.view.Surface;
+
+import java.util.List;
+
+/**
+ * Simple interface for operating the camera, with major camera operations
+ * all performed on a background handler thread.
+ */
+public class CameraOps {
+
+ private static final String TAG = "CameraOps";
+
+ public static final long CAMERA_CLOSE_TIMEOUT = 2000; // ms
+
+ private final CameraManager mCameraManager;
+ private CameraDevice mCameraDevice;
+ private CameraCaptureSession mCameraSession;
+ private List<Surface> mSurfaces;
+
+ private final ConditionVariable mCloseWaiter = new ConditionVariable();
+
+ private HandlerThread mCameraThread;
+ private Handler mCameraHandler;
+
+ private final ErrorDisplayer mErrorDisplayer;
+
+ private final CameraReadyListener mReadyListener;
+ private final Handler mReadyHandler;
+
+ /**
+ * Create a new camera ops thread.
+ *
+ * @param errorDisplayer listener for displaying error messages
+ * @param readyListener listener for notifying when camera is ready for requests
+ * @param readyHandler the handler for calling readyListener methods on
+ */
+ CameraOps(CameraManager manager, ErrorDisplayer errorDisplayer,
+ CameraReadyListener readyListener, Handler readyHandler) {
+ mCameraThread = new HandlerThread("CameraOpsThread");
+ mCameraThread.start();
+
+ if (manager == null || errorDisplayer == null ||
+ readyListener == null || readyHandler == null) {
+ throw new IllegalArgumentException("Need valid displayer, listener, handler");
+ }
+
+ mCameraManager = manager;
+ mErrorDisplayer = errorDisplayer;
+ mReadyListener = readyListener;
+ mReadyHandler = readyHandler;
+ }
+
+ /**
+ * Open the first backfacing camera listed by the camera manager.
+ * Displays a dialog if it cannot open a camera.
+ */
+ public void openCamera(final String cameraId) {
+ mCameraHandler = new Handler(mCameraThread.getLooper());
+
+ mCameraHandler.post(new Runnable() {
+ public void run() {
+ if (mCameraDevice != null) {
+ throw new IllegalStateException("Camera already open");
+ }
+ try {
+ mCameraManager.openCamera(cameraId, mCameraDeviceListener, mCameraHandler);
+ } catch (CameraAccessException e) {
+ String errorMessage = mErrorDisplayer.getErrorString(e);
+ mErrorDisplayer.showErrorDialog(errorMessage);
+ }
+ }
+ });
+ }
+
+ /**
+ * Close the camera and wait for the close callback to be called in the camera thread.
+ * Times out after @{value CAMERA_CLOSE_TIMEOUT} ms.
+ */
+ public void closeCameraAndWait() {
+ mCloseWaiter.close();
+ mCameraHandler.post(mCloseCameraRunnable);
+ boolean closed = mCloseWaiter.block(CAMERA_CLOSE_TIMEOUT);
+ if (!closed) {
+ Log.e(TAG, "Timeout closing camera");
+ }
+ }
+
+ private Runnable mCloseCameraRunnable = new Runnable() {
+ public void run() {
+ if (mCameraDevice != null) {
+ mCameraDevice.close();
+ }
+ mCameraDevice = null;
+ mCameraSession = null;
+ mSurfaces = null;
+ }
+ };
+
+ /**
+ * Set the output Surfaces, and finish configuration if otherwise ready.
+ */
+ public void setSurfaces(final List<Surface> surfaces) {
+ mCameraHandler.post(new Runnable() {
+ public void run() {
+ mSurfaces = surfaces;
+ startCameraSession();
+ }
+ });
+ }
+
+ /**
+ * Get a request builder for the current camera.
+ */
+ public CaptureRequest.Builder createCaptureRequest(int template) throws CameraAccessException {
+ CameraDevice device = mCameraDevice;
+ if (device == null) {
+ throw new IllegalStateException("Can't get requests when no camera is open");
+ }
+ return device.createCaptureRequest(template);
+ }
+
+ /**
+ * Set a repeating request.
+ */
+ public void setRepeatingRequest(final CaptureRequest request,
+ final CameraCaptureSession.CaptureCallback listener,
+ final Handler handler) {
+ mCameraHandler.post(new Runnable() {
+ public void run() {
+ try {
+ mCameraSession.setRepeatingRequest(request, listener, handler);
+ } catch (CameraAccessException e) {
+ String errorMessage = mErrorDisplayer.getErrorString(e);
+ mErrorDisplayer.showErrorDialog(errorMessage);
+ }
+ }
+ });
+ }
+
+ /**
+ * Set a repeating request.
+ */
+ public void setRepeatingBurst(final List<CaptureRequest> requests,
+ final CameraCaptureSession.CaptureCallback listener,
+ final Handler handler) {
+ mCameraHandler.post(new Runnable() {
+ public void run() {
+ try {
+ mCameraSession.setRepeatingBurst(requests, listener, handler);
+ } catch (CameraAccessException e) {
+ String errorMessage = mErrorDisplayer.getErrorString(e);
+ mErrorDisplayer.showErrorDialog(errorMessage);
+ }
+ }
+ });
+ }
+
+ /**
+ * Configure the camera session.
+ */
+ private void startCameraSession() {
+ // Wait until both the camera device is open and the SurfaceView is ready
+ if (mCameraDevice == null || mSurfaces == null) return;
+
+ try {
+ mCameraDevice.createCaptureSession(
+ mSurfaces, mCameraSessionListener, mCameraHandler);
+ } catch (CameraAccessException e) {
+ String errorMessage = mErrorDisplayer.getErrorString(e);
+ mErrorDisplayer.showErrorDialog(errorMessage);
+ mCameraDevice.close();
+ mCameraDevice = null;
+ }
+ }
+
+ /**
+ * Main listener for camera session events
+ * Invoked on mCameraThread
+ */
+ private CameraCaptureSession.StateCallback mCameraSessionListener =
+ new CameraCaptureSession.StateCallback() {
+
+ @Override
+ public void onConfigured(CameraCaptureSession session) {
+ mCameraSession = session;
+ mReadyHandler.post(new Runnable() {
+ public void run() {
+ // This can happen when the screen is turned off and turned back on.
+ if (null == mCameraDevice) {
+ return;
+ }
+
+ mReadyListener.onCameraReady();
+ }
+ });
+
+ }
+
+ @Override
+ public void onConfigureFailed(CameraCaptureSession session) {
+ mErrorDisplayer.showErrorDialog("Unable to configure the capture session");
+ mCameraDevice.close();
+ mCameraDevice = null;
+ }
+ };
+
+ /**
+ * Main listener for camera device events.
+ * Invoked on mCameraThread
+ */
+ private CameraDevice.StateCallback mCameraDeviceListener = new CameraDevice.StateCallback() {
+
+ @Override
+ public void onOpened(CameraDevice camera) {
+ mCameraDevice = camera;
+ startCameraSession();
+ }
+
+ @Override
+ public void onClosed(CameraDevice camera) {
+ mCloseWaiter.open();
+ }
+
+ @Override
+ public void onDisconnected(CameraDevice camera) {
+ mErrorDisplayer.showErrorDialog("The camera device has been disconnected.");
+ camera.close();
+ mCameraDevice = null;
+ }
+
+ @Override
+ public void onError(CameraDevice camera, int error) {
+ mErrorDisplayer.showErrorDialog("The camera encountered an error:" + error);
+ camera.close();
+ mCameraDevice = null;
+ }
+
+ };
+
+ /**
+ * Simple listener for main code to know the camera is ready for requests, or failed to
+ * start.
+ */
+ public interface CameraReadyListener {
+ public void onCameraReady();
+ }
+
+ /**
+ * Simple listener for displaying error messages
+ */
+ public interface ErrorDisplayer {
+ public void showErrorDialog(String errorMessage);
+
+ public String getErrorString(CameraAccessException e);
+ }
+
+}
diff --git a/samples/browseable/HdrViewfinder/src/com.example.android.hdrviewfinder/FixedAspectSurfaceView.java b/samples/browseable/HdrViewfinder/src/com.example.android.hdrviewfinder/FixedAspectSurfaceView.java
new file mode 100644
index 0000000..48d842b
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/src/com.example.android.hdrviewfinder/FixedAspectSurfaceView.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2014 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.hdrviewfinder;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+
+/**
+ * A SurfaceView that maintains its aspect ratio to be a desired target value.
+ *
+ * <p>Depending on the layout, the FixedAspectSurfaceView may not be able to maintain the
+ * requested aspect ratio. This can happen if both the width and the height are exactly
+ * determined by the layout. To avoid this, ensure that either the height or the width is
+ * adjustable by the view; for example, by setting the layout parameters to be WRAP_CONTENT for
+ * the dimension that is best adjusted to maintain the aspect ratio.</p>
+ */
+public class FixedAspectSurfaceView extends SurfaceView {
+
+ /**
+ * Desired width/height ratio
+ */
+ private float mAspectRatio;
+
+ private GestureDetector mGestureDetector;
+
+ public FixedAspectSurfaceView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ // Get initial aspect ratio from custom attributes
+ TypedArray a =
+ context.getTheme().obtainStyledAttributes(attrs,
+ R.styleable.FixedAspectSurfaceView, 0, 0);
+ setAspectRatio(a.getFloat(
+ R.styleable.FixedAspectSurfaceView_aspectRatio, 1.f));
+ a.recycle();
+ }
+
+ /**
+ * Set the desired aspect ratio for this view.
+ *
+ * @param aspect the desired width/height ratio in the current UI orientation. Must be a
+ * positive value.
+ */
+ public void setAspectRatio(float aspect) {
+ if (aspect <= 0) {
+ throw new IllegalArgumentException("Aspect ratio must be positive");
+ }
+ mAspectRatio = aspect;
+ requestLayout();
+ }
+
+ /**
+ * Set a gesture listener to listen for touch events
+ */
+ public void setGestureListener(Context context, GestureDetector.OnGestureListener listener) {
+ if (listener == null) {
+ mGestureDetector = null;
+ } else {
+ mGestureDetector = new GestureDetector(context, listener);
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+
+ int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+ int width = MeasureSpec.getSize(widthMeasureSpec);
+ int height = MeasureSpec.getSize(heightMeasureSpec);
+
+ // General goal: Adjust dimensions to maintain the requested aspect ratio as much
+ // as possible. Depending on the measure specs handed down, this may not be possible
+
+ // Only set one of these to true
+ boolean scaleWidth = false;
+ boolean scaleHeight = false;
+
+ // Sort out which dimension to scale, if either can be. There are 9 combinations of
+ // possible measure specs; a few cases below handle multiple combinations
+ if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY) {
+ // Can't adjust sizes at all, do nothing
+ } else if (widthMode == MeasureSpec.EXACTLY) {
+ // Width is fixed, heightMode either AT_MOST or UNSPECIFIED, so adjust height
+ scaleHeight = true;
+ } else if (heightMode == MeasureSpec.EXACTLY) {
+ // Height is fixed, widthMode either AT_MOST or UNSPECIFIED, so adjust width
+ scaleWidth = true;
+ } else if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {
+ // Need to fit into box <= [width, height] in size.
+ // Maximize the View's area while maintaining aspect ratio
+ // This means keeping one dimension as large as possible and shrinking the other
+ float boxAspectRatio = width / (float) height;
+ if (boxAspectRatio > mAspectRatio) {
+ // Box is wider than requested aspect; pillarbox
+ scaleWidth = true;
+ } else {
+ // Box is narrower than requested aspect; letterbox
+ scaleHeight = true;
+ }
+ } else if (widthMode == MeasureSpec.AT_MOST) {
+ // Maximize width, heightSpec is UNSPECIFIED
+ scaleHeight = true;
+ } else if (heightMode == MeasureSpec.AT_MOST) {
+ // Maximize height, widthSpec is UNSPECIFIED
+ scaleWidth = true;
+ } else {
+ // Both MeasureSpecs are UNSPECIFIED. This is probably a pathological layout,
+ // with width == height == 0
+ // but arbitrarily scale height anyway
+ scaleHeight = true;
+ }
+
+ // Do the scaling
+ if (scaleWidth) {
+ width = (int) (height * mAspectRatio);
+ } else if (scaleHeight) {
+ height = (int) (width / mAspectRatio);
+ }
+
+ // Override width/height if needed for EXACTLY and AT_MOST specs
+ width = View.resolveSizeAndState(width, widthMeasureSpec, 0);
+ height = View.resolveSizeAndState(height, heightMeasureSpec, 0);
+
+ // Finally set the calculated dimensions
+ setMeasuredDimension(width, height);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (mGestureDetector != null) {
+ return mGestureDetector.onTouchEvent(event);
+ }
+ return false;
+ }
+}
diff --git a/samples/browseable/HdrViewfinder/src/com.example.android.hdrviewfinder/HdrViewfinderActivity.java b/samples/browseable/HdrViewfinder/src/com.example.android.hdrviewfinder/HdrViewfinderActivity.java
new file mode 100644
index 0000000..79f1bb6
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/src/com.example.android.hdrviewfinder/HdrViewfinderActivity.java
@@ -0,0 +1,524 @@
+/*
+ * Copyright (C) 2014 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.hdrviewfinder;
+
+import android.app.Activity;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.renderscript.RenderScript;
+import android.util.Log;
+import android.util.Size;
+import android.view.GestureDetector;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A small demo of advanced camera functionality with the Android camera2 API.
+ *
+ * <p>This demo implements a real-time high-dynamic-range camera viewfinder,
+ * by alternating the sensor's exposure time between two exposure values on even and odd
+ * frames, and then compositing together the latest two frames whenever a new frame is
+ * captured.</p>
+ *
+ * <p>The demo has three modes: Regular auto-exposure viewfinder, split-screen manual exposure,
+ * and the fused HDR viewfinder. The latter two use manual exposure controlled by the user,
+ * by swiping up/down on the right and left halves of the viewfinder. The left half controls
+ * the exposure time of even frames, and the right half controls the exposure time of odd frames.
+ * </p>
+ *
+ * <p>In split-screen mode, the even frames are shown on the left and the odd frames on the right,
+ * so the user can see two different exposures of the scene simultaneously. In fused HDR mode,
+ * the even/odd frames are merged together into a single image. By selecting different exposure
+ * values for the even/odd frames, the fused image has a higher dynamic range than the regular
+ * viewfinder.</p>
+ *
+ * <p>The HDR fusion and the split-screen viewfinder processing is done with RenderScript; as is the
+ * necessary YUV->RGB conversion. The camera subsystem outputs YUV images naturally, while the GPU
+ * and display subsystems generally only accept RGB data. Therefore, after the images are
+ * fused/composited, a standard YUV->RGB color transform is applied before the the data is written
+ * to the output Allocation. The HDR fusion algorithm is very simple, and tends to result in
+ * lower-contrast scenes, but has very few artifacts and can run very fast.</p>
+ *
+ * <p>Data is passed between the subsystems (camera, RenderScript, and display) using the
+ * Android {@link android.view.Surface} class, which allows for zero-copy transport of large
+ * buffers between processes and subsystems.</p>
+ */
+public class HdrViewfinderActivity extends Activity implements
+ SurfaceHolder.Callback, CameraOps.ErrorDisplayer, CameraOps.CameraReadyListener {
+
+ private static final String TAG = "HdrViewfinderDemo";
+
+ private static final String FRAGMENT_DIALOG = "dialog";
+
+ /**
+ * View for the camera preview.
+ */
+ private FixedAspectSurfaceView mPreviewView;
+
+ /**
+ * This shows the current mode of the app.
+ */
+ private TextView mModeText;
+
+ // These show lengths of exposure for even frames, exposure for odd frames, and auto exposure.
+ private TextView mEvenExposureText, mOddExposureText, mAutoExposureText;
+
+ private Handler mUiHandler;
+
+ private CameraCharacteristics mCameraInfo;
+
+ private Surface mPreviewSurface;
+ private Surface mProcessingHdrSurface;
+ private Surface mProcessingNormalSurface;
+ CaptureRequest.Builder mHdrBuilder;
+ ArrayList<CaptureRequest> mHdrRequests = new ArrayList<CaptureRequest>(2);
+
+ CaptureRequest mPreviewRequest;
+
+ RenderScript mRS;
+ ViewfinderProcessor mProcessor;
+ CameraManager mCameraManager;
+ CameraOps mCameraOps;
+
+ private int mRenderMode = ViewfinderProcessor.MODE_NORMAL;
+
+ // Durations in nanoseconds
+ private static final long MICRO_SECOND = 1000;
+ private static final long MILLI_SECOND = MICRO_SECOND * 1000;
+ private static final long ONE_SECOND = MILLI_SECOND * 1000;
+
+ private long mOddExposure = ONE_SECOND / 33;
+ private long mEvenExposure = ONE_SECOND / 33;
+
+ private Object mOddExposureTag = new Object();
+ private Object mEvenExposureTag = new Object();
+ private Object mAutoExposureTag = new Object();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+
+ mPreviewView = (FixedAspectSurfaceView) findViewById(R.id.preview);
+ mPreviewView.getHolder().addCallback(this);
+ mPreviewView.setGestureListener(this, mViewListener);
+
+ Button helpButton = (Button) findViewById(R.id.help_button);
+ helpButton.setOnClickListener(mHelpButtonListener);
+
+ mModeText = (TextView) findViewById(R.id.mode_label);
+ mEvenExposureText = (TextView) findViewById(R.id.even_exposure);
+ mOddExposureText = (TextView) findViewById(R.id.odd_exposure);
+ mAutoExposureText = (TextView) findViewById(R.id.auto_exposure);
+
+ mUiHandler = new Handler(Looper.getMainLooper());
+
+ mCameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);
+ mCameraOps = new CameraOps(mCameraManager,
+ /*errorDisplayer*/ this,
+ /*readyListener*/ this,
+ /*readyHandler*/ mUiHandler);
+
+ mHdrRequests.add(null);
+ mHdrRequests.add(null);
+
+ mRS = RenderScript.create(this);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ findAndOpenCamera();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ // Wait until camera is closed to ensure the next application can open it
+ mCameraOps.closeCameraAndWait();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.main, menu);
+ return super.onCreateOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.info: {
+ MessageDialogFragment.newInstance(R.string.intro_message)
+ .show(getFragmentManager(), FRAGMENT_DIALOG);
+ break;
+ }
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private GestureDetector.OnGestureListener mViewListener
+ = new GestureDetector.SimpleOnGestureListener() {
+
+ @Override
+ public boolean onDown(MotionEvent e) {
+ return true;
+ }
+
+ @Override
+ public boolean onSingleTapUp(MotionEvent e) {
+ switchRenderMode(1);
+ return true;
+ }
+
+ @Override
+ public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+ if (mRenderMode == ViewfinderProcessor.MODE_NORMAL) return false;
+
+ float xPosition = e1.getAxisValue(MotionEvent.AXIS_X);
+ float width = mPreviewView.getWidth();
+ float height = mPreviewView.getHeight();
+
+ float xPosNorm = xPosition / width;
+ float yDistNorm = distanceY / height;
+
+ final float ACCELERATION_FACTOR = 8;
+ double scaleFactor = Math.pow(2.f, yDistNorm * ACCELERATION_FACTOR);
+
+ // Even on left, odd on right
+ if (xPosNorm > 0.5) {
+ mOddExposure *= scaleFactor;
+ } else {
+ mEvenExposure *= scaleFactor;
+ }
+
+ setHdrBurst();
+
+ return true;
+ }
+ };
+
+ // Show help dialog
+ private View.OnClickListener mHelpButtonListener = new View.OnClickListener() {
+ public void onClick(View v) {
+ MessageDialogFragment.newInstance(R.string.help_text)
+ .show(getFragmentManager(), FRAGMENT_DIALOG);
+ }
+ };
+
+ private void findAndOpenCamera() {
+
+ String errorMessage = "Unknown error";
+ boolean foundCamera = false;
+ try {
+ // Find first back-facing camera that has necessary capability
+ String[] cameraIds = mCameraManager.getCameraIdList();
+ for (String id : cameraIds) {
+ CameraCharacteristics info = mCameraManager.getCameraCharacteristics(id);
+ int facing = info.get(CameraCharacteristics.LENS_FACING);
+
+ int level = info.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
+ boolean hasFullLevel
+ = (level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL);
+
+ int[] capabilities = info.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
+ int syncLatency = info.get(CameraCharacteristics.SYNC_MAX_LATENCY);
+ boolean hasManualControl = hasCapability(capabilities,
+ CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR);
+ boolean hasEnoughCapability = hasManualControl &&
+ syncLatency == CameraCharacteristics.SYNC_MAX_LATENCY_PER_FRAME_CONTROL;
+
+ // All these are guaranteed by
+ // CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL, but checking for only
+ // the things we care about expands range of devices we can run on
+ // We want:
+ // - Back-facing camera
+ // - Manual sensor control
+ // - Per-frame synchronization (so that exposure can be changed every frame)
+ if (facing == CameraCharacteristics.LENS_FACING_BACK &&
+ (hasFullLevel || hasEnoughCapability)) {
+ // Found suitable camera - get info, open, and set up outputs
+ mCameraInfo = info;
+ mCameraOps.openCamera(id);
+ configureSurfaces();
+ foundCamera = true;
+ break;
+ }
+ }
+ if (!foundCamera) {
+ errorMessage = getString(R.string.camera_no_good);
+ }
+ } catch (CameraAccessException e) {
+ errorMessage = getErrorString(e);
+ }
+
+ if (!foundCamera) {
+ showErrorDialog(errorMessage);
+ }
+ }
+
+ private boolean hasCapability(int[] capabilities, int capability) {
+ for (int c : capabilities) {
+ if (c == capability) return true;
+ }
+ return false;
+ }
+
+ private void switchRenderMode(int direction) {
+ mRenderMode = (mRenderMode + direction) % 3;
+
+ mModeText.setText(getResources().getStringArray(R.array.mode_label_array)[mRenderMode]);
+
+ if (mProcessor != null) {
+ mProcessor.setRenderMode(mRenderMode);
+ }
+ if (mRenderMode == ViewfinderProcessor.MODE_NORMAL) {
+ mCameraOps.setRepeatingRequest(mPreviewRequest,
+ mCaptureCallback, mUiHandler);
+ } else {
+ setHdrBurst();
+ }
+ }
+
+ /**
+ * Configure the surfaceview and RS processing
+ */
+ private void configureSurfaces() {
+ // Find a good size for output - largest 16:9 aspect ratio that's less than 720p
+ final int MAX_WIDTH = 1280;
+ final float TARGET_ASPECT = 16.f / 9.f;
+ final float ASPECT_TOLERANCE = 0.1f;
+
+ StreamConfigurationMap configs =
+ mCameraInfo.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+
+ Size[] outputSizes = configs.getOutputSizes(SurfaceHolder.class);
+
+ Size outputSize = outputSizes[0];
+ float outputAspect = (float) outputSize.getWidth() / outputSize.getHeight();
+ for (Size candidateSize : outputSizes) {
+ if (candidateSize.getWidth() > MAX_WIDTH) continue;
+ float candidateAspect = (float) candidateSize.getWidth() / candidateSize.getHeight();
+ boolean goodCandidateAspect =
+ Math.abs(candidateAspect - TARGET_ASPECT) < ASPECT_TOLERANCE;
+ boolean goodOutputAspect =
+ Math.abs(outputAspect - TARGET_ASPECT) < ASPECT_TOLERANCE;
+ if ((goodCandidateAspect && !goodOutputAspect) ||
+ candidateSize.getWidth() > outputSize.getWidth()) {
+ outputSize = candidateSize;
+ outputAspect = candidateAspect;
+ }
+ }
+ Log.i(TAG, "Resolution chosen: " + outputSize);
+
+ // Configure processing
+ mProcessor = new ViewfinderProcessor(mRS, outputSize);
+ setupProcessor();
+
+ // Configure the output view - this will fire surfaceChanged
+ mPreviewView.setAspectRatio(outputAspect);
+ mPreviewView.getHolder().setFixedSize(outputSize.getWidth(), outputSize.getHeight());
+ }
+
+ /**
+ * Once camera is open and output surfaces are ready, configure the RS processing
+ * and the camera device inputs/outputs.
+ */
+ private void setupProcessor() {
+ if (mProcessor == null || mPreviewSurface == null) return;
+
+ mProcessor.setOutputSurface(mPreviewSurface);
+ mProcessingHdrSurface = mProcessor.getInputHdrSurface();
+ mProcessingNormalSurface = mProcessor.getInputNormalSurface();
+
+ List<Surface> cameraOutputSurfaces = new ArrayList<Surface>();
+ cameraOutputSurfaces.add(mProcessingHdrSurface);
+ cameraOutputSurfaces.add(mProcessingNormalSurface);
+
+ mCameraOps.setSurfaces(cameraOutputSurfaces);
+ }
+
+ /**
+ * Start running an HDR burst on a configured camera session
+ */
+ public void setHdrBurst() {
+
+ mHdrBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, 1600);
+ mHdrBuilder.set(CaptureRequest.SENSOR_FRAME_DURATION, ONE_SECOND / 30);
+
+ mHdrBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, mEvenExposure);
+ mHdrBuilder.setTag(mEvenExposureTag);
+ mHdrRequests.set(0, mHdrBuilder.build());
+
+ mHdrBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, mOddExposure);
+ mHdrBuilder.setTag(mOddExposureTag);
+ mHdrRequests.set(1, mHdrBuilder.build());
+
+ mCameraOps.setRepeatingBurst(mHdrRequests, mCaptureCallback, mUiHandler);
+ }
+
+ /**
+ * Listener for completed captures
+ * Invoked on UI thread
+ */
+ private CameraCaptureSession.CaptureCallback mCaptureCallback
+ = new CameraCaptureSession.CaptureCallback() {
+
+ public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
+ TotalCaptureResult result) {
+
+ // Only update UI every so many frames
+ // Use an odd number here to ensure both even and odd exposures get an occasional update
+ long frameNumber = result.getFrameNumber();
+ if (frameNumber % 3 != 0) return;
+
+ long exposureTime = result.get(CaptureResult.SENSOR_EXPOSURE_TIME);
+
+ // Format exposure time nicely
+ String exposureText;
+ if (exposureTime > ONE_SECOND) {
+ exposureText = String.format("%.2f s", exposureTime / 1e9);
+ } else if (exposureTime > MILLI_SECOND) {
+ exposureText = String.format("%.2f ms", exposureTime / 1e6);
+ } else if (exposureTime > MICRO_SECOND) {
+ exposureText = String.format("%.2f us", exposureTime / 1e3);
+ } else {
+ exposureText = String.format("%d ns", exposureTime);
+ }
+
+ Object tag = request.getTag();
+ Log.i(TAG, "Exposure: " + exposureText);
+
+ if (tag == mEvenExposureTag) {
+ mEvenExposureText.setText(exposureText);
+
+ mEvenExposureText.setEnabled(true);
+ mOddExposureText.setEnabled(true);
+ mAutoExposureText.setEnabled(false);
+ } else if (tag == mOddExposureTag) {
+ mOddExposureText.setText(exposureText);
+
+ mEvenExposureText.setEnabled(true);
+ mOddExposureText.setEnabled(true);
+ mAutoExposureText.setEnabled(false);
+ } else {
+ mAutoExposureText.setText(exposureText);
+
+ mEvenExposureText.setEnabled(false);
+ mOddExposureText.setEnabled(false);
+ mAutoExposureText.setEnabled(true);
+ }
+ }
+ };
+
+ /**
+ * Callbacks for the FixedAspectSurfaceView
+ */
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ mPreviewSurface = holder.getSurface();
+
+ setupProcessor();
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ // ignored
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ mPreviewSurface = null;
+ }
+
+ /**
+ * Callbacks for CameraOps
+ */
+ @Override
+ public void onCameraReady() {
+ // Ready to send requests in, so set them up
+ try {
+ CaptureRequest.Builder previewBuilder =
+ mCameraOps.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+ previewBuilder.addTarget(mProcessingNormalSurface);
+ previewBuilder.setTag(mAutoExposureTag);
+ mPreviewRequest = previewBuilder.build();
+
+ mHdrBuilder =
+ mCameraOps.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+ mHdrBuilder.set(CaptureRequest.CONTROL_AE_MODE,
+ CaptureRequest.CONTROL_AE_MODE_OFF);
+ mHdrBuilder.addTarget(mProcessingHdrSurface);
+
+ switchRenderMode(0);
+
+ } catch (CameraAccessException e) {
+ String errorMessage = getErrorString(e);
+ showErrorDialog(errorMessage);
+ }
+ }
+
+ /**
+ * Utility methods
+ */
+ @Override
+ public void showErrorDialog(String errorMessage) {
+ MessageDialogFragment.newInstance(errorMessage).show(getFragmentManager(), FRAGMENT_DIALOG);
+ }
+
+ @Override
+ public String getErrorString(CameraAccessException e) {
+ String errorMessage;
+ switch (e.getReason()) {
+ case CameraAccessException.CAMERA_DISABLED:
+ errorMessage = getString(R.string.camera_disabled);
+ break;
+ case CameraAccessException.CAMERA_DISCONNECTED:
+ errorMessage = getString(R.string.camera_disconnected);
+ break;
+ case CameraAccessException.CAMERA_ERROR:
+ errorMessage = getString(R.string.camera_error);
+ break;
+ default:
+ errorMessage = getString(R.string.camera_unknown, e.getReason());
+ break;
+ }
+ return errorMessage;
+ }
+
+}
diff --git a/samples/browseable/HdrViewfinder/src/com.example.android.hdrviewfinder/MessageDialogFragment.java b/samples/browseable/HdrViewfinder/src/com.example.android.hdrviewfinder/MessageDialogFragment.java
new file mode 100644
index 0000000..b1bdf9e
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/src/com.example.android.hdrviewfinder/MessageDialogFragment.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2014 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.hdrviewfinder;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.os.Bundle;
+
+public class MessageDialogFragment extends DialogFragment {
+
+ private static final String ARG_MESSAGE_INT = "message_int";
+ private static final String ARG_MESSAGE_STRING = "message_string";
+
+ public static MessageDialogFragment newInstance(int message) {
+ MessageDialogFragment fragment = new MessageDialogFragment();
+ Bundle args = new Bundle();
+ args.putInt(ARG_MESSAGE_INT, message);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ public static MessageDialogFragment newInstance(String message) {
+ MessageDialogFragment fragment = new MessageDialogFragment();
+ Bundle args = new Bundle();
+ args.putString(ARG_MESSAGE_STRING, message);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setPositiveButton(android.R.string.ok, null);
+ Bundle args = getArguments();
+ if (args.containsKey(ARG_MESSAGE_INT)) {
+ builder.setMessage(args.getInt(ARG_MESSAGE_INT));
+ } else if (args.containsKey(ARG_MESSAGE_STRING)) {
+ builder.setMessage(args.getString(ARG_MESSAGE_STRING));
+ }
+ return builder.create();
+ }
+
+}
diff --git a/samples/browseable/HdrViewfinder/src/com.example.android.hdrviewfinder/ViewfinderProcessor.java b/samples/browseable/HdrViewfinder/src/com.example.android.hdrviewfinder/ViewfinderProcessor.java
new file mode 100644
index 0000000..f51dfaa
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/src/com.example.android.hdrviewfinder/ViewfinderProcessor.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2014 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.hdrviewfinder;
+
+import android.graphics.ImageFormat;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.RenderScript;
+import android.renderscript.Type;
+import android.util.Size;
+import android.view.Surface;
+
+/**
+ * Renderscript-based merger for an HDR viewfinder
+ */
+public class ViewfinderProcessor {
+
+ private Allocation mInputHdrAllocation;
+ private Allocation mInputNormalAllocation;
+ private Allocation mPrevAllocation;
+ private Allocation mOutputAllocation;
+
+ private Surface mOutputSurface;
+ private HandlerThread mProcessingThread;
+ private Handler mProcessingHandler;
+ private ScriptC_hdr_merge mHdrMergeScript;
+
+ public ProcessingTask mHdrTask;
+ public ProcessingTask mNormalTask;
+
+ private Size mSize;
+
+ private int mMode;
+
+ public final static int MODE_NORMAL = 0;
+ public final static int MODE_SIDE_BY_SIDE = 1;
+ public final static int MODE_HDR = 2;
+
+ public ViewfinderProcessor(RenderScript rs, Size dimensions) {
+ mSize = dimensions;
+
+ Type.Builder yuvTypeBuilder = new Type.Builder(rs, Element.YUV(rs));
+ yuvTypeBuilder.setX(dimensions.getWidth());
+ yuvTypeBuilder.setY(dimensions.getHeight());
+ yuvTypeBuilder.setYuvFormat(ImageFormat.YUV_420_888);
+ mInputHdrAllocation = Allocation.createTyped(rs, yuvTypeBuilder.create(),
+ Allocation.USAGE_IO_INPUT | Allocation.USAGE_SCRIPT);
+ mInputNormalAllocation = Allocation.createTyped(rs, yuvTypeBuilder.create(),
+ Allocation.USAGE_IO_INPUT | Allocation.USAGE_SCRIPT);
+
+ Type.Builder rgbTypeBuilder = new Type.Builder(rs, Element.RGBA_8888(rs));
+ rgbTypeBuilder.setX(dimensions.getWidth());
+ rgbTypeBuilder.setY(dimensions.getHeight());
+ mPrevAllocation = Allocation.createTyped(rs, rgbTypeBuilder.create(),
+ Allocation.USAGE_SCRIPT);
+ mOutputAllocation = Allocation.createTyped(rs, rgbTypeBuilder.create(),
+ Allocation.USAGE_IO_OUTPUT | Allocation.USAGE_SCRIPT);
+
+ mProcessingThread = new HandlerThread("ViewfinderProcessor");
+ mProcessingThread.start();
+ mProcessingHandler = new Handler(mProcessingThread.getLooper());
+
+ mHdrMergeScript = new ScriptC_hdr_merge(rs);
+
+ mHdrMergeScript.set_gPrevFrame(mPrevAllocation);
+
+ mHdrTask = new ProcessingTask(mInputHdrAllocation, dimensions.getWidth()/2, true);
+ mNormalTask = new ProcessingTask(mInputNormalAllocation, 0, false);
+
+ setRenderMode(MODE_NORMAL);
+ }
+
+ public Surface getInputHdrSurface() {
+ return mInputHdrAllocation.getSurface();
+ }
+
+ public Surface getInputNormalSurface() {
+ return mInputNormalAllocation.getSurface();
+ }
+
+ public void setOutputSurface(Surface output) {
+ mOutputAllocation.setSurface(output);
+ }
+
+ public void setRenderMode(int mode) {
+ mMode = mode;
+ }
+
+ /**
+ * Simple class to keep track of incoming frame count,
+ * and to process the newest one in the processing thread
+ */
+ class ProcessingTask implements Runnable, Allocation.OnBufferAvailableListener {
+ private int mPendingFrames = 0;
+ private int mFrameCounter = 0;
+ private int mCutPointX;
+ private boolean mCheckMerge;
+
+ private Allocation mInputAllocation;
+
+ public ProcessingTask(Allocation input, int cutPointX, boolean checkMerge) {
+ mInputAllocation = input;
+ mInputAllocation.setOnBufferAvailableListener(this);
+ mCutPointX = cutPointX;
+ mCheckMerge = checkMerge;
+ }
+
+ @Override
+ public void onBufferAvailable(Allocation a) {
+ synchronized(this) {
+ mPendingFrames++;
+ mProcessingHandler.post(this);
+ }
+ }
+
+ @Override
+ public void run() {
+
+ // Find out how many frames have arrived
+ int pendingFrames;
+ synchronized(this) {
+ pendingFrames = mPendingFrames;
+ mPendingFrames = 0;
+
+ // Discard extra messages in case processing is slower than frame rate
+ mProcessingHandler.removeCallbacks(this);
+ }
+
+ // Get to newest input
+ for (int i = 0; i < pendingFrames; i++) {
+ mInputAllocation.ioReceive();
+ }
+
+ mHdrMergeScript.set_gFrameCounter(mFrameCounter++);
+ mHdrMergeScript.set_gCurrentFrame(mInputAllocation);
+ mHdrMergeScript.set_gCutPointX(mCutPointX);
+ if (mCheckMerge && mMode == MODE_HDR) {
+ mHdrMergeScript.set_gDoMerge(1);
+ } else {
+ mHdrMergeScript.set_gDoMerge(0);
+ }
+
+ // Run processing pass
+ mHdrMergeScript.forEach_mergeHdrFrames(mPrevAllocation, mOutputAllocation);
+ mOutputAllocation.ioSend();
+ }
+ }
+
+}
diff --git a/samples/browseable/HdrViewfinder/src/rs/hdr_merge.rs b/samples/browseable/HdrViewfinder/src/rs/hdr_merge.rs
new file mode 100644
index 0000000..f176fd7
--- /dev/null
+++ b/samples/browseable/HdrViewfinder/src/rs/hdr_merge.rs
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+#pragma version(1)
+#pragma rs java_package_name(com.example.android.hdrviewfinder)
+#pragma rs_fp_relaxed
+
+rs_allocation gCurrentFrame;
+rs_allocation gPrevFrame;
+
+int gCutPointX = 0;
+int gDoMerge = 0;
+int gFrameCounter = 0;
+
+uchar4 __attribute__((kernel)) mergeHdrFrames(uchar4 prevPixel, uint32_t x, uint32_t y) {
+
+ // Read in pixel values from latest frame - YUV color space
+
+ uchar4 curPixel;
+ curPixel.r = rsGetElementAtYuv_uchar_Y(gCurrentFrame, x, y);
+ curPixel.g = rsGetElementAtYuv_uchar_U(gCurrentFrame, x, y);
+ curPixel.b = rsGetElementAtYuv_uchar_V(gCurrentFrame, x, y);
+ curPixel.a = 255;
+
+ uchar4 mergedPixel;
+ if (gDoMerge == 1) {
+ // Complex HDR fusion technique
+ mergedPixel = curPixel / 2 + prevPixel / 2;
+
+ /* Experimental color saturation boosting merge
+ mergedPixel.r = curPixel.r / 2 + prevPixel.r / 2;
+
+ uchar saturationCurrent = abs(curPixel.g - 128) + abs(curPixel.b - 128);
+ uchar saturationPrev = abs(prevPixel.g - 128) + abs(prevPixel.b - 128);
+ mergedPixel.g = saturationCurrent > saturationPrev ? curPixel.g : prevPixel.g;
+ mergedPixel.b = saturationCurrent > saturationPrev ? curPixel.b : prevPixel.b;
+ */
+ } else if (gCutPointX > 0) {
+ // Composite side by side
+ mergedPixel = ((x < gCutPointX) ^ (gFrameCounter & 0x1)) ?
+ curPixel : prevPixel;
+ } else {
+ // Straight passthrough
+ mergedPixel = curPixel;
+ }
+
+ // Convert YUV to RGB, JFIF transform with fixed-point math
+ // R = Y + 1.402 * (V - 128)
+ // G = Y - 0.34414 * (U - 128) - 0.71414 * (V - 128)
+ // B = Y + 1.772 * (U - 128)
+
+ int4 rgb;
+ rgb.r = mergedPixel.r +
+ mergedPixel.b * 1436 / 1024 - 179;
+ rgb.g = mergedPixel.r -
+ mergedPixel.g * 46549 / 131072 + 44 -
+ mergedPixel.b * 93604 / 131072 + 91;
+ rgb.b = mergedPixel.r +
+ mergedPixel.g * 1814 / 1024 - 227;
+ rgb.a = 255;
+
+ // Store current pixel for next frame
+ rsSetElementAt_uchar4(gPrevFrame, curPixel, x, y);
+
+ // Write out merged HDR result
+ uchar4 out = convert_uchar4(clamp(rgb, 0, 255));
+
+ return out;
+}
diff --git a/samples/browseable/Interpolator/AndroidManifest.xml b/samples/browseable/Interpolator/AndroidManifest.xml
new file mode 100644
index 0000000..85f50b2
--- /dev/null
+++ b/samples/browseable/Interpolator/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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.interpolator"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
+ <application android:allowBackup="true"
+ android:label="@string/app_name"
+ android:icon="@drawable/ic_launcher"
+ android:theme="@style/AppTheme">
+
+ <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>
+ </application>
+
+
+</manifest>
diff --git a/samples/browseable/Interpolator/_index.jd b/samples/browseable/Interpolator/_index.jd
new file mode 100644
index 0000000..30aa7a8
--- /dev/null
+++ b/samples/browseable/Interpolator/_index.jd
@@ -0,0 +1,11 @@
+page.tags="Interpolator"
+sample.group=UI
+@jd:body
+
+<p>
+
+ This sample demonstrates the use of animation interpolators and path animations for
+ Material Design. It shows how an ObjectAnimator is used to animate two properties of a
+ view (scale X and Y) along a path.
+
+ </p>
diff --git a/samples/browseable/Interpolator/res/drawable-hdpi/ic_launcher.png b/samples/browseable/Interpolator/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..14a1e3a
--- /dev/null
+++ b/samples/browseable/Interpolator/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Interpolator/res/drawable-hdpi/tile.9.png b/samples/browseable/Interpolator/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/Interpolator/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/Interpolator/res/drawable-mdpi/ic_launcher.png b/samples/browseable/Interpolator/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..e328c42
--- /dev/null
+++ b/samples/browseable/Interpolator/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Interpolator/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/Interpolator/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..c78e0c4
--- /dev/null
+++ b/samples/browseable/Interpolator/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Interpolator/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/Interpolator/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..0be3d8b
--- /dev/null
+++ b/samples/browseable/Interpolator/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Interpolator/res/layout-w720dp/activity_main.xml b/samples/browseable/Interpolator/res/layout-w720dp/activity_main.xml
new file mode 100755
index 0000000..c9a52f6
--- /dev/null
+++ b/samples/browseable/Interpolator/res/layout-w720dp/activity_main.xml
@@ -0,0 +1,73 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<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/sample_main_layout">
+
+ <LinearLayout
+ android:id="@+id/sample_output"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <FrameLayout
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/margin_medium"
+ android:paddingRight="@dimen/margin_medium"
+ android:paddingTop="@dimen/margin_large"
+ android:paddingBottom="@dimen/margin_large"
+ android:text="@string/intro_message" />
+ </FrameLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1" />
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="0px"
+ android:layout_height="match_parent" />
+
+</LinearLayout>
+
+
diff --git a/samples/browseable/Interpolator/res/layout/activity_main.xml b/samples/browseable/Interpolator/res/layout/activity_main.xml
new file mode 100755
index 0000000..1ae4f98
--- /dev/null
+++ b/samples/browseable/Interpolator/res/layout/activity_main.xml
@@ -0,0 +1,65 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<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/sample_main_layout">
+
+ <ViewAnimator
+ android:id="@+id/sample_output"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1">
+
+ <ScrollView
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/horizontal_page_margin"
+ android:paddingRight="@dimen/horizontal_page_margin"
+ android:paddingTop="@dimen/vertical_page_margin"
+ android:paddingBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </ScrollView>
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ </ViewAnimator>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="match_parent"
+ android:layout_height="0px" />
+
+</LinearLayout>
+
diff --git a/samples/browseable/Interpolator/res/layout/interpolator_fragment.xml b/samples/browseable/Interpolator/res/layout/interpolator_fragment.xml
new file mode 100644
index 0000000..6e1cb04
--- /dev/null
+++ b/samples/browseable/Interpolator/res/layout/interpolator_fragment.xml
@@ -0,0 +1,86 @@
+<!--
+Copyright 2014 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.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingBottom="@dimen/vertical_page_margin"
+ android:paddingLeft="@dimen/horizontal_page_margin"
+ android:paddingRight="@dimen/horizontal_page_margin"
+ android:paddingTop="@dimen/vertical_page_margin">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:id="@+id/interpolatorLabel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignBottom="@+id/interpolatorSpinner"
+ android:layout_alignParentStart="true"
+ android:layout_alignParentTop="true"
+ android:gravity="center_vertical"
+ android:text="@string/interpolator" />
+
+ <Spinner
+ android:id="@+id/interpolatorSpinner"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_toEndOf="@+id/interpolatorLabel" />
+
+
+ <SeekBar
+ android:id="@+id/durationSeek"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentEnd="true"
+ android:layout_below="@+id/durationLabel"
+ android:max="5000" />
+
+ <TextView
+ android:id="@+id/durationLabel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentStart="true"
+ android:layout_below="@+id/interpolatorSpinner"
+ android:gravity="center_vertical" />
+
+ <Button
+ android:id="@+id/animateButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/durationSeek"
+ android:layout_centerHorizontal="true"
+ android:text="@string/animate" />
+
+ <View
+ android:id="@+id/square"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentBottom="true"
+ android:layout_below="@+id/animateButton"
+ android:layout_centerHorizontal="true"
+ android:layout_margin="10dp"
+ android:background="@color/purple"
+ android:minHeight="100dp"
+ android:minWidth="100dp" />
+
+ </RelativeLayout>
+
+</ScrollView>
\ No newline at end of file
diff --git a/samples/browseable/Interpolator/res/menu/main.xml b/samples/browseable/Interpolator/res/menu/main.xml
new file mode 100644
index 0000000..b49c2c5
--- /dev/null
+++ b/samples/browseable/Interpolator/res/menu/main.xml
@@ -0,0 +1,21 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/menu_toggle_log"
+ android:showAsAction="always"
+ android:title="@string/sample_show_log" />
+</menu>
diff --git a/samples/browseable/Interpolator/res/values-sw600dp/template-dimens.xml b/samples/browseable/Interpolator/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/Interpolator/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/Interpolator/res/values-sw600dp/template-styles.xml b/samples/browseable/Interpolator/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/Interpolator/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/Interpolator/res/values-v11/template-styles.xml b/samples/browseable/Interpolator/res/values-v11/template-styles.xml
new file mode 100644
index 0000000..8c1ea66
--- /dev/null
+++ b/samples/browseable/Interpolator/res/values-v11/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/samples/browseable/Interpolator/res/values-v21/template-styles.xml b/samples/browseable/Interpolator/res/values-v21/template-styles.xml
new file mode 100644
index 0000000..134fcd9
--- /dev/null
+++ b/samples/browseable/Interpolator/res/values-v21/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2014 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>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Material.Light" />
+
+</resources>
diff --git a/samples/browseable/Interpolator/res/values/base-strings.xml b/samples/browseable/Interpolator/res/values/base-strings.xml
new file mode 100644
index 0000000..4997667
--- /dev/null
+++ b/samples/browseable/Interpolator/res/values/base-strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">Interpolator</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ This sample demonstrates the use of animation interpolators and path animations for
+ Material Design. It shows how an ObjectAnimator is used to animate two properties of a
+ view (scale X and Y) along a path.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/Interpolator/res/values/color.xml b/samples/browseable/Interpolator/res/values/color.xml
new file mode 100644
index 0000000..aa18437
--- /dev/null
+++ b/samples/browseable/Interpolator/res/values/color.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2014 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>
+ <color name="purple">#9c27b0</color>
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/Interpolator/res/values/fragmentview_strings.xml b/samples/browseable/Interpolator/res/values/fragmentview_strings.xml
new file mode 100755
index 0000000..7b9d9ec
--- /dev/null
+++ b/samples/browseable/Interpolator/res/values/fragmentview_strings.xml
@@ -0,0 +1,19 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="sample_show_log">Show Log</string>
+ <string name="sample_hide_log">Hide Log</string>
+</resources>
diff --git a/samples/browseable/Interpolator/res/values/strings.xml b/samples/browseable/Interpolator/res/values/strings.xml
new file mode 100644
index 0000000..e2cfb2a
--- /dev/null
+++ b/samples/browseable/Interpolator/res/values/strings.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2014 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="animation_duration">Duration: %1$d ms</string>
+ <string name="interpolator">Interpolator:</string>
+ <string name="animate">Animate!</string>
+ <string-array name="interpolator_names">
+ <item>Linear</item>
+ <item>Fast Out Linear In</item>
+ <item>Fast Out Slow In</item>
+ <item>Linear Out Slow In</item>
+ </string-array>
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/Interpolator/res/values/template-dimens.xml b/samples/browseable/Interpolator/res/values/template-dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/Interpolator/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/Interpolator/res/values/template-styles.xml b/samples/browseable/Interpolator/res/values/template-styles.xml
new file mode 100644
index 0000000..6e7d593
--- /dev/null
+++ b/samples/browseable/Interpolator/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/Interpolator/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/Interpolator/src/com.example.android.common/activities/SampleActivityBase.java
new file mode 100644
index 0000000..3228927
--- /dev/null
+++ b/samples/browseable/Interpolator/src/com.example.android.common/activities/SampleActivityBase.java
@@ -0,0 +1,52 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.common.activities;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogWrapper;
+
+/**
+ * Base launcher activity, to handle most of the common plumbing for samples.
+ */
+public class SampleActivityBase extends FragmentActivity {
+
+ public static final String TAG = "SampleActivityBase";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ initializeLogging();
+ }
+
+ /** Set up targets to receive log data */
+ public void initializeLogging() {
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ // Wraps Android's native log framework
+ LogWrapper logWrapper = new LogWrapper();
+ Log.setLogNode(logWrapper);
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/Interpolator/src/com.example.android.common/logger/Log.java b/samples/browseable/Interpolator/src/com.example.android.common/logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/Interpolator/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+ // Grabbing the native values from Android's native logging facilities,
+ // to make for easy migration and interop.
+ public static final int NONE = -1;
+ public static final int VERBOSE = android.util.Log.VERBOSE;
+ public static final int DEBUG = android.util.Log.DEBUG;
+ public static final int INFO = android.util.Log.INFO;
+ public static final int WARN = android.util.Log.WARN;
+ public static final int ERROR = android.util.Log.ERROR;
+ public static final int ASSERT = android.util.Log.ASSERT;
+
+ // Stores the beginning of the LogNode topology.
+ private static LogNode mLogNode;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public static LogNode getLogNode() {
+ return mLogNode;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to.
+ */
+ public static void setLogNode(LogNode node) {
+ mLogNode = node;
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void println(int priority, String tag, String msg, Throwable tr) {
+ if (mLogNode != null) {
+ mLogNode.println(priority, tag, msg, tr);
+ }
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ */
+ public static void println(int priority, String tag, String msg) {
+ println(priority, tag, msg, null);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void v(String tag, String msg, Throwable tr) {
+ println(VERBOSE, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void v(String tag, String msg) {
+ v(tag, msg, null);
+ }
+
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void d(String tag, String msg, Throwable tr) {
+ println(DEBUG, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void d(String tag, String msg) {
+ d(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void i(String tag, String msg, Throwable tr) {
+ println(INFO, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void i(String tag, String msg) {
+ i(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, String msg, Throwable tr) {
+ println(WARN, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void w(String tag, String msg) {
+ w(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, Throwable tr) {
+ w(tag, null, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void e(String tag, String msg, Throwable tr) {
+ println(ERROR, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void e(String tag, String msg) {
+ e(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, String msg, Throwable tr) {
+ println(ASSERT, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void wtf(String tag, String msg) {
+ wtf(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, Throwable tr) {
+ wtf(tag, null, tr);
+ }
+}
diff --git a/samples/browseable/Interpolator/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/Interpolator/src/com.example.android.common/logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/Interpolator/src/com.example.android.common/logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+ private LogView mLogView;
+ private ScrollView mScrollView;
+
+ public LogFragment() {}
+
+ public View inflateViews() {
+ mScrollView = new ScrollView(getActivity());
+ ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ mScrollView.setLayoutParams(scrollParams);
+
+ mLogView = new LogView(getActivity());
+ ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+ logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ mLogView.setLayoutParams(logParams);
+ mLogView.setClickable(true);
+ mLogView.setFocusable(true);
+ mLogView.setTypeface(Typeface.MONOSPACE);
+
+ // Want to set padding as 16 dips, setPadding takes pixels. Hooray math!
+ int paddingDips = 16;
+ double scale = getResources().getDisplayMetrics().density;
+ int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+ mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+ mLogView.setCompoundDrawablePadding(paddingPixels);
+
+ mLogView.setGravity(Gravity.BOTTOM);
+ mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+ mScrollView.addView(mLogView);
+ return mScrollView;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ View result = inflateViews();
+
+ mLogView.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+ }
+ });
+ return result;
+ }
+
+ public LogView getLogView() {
+ return mLogView;
+ }
+}
\ No newline at end of file
diff --git a/samples/browseable/Interpolator/src/com.example.android.common/logger/LogNode.java b/samples/browseable/Interpolator/src/com.example.android.common/logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/Interpolator/src/com.example.android.common/logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 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.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+ /**
+ * Instructs first LogNode in the list to print the log data provided.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/Interpolator/src/com.example.android.common/logger/LogView.java b/samples/browseable/Interpolator/src/com.example.android.common/logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/Interpolator/src/com.example.android.common/logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+ public LogView(Context context) {
+ super(context);
+ }
+
+ public LogView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public LogView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * Formats the log data and prints it out to the LogView.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+
+
+ String priorityStr = null;
+
+ // For the purposes of this View, we want to print the priority as readable text.
+ switch(priority) {
+ case android.util.Log.VERBOSE:
+ priorityStr = "VERBOSE";
+ break;
+ case android.util.Log.DEBUG:
+ priorityStr = "DEBUG";
+ break;
+ case android.util.Log.INFO:
+ priorityStr = "INFO";
+ break;
+ case android.util.Log.WARN:
+ priorityStr = "WARN";
+ break;
+ case android.util.Log.ERROR:
+ priorityStr = "ERROR";
+ break;
+ case android.util.Log.ASSERT:
+ priorityStr = "ASSERT";
+ break;
+ default:
+ break;
+ }
+
+ // Handily, the Log class has a facility for converting a stack trace into a usable string.
+ String exceptionStr = null;
+ if (tr != null) {
+ exceptionStr = android.util.Log.getStackTraceString(tr);
+ }
+
+ // Take the priority, tag, message, and exception, and concatenate as necessary
+ // into one usable line of text.
+ final StringBuilder outputBuilder = new StringBuilder();
+
+ String delimiter = "\t";
+ appendIfNotNull(outputBuilder, priorityStr, delimiter);
+ appendIfNotNull(outputBuilder, tag, delimiter);
+ appendIfNotNull(outputBuilder, msg, delimiter);
+ appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+ // In case this was originally called from an AsyncTask or some other off-UI thread,
+ // make sure the update occurs within the UI thread.
+ ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+ @Override
+ public void run() {
+ // Display the text we just generated within the LogView.
+ appendToLog(outputBuilder.toString());
+ }
+ })));
+
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+ * the logger takes so many arguments that might be null, this method helps cut out some of the
+ * agonizing tedium of writing the same 3 lines over and over.
+ * @param source StringBuilder containing the text to append to.
+ * @param addStr The String to append
+ * @param delimiter The String to separate the source and appended strings. A tab or comma,
+ * for instance.
+ * @return The fully concatenated String as a StringBuilder
+ */
+ private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+ if (addStr != null) {
+ if (addStr.length() == 0) {
+ delimiter = "";
+ }
+
+ return source.append(addStr).append(delimiter);
+ }
+ return source;
+ }
+
+ // The next LogNode in the chain.
+ LogNode mNext;
+
+ /** Outputs the string as a new line of log data in the LogView. */
+ public void appendToLog(String s) {
+ append("\n" + s);
+ }
+
+
+}
diff --git a/samples/browseable/Interpolator/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/Interpolator/src/com.example.android.common/logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/Interpolator/src/com.example.android.common/logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 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.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface. This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+ // For piping: The next node to receive Log data after this one has done its work.
+ private LogNode mNext;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /**
+ * Prints data out to the console using Android's native log mechanism.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ // There actually are log methods that don't take a msg parameter. For now,
+ // if that's the case, just convert null to the empty string and move on.
+ String useMsg = msg;
+ if (useMsg == null) {
+ useMsg = "";
+ }
+
+ // If an exeption was provided, convert that exception to a usable string and attach
+ // it to the end of the msg method.
+ if (tr != null) {
+ msg += "\n" + Log.getStackTraceString(tr);
+ }
+
+ // This is functionally identical to Log.x(tag, useMsg);
+ // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+ Log.println(priority, tag, useMsg);
+
+ // If this isn't the last node in the chain, move things along.
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+}
diff --git a/samples/browseable/Interpolator/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/Interpolator/src/com.example.android.common/logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/Interpolator/src/com.example.android.common/logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+ LogNode mNext;
+
+ /**
+ * Takes the "next" LogNode as a parameter, to simplify chaining.
+ *
+ * @param next The next LogNode in the pipeline.
+ */
+ public MessageOnlyLogFilter(LogNode next) {
+ mNext = next;
+ }
+
+ public MessageOnlyLogFilter() {
+ }
+
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ if (mNext != null) {
+ getNext().println(Log.NONE, null, msg, null);
+ }
+ }
+
+ /**
+ * Returns the next LogNode in the chain.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+}
diff --git a/samples/browseable/Interpolator/src/com.example.android.interpolator/InterpolatorFragment.java b/samples/browseable/Interpolator/src/com.example.android.interpolator/InterpolatorFragment.java
new file mode 100644
index 0000000..07ecc95
--- /dev/null
+++ b/samples/browseable/Interpolator/src/com.example.android.interpolator/InterpolatorFragment.java
@@ -0,0 +1,244 @@
+/*
+* Copyright 2014 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.interpolator;
+
+import android.animation.ObjectAnimator;
+import android.graphics.Path;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.SeekBar;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import com.example.android.common.logger.Log;
+
+/**
+ * This sample demonstrates the use of animation interpolators and path animations for
+ * Material Design.
+ * It shows how an {@link android.animation.ObjectAnimator} is used to animate two properties of a
+ * view (scale X and Y) along a path.
+ */
+public class InterpolatorFragment extends Fragment {
+
+ /**
+ * View that is animated.
+ */
+ private View mView;
+ /**
+ * Spinner for selection of interpolator.
+ */
+ private Spinner mInterpolatorSpinner;
+ /**
+ * SeekBar for selection of duration of animation.
+ */
+ private SeekBar mDurationSeekbar;
+ /**
+ * TextView that shows animation selected in SeekBar.
+ */
+ private TextView mDurationLabel;
+
+ /**
+ * Interpolators used for animation.
+ */
+ private Interpolator mInterpolators[];
+ /**
+ * Path for in (shrinking) animation, from 100% scale to 20%.
+ */
+ private Path mPathIn;
+ /**
+ * Path for out (growing) animation, from 20% to 100%.
+ */
+ private Path mPathOut;
+
+ /**
+ * Set to true if View is animated out (is shrunk).
+ */
+ private boolean mIsOut = false;
+
+ /**
+ * Default duration of animation in ms.
+ */
+ private static final int INITIAL_DURATION_MS = 750;
+
+ /**
+ * String used for logging.
+ */
+ public static final String TAG = "InterpolatorplaygroundFragment";
+
+ public InterpolatorFragment() {
+ // Required empty public constructor
+ }
+
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ // Inflate the fragment_animation layout
+ View v = inflater.inflate(R.layout.interpolator_fragment, container, false);
+
+ // Set up the 'animate' button, when it is clicked the view is animated with the options
+ // selected: the Interpolator, duration and animation path
+ Button button = (Button) v.findViewById(R.id.animateButton);
+ button.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ // Interpolator selected in the spinner
+ Interpolator interpolator = mInterpolators[mInterpolatorSpinner.getSelectedItemPosition()];
+ // Duration selected in SeekBar
+ long duration = mDurationSeekbar.getProgress();
+ // Animation path is based on whether animating in or out
+ Path path = mIsOut ? mPathIn : mPathOut;
+
+ // Log animation details
+ Log.i(TAG, String.format("Starting animation: [%d ms, %s, %s]",
+ duration, (String) mInterpolatorSpinner.getSelectedItem(),
+ ((mIsOut) ? "Out (growing)" : "In (shrinking)")));
+
+ // Start the animation with the selected options
+ startAnimation(interpolator, duration, path);
+
+ // Toggle direction of animation (path)
+ mIsOut = !mIsOut;
+ }
+ });
+
+ // Get the label to display the selected duration
+ mDurationLabel = (TextView) v.findViewById(R.id.durationLabel);
+
+ // Initialize Interpolators programmatically by loading them from their XML definitions
+ // provided by the framework.
+ mInterpolators = new Interpolator[]{
+ new AnimationUtils().loadInterpolator(getActivity(),
+ android.R.interpolator.linear),
+ new AnimationUtils().loadInterpolator(getActivity(),
+ android.R.interpolator.fast_out_linear_in),
+ new AnimationUtils().loadInterpolator(getActivity(),
+ android.R.interpolator.fast_out_slow_in),
+ new AnimationUtils().loadInterpolator(getActivity(),
+ android.R.interpolator.linear_out_slow_in)
+ };
+
+ // Load names of interpolators from a resource
+ String[] interpolatorNames = getResources().getStringArray(R.array.interpolator_names);
+
+ // Set up the Spinner with the names of interpolators
+ mInterpolatorSpinner = (Spinner) v.findViewById(R.id.interpolatorSpinner);
+ ArrayAdapter<String> spinnerAdapter =
+ new ArrayAdapter<String>(getActivity(),
+ android.R.layout.simple_spinner_dropdown_item, interpolatorNames);
+ mInterpolatorSpinner.setAdapter(spinnerAdapter);
+
+ // Set up SeekBar that defines the duration of the animation
+ mDurationSeekbar = (SeekBar) v.findViewById(R.id.durationSeek);
+
+ // Register listener to update the text label when the SeekBar value is updated
+ mDurationSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
+ mDurationLabel.setText(getResources().getString(R.string.animation_duration, i));
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+ });
+
+ // Set initial progress to trigger SeekBarChangeListener and update UI
+ mDurationSeekbar.setProgress(INITIAL_DURATION_MS);
+
+ // Get the view that will be animated
+ mView = v.findViewById(R.id.square);
+
+ // The following Path definitions are used by the ObjectAnimator to scale the view.
+
+ // Path for 'in' animation: growing from 20% to 100%
+ mPathIn = new Path();
+ mPathIn.moveTo(0.2f, 0.2f);
+ mPathIn.lineTo(1f, 1f);
+
+ // Path for 'out' animation: shrinking from 100% to 20%
+ mPathOut = new Path();
+ mPathOut.moveTo(1f, 1f);
+ mPathOut.lineTo(0.2f, 0.2f);
+ return v;
+ }
+
+ /**
+ * Start an animation on the sample view.
+ * The view is animated using an {@link android.animation.ObjectAnimator} on the
+ * {@link View#SCALE_X} and {@link View#SCALE_Y} properties, with its animation based on a path.
+ * The only two paths defined here ({@link #mPathIn} and {@link #mPathOut}) scale the view
+ * uniformly.
+ *
+ * @param interpolator The interpolator to use for the animation.
+ * @param duration Duration of the animation in ms.
+ * @param path Path of the animation
+ * @return The ObjectAnimator used for this animation
+ * @see android.animation.ObjectAnimator#ofFloat(Object, String, String, android.graphics.Path)
+ */
+ public ObjectAnimator startAnimation(Interpolator interpolator, long duration, Path path) {
+ // This ObjectAnimator uses the path to change the x and y scale of the mView object.
+ ObjectAnimator animator = ObjectAnimator.ofFloat(mView, View.SCALE_X, View.SCALE_Y, path);
+
+ // Set the duration and interpolator for this animation
+ animator.setDuration(duration);
+ animator.setInterpolator(interpolator);
+
+ animator.start();
+
+ return animator;
+ }
+
+ /**
+ * Return the array of loaded Interpolators available in this Fragment.
+ *
+ * @return Interpolators
+ */
+ public Interpolator[] getInterpolators() {
+ return mInterpolators;
+ }
+
+ /**
+ * Return the animation path for the 'in' (shrinking) animation.
+ *
+ * @return
+ */
+ public Path getPathIn() {
+ return mPathIn;
+ }
+
+ /**
+ * Return the animation path for the 'out' (growing) animation.
+ *
+ * @return
+ */
+ public Path getPathOut() {
+ return mPathOut;
+ }
+}
\ No newline at end of file
diff --git a/samples/browseable/Interpolator/src/com.example.android.interpolator/MainActivity.java b/samples/browseable/Interpolator/src/com.example.android.interpolator/MainActivity.java
new file mode 100644
index 0000000..f71fd05
--- /dev/null
+++ b/samples/browseable/Interpolator/src/com.example.android.interpolator/MainActivity.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.interpolator;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ViewAnimator;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description, sample log and a custom
+ * {@link android.support.v4.app.Fragment} which can display a view.
+ * <p>
+ * For devices with displays with a width of 720dp or greater, the sample log is always visible,
+ * on other devices it's visibility is controlled by an item on the Action Bar.
+ */
+public class MainActivity extends SampleActivityBase {
+
+ public static final String TAG = "MainActivity";
+
+ // Whether the Log Fragment is currently shown
+ private boolean mLogShown;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ if (savedInstanceState == null) {
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ InterpolatorFragment fragment = new InterpolatorFragment();
+ transaction.replace(R.id.sample_content_fragment, fragment);
+ transaction.commit();
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
+ logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
+ logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);
+
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch(item.getItemId()) {
+ case R.id.menu_toggle_log:
+ mLogShown = !mLogShown;
+ ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);
+ if (mLogShown) {
+ output.setDisplayedChild(1);
+ } else {
+ output.setDisplayedChild(0);
+ }
+ supportInvalidateOptionsMenu();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ /** Create a chain of targets that will receive log data */
+ @Override
+ public void initializeLogging() {
+ // Wraps Android's native log framework.
+ LogWrapper logWrapper = new LogWrapper();
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ Log.setLogNode(logWrapper);
+
+ // Filter strips out everything except the message text.
+ MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+ logWrapper.setNext(msgFilter);
+
+ // On screen logging via a fragment with a TextView.
+ LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+ .findFragmentById(R.id.log_fragment);
+ msgFilter.setNext(logFragment.getLogView());
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/JobScheduler/AndroidManifest.xml b/samples/browseable/JobScheduler/AndroidManifest.xml
new file mode 100644
index 0000000..06a927b
--- /dev/null
+++ b/samples/browseable/JobScheduler/AndroidManifest.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.jobscheduler" >
+
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+
+ <application
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme" >
+ <activity
+ android:name=".MainActivity"
+ android:label="@string/app_name"
+ android:windowSoftInputMode="stateHidden" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <service
+ android:name=".service.TestJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE"
+ android:exported="true"/>
+ </application>
+
+</manifest>
diff --git a/samples/browseable/JobScheduler/_index.jd b/samples/browseable/JobScheduler/_index.jd
new file mode 100644
index 0000000..7f438ea
--- /dev/null
+++ b/samples/browseable/JobScheduler/_index.jd
@@ -0,0 +1,10 @@
+page.tags="JobScheduler"
+sample.group=Background
+@jd:body
+
+<p>
+
+ Demonstration of the JobScheduler API, which provides an interface for scheduling
+ background tasks when certain tasks apply.
+
+ </p>
diff --git a/samples/browseable/JobScheduler/res/drawable-hdpi/ic_launcher.png b/samples/browseable/JobScheduler/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..9cb5f74
--- /dev/null
+++ b/samples/browseable/JobScheduler/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/JobScheduler/res/drawable-hdpi/tile.9.png b/samples/browseable/JobScheduler/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/JobScheduler/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/JobScheduler/res/drawable-mdpi/ic_launcher.png b/samples/browseable/JobScheduler/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..869355b
--- /dev/null
+++ b/samples/browseable/JobScheduler/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/JobScheduler/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/JobScheduler/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..679fc16
--- /dev/null
+++ b/samples/browseable/JobScheduler/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/JobScheduler/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/JobScheduler/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..1734fd3
--- /dev/null
+++ b/samples/browseable/JobScheduler/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/JobScheduler/res/layout/activity_main.xml b/samples/browseable/JobScheduler/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/JobScheduler/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/horizontal_page_margin"
+ android:layout_marginRight="@dimen/horizontal_page_margin"
+ android:layout_marginTop="@dimen/vertical_page_margin"
+ android:layout_marginBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/JobScheduler/res/layout/sample_main.xml b/samples/browseable/JobScheduler/res/layout/sample_main.xml
new file mode 100644
index 0000000..94b1624
--- /dev/null
+++ b/samples/browseable/JobScheduler/res/layout/sample_main.xml
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2014 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.
+-->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="100dp">
+ <TextView
+ android:id="@+id/onstart_textview"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@color/none_received"
+ android:gravity="center"
+ android:text="@string/onstarttask"/>
+ <TextView
+ android:id="@+id/onstop_textview"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:background="@color/none_received"
+ android:gravity="center"
+ android:text="@string/onstoptask"/>
+ </LinearLayout>
+ <Button
+ android:id="@+id/finished_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="20dp"
+ android:layout_marginBottom="5dp"
+ android:onClick="finishJob"
+ android:text="@string/finish_job_button_text"/>
+
+ <TextView
+ android:id="@+id/task_params"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/defaultparamtext"
+ android:gravity="center"
+ android:textSize="20dp"
+
+ android:padding="15dp"
+ android:layout_marginBottom="10dp" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/constraints"
+ android:layout_margin="15dp"
+ android:textSize="18dp"/>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_marginLeft="10dp">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/connectivity"
+ android:layout_marginRight="10dp"/>
+ <RadioGroup
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <RadioButton android:id="@+id/checkbox_any"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/any"/>
+ <RadioButton android:id="@+id/checkbox_unmetered"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/unmetered"/>
+ </RadioGroup>
+
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/timing"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="15dp"
+ android:textSize="17dp"
+ android:text="@string/delay"/>
+ <EditText
+ android:id="@+id/delay_time"
+ android:layout_width="60dp"
+ android:layout_height="wrap_content"
+ android:inputType="number"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/deadline"
+ android:textSize="17dp"/>
+ <EditText
+ android:id="@+id/deadline_time"
+ android:layout_width="60dp"
+ android:layout_height="wrap_content"
+ android:inputType="number"/>
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/charging_caption"
+ android:layout_marginRight="15dp"/>
+ <CheckBox
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/checkbox_charging"
+ android:text="@string/charging_text"/>
+ </LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/idle_caption"
+ android:layout_marginRight="15dp"/>
+ <CheckBox
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/checkbox_idle"
+ android:text="@string/idle_mode_text"/>
+ </LinearLayout>
+
+ </LinearLayout>
+ <Button
+ android:id="@+id/schedule_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="20dp"
+ android:layout_marginLeft="40dp"
+ android:layout_marginRight="40dp"
+ android:onClick="scheduleJob"
+ android:text="@string/schedule_job_button_text"/>
+ <Button
+ android:id="@+id/cancel_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="40dp"
+ android:layout_marginRight="40dp"
+ android:onClick="cancelAllJobs"
+ android:text="@string/cancel_all_jobs_button_text"/>
+ </LinearLayout>
+</ScrollView>
diff --git a/samples/browseable/JobScheduler/res/values-sw600dp/template-dimens.xml b/samples/browseable/JobScheduler/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/JobScheduler/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/JobScheduler/res/values-sw600dp/template-styles.xml b/samples/browseable/JobScheduler/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/JobScheduler/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/JobScheduler/res/values-v11/styles.xml b/samples/browseable/JobScheduler/res/values-v11/styles.xml
new file mode 100644
index 0000000..a181ed0
--- /dev/null
+++ b/samples/browseable/JobScheduler/res/values-v11/styles.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<resources>
+
+ <!--
+ Base application theme for API 11+. This theme completely replaces
+ AppBaseTheme from res/values/sample-styles.xml on API 11+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
+ <!-- API 11 theme customizations can go here. -->
+ </style>
+
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/JobScheduler/res/values-v11/template-styles.xml b/samples/browseable/JobScheduler/res/values-v11/template-styles.xml
new file mode 100644
index 0000000..8c1ea66
--- /dev/null
+++ b/samples/browseable/JobScheduler/res/values-v11/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/samples/browseable/JobScheduler/res/values-v14/styles.xml b/samples/browseable/JobScheduler/res/values-v14/styles.xml
new file mode 100644
index 0000000..53cc49d
--- /dev/null
+++ b/samples/browseable/JobScheduler/res/values-v14/styles.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<resources>
+
+ <!--
+ Base application theme for API 14+. This theme completely replaces
+ AppBaseTheme from BOTH res/values/sample-styles.xml and
+ res/values-v11/sample-styles.xml on API 14+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+ <!-- API 14 theme customizations can go here. -->
+ </style>
+
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/JobScheduler/res/values-v21/template-styles.xml b/samples/browseable/JobScheduler/res/values-v21/template-styles.xml
new file mode 100644
index 0000000..134fcd9
--- /dev/null
+++ b/samples/browseable/JobScheduler/res/values-v21/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2014 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>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Material.Light" />
+
+</resources>
diff --git a/samples/browseable/JobScheduler/res/values/base-strings.xml b/samples/browseable/JobScheduler/res/values/base-strings.xml
new file mode 100644
index 0000000..90ee18a
--- /dev/null
+++ b/samples/browseable/JobScheduler/res/values/base-strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">JobScheduler</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ Demonstration of the JobScheduler API, which provides an interface for scheduling
+ background tasks when certain tasks apply.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/JobScheduler/res/values/color.xml b/samples/browseable/JobScheduler/res/values/color.xml
new file mode 100644
index 0000000..b1e5338
--- /dev/null
+++ b/samples/browseable/JobScheduler/res/values/color.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2014 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>
+ <color name="none_received">#999999</color>
+ <color name="start_received">#00FF00</color>
+ <color name="stop_received">#FF0000</color>
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/JobScheduler/res/values/strings.xml b/samples/browseable/JobScheduler/res/values/strings.xml
new file mode 100644
index 0000000..89524b2
--- /dev/null
+++ b/samples/browseable/JobScheduler/res/values/strings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2014 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="onstoptask">onStopTask</string>
+ <string name="onstarttask">onStartTask</string>
+ <string name="defaultparamtext">task params will show up here.</string>
+ <string name="schedule_job_button_text">Schedule Job</string>
+ <string name="cancel_all_jobs_button_text">Cancel all</string>
+ <string name="finish_job_button_text">taskFinished</string>
+ <string name="idle_mode_text">Requires device in idle mode.</string>
+ <string name="charging_caption">Charging:</string>
+ <string name="charging_text">Requires device plugged in.</string>
+ <string name="idle_caption">Idle:</string>
+ <string name="constraints">Constraints</string>
+ <string name="connectivity">Connectivity:</string>
+ <string name="any">Any</string>
+ <string name="unmetered">WiFi</string>
+ <string name="timing">Timing:</string>
+ <string name="delay">Delay:</string>
+ <string name="deadline">Deadline:</string>
+</resources>
diff --git a/samples/browseable/JobScheduler/res/values/styles.xml b/samples/browseable/JobScheduler/res/values/styles.xml
new file mode 100644
index 0000000..b767e51
--- /dev/null
+++ b/samples/browseable/JobScheduler/res/values/styles.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2014 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>
+
+ <!--
+ Base application theme, dependent on API level. This theme is replaced
+ by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Light">
+ <!--
+ Theme customizations available in newer API levels can go in
+ res/values-vXX/styles.xml, while customizations related to
+ backward-compatibility can go here.
+ -->
+ </style>
+
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/JobScheduler/res/values/template-dimens.xml b/samples/browseable/JobScheduler/res/values/template-dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/JobScheduler/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/JobScheduler/res/values/template-styles.xml b/samples/browseable/JobScheduler/res/values/template-styles.xml
new file mode 100644
index 0000000..6e7d593
--- /dev/null
+++ b/samples/browseable/JobScheduler/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/JobScheduler/src/com.example.android.common.logger/Log.java b/samples/browseable/JobScheduler/src/com.example.android.common.logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/JobScheduler/src/com.example.android.common.logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+ // Grabbing the native values from Android's native logging facilities,
+ // to make for easy migration and interop.
+ public static final int NONE = -1;
+ public static final int VERBOSE = android.util.Log.VERBOSE;
+ public static final int DEBUG = android.util.Log.DEBUG;
+ public static final int INFO = android.util.Log.INFO;
+ public static final int WARN = android.util.Log.WARN;
+ public static final int ERROR = android.util.Log.ERROR;
+ public static final int ASSERT = android.util.Log.ASSERT;
+
+ // Stores the beginning of the LogNode topology.
+ private static LogNode mLogNode;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public static LogNode getLogNode() {
+ return mLogNode;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to.
+ */
+ public static void setLogNode(LogNode node) {
+ mLogNode = node;
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void println(int priority, String tag, String msg, Throwable tr) {
+ if (mLogNode != null) {
+ mLogNode.println(priority, tag, msg, tr);
+ }
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ */
+ public static void println(int priority, String tag, String msg) {
+ println(priority, tag, msg, null);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void v(String tag, String msg, Throwable tr) {
+ println(VERBOSE, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void v(String tag, String msg) {
+ v(tag, msg, null);
+ }
+
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void d(String tag, String msg, Throwable tr) {
+ println(DEBUG, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void d(String tag, String msg) {
+ d(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void i(String tag, String msg, Throwable tr) {
+ println(INFO, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void i(String tag, String msg) {
+ i(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, String msg, Throwable tr) {
+ println(WARN, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void w(String tag, String msg) {
+ w(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, Throwable tr) {
+ w(tag, null, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void e(String tag, String msg, Throwable tr) {
+ println(ERROR, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void e(String tag, String msg) {
+ e(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, String msg, Throwable tr) {
+ println(ASSERT, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void wtf(String tag, String msg) {
+ wtf(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, Throwable tr) {
+ wtf(tag, null, tr);
+ }
+}
diff --git a/samples/browseable/JobScheduler/src/com.example.android.common.logger/LogFragment.java b/samples/browseable/JobScheduler/src/com.example.android.common.logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/JobScheduler/src/com.example.android.common.logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+ private LogView mLogView;
+ private ScrollView mScrollView;
+
+ public LogFragment() {}
+
+ public View inflateViews() {
+ mScrollView = new ScrollView(getActivity());
+ ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ mScrollView.setLayoutParams(scrollParams);
+
+ mLogView = new LogView(getActivity());
+ ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+ logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ mLogView.setLayoutParams(logParams);
+ mLogView.setClickable(true);
+ mLogView.setFocusable(true);
+ mLogView.setTypeface(Typeface.MONOSPACE);
+
+ // Want to set padding as 16 dips, setPadding takes pixels. Hooray math!
+ int paddingDips = 16;
+ double scale = getResources().getDisplayMetrics().density;
+ int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+ mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+ mLogView.setCompoundDrawablePadding(paddingPixels);
+
+ mLogView.setGravity(Gravity.BOTTOM);
+ mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+ mScrollView.addView(mLogView);
+ return mScrollView;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ View result = inflateViews();
+
+ mLogView.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+ }
+ });
+ return result;
+ }
+
+ public LogView getLogView() {
+ return mLogView;
+ }
+}
\ No newline at end of file
diff --git a/samples/browseable/JobScheduler/src/com.example.android.common.logger/LogNode.java b/samples/browseable/JobScheduler/src/com.example.android.common.logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/JobScheduler/src/com.example.android.common.logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 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.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+ /**
+ * Instructs first LogNode in the list to print the log data provided.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/JobScheduler/src/com.example.android.common.logger/LogView.java b/samples/browseable/JobScheduler/src/com.example.android.common.logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/JobScheduler/src/com.example.android.common.logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+ public LogView(Context context) {
+ super(context);
+ }
+
+ public LogView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public LogView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * Formats the log data and prints it out to the LogView.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+
+
+ String priorityStr = null;
+
+ // For the purposes of this View, we want to print the priority as readable text.
+ switch(priority) {
+ case android.util.Log.VERBOSE:
+ priorityStr = "VERBOSE";
+ break;
+ case android.util.Log.DEBUG:
+ priorityStr = "DEBUG";
+ break;
+ case android.util.Log.INFO:
+ priorityStr = "INFO";
+ break;
+ case android.util.Log.WARN:
+ priorityStr = "WARN";
+ break;
+ case android.util.Log.ERROR:
+ priorityStr = "ERROR";
+ break;
+ case android.util.Log.ASSERT:
+ priorityStr = "ASSERT";
+ break;
+ default:
+ break;
+ }
+
+ // Handily, the Log class has a facility for converting a stack trace into a usable string.
+ String exceptionStr = null;
+ if (tr != null) {
+ exceptionStr = android.util.Log.getStackTraceString(tr);
+ }
+
+ // Take the priority, tag, message, and exception, and concatenate as necessary
+ // into one usable line of text.
+ final StringBuilder outputBuilder = new StringBuilder();
+
+ String delimiter = "\t";
+ appendIfNotNull(outputBuilder, priorityStr, delimiter);
+ appendIfNotNull(outputBuilder, tag, delimiter);
+ appendIfNotNull(outputBuilder, msg, delimiter);
+ appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+ // In case this was originally called from an AsyncTask or some other off-UI thread,
+ // make sure the update occurs within the UI thread.
+ ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+ @Override
+ public void run() {
+ // Display the text we just generated within the LogView.
+ appendToLog(outputBuilder.toString());
+ }
+ })));
+
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+ * the logger takes so many arguments that might be null, this method helps cut out some of the
+ * agonizing tedium of writing the same 3 lines over and over.
+ * @param source StringBuilder containing the text to append to.
+ * @param addStr The String to append
+ * @param delimiter The String to separate the source and appended strings. A tab or comma,
+ * for instance.
+ * @return The fully concatenated String as a StringBuilder
+ */
+ private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+ if (addStr != null) {
+ if (addStr.length() == 0) {
+ delimiter = "";
+ }
+
+ return source.append(addStr).append(delimiter);
+ }
+ return source;
+ }
+
+ // The next LogNode in the chain.
+ LogNode mNext;
+
+ /** Outputs the string as a new line of log data in the LogView. */
+ public void appendToLog(String s) {
+ append("\n" + s);
+ }
+
+
+}
diff --git a/samples/browseable/JobScheduler/src/com.example.android.common.logger/LogWrapper.java b/samples/browseable/JobScheduler/src/com.example.android.common.logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/JobScheduler/src/com.example.android.common.logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 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.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface. This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+ // For piping: The next node to receive Log data after this one has done its work.
+ private LogNode mNext;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /**
+ * Prints data out to the console using Android's native log mechanism.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ // There actually are log methods that don't take a msg parameter. For now,
+ // if that's the case, just convert null to the empty string and move on.
+ String useMsg = msg;
+ if (useMsg == null) {
+ useMsg = "";
+ }
+
+ // If an exeption was provided, convert that exception to a usable string and attach
+ // it to the end of the msg method.
+ if (tr != null) {
+ msg += "\n" + Log.getStackTraceString(tr);
+ }
+
+ // This is functionally identical to Log.x(tag, useMsg);
+ // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+ Log.println(priority, tag, useMsg);
+
+ // If this isn't the last node in the chain, move things along.
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+}
diff --git a/samples/browseable/JobScheduler/src/com.example.android.common.logger/MessageOnlyLogFilter.java b/samples/browseable/JobScheduler/src/com.example.android.common.logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/JobScheduler/src/com.example.android.common.logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+ LogNode mNext;
+
+ /**
+ * Takes the "next" LogNode as a parameter, to simplify chaining.
+ *
+ * @param next The next LogNode in the pipeline.
+ */
+ public MessageOnlyLogFilter(LogNode next) {
+ mNext = next;
+ }
+
+ public MessageOnlyLogFilter() {
+ }
+
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ if (mNext != null) {
+ getNext().println(Log.NONE, null, msg, null);
+ }
+ }
+
+ /**
+ * Returns the next LogNode in the chain.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+}
diff --git a/samples/browseable/JobScheduler/src/com.example.android.jobscheduler/MainActivity.java b/samples/browseable/JobScheduler/src/com.example.android.jobscheduler/MainActivity.java
new file mode 100644
index 0000000..f495bf1
--- /dev/null
+++ b/samples/browseable/JobScheduler/src/com.example.android.jobscheduler/MainActivity.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.jobscheduler;
+
+import android.app.Activity;
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.RadioButton;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.example.android.jobscheduler.service.TestJobService;
+
+public class MainActivity extends Activity {
+
+ private static final String TAG = "MainActivity";
+
+ public static final int MSG_UNCOLOUR_START = 0;
+ public static final int MSG_UNCOLOUR_STOP = 1;
+ public static final int MSG_SERVICE_OBJ = 2;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.sample_main);
+ Resources res = getResources();
+ defaultColor = res.getColor(R.color.none_received);
+ startJobColor = res.getColor(R.color.start_received);
+ stopJobColor = res.getColor(R.color.stop_received);
+
+ // Set up UI.
+ mShowStartView = (TextView) findViewById(R.id.onstart_textview);
+ mShowStopView = (TextView) findViewById(R.id.onstop_textview);
+ mParamsTextView = (TextView) findViewById(R.id.task_params);
+ mDelayEditText = (EditText) findViewById(R.id.delay_time);
+ mDeadlineEditText = (EditText) findViewById(R.id.deadline_time);
+ mWiFiConnectivityRadioButton = (RadioButton) findViewById(R.id.checkbox_unmetered);
+ mAnyConnectivityRadioButton = (RadioButton) findViewById(R.id.checkbox_any);
+ mRequiresChargingCheckBox = (CheckBox) findViewById(R.id.checkbox_charging);
+ mRequiresIdleCheckbox = (CheckBox) findViewById(R.id.checkbox_idle);
+ mServiceComponent = new ComponentName(this, TestJobService.class);
+ // Start service and provide it a way to communicate with us.
+ Intent startServiceIntent = new Intent(this, TestJobService.class);
+ startServiceIntent.putExtra("messenger", new Messenger(mHandler));
+ startService(startServiceIntent);
+ }
+ // UI fields.
+ int defaultColor;
+ int startJobColor;
+ int stopJobColor;
+
+ private TextView mShowStartView;
+ private TextView mShowStopView;
+ private TextView mParamsTextView;
+ private EditText mDelayEditText;
+ private EditText mDeadlineEditText;
+ private RadioButton mWiFiConnectivityRadioButton;
+ private RadioButton mAnyConnectivityRadioButton;
+ private CheckBox mRequiresChargingCheckBox;
+ private CheckBox mRequiresIdleCheckbox;
+
+ ComponentName mServiceComponent;
+ /** Service object to interact scheduled jobs. */
+ TestJobService mTestService;
+
+ private static int kJobId = 0;
+
+ Handler mHandler = new Handler(/* default looper */) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_UNCOLOUR_START:
+ mShowStartView.setBackgroundColor(defaultColor);
+ break;
+ case MSG_UNCOLOUR_STOP:
+ mShowStopView.setBackgroundColor(defaultColor);
+ break;
+ case MSG_SERVICE_OBJ:
+ mTestService = (TestJobService) msg.obj;
+ mTestService.setUiCallback(MainActivity.this);
+ }
+ }
+ };
+
+ private boolean ensureTestService() {
+ if (mTestService == null) {
+ Toast.makeText(MainActivity.this, "Service null, never got callback?",
+ Toast.LENGTH_SHORT).show();
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * UI onclick listener to schedule a job. What this job is is defined in
+ * TestJobService#scheduleJob().
+ */
+ public void scheduleJob(View v) {
+ if (!ensureTestService()) {
+ return;
+ }
+
+ JobInfo.Builder builder = new JobInfo.Builder(kJobId++, mServiceComponent);
+
+ String delay = mDelayEditText.getText().toString();
+ if (delay != null && !TextUtils.isEmpty(delay)) {
+ builder.setMinimumLatency(Long.valueOf(delay) * 1000);
+ }
+ String deadline = mDeadlineEditText.getText().toString();
+ if (deadline != null && !TextUtils.isEmpty(deadline)) {
+ builder.setOverrideDeadline(Long.valueOf(deadline) * 1000);
+ }
+ boolean requiresUnmetered = mWiFiConnectivityRadioButton.isChecked();
+ boolean requiresAnyConnectivity = mAnyConnectivityRadioButton.isChecked();
+ if (requiresUnmetered) {
+ builder.setRequiredNetworkCapabilities(JobInfo.NetworkType.UNMETERED);
+ } else if (requiresAnyConnectivity) {
+ builder.setRequiredNetworkCapabilities(JobInfo.NetworkType.ANY);
+ }
+ builder.setRequiresDeviceIdle(mRequiresIdleCheckbox.isChecked());
+ builder.setRequiresCharging(mRequiresChargingCheckBox.isChecked());
+
+ mTestService.scheduleJob(builder.build());
+
+ }
+
+ public void cancelAllJobs(View v) {
+ JobScheduler tm =
+ (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
+ tm.cancelAll();
+ }
+
+ /**
+ * UI onclick listener to call jobFinished() in our service.
+ */
+ public void finishJob(View v) {
+ if (!ensureTestService()) {
+ return;
+ }
+ mTestService.callJobFinished();
+ mParamsTextView.setText("");
+ }
+
+ /**
+ * Receives callback from the service when a job has landed
+ * on the app. Colours the UI and post a message to
+ * uncolour it after a second.
+ */
+ public void onReceivedStartJob(JobParameters params) {
+ mShowStartView.setBackgroundColor(startJobColor);
+ Message m = Message.obtain(mHandler, MSG_UNCOLOUR_START);
+ mHandler.sendMessageDelayed(m, 1000L); // uncolour in 1 second.
+ mParamsTextView.setText("Executing: " + params.getJobId() + " " + params.getExtras());
+ }
+
+ /**
+ * Receives callback from the service when a job that
+ * previously landed on the app must stop executing.
+ * Colours the UI and post a message to uncolour it after a
+ * second.
+ */
+ public void onReceivedStopJob() {
+ mShowStopView.setBackgroundColor(stopJobColor);
+ Message m = Message.obtain(mHandler, MSG_UNCOLOUR_STOP);
+ mHandler.sendMessageDelayed(m, 2000L); // uncolour in 1 second.
+ mParamsTextView.setText("");
+ }
+}
diff --git a/samples/browseable/JobScheduler/src/com.example.android.jobscheduler/service/TestJobService.java b/samples/browseable/JobScheduler/src/com.example.android.jobscheduler/service/TestJobService.java
new file mode 100644
index 0000000..8608be5
--- /dev/null
+++ b/samples/browseable/JobScheduler/src/com.example.android.jobscheduler/service/TestJobService.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * 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.jobscheduler.service;
+
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.app.job.JobParameters;
+import android.app.job.JobService;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.example.android.jobscheduler.MainActivity;
+
+import java.util.LinkedList;
+
+
+/**
+ * Service to handle callbacks from the JobScheduler. Requests scheduled with the JobScheduler
+ * ultimately land on this service's "onStartJob" method. Currently all this does is post a message
+ * to the app's main activity to change the state of the UI.
+ */
+public class TestJobService extends JobService {
+ private static final String TAG = "SyncService";
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ Log.i(TAG, "Service created");
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ Log.i(TAG, "Service destroyed");
+ }
+
+ /**
+ * When the app's MainActivity is created, it starts this service. This is so that the
+ * activity and this service can communicate back and forth. See "setUiCalback()"
+ */
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ Messenger callback = intent.getParcelableExtra("messenger");
+ Message m = Message.obtain();
+ m.what = MainActivity.MSG_SERVICE_OBJ;
+ m.obj = this;
+ try {
+ callback.send(m);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error passing service object back to activity.");
+ }
+ return START_NOT_STICKY;
+ }
+
+ @Override
+ public boolean onStartJob(JobParameters params) {
+ // We don't do any real 'work' in this sample app. All we'll
+ // do is track which jobs have landed on our service, and
+ // update the UI accordingly.
+ jobParamsMap.add(params);
+ if (mActivity != null) {
+ mActivity.onReceivedStartJob(params);
+ }
+ Log.i(TAG, "on start job: " + params.getJobId());
+ return true;
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ // Stop tracking these job parameters, as we've 'finished' executing.
+ jobParamsMap.remove(params);
+ if (mActivity != null) {
+ mActivity.onReceivedStopJob();
+ }
+ Log.i(TAG, "on stop job: " + params.getJobId());
+ return true;
+ }
+
+ MainActivity mActivity;
+ private final LinkedList<JobParameters> jobParamsMap = new LinkedList<JobParameters>();
+
+ public void setUiCallback(MainActivity activity) {
+ mActivity = activity;
+ }
+
+ /** Send job to the JobScheduler. */
+ public void scheduleJob(JobInfo t) {
+ Log.d(TAG, "Scheduling job");
+ JobScheduler tm =
+ (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
+ tm.schedule(t);
+ }
+
+ /**
+ * Not currently used, but as an exercise you can hook this
+ * up to a button in the UI to finish a job that has landed
+ * in onStartJob().
+ */
+ public boolean callJobFinished() {
+ JobParameters params = jobParamsMap.poll();
+ if (params == null) {
+ return false;
+ } else {
+ jobFinished(params, false);
+ return true;
+ }
+ }
+
+}
diff --git a/samples/browseable/LNotifications/AndroidManifest.xml b/samples/browseable/LNotifications/AndroidManifest.xml
new file mode 100644
index 0000000..816d78f
--- /dev/null
+++ b/samples/browseable/LNotifications/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.lnotifications"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
+
+ <application
+ android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme" >
+ <activity
+ android:name=".LNotificationActivity"
+ android:label="@string/app_name" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
diff --git a/samples/browseable/LNotifications/_index.jd b/samples/browseable/LNotifications/_index.jd
new file mode 100644
index 0000000..a993bb7
--- /dev/null
+++ b/samples/browseable/LNotifications/_index.jd
@@ -0,0 +1,11 @@
+page.tags="LNotifications Sample"
+sample.group=UI
+@jd:body
+
+<p>
+
+ This sample demonstrates how new features for notifications introduced in Android L
+ are used such as Heads-Up notifications, visibility, people, category and priority
+ metadata. (Priority metadata has been present since Jelly Bean, but actually unused).
+
+ </p>
diff --git a/samples/browseable/LNotifications/res/drawable-hdpi/ic_contact_picture.png b/samples/browseable/LNotifications/res/drawable-hdpi/ic_contact_picture.png
new file mode 100644
index 0000000..00d0ec4
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-hdpi/ic_contact_picture.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-hdpi/ic_launcher.png b/samples/browseable/LNotifications/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..015d248
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-hdpi/ic_launcher_notification.png b/samples/browseable/LNotifications/res/drawable-hdpi/ic_launcher_notification.png
new file mode 100644
index 0000000..4b058c1
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-hdpi/ic_launcher_notification.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-hdpi/ic_private.png b/samples/browseable/LNotifications/res/drawable-hdpi/ic_private.png
new file mode 100644
index 0000000..663f93e
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-hdpi/ic_private.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-hdpi/ic_private_notification.png b/samples/browseable/LNotifications/res/drawable-hdpi/ic_private_notification.png
new file mode 100644
index 0000000..dbf5139
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-hdpi/ic_private_notification.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-hdpi/ic_public.png b/samples/browseable/LNotifications/res/drawable-hdpi/ic_public.png
new file mode 100644
index 0000000..033281d
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-hdpi/ic_public.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-hdpi/ic_public_notification.png b/samples/browseable/LNotifications/res/drawable-hdpi/ic_public_notification.png
new file mode 100644
index 0000000..fe1ee81
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-hdpi/ic_public_notification.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-hdpi/ic_secret.png b/samples/browseable/LNotifications/res/drawable-hdpi/ic_secret.png
new file mode 100644
index 0000000..a22dbdf
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-hdpi/ic_secret.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-hdpi/ic_secret_notification.png b/samples/browseable/LNotifications/res/drawable-hdpi/ic_secret_notification.png
new file mode 100644
index 0000000..5776624
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-hdpi/ic_secret_notification.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-hdpi/tile.9.png b/samples/browseable/LNotifications/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-mdpi/ic_contact_picture.png b/samples/browseable/LNotifications/res/drawable-mdpi/ic_contact_picture.png
new file mode 100644
index 0000000..771cb6b
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-mdpi/ic_contact_picture.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-mdpi/ic_launcher.png b/samples/browseable/LNotifications/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..605a256
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-mdpi/ic_launcher_notification.png b/samples/browseable/LNotifications/res/drawable-mdpi/ic_launcher_notification.png
new file mode 100644
index 0000000..72cd1b3
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-mdpi/ic_launcher_notification.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-mdpi/ic_private.png b/samples/browseable/LNotifications/res/drawable-mdpi/ic_private.png
new file mode 100644
index 0000000..2556153
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-mdpi/ic_private.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-mdpi/ic_private_notification.png b/samples/browseable/LNotifications/res/drawable-mdpi/ic_private_notification.png
new file mode 100644
index 0000000..df93964
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-mdpi/ic_private_notification.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-mdpi/ic_public.png b/samples/browseable/LNotifications/res/drawable-mdpi/ic_public.png
new file mode 100644
index 0000000..ff0c653
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-mdpi/ic_public.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-mdpi/ic_public_notification.png b/samples/browseable/LNotifications/res/drawable-mdpi/ic_public_notification.png
new file mode 100644
index 0000000..7c69019
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-mdpi/ic_public_notification.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-mdpi/ic_secret.png b/samples/browseable/LNotifications/res/drawable-mdpi/ic_secret.png
new file mode 100644
index 0000000..2843164
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-mdpi/ic_secret.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-mdpi/ic_secret_notification.png b/samples/browseable/LNotifications/res/drawable-mdpi/ic_secret_notification.png
new file mode 100644
index 0000000..652e8b0
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-mdpi/ic_secret_notification.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-xhdpi/ic_contact_picture.png b/samples/browseable/LNotifications/res/drawable-xhdpi/ic_contact_picture.png
new file mode 100644
index 0000000..bdba57b
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-xhdpi/ic_contact_picture.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/LNotifications/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..c08bafa
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-xhdpi/ic_launcher_notification.png b/samples/browseable/LNotifications/res/drawable-xhdpi/ic_launcher_notification.png
new file mode 100644
index 0000000..9a42c7a
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-xhdpi/ic_launcher_notification.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-xhdpi/ic_private.png b/samples/browseable/LNotifications/res/drawable-xhdpi/ic_private.png
new file mode 100644
index 0000000..823d942
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-xhdpi/ic_private.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-xhdpi/ic_private_notification.png b/samples/browseable/LNotifications/res/drawable-xhdpi/ic_private_notification.png
new file mode 100644
index 0000000..497a1ac
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-xhdpi/ic_private_notification.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-xhdpi/ic_public.png b/samples/browseable/LNotifications/res/drawable-xhdpi/ic_public.png
new file mode 100644
index 0000000..93b89ff
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-xhdpi/ic_public.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-xhdpi/ic_public_notification.png b/samples/browseable/LNotifications/res/drawable-xhdpi/ic_public_notification.png
new file mode 100644
index 0000000..1d6f1f1
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-xhdpi/ic_public_notification.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-xhdpi/ic_secret.png b/samples/browseable/LNotifications/res/drawable-xhdpi/ic_secret.png
new file mode 100644
index 0000000..5124eee
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-xhdpi/ic_secret.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-xhdpi/ic_secret_notification.png b/samples/browseable/LNotifications/res/drawable-xhdpi/ic_secret_notification.png
new file mode 100644
index 0000000..8388dd5
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-xhdpi/ic_secret_notification.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_contact_picture.png b/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_contact_picture.png
new file mode 100644
index 0000000..b36ec17
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_contact_picture.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..1224b39
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_launcher_notification.png b/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_launcher_notification.png
new file mode 100644
index 0000000..e25fff1
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_launcher_notification.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_private.png b/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_private.png
new file mode 100644
index 0000000..4e4d3d6
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_private.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_private_notification.png b/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_private_notification.png
new file mode 100644
index 0000000..dd5de27
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_private_notification.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_public.png b/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_public.png
new file mode 100644
index 0000000..6aede4e
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_public.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_public_notification.png b/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_public_notification.png
new file mode 100644
index 0000000..9b8c59f
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_public_notification.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_secret.png b/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_secret.png
new file mode 100644
index 0000000..d1e126c
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_secret.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_secret_notification.png b/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_secret_notification.png
new file mode 100644
index 0000000..be59c8f
--- /dev/null
+++ b/samples/browseable/LNotifications/res/drawable-xxhdpi/ic_secret_notification.png
Binary files differ
diff --git a/samples/browseable/LNotifications/res/layout/activity_main.xml b/samples/browseable/LNotifications/res/layout/activity_main.xml
new file mode 100755
index 0000000..be1aa49
--- /dev/null
+++ b/samples/browseable/LNotifications/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/horizontal_page_margin"
+ android:layout_marginRight="@dimen/horizontal_page_margin"
+ android:layout_marginTop="@dimen/vertical_page_margin"
+ android:layout_marginBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/samples/browseable/LNotifications/res/layout/activity_notification.xml b/samples/browseable/LNotifications/res/layout/activity_notification.xml
new file mode 100644
index 0000000..cd0cd68
--- /dev/null
+++ b/samples/browseable/LNotifications/res/layout/activity_notification.xml
@@ -0,0 +1,27 @@
+<!--
+ Copyright 2014 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"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ tools:context="com.example.android.lnotifications.LNotificationActivity">
+</FrameLayout>
diff --git a/samples/browseable/LNotifications/res/layout/contact_entry.xml b/samples/browseable/LNotifications/res/layout/contact_entry.xml
new file mode 100644
index 0000000..90ab4b8
--- /dev/null
+++ b/samples/browseable/LNotifications/res/layout/contact_entry.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@+id/contact_photo"
+ android:layout_width="96dp"
+ android:layout_height="96dp"
+ android:src="@drawable/ic_contact_picture"
+ />
+
+ <TextView
+ android:id="@+id/contact_name"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dp"
+ android:layout_toRightOf="@id/contact_photo"
+ />
+
+ <TextView
+ android:id="@+id/click_to_change"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dp"
+ android:layout_marginLeft="10dp"
+ android:clickable="true"
+ android:layout_below="@id/contact_name"
+ android:layout_toRightOf="@id/contact_photo"
+ android:text="@string/click_to_change"
+ android:textColor="@color/link_text"
+ />
+</RelativeLayout>
\ No newline at end of file
diff --git a/samples/browseable/LNotifications/res/layout/fragment_heads_up_notification.xml b/samples/browseable/LNotifications/res/layout/fragment_heads_up_notification.xml
new file mode 100644
index 0000000..bbcb84b
--- /dev/null
+++ b/samples/browseable/LNotifications/res/layout/fragment_heads_up_notification.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/heads_up_notification_description"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/heads_up_notification_description"
+ />
+
+ <CheckBox
+ android:id="@+id/use_heads_up_checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/heads_up_notification_description"
+ android:text="@string/use_heads_up_notification_where_possible"/>
+
+ <Button
+ android:id="@+id/show_notification_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_marginTop="20dp"
+ android:text="@string/show_notification"
+ />
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/browseable/LNotifications/res/layout/fragment_other_metadata.xml b/samples/browseable/LNotifications/res/layout/fragment_other_metadata.xml
new file mode 100644
index 0000000..5222302
--- /dev/null
+++ b/samples/browseable/LNotifications/res/layout/fragment_other_metadata.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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.
+-->
+
+<ScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent">
+
+ <LinearLayout android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/notification_metadata_description"
+ />
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/margin_medium"
+ android:orientation="horizontal"
+ android:paddingLeft="@dimen/margin_tiny"
+ android:paddingRight="@dimen/margin_tiny"
+ >
+
+ <TextView
+ android:layout_width="70dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:text="@string/label_category"
+ />
+ <Spinner
+ android:id="@+id/category_spinner"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/margin_medium"
+ android:orientation="horizontal"
+ android:paddingLeft="@dimen/margin_tiny"
+ android:paddingRight="@dimen/margin_tiny"
+ >
+ <TextView
+ android:layout_width="70dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:text="@string/label_priority"
+ />
+ <Spinner
+ android:id="@+id/priority_spinner"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ />
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/attach_person"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/margin_medium"
+ android:clickable="true"
+ android:text="@string/attach_person"
+ android:textColor="@color/link_text"
+ android:paddingLeft="@dimen/margin_tiny"
+ android:paddingRight="@dimen/margin_tiny"
+ />
+
+ <include
+ layout="@layout/contact_entry"
+ android:id="@+id/contact_entry"
+ android:layout_marginTop="@dimen/margin_medium"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:paddingLeft="@dimen/margin_tiny"
+ android:paddingRight="@dimen/margin_tiny"
+ />
+
+ <Button
+ android:id="@+id/show_notification_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/margin_medium"
+ android:text="@string/show_notification"
+ />
+ </LinearLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/samples/browseable/LNotifications/res/layout/fragment_visibility_metadata_notification.xml b/samples/browseable/LNotifications/res/layout/fragment_visibility_metadata_notification.xml
new file mode 100644
index 0000000..2a7bbca
--- /dev/null
+++ b/samples/browseable/LNotifications/res/layout/fragment_visibility_metadata_notification.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/visibility_metadata_notification_description"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/visibility_metadata_description"
+ />
+
+ <RadioGroup
+ android:id="@+id/visibility_radio_group"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:checkedButton="@+id/visibility_public_radio_button"
+ android:layout_marginTop="20dp">
+
+ <RadioButton
+ android:id="@+id/visibility_public_radio_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:drawableLeft="@drawable/ic_public"
+ android:text="@string/visibility_public"
+ />
+
+ <RadioButton
+ android:id="@+id/visibility_private_radio_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:drawableLeft="@drawable/ic_private"
+ android:text="@string/visibility_private"
+ />
+
+ <RadioButton
+ android:id="@+id/visibility_secret_radio_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:drawableLeft="@drawable/ic_secret"
+ android:text="@string/visibility_secret"
+ />
+
+ </RadioGroup>
+
+ <Button
+ android:id="@+id/show_notification_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_marginTop="20dp"
+ android:text="@string/show_notification"
+ />
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/browseable/LNotifications/res/values-sw600dp/template-dimens.xml b/samples/browseable/LNotifications/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/LNotifications/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/LNotifications/res/values-sw600dp/template-styles.xml b/samples/browseable/LNotifications/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/LNotifications/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/LNotifications/res/values-v11/template-styles.xml b/samples/browseable/LNotifications/res/values-v11/template-styles.xml
new file mode 100644
index 0000000..8c1ea66
--- /dev/null
+++ b/samples/browseable/LNotifications/res/values-v11/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/samples/browseable/LNotifications/res/values-v21/template-styles.xml b/samples/browseable/LNotifications/res/values-v21/template-styles.xml
new file mode 100644
index 0000000..134fcd9
--- /dev/null
+++ b/samples/browseable/LNotifications/res/values-v21/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2014 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>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Material.Light" />
+
+</resources>
diff --git a/samples/browseable/LNotifications/res/values/base-strings.xml b/samples/browseable/LNotifications/res/values/base-strings.xml
new file mode 100644
index 0000000..417452d
--- /dev/null
+++ b/samples/browseable/LNotifications/res/values/base-strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">LNotifications Sample</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ This sample demonstrates how new features for notifications introduced in Android L
+ are used such as Heads-Up notifications, visibility, people, category and priority
+ metadata. (Priority metadata has been present since Jelly Bean, but actually unused).
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/LNotifications/res/values/colors.xml b/samples/browseable/LNotifications/res/values/colors.xml
new file mode 100644
index 0000000..31d81ee
--- /dev/null
+++ b/samples/browseable/LNotifications/res/values/colors.xml
@@ -0,0 +1,20 @@
+<!--
+ Copyright 2014 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>
+ <color name="black_overlay">#66000000</color>
+ <color name="link_text">#6DB7C4</color>
+</resources>
diff --git a/samples/browseable/LNotifications/res/values/dimens.xml b/samples/browseable/LNotifications/res/values/dimens.xml
new file mode 100644
index 0000000..a776bac
--- /dev/null
+++ b/samples/browseable/LNotifications/res/values/dimens.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+ <dimen name="navigation_drawer_width">240dp</dimen>
+
+</resources>
diff --git a/samples/browseable/LNotifications/res/values/strings.xml b/samples/browseable/LNotifications/res/values/strings.xml
new file mode 100644
index 0000000..e6cb124
--- /dev/null
+++ b/samples/browseable/LNotifications/res/values/strings.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2014 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="action_settings">Settings</string>
+ <string name="heads_up_notification_description">This sample demonstrates options for displaying Heads-Up Notifications on Android.
+ \n\n
+ On Android L or above, you have options to display important information in front of the user (Heads-Up Notifications) which
+ does not obscure the entire viewport.\n</string>
+ <string name="notification_metadata_description">This sample demonstrates how to attach
+ metadata introduced in Android L, such as
+ priority data, notification category and person data.\n
+ </string>
+ <string name="visibility_metadata_description">
+ This sample demonstrates how to attach visibility metadata.\n
+ You need to have your lockscreen secured(PIN, Pattern, or Password) if you don\'t want to
+ show sensitive information on it.
+ </string>
+ <string name="visibility_public">Public</string>
+ <string name="visibility_private">Private</string>
+ <string name="visibility_secret">Secret</string>
+ <string name="title_lnotification_activity">Notification samples for L</string>
+ <string name="attach_person">Attach Person</string>
+ <string name="click_to_change">Click to Change</string>
+ <string name="show_notification">Show notification</string>
+ <string name="use_heads_up_notification_where_possible">Use Heads Up Notification when possible</string>
+ <string name="label_category">Category</string>
+ <string name="label_priority">Priority</string>
+</resources>
diff --git a/samples/browseable/LNotifications/res/values/template-dimens.xml b/samples/browseable/LNotifications/res/values/template-dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/LNotifications/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/LNotifications/res/values/template-styles.xml b/samples/browseable/LNotifications/res/values/template-styles.xml
new file mode 100644
index 0000000..6e7d593
--- /dev/null
+++ b/samples/browseable/LNotifications/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/LNotifications/src/com.example.android.lnotifications/HeadsUpNotificationFragment.java b/samples/browseable/LNotifications/src/com.example.android.lnotifications/HeadsUpNotificationFragment.java
new file mode 100644
index 0000000..d304cf4
--- /dev/null
+++ b/samples/browseable/LNotifications/src/com.example.android.lnotifications/HeadsUpNotificationFragment.java
@@ -0,0 +1,134 @@
+/*
+* Copyright 2014 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.lnotifications;
+
+import android.app.Fragment;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.Toast;
+
+/**
+ * Fragment that demonstrates options for displaying Heads-Up Notifications.
+ */
+public class HeadsUpNotificationFragment extends Fragment {
+
+ /**
+ * NotificationId used for the notifications from this Fragment.
+ */
+ private static final int NOTIFICATION_ID = 1;
+
+ private NotificationManager mNotificationManager;
+
+ /**
+ * Button to show a notification.
+ */
+ private Button mShowNotificationButton;
+
+ /**
+ * If checked, notifications that this Fragment creates will be displayed as Heads-Up
+ * Notifications.
+ */
+ private CheckBox mUseHeadsUpCheckbox;
+
+ /**
+ * Use this factory method to create a new instance of
+ * this fragment using the provided parameters.
+ *
+ * @return A new instance of fragment NotificationFragment.
+ */
+ public static HeadsUpNotificationFragment newInstance() {
+ HeadsUpNotificationFragment fragment = new HeadsUpNotificationFragment();
+ fragment.setRetainInstance(true);
+ return fragment;
+ }
+
+ public HeadsUpNotificationFragment() {
+ // Required empty public constructor
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mNotificationManager = (NotificationManager) getActivity().getSystemService(Context
+ .NOTIFICATION_SERVICE);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_heads_up_notification, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ mShowNotificationButton = (Button) view.findViewById(R.id.show_notification_button);
+ mShowNotificationButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ mNotificationManager.notify(NOTIFICATION_ID, createNotification(
+ mUseHeadsUpCheckbox.isChecked()));
+ Toast.makeText(getActivity(), "Show Notification clicked", Toast.LENGTH_SHORT).show();
+ }
+ });
+ mUseHeadsUpCheckbox = (CheckBox) view.findViewById(R.id.use_heads_up_checkbox);
+ }
+
+ /**
+ * Creates a new notification depending on the argument.
+ *
+ * @param makeHeadsUpNotification A boolean value to indicating whether a notification will be
+ * created as a heads-up notification or not.
+ * <ul>
+ * <li>true : Creates a heads-up notification.</li>
+ * <li>false : Creates a non-heads-up notification.</li>
+ * </ul>
+ *
+ * @return A Notification instance.
+ */
+ //@VisibleForTesting
+ Notification createNotification(boolean makeHeadsUpNotification) {
+ Notification.Builder notificationBuilder = new Notification.Builder(getActivity())
+ .setSmallIcon(R.drawable.ic_launcher_notification)
+ .setPriority(Notification.PRIORITY_DEFAULT)
+ .setCategory(Notification.CATEGORY_MESSAGE)
+ .setContentTitle("Sample Notification")
+ .setContentText("This is a normal notification.");
+ if (makeHeadsUpNotification) {
+ Intent push = new Intent();
+ push.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ push.setClass(getActivity(), LNotificationActivity.class);
+
+ PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(getActivity(), 0,
+ push, PendingIntent.FLAG_CANCEL_CURRENT);
+ notificationBuilder
+ .setContentText("Heads-Up Notification on Android L or above.")
+ .setFullScreenIntent(fullScreenPendingIntent, true);
+ }
+ return notificationBuilder.build();
+ }
+}
diff --git a/samples/browseable/LNotifications/src/com.example.android.lnotifications/LNotificationActivity.java b/samples/browseable/LNotifications/src/com.example.android.lnotifications/LNotificationActivity.java
new file mode 100644
index 0000000..fbc3e62
--- /dev/null
+++ b/samples/browseable/LNotifications/src/com.example.android.lnotifications/LNotificationActivity.java
@@ -0,0 +1,80 @@
+/*
+* Copyright 2014 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.lnotifications;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentTransaction;
+import android.os.Bundle;
+
+/**
+ * Launcher Activity for the L Notification samples application.
+ */
+public class LNotificationActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_notification);
+ setTitle(R.string.title_lnotification_activity);
+ ActionBar actionBar = getActionBar();
+
+ // Use ViewPager in the support library where possible.
+ // At this time, the support library for L is not ready so using the deprecated method
+ // to create tabs.
+ actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+ ActionBar.Tab tabHeadsUpNotification = actionBar.newTab().setText("Heads Up");
+ ActionBar.Tab tabVisibilityMetadata = actionBar.newTab().setText("Visibility");
+ ActionBar.Tab tabOtherMetadata = actionBar.newTab().setText("Others");
+ tabHeadsUpNotification.setTabListener(new FragmentTabListener(HeadsUpNotificationFragment
+ .newInstance()));
+ tabVisibilityMetadata.setTabListener(new FragmentTabListener(VisibilityMetadataFragment
+ .newInstance()));
+ tabOtherMetadata.setTabListener(new FragmentTabListener(OtherMetadataFragment.newInstance
+ ()));
+ actionBar.addTab(tabHeadsUpNotification, 0);
+ actionBar.addTab(tabVisibilityMetadata, 1);
+ actionBar.addTab(tabOtherMetadata, 2);
+ }
+
+ /**
+ * TabListener that replaces a Fragment when a tab is clicked.
+ */
+ private static class FragmentTabListener implements ActionBar.TabListener {
+ public Fragment fragment;
+
+ public FragmentTabListener(Fragment fragment) {
+ this.fragment = fragment;
+ }
+
+ @Override
+ public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
+ //do nothing.
+ }
+
+ @Override
+ public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
+ ft.replace(R.id.container, fragment);
+ }
+
+ @Override
+ public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
+ ft.remove(fragment);
+ }
+ }
+}
diff --git a/samples/browseable/LNotifications/src/com.example.android.lnotifications/OtherMetadataFragment.java b/samples/browseable/LNotifications/src/com.example.android.lnotifications/OtherMetadataFragment.java
new file mode 100644
index 0000000..51616e7
--- /dev/null
+++ b/samples/browseable/LNotifications/src/com.example.android.lnotifications/OtherMetadataFragment.java
@@ -0,0 +1,345 @@
+/*
+* Copyright 2014 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.lnotifications;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract;
+import android.provider.MediaStore;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.Spinner;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.io.IOException;
+import java.util.Random;
+
+/**
+ * Fragment that demonstrates how to attach metadata introduced in Android L, such as
+ * priority data, notification category and person data.
+ */
+public class OtherMetadataFragment extends Fragment {
+
+ private static final String TAG = OtherMetadataFragment.class.getSimpleName();
+
+ /**
+ * Request code used for picking a contact.
+ */
+ public static final int REQUEST_CODE_PICK_CONTACT = 1;
+
+ /**
+ * Incremental Integer used for ID for notifications so that each notification will be
+ * treated differently.
+ */
+ private Integer mIncrementalNotificationId = Integer.valueOf(0);
+
+ private NotificationManager mNotificationManager;
+
+ /**
+ * Button to show a notification.
+ */
+ private Button mShowNotificationButton;
+
+ /**
+ * Spinner that holds possible categories used for a notification as
+ * {@link Notification.Builder#setCategory(String)}.
+ */
+ private Spinner mCategorySpinner;
+
+ /**
+ * Spinner that holds possible priorities used for a notification as
+ * {@link Notification.Builder#setPriority(int)}.
+ */
+ private Spinner mPrioritySpinner;
+
+ /**
+ * Holds a URI for the person to be attached to the notification.
+ */
+ //@VisibleForTesting
+ Uri mContactUri;
+
+ /**
+ * Use this factory method to create a new instance of
+ * this fragment using the provided parameters.
+ *
+ * @return A new instance of fragment NotificationFragment.
+ */
+ public static OtherMetadataFragment newInstance() {
+ OtherMetadataFragment fragment = new OtherMetadataFragment();
+ fragment.setRetainInstance(true);
+ return fragment;
+ }
+
+ public OtherMetadataFragment() {
+ // Required empty public constructor
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mNotificationManager = (NotificationManager) getActivity().getSystemService(Context
+ .NOTIFICATION_SERVICE);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_other_metadata, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ mShowNotificationButton = (Button) view.findViewById(R.id.show_notification_button);
+ mShowNotificationButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Priority selectedPriority = (Priority) mPrioritySpinner.getSelectedItem();
+ Category selectedCategory = (Category) mCategorySpinner.getSelectedItem();
+ showNotificationClicked(selectedPriority, selectedCategory, mContactUri);
+ }
+ });
+
+ mCategorySpinner = (Spinner) view.findViewById(R.id.category_spinner);
+ ArrayAdapter<Category> categoryArrayAdapter = new ArrayAdapter<Category>(getActivity(),
+ android.R.layout.simple_spinner_item, Category.values());
+ categoryArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mCategorySpinner.setAdapter(categoryArrayAdapter);
+
+ mPrioritySpinner = (Spinner) view.findViewById(R.id.priority_spinner);
+ ArrayAdapter<Priority> priorityArrayAdapter = new ArrayAdapter<Priority>(getActivity(),
+ android.R.layout.simple_spinner_item, Priority.values());
+ priorityArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mPrioritySpinner.setAdapter(priorityArrayAdapter);
+
+ view.findViewById(R.id.attach_person).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ findContact();
+ }
+ });
+
+ view.findViewById(R.id.contact_entry).setVisibility(View.GONE);
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ switch (requestCode) {
+ case REQUEST_CODE_PICK_CONTACT:
+ if (resultCode == Activity.RESULT_OK) {
+ Uri contactUri = data.getData();
+ mContactUri = contactUri;
+ updateContactEntryFromUri(contactUri);
+ }
+ break;
+ }
+ }
+
+ /**
+ * Invoked when {@link #mShowNotificationButton} is clicked.
+ * Creates a new notification and sets metadata passed as arguments.
+ *
+ * @param priority The priority metadata.
+ * @param category The category metadata.
+ * @param contactUri The URI to be added to the new notification as metadata.
+ *
+ * @return A Notification instance.
+ */
+ //@VisibleForTesting
+ Notification createNotification(Priority priority, Category category, Uri contactUri) {
+ Notification.Builder notificationBuilder = new Notification.Builder(getActivity())
+ .setContentTitle("Notification with other metadata")
+ .setSmallIcon(R.drawable.ic_launcher_notification)
+ .setPriority(priority.value)
+ .setCategory(category.value)
+ .setContentText(String.format("Category %s, Priority %s", category.value,
+ priority.name()));
+ if (contactUri != null) {
+ notificationBuilder.addPerson(contactUri.toString());
+ Bitmap photoBitmap = loadBitmapFromContactUri(contactUri);
+ if (photoBitmap != null) {
+ notificationBuilder.setLargeIcon(photoBitmap);
+ }
+ }
+ return notificationBuilder.build();
+ }
+
+ /**
+ * Invoked when {@link #mShowNotificationButton} is clicked.
+ * Creates a new notification and sets metadata passed as arguments.
+ *
+ * @param priority The priority metadata.
+ * @param category The category metadata.
+ * @param contactUri The URI to be added to the new notification as metadata.
+ */
+ private void showNotificationClicked(Priority priority, Category category, Uri contactUri) {
+ // Assigns a unique (incremented) notification ID in order to treat each notification as a
+ // different one. This helps demonstrate how a priority flag affects ordering.
+ mIncrementalNotificationId = new Integer(mIncrementalNotificationId + 1);
+ mNotificationManager.notify(mIncrementalNotificationId, createNotification(priority,
+ category, contactUri));
+ Toast.makeText(getActivity(), "Show Notification clicked", Toast.LENGTH_SHORT).show();
+ }
+
+ private void findContact() {
+ Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
+ startActivityForResult(intent, REQUEST_CODE_PICK_CONTACT);
+ }
+
+ /**
+ * Returns a {@link Bitmap} from the Uri specified as the argument.
+ *
+ * @param contactUri The Uri from which the result Bitmap is created.
+ * @return The {@link Bitmap} instance retrieved from the contactUri.
+ */
+ private Bitmap loadBitmapFromContactUri(Uri contactUri) {
+ if (contactUri == null) {
+ return null;
+ }
+ Bitmap result = null;
+ Cursor cursor = getActivity().getContentResolver().query(contactUri, null, null, null,
+ null);
+ if (cursor != null && cursor.moveToFirst()) {
+ int idx = cursor.getColumnIndex(ContactsContract.Contacts.PHOTO_ID);
+ String hasPhoto = cursor.getString(idx);
+ Uri photoUri = Uri.withAppendedPath(contactUri, ContactsContract.Contacts.Photo
+ .CONTENT_DIRECTORY);
+ if (hasPhoto != null) {
+ try {
+ result = MediaStore.Images.Media.getBitmap(getActivity().getContentResolver()
+ , photoUri);
+ } catch (IOException e) {
+ Log.e(TAG, String.format("Failed to load resource. Uri %s", photoUri), e);
+ }
+ } else {
+ Drawable defaultContactDrawable = getActivity().getResources().getDrawable(R
+ .drawable.ic_contact_picture);
+ result = ((BitmapDrawable) defaultContactDrawable).getBitmap();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Updates the Contact information on the screen when a contact is picked.
+ *
+ * @param contactUri The Uri from which the contact is retrieved.
+ */
+ private void updateContactEntryFromUri(Uri contactUri) {
+ Cursor cursor = getActivity().getContentResolver().query(contactUri, null, null, null,
+ null);
+ if (cursor != null && cursor.moveToFirst()) {
+ int idx = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
+ String name = cursor.getString(idx);
+ idx = cursor.getColumnIndex(ContactsContract.Contacts.PHOTO_ID);
+ String hasPhoto = cursor.getString(idx);
+
+ Uri photoUri = Uri.withAppendedPath(contactUri, ContactsContract.Contacts.Photo
+ .CONTENT_DIRECTORY);
+ ImageView contactPhoto = (ImageView) getActivity().findViewById(R.id.contact_photo);
+ if (hasPhoto != null) {
+ contactPhoto.setImageURI(photoUri);
+ } else {
+ Drawable defaultContactDrawable = getActivity().getResources().getDrawable(R
+ .drawable.ic_contact_picture);
+ contactPhoto.setImageDrawable(defaultContactDrawable);
+ }
+ TextView contactName = (TextView) getActivity().findViewById(R.id.contact_name);
+ contactName.setText(name);
+
+ getActivity().findViewById(R.id.contact_entry).setVisibility(View.VISIBLE);
+ getActivity().findViewById(R.id.attach_person).setVisibility(View.GONE);
+ getActivity().findViewById(R.id.click_to_change).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ findContact();
+ }
+ });
+ Log.i(TAG, String.format("Contact updated. Name %s, PhotoUri %s", name, photoUri));
+ }
+ }
+
+ /**
+ * Enum indicating possible categories in {@link Notification} used from
+ * {@link #mCategorySpinner}.
+ */
+ //@VisibleForTesting
+ static enum Category {
+ ALARM("alarm"),
+ CALL("call"),
+ EMAIL("email"),
+ ERROR("err"),
+ EVENT("event"),
+ MESSAGE("msg"),
+ PROGRESS("progress"),
+ PROMO("promo"),
+ RECOMMENDATION("recommendation"),
+ SERVICE("service"),
+ SOCIAL("social"),
+ STATUS("status"),
+ SYSTEM("sys"),
+ TRANSPORT("transport");
+
+ private final String value;
+
+ Category(String value) {
+ this.value = value;
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+ }
+
+ /**
+ * Enum indicating possible priorities in {@link Notification} used from
+ * {@link #mPrioritySpinner}.
+ */
+ //@VisibleForTesting
+ static enum Priority {
+ DEFAULT(Notification.PRIORITY_DEFAULT),
+ MAX(Notification.PRIORITY_MAX),
+ HIGH(Notification.PRIORITY_HIGH),
+ LOW(Notification.PRIORITY_LOW),
+ MIN(Notification.PRIORITY_MIN);
+
+ private final int value;
+
+ Priority(int value) {
+ this.value = value;
+ }
+ }
+}
diff --git a/samples/browseable/LNotifications/src/com.example.android.lnotifications/VisibilityMetadataFragment.java b/samples/browseable/LNotifications/src/com.example.android.lnotifications/VisibilityMetadataFragment.java
new file mode 100644
index 0000000..616632b
--- /dev/null
+++ b/samples/browseable/LNotifications/src/com.example.android.lnotifications/VisibilityMetadataFragment.java
@@ -0,0 +1,202 @@
+/*
+* Copyright 2014 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.lnotifications;
+
+import android.app.Fragment;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.RadioGroup;
+import android.widget.Toast;
+
+import java.util.Random;
+
+
+/**
+ * Fragment that demonstrates how notifications with different visibility metadata differ on
+ * a lockscreen.
+ */
+public class VisibilityMetadataFragment extends Fragment {
+
+ private NotificationManager mNotificationManager;
+
+ /**
+ * {@link RadioGroup} that has Visibility RadioButton in its children.
+ */
+ private RadioGroup mRadioGroup;
+
+ /**
+ * Incremental Integer used for ID for notifications so that each notification will be
+ * treated differently.
+ */
+ private Integer mIncrementalNotificationId = Integer.valueOf(0);
+
+ /**
+ * Button to show a notification.
+ */
+ private Button mShowNotificationButton;
+
+ /**
+ * Use this factory method to create a new instance of
+ * this fragment using the provided parameters.
+ *
+ * @return A new instance of fragment NotificationFragment.
+ */
+ public static VisibilityMetadataFragment newInstance() {
+ VisibilityMetadataFragment fragment = new VisibilityMetadataFragment();
+ fragment.setRetainInstance(true);
+ return fragment;
+ }
+
+ public VisibilityMetadataFragment() {
+ // Required empty public constructor
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mNotificationManager = (NotificationManager) getActivity().getSystemService(Context
+ .NOTIFICATION_SERVICE);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_visibility_metadata_notification, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ mShowNotificationButton = (Button) view.findViewById(R.id.show_notification_button);
+ mShowNotificationButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ NotificationVisibility visibility = getVisibilityFromSelectedRadio(mRadioGroup);
+ showNotificationClicked(visibility);
+ }
+ });
+ mRadioGroup = (RadioGroup) view.findViewById(R.id.visibility_radio_group);
+ }
+
+ /**
+ * Creates a new notification with a different visibility level.
+ *
+ * @param visibility The visibility of the notification to be created.
+ *
+ * @return A Notification instance.
+ */
+ //@VisibleForTesting
+ Notification createNotification(NotificationVisibility visibility) {
+ Notification.Builder notificationBuilder = new Notification.Builder(getActivity())
+ .setContentTitle("Notification for Visibility metadata");
+
+ notificationBuilder.setVisibility(visibility.getVisibility());
+ notificationBuilder.setContentText(String.format("Visibility : %s",
+ visibility.getDescription()));
+ notificationBuilder.setSmallIcon(visibility.getNotificationIconId());
+
+ return notificationBuilder.build();
+ }
+
+ /**
+ * Returns a {@link NotificationVisibility} depending on which RadioButton in the radiogroup
+ * is selected.
+ *
+ * @param radiogroup The RadioGroup.
+ * @return The instance of {@link NotificationVisibility} corresponding to RadioButton.
+ */
+ private NotificationVisibility getVisibilityFromSelectedRadio(RadioGroup radiogroup) {
+ switch (radiogroup.getCheckedRadioButtonId()) {
+ case R.id.visibility_public_radio_button:
+ return NotificationVisibility.PUBLIC;
+ case R.id.visibility_private_radio_button:
+ return NotificationVisibility.PRIVATE;
+ case R.id.visibility_secret_radio_button:
+ return NotificationVisibility.SECRET;
+ default:
+ //If not selected, returns PUBLIC as default.
+ return NotificationVisibility.PUBLIC;
+ }
+ }
+
+ /**
+ * Invoked when {@link #mShowNotificationButton} is clicked.
+ * Creates a new notification with a different visibility level.
+ *
+ * @param visibility The visibility of the notification to be created.
+ */
+ private void showNotificationClicked(NotificationVisibility visibility) {
+ // Assigns a unique (incremented) notification ID in order to treat each notification as a
+ // different one. This helps demonstrate how a notification with a different visibility
+ // level differs on the lockscreen.
+ mIncrementalNotificationId = new Integer(mIncrementalNotificationId + 1);
+ mNotificationManager.notify(mIncrementalNotificationId, createNotification(visibility));
+ Toast.makeText(getActivity(), "Show Notification clicked", Toast.LENGTH_SHORT).show();
+ }
+
+ /**
+ * Enum indicating possible visibility levels for notifications and related data(String
+ * representation of visibility levels, an icon ID to create a notification) to
+ * create a notification.
+ */
+ //@VisibleForTesting
+ static enum NotificationVisibility {
+ PUBLIC(Notification.VISIBILITY_PUBLIC, "Public", R.drawable.ic_public_notification),
+ PRIVATE(Notification.VISIBILITY_PRIVATE, "Private", R.drawable.ic_private_notification),
+ SECRET(Notification.VISIBILITY_SECRET, "Secret", R.drawable.ic_secret_notification);
+
+ /**
+ * Visibility level of the notification.
+ */
+ private final int mVisibility;
+
+ /**
+ * String representation of the visibility.
+ */
+ private final String mDescription;
+
+ /**
+ * Id of an icon used for notifications created from the visibility.
+ */
+ private final int mNotificationIconId;
+
+ NotificationVisibility(int visibility, String description, int notificationIconId) {
+ mVisibility = visibility;
+ mDescription = description;
+ mNotificationIconId = notificationIconId;
+ }
+
+ public int getVisibility() {
+ return mVisibility;
+ }
+
+ public String getDescription() {
+ return mDescription;
+ }
+
+ public int getNotificationIconId() {
+ return mNotificationIconId;
+ }
+ }
+}
diff --git a/samples/browseable/NavigationDrawer/AndroidManifest.xml b/samples/browseable/NavigationDrawer/AndroidManifest.xml
new file mode 100644
index 0000000..ab2e141
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/AndroidManifest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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.navigationdrawer"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
+ <application
+ android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme" >
+ <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>
+ <activity
+ android:name=".NavigationDrawerActivity"
+ android:label="@string/app_name" >
+ </activity>
+ </application>
+
+</manifest>
diff --git a/samples/browseable/NavigationDrawer/_index.jd b/samples/browseable/NavigationDrawer/_index.jd
new file mode 100644
index 0000000..7238cf1
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/_index.jd
@@ -0,0 +1,10 @@
+page.tags="Navigation Drawer"
+sample.group=UI
+@jd:body
+
+<p>
+
+ This example illustrates a common usage of the DrawerLayout widget in the Android
+ support library.
+
+ </p>
diff --git a/samples/browseable/NavigationDrawer/res/drawable-hdpi/action_search.png b/samples/browseable/NavigationDrawer/res/drawable-hdpi/action_search.png
new file mode 100755
index 0000000..f12e005
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/drawable-hdpi/action_search.png
Binary files differ
diff --git a/samples/browseable/NavigationDrawer/res/drawable-hdpi/drawer_shadow.9.png b/samples/browseable/NavigationDrawer/res/drawable-hdpi/drawer_shadow.9.png
new file mode 100644
index 0000000..224cc4f
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/drawable-hdpi/drawer_shadow.9.png
Binary files differ
diff --git a/samples/browseable/NavigationDrawer/res/drawable-hdpi/ic_drawer.png b/samples/browseable/NavigationDrawer/res/drawable-hdpi/ic_drawer.png
new file mode 100644
index 0000000..ff7b1de
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/drawable-hdpi/ic_drawer.png
Binary files differ
diff --git a/samples/browseable/NavigationDrawer/res/drawable-hdpi/ic_launcher.png b/samples/browseable/NavigationDrawer/res/drawable-hdpi/ic_launcher.png
new file mode 100755
index 0000000..b460d60
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/NavigationDrawer/res/drawable-hdpi/tile.9.png b/samples/browseable/NavigationDrawer/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/NavigationDrawer/res/drawable-mdpi/action_search.png b/samples/browseable/NavigationDrawer/res/drawable-mdpi/action_search.png
new file mode 100755
index 0000000..587d9e0
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/drawable-mdpi/action_search.png
Binary files differ
diff --git a/samples/browseable/NavigationDrawer/res/drawable-mdpi/drawer_shadow.9.png b/samples/browseable/NavigationDrawer/res/drawable-mdpi/drawer_shadow.9.png
new file mode 100644
index 0000000..3797f99
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/drawable-mdpi/drawer_shadow.9.png
Binary files differ
diff --git a/samples/browseable/NavigationDrawer/res/drawable-mdpi/ic_drawer.png b/samples/browseable/NavigationDrawer/res/drawable-mdpi/ic_drawer.png
new file mode 100644
index 0000000..fb681ba
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/drawable-mdpi/ic_drawer.png
Binary files differ
diff --git a/samples/browseable/NavigationDrawer/res/drawable-mdpi/ic_launcher.png b/samples/browseable/NavigationDrawer/res/drawable-mdpi/ic_launcher.png
new file mode 100755
index 0000000..dee53f4
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/NavigationDrawer/res/drawable-xhdpi/action_search.png b/samples/browseable/NavigationDrawer/res/drawable-xhdpi/action_search.png
new file mode 100755
index 0000000..3549f84
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/drawable-xhdpi/action_search.png
Binary files differ
diff --git a/samples/browseable/NavigationDrawer/res/drawable-xhdpi/drawer_shadow.9.png b/samples/browseable/NavigationDrawer/res/drawable-xhdpi/drawer_shadow.9.png
new file mode 100644
index 0000000..fa3d853
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/drawable-xhdpi/drawer_shadow.9.png
Binary files differ
diff --git a/samples/browseable/NavigationDrawer/res/drawable-xhdpi/ic_drawer.png b/samples/browseable/NavigationDrawer/res/drawable-xhdpi/ic_drawer.png
new file mode 100644
index 0000000..b9bc3d7
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/drawable-xhdpi/ic_drawer.png
Binary files differ
diff --git a/samples/browseable/NavigationDrawer/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/NavigationDrawer/res/drawable-xhdpi/ic_launcher.png
new file mode 100755
index 0000000..d4e1215
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/NavigationDrawer/res/drawable-xhdpi/sample_dashboard_item_background.9.png b/samples/browseable/NavigationDrawer/res/drawable-xhdpi/sample_dashboard_item_background.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/drawable-xhdpi/sample_dashboard_item_background.9.png
Binary files differ
diff --git a/samples/browseable/NavigationDrawer/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/NavigationDrawer/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..6ef21e1
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/NavigationDrawer/res/drawable/earth.jpg b/samples/browseable/NavigationDrawer/res/drawable/earth.jpg
new file mode 100644
index 0000000..6cabbf4
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/drawable/earth.jpg
Binary files differ
diff --git a/samples/browseable/NavigationDrawer/res/drawable/jupiter.jpg b/samples/browseable/NavigationDrawer/res/drawable/jupiter.jpg
new file mode 100644
index 0000000..24e8eea
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/drawable/jupiter.jpg
Binary files differ
diff --git a/samples/browseable/NavigationDrawer/res/drawable/mars.jpg b/samples/browseable/NavigationDrawer/res/drawable/mars.jpg
new file mode 100644
index 0000000..db253ef
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/drawable/mars.jpg
Binary files differ
diff --git a/samples/browseable/NavigationDrawer/res/drawable/mercury.jpg b/samples/browseable/NavigationDrawer/res/drawable/mercury.jpg
new file mode 100644
index 0000000..531790b
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/drawable/mercury.jpg
Binary files differ
diff --git a/samples/browseable/NavigationDrawer/res/drawable/neptune.jpg b/samples/browseable/NavigationDrawer/res/drawable/neptune.jpg
new file mode 100644
index 0000000..88467c5
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/drawable/neptune.jpg
Binary files differ
diff --git a/samples/browseable/NavigationDrawer/res/drawable/saturn.jpg b/samples/browseable/NavigationDrawer/res/drawable/saturn.jpg
new file mode 100644
index 0000000..8219d18
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/drawable/saturn.jpg
Binary files differ
diff --git a/samples/browseable/NavigationDrawer/res/drawable/uranus.jpg b/samples/browseable/NavigationDrawer/res/drawable/uranus.jpg
new file mode 100644
index 0000000..fa32e37
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/drawable/uranus.jpg
Binary files differ
diff --git a/samples/browseable/NavigationDrawer/res/drawable/venus.jpg b/samples/browseable/NavigationDrawer/res/drawable/venus.jpg
new file mode 100644
index 0000000..e04f078
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/drawable/venus.jpg
Binary files differ
diff --git a/samples/browseable/NavigationDrawer/res/layout/activity_main.xml b/samples/browseable/NavigationDrawer/res/layout/activity_main.xml
new file mode 100755
index 0000000..88cdb80
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/layout/activity_main.xml
@@ -0,0 +1,41 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <TextView style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/horizontal_page_margin"
+ android:layout_marginRight="@dimen/horizontal_page_margin"
+ android:layout_marginTop="@dimen/vertical_page_margin"
+ android:layout_marginBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+
+ <GridView android:id="@android:id/list"
+ style="@style/Widget.SampleDashboard.Grid"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:paddingLeft="@dimen/horizontal_page_margin"
+ android:paddingRight="@dimen/horizontal_page_margin"
+ android:paddingBottom="@dimen/vertical_page_margin"
+ android:scrollbarStyle="outsideOverlay" />
+
+</LinearLayout>
diff --git a/samples/browseable/NavigationDrawer/res/layout/activity_navigation_drawer.xml b/samples/browseable/NavigationDrawer/res/layout/activity_navigation_drawer.xml
new file mode 100644
index 0000000..4e61639
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/layout/activity_navigation_drawer.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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.
+ -->
+
+
+<!-- A DrawerLayout is intended to be used as the top-level content view using match_parent for both width and height to consume the full space available. -->
+<android.support.v4.widget.DrawerLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/drawer_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <!-- As the main content view, the view below consumes the entire
+ space available using match_parent in both dimensions. -->
+ <FrameLayout
+ android:id="@+id/content_frame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ <!-- android:layout_gravity="start" tells DrawerLayout to treat
+ this as a sliding drawer on the left side for left-to-right
+ languages and on the right side for right-to-left languages.
+ The drawer is given a fixed width in dp and extends the full height of
+ the container. A solid background is used for contrast
+ with the content view. -->
+ <android.support.v7.widget.RecyclerView
+ android:id="@+id/left_drawer"
+ android:scrollbars="vertical"
+ android:layout_width="240dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="left|start"
+ android:choiceMode="singleChoice"
+ android:divider="@null"
+ />
+</android.support.v4.widget.DrawerLayout>
\ No newline at end of file
diff --git a/samples/browseable/NavigationDrawer/res/layout/drawer_list_item.xml b/samples/browseable/NavigationDrawer/res/layout/drawer_list_item.xml
new file mode 100644
index 0000000..6d059ca
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/layout/drawer_list_item.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceListItemSmall"
+ android:gravity="center_vertical"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:textColor="#fff"
+ android:background="?android:attr/activatedBackgroundIndicator"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"/>
diff --git a/samples/browseable/NavigationDrawer/res/layout/fragment_planet.xml b/samples/browseable/NavigationDrawer/res/layout/fragment_planet.xml
new file mode 100644
index 0000000..7471a8f
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/layout/fragment_planet.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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.
+ -->
+
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/image"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/black"
+ android:gravity="center"
+ android:padding="32dp" />
+
diff --git a/samples/browseable/NavigationDrawer/res/layout/sample_dashboard_item.xml b/samples/browseable/NavigationDrawer/res/layout/sample_dashboard_item.xml
new file mode 100644
index 0000000..516d289
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/layout/sample_dashboard_item.xml
@@ -0,0 +1,50 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <!-- The CardView needs to be wrapped to ensure spacing is applied correctly. -->
+
+ <android.support.v7.widget.CardView
+ style="@style/Widget.SampleDashboard.Card"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <LinearLayout
+ style="@style/Widget.SampleDashboard.Item"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@android:id/text1"
+ style="@style/Widget.SampleDashboard.Item.Title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Hello world" />
+
+ <TextView
+ android:id="@android:id/text2"
+ style="@style/Widget.SampleDashboard.Item.Description"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ </LinearLayout>
+
+ </android.support.v7.widget.CardView>
+
+</FrameLayout>
diff --git a/samples/browseable/NavigationDrawer/res/menu/navigation_drawer.xml b/samples/browseable/NavigationDrawer/res/menu/navigation_drawer.xml
new file mode 100644
index 0000000..2549927
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/menu/navigation_drawer.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/action_websearch"
+ android:icon="@drawable/action_search"
+ android:title="@string/action_websearch"
+ android:showAsAction="ifRoom|withText" />
+</menu>
\ No newline at end of file
diff --git a/samples/browseable/NavigationDrawer/res/values-sw600dp/template-dimens.xml b/samples/browseable/NavigationDrawer/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/NavigationDrawer/res/values-sw600dp/template-styles.xml b/samples/browseable/NavigationDrawer/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/NavigationDrawer/res/values-v11/template-styles.xml b/samples/browseable/NavigationDrawer/res/values-v11/template-styles.xml
new file mode 100644
index 0000000..8c1ea66
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/values-v11/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/samples/browseable/NavigationDrawer/res/values-v20/styles.xml b/samples/browseable/NavigationDrawer/res/values-v20/styles.xml
new file mode 100644
index 0000000..01a2e28
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/values-v20/styles.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2014 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>
+ <!-- Base application theme. -->
+ <style name="AppTheme" parent="android:Theme.Material.Light">
+ </style>
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/NavigationDrawer/res/values-v21/template-styles.xml b/samples/browseable/NavigationDrawer/res/values-v21/template-styles.xml
new file mode 100644
index 0000000..134fcd9
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/values-v21/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2014 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>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Material.Light" />
+
+</resources>
diff --git a/samples/browseable/NavigationDrawer/res/values/activitycards-colors.xml b/samples/browseable/NavigationDrawer/res/values/activitycards-colors.xml
new file mode 100644
index 0000000..79605c7
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/values/activitycards-colors.xml
@@ -0,0 +1,21 @@
+<!--
+ Copyright 2014 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>
+ <color name="teal">#009688</color>
+ <color name="black_87">#DD000000</color>
+ <color name="black_54">#89000000</color>
+</resources>
diff --git a/samples/browseable/NavigationDrawer/res/values/activitycards-dimens.xml b/samples/browseable/NavigationDrawer/res/values/activitycards-dimens.xml
new file mode 100644
index 0000000..714cb00
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/values/activitycards-dimens.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <dimen name="card_padding">16dp</dimen>
+ <dimen name="card_margin">8dp</dimen>
+
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/NavigationDrawer/res/values/activitycards-strings.xml b/samples/browseable/NavigationDrawer/res/values/activitycards-strings.xml
new file mode 100644
index 0000000..885a1ec
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/values/activitycards-strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <string name="navigationdraweractivity_title">Navigation Drawer Example</string>
+ <string name="navigationdraweractivity_description">This example illustrates a common usage of the DrawerLayout widget in the Android
+ support library.</string>
+</resources>
diff --git a/samples/browseable/NavigationDrawer/res/values/base-strings.xml b/samples/browseable/NavigationDrawer/res/values/base-strings.xml
new file mode 100644
index 0000000..62e8426
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/values/base-strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">Navigation Drawer</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ This example illustrates a common usage of the DrawerLayout widget in the Android
+ support library.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/NavigationDrawer/res/values/strings.xml b/samples/browseable/NavigationDrawer/res/values/strings.xml
new file mode 100644
index 0000000..7f8de63
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/values/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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-array name="planets_array">
+ <item>Mercury</item>
+ <item>Venus</item>
+ <item>Earth</item>
+ <item>Mars</item>
+ <item>Jupiter</item>
+ <item>Saturn</item>
+ <item>Uranus</item>
+ <item>Neptune</item>
+ </string-array>
+ <string name="drawer_open">Open navigation drawer</string>
+ <string name="drawer_close">Close navigation drawer</string>
+ <string name="action_websearch">Web search</string>
+ <string name="app_not_available">Sorry, there\'s no web browser available</string>
+</resources>
diff --git a/samples/browseable/NavigationDrawer/res/values/template-dimens.xml b/samples/browseable/NavigationDrawer/res/values/template-dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/NavigationDrawer/res/values/template-styles.xml b/samples/browseable/NavigationDrawer/res/values/template-styles.xml
new file mode 100644
index 0000000..374dc51
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/res/values/template-styles.xml
@@ -0,0 +1,76 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleContentContainer">
+ <item name="android:paddingTop">@dimen/vertical_page_margin</item>
+ <item name="android:paddingBottom">@dimen/vertical_page_margin</item>
+ <item name="android:paddingLeft">@dimen/horizontal_page_margin</item>
+ <item name="android:paddingRight">@dimen/horizontal_page_margin</item>
+ </style>
+
+<style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ <item name="android:textColor">@color/black_54</item>
+ </style>
+
+ <style name="Widget.SampleDashboard.Grid" parent="Widget">
+ <item name="android:stretchMode">columnWidth</item>
+ <item name="android:columnWidth">200dp</item>
+ <item name="android:numColumns">auto_fit</item>
+ <item name="android:drawSelectorOnTop">true</item>
+ <item name="android:horizontalSpacing">0dp</item>
+ <item name="android:verticalSpacing">0dp</item>
+ </style>
+
+ <style name="Widget.SampleDashboard.Card" parent="Widget">
+ <item name="android:gravity">center</item>
+ <item name="android:layout_margin">@dimen/card_margin</item>
+ <item name="cardCornerRadius">4dp</item>
+ <item name="cardElevation">5dp</item>
+ <item name="contentPadding">@dimen/card_padding</item>
+ </style>
+
+ <style name="Widget.SampleDashboard.Item" parent="Widget">
+ </style>
+
+ <style name="Widget.SampleDashboard.Item.Title" parent="Widget">
+ <item name="android:layout_marginBottom">@dimen/margin_tiny</item>
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:textColor">@color/teal</item>
+ <item name="android:fontFamily">sans-serif</item>
+ <item name="android:textSize">24sp</item>
+ </style>
+
+ <style name="Widget.SampleDashboard.Item.Description" parent="Widget">
+ <item name="android:textAppearance">?android:textAppearanceSmall</item>
+ <item name="android:fontFamily">sans-serif-light</item>
+ <item name="android:textColor">@color/black_87</item>
+ </style>
+</resources>
diff --git a/samples/browseable/NavigationDrawer/src/com.example.android.common.logger/Log.java b/samples/browseable/NavigationDrawer/src/com.example.android.common.logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/src/com.example.android.common.logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+ // Grabbing the native values from Android's native logging facilities,
+ // to make for easy migration and interop.
+ public static final int NONE = -1;
+ public static final int VERBOSE = android.util.Log.VERBOSE;
+ public static final int DEBUG = android.util.Log.DEBUG;
+ public static final int INFO = android.util.Log.INFO;
+ public static final int WARN = android.util.Log.WARN;
+ public static final int ERROR = android.util.Log.ERROR;
+ public static final int ASSERT = android.util.Log.ASSERT;
+
+ // Stores the beginning of the LogNode topology.
+ private static LogNode mLogNode;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public static LogNode getLogNode() {
+ return mLogNode;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to.
+ */
+ public static void setLogNode(LogNode node) {
+ mLogNode = node;
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void println(int priority, String tag, String msg, Throwable tr) {
+ if (mLogNode != null) {
+ mLogNode.println(priority, tag, msg, tr);
+ }
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ */
+ public static void println(int priority, String tag, String msg) {
+ println(priority, tag, msg, null);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void v(String tag, String msg, Throwable tr) {
+ println(VERBOSE, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void v(String tag, String msg) {
+ v(tag, msg, null);
+ }
+
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void d(String tag, String msg, Throwable tr) {
+ println(DEBUG, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void d(String tag, String msg) {
+ d(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void i(String tag, String msg, Throwable tr) {
+ println(INFO, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void i(String tag, String msg) {
+ i(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, String msg, Throwable tr) {
+ println(WARN, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void w(String tag, String msg) {
+ w(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, Throwable tr) {
+ w(tag, null, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void e(String tag, String msg, Throwable tr) {
+ println(ERROR, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void e(String tag, String msg) {
+ e(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, String msg, Throwable tr) {
+ println(ASSERT, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void wtf(String tag, String msg) {
+ wtf(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, Throwable tr) {
+ wtf(tag, null, tr);
+ }
+}
diff --git a/samples/browseable/NavigationDrawer/src/com.example.android.common.logger/LogFragment.java b/samples/browseable/NavigationDrawer/src/com.example.android.common.logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/src/com.example.android.common.logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+ private LogView mLogView;
+ private ScrollView mScrollView;
+
+ public LogFragment() {}
+
+ public View inflateViews() {
+ mScrollView = new ScrollView(getActivity());
+ ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ mScrollView.setLayoutParams(scrollParams);
+
+ mLogView = new LogView(getActivity());
+ ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+ logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ mLogView.setLayoutParams(logParams);
+ mLogView.setClickable(true);
+ mLogView.setFocusable(true);
+ mLogView.setTypeface(Typeface.MONOSPACE);
+
+ // Want to set padding as 16 dips, setPadding takes pixels. Hooray math!
+ int paddingDips = 16;
+ double scale = getResources().getDisplayMetrics().density;
+ int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+ mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+ mLogView.setCompoundDrawablePadding(paddingPixels);
+
+ mLogView.setGravity(Gravity.BOTTOM);
+ mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+ mScrollView.addView(mLogView);
+ return mScrollView;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ View result = inflateViews();
+
+ mLogView.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+ }
+ });
+ return result;
+ }
+
+ public LogView getLogView() {
+ return mLogView;
+ }
+}
\ No newline at end of file
diff --git a/samples/browseable/NavigationDrawer/src/com.example.android.common.logger/LogNode.java b/samples/browseable/NavigationDrawer/src/com.example.android.common.logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/src/com.example.android.common.logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 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.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+ /**
+ * Instructs first LogNode in the list to print the log data provided.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/NavigationDrawer/src/com.example.android.common.logger/LogView.java b/samples/browseable/NavigationDrawer/src/com.example.android.common.logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/src/com.example.android.common.logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+ public LogView(Context context) {
+ super(context);
+ }
+
+ public LogView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public LogView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * Formats the log data and prints it out to the LogView.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+
+
+ String priorityStr = null;
+
+ // For the purposes of this View, we want to print the priority as readable text.
+ switch(priority) {
+ case android.util.Log.VERBOSE:
+ priorityStr = "VERBOSE";
+ break;
+ case android.util.Log.DEBUG:
+ priorityStr = "DEBUG";
+ break;
+ case android.util.Log.INFO:
+ priorityStr = "INFO";
+ break;
+ case android.util.Log.WARN:
+ priorityStr = "WARN";
+ break;
+ case android.util.Log.ERROR:
+ priorityStr = "ERROR";
+ break;
+ case android.util.Log.ASSERT:
+ priorityStr = "ASSERT";
+ break;
+ default:
+ break;
+ }
+
+ // Handily, the Log class has a facility for converting a stack trace into a usable string.
+ String exceptionStr = null;
+ if (tr != null) {
+ exceptionStr = android.util.Log.getStackTraceString(tr);
+ }
+
+ // Take the priority, tag, message, and exception, and concatenate as necessary
+ // into one usable line of text.
+ final StringBuilder outputBuilder = new StringBuilder();
+
+ String delimiter = "\t";
+ appendIfNotNull(outputBuilder, priorityStr, delimiter);
+ appendIfNotNull(outputBuilder, tag, delimiter);
+ appendIfNotNull(outputBuilder, msg, delimiter);
+ appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+ // In case this was originally called from an AsyncTask or some other off-UI thread,
+ // make sure the update occurs within the UI thread.
+ ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+ @Override
+ public void run() {
+ // Display the text we just generated within the LogView.
+ appendToLog(outputBuilder.toString());
+ }
+ })));
+
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+ * the logger takes so many arguments that might be null, this method helps cut out some of the
+ * agonizing tedium of writing the same 3 lines over and over.
+ * @param source StringBuilder containing the text to append to.
+ * @param addStr The String to append
+ * @param delimiter The String to separate the source and appended strings. A tab or comma,
+ * for instance.
+ * @return The fully concatenated String as a StringBuilder
+ */
+ private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+ if (addStr != null) {
+ if (addStr.length() == 0) {
+ delimiter = "";
+ }
+
+ return source.append(addStr).append(delimiter);
+ }
+ return source;
+ }
+
+ // The next LogNode in the chain.
+ LogNode mNext;
+
+ /** Outputs the string as a new line of log data in the LogView. */
+ public void appendToLog(String s) {
+ append("\n" + s);
+ }
+
+
+}
diff --git a/samples/browseable/NavigationDrawer/src/com.example.android.common.logger/LogWrapper.java b/samples/browseable/NavigationDrawer/src/com.example.android.common.logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/src/com.example.android.common.logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 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.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface. This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+ // For piping: The next node to receive Log data after this one has done its work.
+ private LogNode mNext;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /**
+ * Prints data out to the console using Android's native log mechanism.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ // There actually are log methods that don't take a msg parameter. For now,
+ // if that's the case, just convert null to the empty string and move on.
+ String useMsg = msg;
+ if (useMsg == null) {
+ useMsg = "";
+ }
+
+ // If an exeption was provided, convert that exception to a usable string and attach
+ // it to the end of the msg method.
+ if (tr != null) {
+ msg += "\n" + Log.getStackTraceString(tr);
+ }
+
+ // This is functionally identical to Log.x(tag, useMsg);
+ // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+ Log.println(priority, tag, useMsg);
+
+ // If this isn't the last node in the chain, move things along.
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+}
diff --git a/samples/browseable/NavigationDrawer/src/com.example.android.common.logger/MessageOnlyLogFilter.java b/samples/browseable/NavigationDrawer/src/com.example.android.common.logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/src/com.example.android.common.logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+ LogNode mNext;
+
+ /**
+ * Takes the "next" LogNode as a parameter, to simplify chaining.
+ *
+ * @param next The next LogNode in the pipeline.
+ */
+ public MessageOnlyLogFilter(LogNode next) {
+ mNext = next;
+ }
+
+ public MessageOnlyLogFilter() {
+ }
+
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ if (mNext != null) {
+ getNext().println(Log.NONE, null, msg, null);
+ }
+ }
+
+ /**
+ * Returns the next LogNode in the chain.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+}
diff --git a/samples/browseable/NavigationDrawer/src/com.example.android.navigationdrawer/MainActivity.java b/samples/browseable/NavigationDrawer/src/com.example.android.navigationdrawer/MainActivity.java
new file mode 100644
index 0000000..665edf3
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/src/com.example.android.navigationdrawer/MainActivity.java
@@ -0,0 +1,107 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.navigationdrawer;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.GridView;
+import android.widget.TextView;
+
+/**
+ * A simple launcher activity offering access to the individual samples in this project.
+ */
+public class MainActivity extends Activity implements AdapterView.OnItemClickListener {
+ private Sample[] mSamples;
+ private GridView mGridView;
+
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ // Prepare list of samples in this dashboard.
+ mSamples = new Sample[]{
+ new Sample(R.string.navigationdraweractivity_title, R.string.navigationdraweractivity_description,
+ NavigationDrawerActivity.class),
+ };
+
+ // Prepare the GridView
+ mGridView = (GridView) findViewById(android.R.id.list);
+ mGridView.setAdapter(new SampleAdapter());
+ mGridView.setOnItemClickListener(this);
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> container, View view, int position, long id) {
+ startActivity(mSamples[position].intent);
+ }
+
+ private class SampleAdapter extends BaseAdapter {
+ @Override
+ public int getCount() {
+ return mSamples.length;
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return mSamples[position];
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return mSamples[position].hashCode();
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup container) {
+ if (convertView == null) {
+ convertView = getLayoutInflater().inflate(R.layout.sample_dashboard_item,
+ container, false);
+ }
+
+ ((TextView) convertView.findViewById(android.R.id.text1)).setText(
+ mSamples[position].titleResId);
+ ((TextView) convertView.findViewById(android.R.id.text2)).setText(
+ mSamples[position].descriptionResId);
+ return convertView;
+ }
+ }
+
+ private class Sample {
+ int titleResId;
+ int descriptionResId;
+ Intent intent;
+
+ private Sample(int titleResId, int descriptionResId, Intent intent) {
+ this.intent = intent;
+ this.titleResId = titleResId;
+ this.descriptionResId = descriptionResId;
+ }
+
+ private Sample(int titleResId, int descriptionResId,
+ Class<? extends Activity> activityClass) {
+ this(titleResId, descriptionResId,
+ new Intent(MainActivity.this, activityClass));
+ }
+ }
+}
diff --git a/samples/browseable/NavigationDrawer/src/com.example.android.navigationdrawer/NavigationDrawerActivity.java b/samples/browseable/NavigationDrawer/src/com.example.android.navigationdrawer/NavigationDrawerActivity.java
new file mode 100644
index 0000000..1176757
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/src/com.example.android.navigationdrawer/NavigationDrawerActivity.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2014 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.navigationdrawer;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.app.SearchManager;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.support.v4.app.ActionBarDrawerToggle;
+import android.support.v4.view.GravityCompat;
+import android.support.v4.widget.DrawerLayout;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.Toast;
+
+import java.util.Locale;
+
+/**
+ * This example illustrates a common usage of the DrawerLayout widget
+ * in the Android support library.
+ * <p/>
+ * <p>When a navigation (left) drawer is present, the host activity should detect presses of
+ * the action bar's Up affordance as a signal to open and close the navigation drawer. The
+ * ActionBarDrawerToggle facilitates this behavior.
+ * Items within the drawer should fall into one of two categories:</p>
+ * <p/>
+ * <ul>
+ * <li><strong>View switches</strong>. A view switch follows the same basic policies as
+ * list or tab navigation in that a view switch does not create navigation history.
+ * This pattern should only be used at the root activity of a task, leaving some form
+ * of Up navigation active for activities further down the navigation hierarchy.</li>
+ * <li><strong>Selective Up</strong>. The drawer allows the user to choose an alternate
+ * parent for Up navigation. This allows a user to jump across an app's navigation
+ * hierarchy at will. The application should treat this as it treats Up navigation from
+ * a different task, replacing the current task stack using TaskStackBuilder or similar.
+ * This is the only form of navigation drawer that should be used outside of the root
+ * activity of a task.</li>
+ * </ul>
+ * <p/>
+ * <p>Right side drawers should be used for actions, not navigation. This follows the pattern
+ * established by the Action Bar that navigation should be to the left and actions to the right.
+ * An action should be an operation performed on the current contents of the window,
+ * for example enabling or disabling a data overlay on top of the current content.</p>
+ */
+public class NavigationDrawerActivity extends Activity implements PlanetAdapter.OnItemClickListener {
+ private DrawerLayout mDrawerLayout;
+ private RecyclerView mDrawerList;
+ private ActionBarDrawerToggle mDrawerToggle;
+
+ private CharSequence mDrawerTitle;
+ private CharSequence mTitle;
+ private String[] mPlanetTitles;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_navigation_drawer);
+
+ mTitle = mDrawerTitle = getTitle();
+ mPlanetTitles = getResources().getStringArray(R.array.planets_array);
+ mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
+ mDrawerList = (RecyclerView) findViewById(R.id.left_drawer);
+
+ // set a custom shadow that overlays the main content when the drawer opens
+ mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
+ // improve performance by indicating the list if fixed size.
+ mDrawerList.setHasFixedSize(true);
+ mDrawerList.setLayoutManager(new LinearLayoutManager(this));
+
+ // set up the drawer's list view with items and click listener
+ mDrawerList.setAdapter(new PlanetAdapter(mPlanetTitles, this));
+ // enable ActionBar app icon to behave as action to toggle nav drawer
+ getActionBar().setDisplayHomeAsUpEnabled(true);
+ getActionBar().setHomeButtonEnabled(true);
+
+ // ActionBarDrawerToggle ties together the the proper interactions
+ // between the sliding drawer and the action bar app icon
+ mDrawerToggle = new ActionBarDrawerToggle(
+ this, /* host Activity */
+ mDrawerLayout, /* DrawerLayout object */
+ R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */
+ R.string.drawer_open, /* "open drawer" description for accessibility */
+ R.string.drawer_close /* "close drawer" description for accessibility */
+ ) {
+ public void onDrawerClosed(View view) {
+ getActionBar().setTitle(mTitle);
+ invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
+ }
+
+ public void onDrawerOpened(View drawerView) {
+ getActionBar().setTitle(mDrawerTitle);
+ invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
+ }
+ };
+ mDrawerLayout.setDrawerListener(mDrawerToggle);
+
+ if (savedInstanceState == null) {
+ selectItem(0);
+ }
+ }
+
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ getMenuInflater().inflate(R.menu.navigation_drawer, menu);
+ return true;
+ }
+
+ /* Called whenever we call invalidateOptionsMenu() */
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ // If the nav drawer is open, hide action items related to the content view
+ boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
+ menu.findItem(R.id.action_websearch).setVisible(!drawerOpen);
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ // The action bar home/up action should open or close the drawer.
+ // ActionBarDrawerToggle will take care of this.
+ if (mDrawerToggle.onOptionsItemSelected(item)) {
+ return true;
+ }
+ // Handle action buttons
+ switch (item.getItemId()) {
+ case R.id.action_websearch:
+ // create intent to perform web search for this planet
+ Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
+ intent.putExtra(SearchManager.QUERY, getActionBar().getTitle());
+ // catch event that there's no activity to handle intent
+ if (intent.resolveActivity(getPackageManager()) != null) {
+ startActivity(intent);
+ } else {
+ Toast.makeText(this, R.string.app_not_available, Toast.LENGTH_LONG).show();
+ }
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ /* The click listener for RecyclerView in the navigation drawer */
+ @Override
+ public void onClick(View view, int position) {
+ selectItem(position);
+ }
+
+ private void selectItem(int position) {
+ // update the main content by replacing fragments
+ Fragment fragment = PlanetFragment.newInstance(position);
+
+ FragmentManager fragmentManager = getFragmentManager();
+ FragmentTransaction ft = fragmentManager.beginTransaction();
+ ft.replace(R.id.content_frame, fragment);
+ ft.commit();
+
+ // update selected item title, then close the drawer
+ setTitle(mPlanetTitles[position]);
+ mDrawerLayout.closeDrawer(mDrawerList);
+ }
+
+ @Override
+ public void setTitle(CharSequence title) {
+ mTitle = title;
+ getActionBar().setTitle(mTitle);
+ }
+
+ /**
+ * When using the ActionBarDrawerToggle, you must call it during
+ * onPostCreate() and onConfigurationChanged()...
+ */
+
+ @Override
+ protected void onPostCreate(Bundle savedInstanceState) {
+ super.onPostCreate(savedInstanceState);
+ // Sync the toggle state after onRestoreInstanceState has occurred.
+ mDrawerToggle.syncState();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ // Pass any configuration change to the drawer toggls
+ mDrawerToggle.onConfigurationChanged(newConfig);
+ }
+
+ /**
+ * Fragment that appears in the "content_frame", shows a planet
+ */
+ public static class PlanetFragment extends Fragment {
+ public static final String ARG_PLANET_NUMBER = "planet_number";
+
+ public PlanetFragment() {
+ // Empty constructor required for fragment subclasses
+ }
+
+ public static Fragment newInstance(int position) {
+ Fragment fragment = new PlanetFragment();
+ Bundle args = new Bundle();
+ args.putInt(PlanetFragment.ARG_PLANET_NUMBER, position);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View rootView = inflater.inflate(R.layout.fragment_planet, container, false);
+ int i = getArguments().getInt(ARG_PLANET_NUMBER);
+ String planet = getResources().getStringArray(R.array.planets_array)[i];
+
+ int imageId = getResources().getIdentifier(planet.toLowerCase(Locale.getDefault()),
+ "drawable", getActivity().getPackageName());
+ ImageView iv = ((ImageView) rootView.findViewById(R.id.image));
+ iv.setImageResource(imageId);
+
+ getActivity().setTitle(planet);
+ return rootView;
+ }
+ }
+}
diff --git a/samples/browseable/NavigationDrawer/src/com.example.android.navigationdrawer/PlanetAdapter.java b/samples/browseable/NavigationDrawer/src/com.example.android.navigationdrawer/PlanetAdapter.java
new file mode 100644
index 0000000..5b449d0
--- /dev/null
+++ b/samples/browseable/NavigationDrawer/src/com.example.android.navigationdrawer/PlanetAdapter.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2014 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.navigationdrawer;
+
+import android.content.Context;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.TextView;
+
+/**
+ * Adapter for the planet data used in our drawer menu,
+ */
+public class PlanetAdapter extends RecyclerView.Adapter<PlanetAdapter.ViewHolder> {
+ private String[] mDataset;
+ private OnItemClickListener mListener;
+
+ /**
+ * Interface for receiving click events from cells.
+ */
+ public interface OnItemClickListener {
+ public void onClick(View view, int position);
+ }
+
+ /**
+ * Custom viewholder for our planet views.
+ */
+ public static class ViewHolder extends RecyclerView.ViewHolder {
+ public final TextView mTextView;
+
+ public ViewHolder(TextView v) {
+ super(v);
+ mTextView = v;
+ }
+ }
+
+ public PlanetAdapter(String[] myDataset, OnItemClickListener listener) {
+ mDataset = myDataset;
+ mListener = listener;
+ }
+
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ LayoutInflater vi = LayoutInflater.from(parent.getContext());
+ View v = vi.inflate(R.layout.drawer_list_item, parent, false);
+ TextView tv = (TextView) v.findViewById(android.R.id.text1);
+ return new ViewHolder(tv);
+ }
+
+ @Override
+ public void onBindViewHolder(ViewHolder holder, final int position) {
+ holder.mTextView.setText(mDataset[position]);
+ holder.mTextView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ mListener.onClick(view, position);
+ }
+ });
+ }
+
+ @Override
+ public int getItemCount() {
+ return mDataset.length;
+ }
+}
diff --git a/samples/browseable/RecyclerView/AndroidManifest.xml b/samples/browseable/RecyclerView/AndroidManifest.xml
new file mode 100644
index 0000000..2870f1e
--- /dev/null
+++ b/samples/browseable/RecyclerView/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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.recyclerview"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
+ <application android:allowBackup="true"
+ android:label="@string/app_name"
+ android:icon="@drawable/ic_launcher"
+ android:theme="@style/AppTheme">
+
+ <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>
+ </application>
+
+
+</manifest>
diff --git a/samples/browseable/RecyclerView/_index.jd b/samples/browseable/RecyclerView/_index.jd
new file mode 100644
index 0000000..e4e2534
--- /dev/null
+++ b/samples/browseable/RecyclerView/_index.jd
@@ -0,0 +1,9 @@
+page.tags="RecyclerView"
+sample.group=UI
+@jd:body
+
+<p>
+
+ Demonstration of using RecyclerView with a LayoutManager to create a vertical ListView.
+
+ </p>
diff --git a/samples/browseable/RecyclerView/res/drawable-hdpi/ic_launcher.png b/samples/browseable/RecyclerView/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..bcb72b1
--- /dev/null
+++ b/samples/browseable/RecyclerView/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/RecyclerView/res/drawable-hdpi/tile.9.png b/samples/browseable/RecyclerView/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/RecyclerView/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/RecyclerView/res/drawable-mdpi/ic_launcher.png b/samples/browseable/RecyclerView/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..37e5bce
--- /dev/null
+++ b/samples/browseable/RecyclerView/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/RecyclerView/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/RecyclerView/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..1c4a85a
--- /dev/null
+++ b/samples/browseable/RecyclerView/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/RecyclerView/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/RecyclerView/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b26545c
--- /dev/null
+++ b/samples/browseable/RecyclerView/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/RecyclerView/res/layout-w720dp/activity_main.xml b/samples/browseable/RecyclerView/res/layout-w720dp/activity_main.xml
new file mode 100755
index 0000000..c9a52f6
--- /dev/null
+++ b/samples/browseable/RecyclerView/res/layout-w720dp/activity_main.xml
@@ -0,0 +1,73 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<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/sample_main_layout">
+
+ <LinearLayout
+ android:id="@+id/sample_output"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <FrameLayout
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/margin_medium"
+ android:paddingRight="@dimen/margin_medium"
+ android:paddingTop="@dimen/margin_large"
+ android:paddingBottom="@dimen/margin_large"
+ android:text="@string/intro_message" />
+ </FrameLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1" />
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="0px"
+ android:layout_height="match_parent" />
+
+</LinearLayout>
+
+
diff --git a/samples/browseable/RecyclerView/res/layout/activity_main.xml b/samples/browseable/RecyclerView/res/layout/activity_main.xml
new file mode 100755
index 0000000..1ae4f98
--- /dev/null
+++ b/samples/browseable/RecyclerView/res/layout/activity_main.xml
@@ -0,0 +1,65 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<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/sample_main_layout">
+
+ <ViewAnimator
+ android:id="@+id/sample_output"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1">
+
+ <ScrollView
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/horizontal_page_margin"
+ android:paddingRight="@dimen/horizontal_page_margin"
+ android:paddingTop="@dimen/vertical_page_margin"
+ android:paddingBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </ScrollView>
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ </ViewAnimator>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="match_parent"
+ android:layout_height="0px" />
+
+</LinearLayout>
+
diff --git a/samples/browseable/RecyclerView/res/layout/recycler_view_frag.xml b/samples/browseable/RecyclerView/res/layout/recycler_view_frag.xml
new file mode 100644
index 0000000..6682468
--- /dev/null
+++ b/samples/browseable/RecyclerView/res/layout/recycler_view_frag.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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:orientation="vertical">
+
+ <android.support.v7.widget.RecyclerView
+ android:id="@+id/recyclerView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+</FrameLayout>
diff --git a/samples/browseable/RecyclerView/res/layout/text_row_item.xml b/samples/browseable/RecyclerView/res/layout/text_row_item.xml
new file mode 100644
index 0000000..d552e0e
--- /dev/null
+++ b/samples/browseable/RecyclerView/res/layout/text_row_item.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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_margin="@dimen/margin_small"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/element_text"
+ android:id="@+id/textView"
+ android:layout_gravity="center_horizontal"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/browseable/RecyclerView/res/menu/main.xml b/samples/browseable/RecyclerView/res/menu/main.xml
new file mode 100644
index 0000000..b49c2c5
--- /dev/null
+++ b/samples/browseable/RecyclerView/res/menu/main.xml
@@ -0,0 +1,21 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/menu_toggle_log"
+ android:showAsAction="always"
+ android:title="@string/sample_show_log" />
+</menu>
diff --git a/samples/browseable/RecyclerView/res/values-sw600dp/template-dimens.xml b/samples/browseable/RecyclerView/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/RecyclerView/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/RecyclerView/res/values-sw600dp/template-styles.xml b/samples/browseable/RecyclerView/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/RecyclerView/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/RecyclerView/res/values-v11/template-styles.xml b/samples/browseable/RecyclerView/res/values-v11/template-styles.xml
new file mode 100644
index 0000000..8c1ea66
--- /dev/null
+++ b/samples/browseable/RecyclerView/res/values-v11/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/samples/browseable/RecyclerView/res/values-v21/template-styles.xml b/samples/browseable/RecyclerView/res/values-v21/template-styles.xml
new file mode 100644
index 0000000..134fcd9
--- /dev/null
+++ b/samples/browseable/RecyclerView/res/values-v21/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2014 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>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Material.Light" />
+
+</resources>
diff --git a/samples/browseable/RecyclerView/res/values/base-strings.xml b/samples/browseable/RecyclerView/res/values/base-strings.xml
new file mode 100644
index 0000000..b6efd8e
--- /dev/null
+++ b/samples/browseable/RecyclerView/res/values/base-strings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">RecyclerView</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ Demonstration of using RecyclerView with a LayoutManager to create a vertical ListView.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/RecyclerView/res/values/fragmentview_strings.xml b/samples/browseable/RecyclerView/res/values/fragmentview_strings.xml
new file mode 100755
index 0000000..7b9d9ec
--- /dev/null
+++ b/samples/browseable/RecyclerView/res/values/fragmentview_strings.xml
@@ -0,0 +1,19 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="sample_show_log">Show Log</string>
+ <string name="sample_hide_log">Hide Log</string>
+</resources>
diff --git a/samples/browseable/RecyclerView/res/values/strings.xml b/samples/browseable/RecyclerView/res/values/strings.xml
new file mode 100644
index 0000000..179529c
--- /dev/null
+++ b/samples/browseable/RecyclerView/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 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="element_text">Element</string>
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/RecyclerView/res/values/template-dimens.xml b/samples/browseable/RecyclerView/res/values/template-dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/RecyclerView/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/RecyclerView/res/values/template-styles.xml b/samples/browseable/RecyclerView/res/values/template-styles.xml
new file mode 100644
index 0000000..6e7d593
--- /dev/null
+++ b/samples/browseable/RecyclerView/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/RecyclerView/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/RecyclerView/src/com.example.android.common/activities/SampleActivityBase.java
new file mode 100644
index 0000000..3228927
--- /dev/null
+++ b/samples/browseable/RecyclerView/src/com.example.android.common/activities/SampleActivityBase.java
@@ -0,0 +1,52 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.common.activities;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogWrapper;
+
+/**
+ * Base launcher activity, to handle most of the common plumbing for samples.
+ */
+public class SampleActivityBase extends FragmentActivity {
+
+ public static final String TAG = "SampleActivityBase";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ initializeLogging();
+ }
+
+ /** Set up targets to receive log data */
+ public void initializeLogging() {
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ // Wraps Android's native log framework
+ LogWrapper logWrapper = new LogWrapper();
+ Log.setLogNode(logWrapper);
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/RecyclerView/src/com.example.android.common/logger/Log.java b/samples/browseable/RecyclerView/src/com.example.android.common/logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/RecyclerView/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+ // Grabbing the native values from Android's native logging facilities,
+ // to make for easy migration and interop.
+ public static final int NONE = -1;
+ public static final int VERBOSE = android.util.Log.VERBOSE;
+ public static final int DEBUG = android.util.Log.DEBUG;
+ public static final int INFO = android.util.Log.INFO;
+ public static final int WARN = android.util.Log.WARN;
+ public static final int ERROR = android.util.Log.ERROR;
+ public static final int ASSERT = android.util.Log.ASSERT;
+
+ // Stores the beginning of the LogNode topology.
+ private static LogNode mLogNode;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public static LogNode getLogNode() {
+ return mLogNode;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to.
+ */
+ public static void setLogNode(LogNode node) {
+ mLogNode = node;
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void println(int priority, String tag, String msg, Throwable tr) {
+ if (mLogNode != null) {
+ mLogNode.println(priority, tag, msg, tr);
+ }
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ */
+ public static void println(int priority, String tag, String msg) {
+ println(priority, tag, msg, null);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void v(String tag, String msg, Throwable tr) {
+ println(VERBOSE, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void v(String tag, String msg) {
+ v(tag, msg, null);
+ }
+
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void d(String tag, String msg, Throwable tr) {
+ println(DEBUG, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void d(String tag, String msg) {
+ d(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void i(String tag, String msg, Throwable tr) {
+ println(INFO, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void i(String tag, String msg) {
+ i(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, String msg, Throwable tr) {
+ println(WARN, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void w(String tag, String msg) {
+ w(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, Throwable tr) {
+ w(tag, null, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void e(String tag, String msg, Throwable tr) {
+ println(ERROR, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void e(String tag, String msg) {
+ e(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, String msg, Throwable tr) {
+ println(ASSERT, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void wtf(String tag, String msg) {
+ wtf(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, Throwable tr) {
+ wtf(tag, null, tr);
+ }
+}
diff --git a/samples/browseable/RecyclerView/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/RecyclerView/src/com.example.android.common/logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/RecyclerView/src/com.example.android.common/logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+ private LogView mLogView;
+ private ScrollView mScrollView;
+
+ public LogFragment() {}
+
+ public View inflateViews() {
+ mScrollView = new ScrollView(getActivity());
+ ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ mScrollView.setLayoutParams(scrollParams);
+
+ mLogView = new LogView(getActivity());
+ ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+ logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ mLogView.setLayoutParams(logParams);
+ mLogView.setClickable(true);
+ mLogView.setFocusable(true);
+ mLogView.setTypeface(Typeface.MONOSPACE);
+
+ // Want to set padding as 16 dips, setPadding takes pixels. Hooray math!
+ int paddingDips = 16;
+ double scale = getResources().getDisplayMetrics().density;
+ int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+ mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+ mLogView.setCompoundDrawablePadding(paddingPixels);
+
+ mLogView.setGravity(Gravity.BOTTOM);
+ mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+ mScrollView.addView(mLogView);
+ return mScrollView;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ View result = inflateViews();
+
+ mLogView.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+ }
+ });
+ return result;
+ }
+
+ public LogView getLogView() {
+ return mLogView;
+ }
+}
\ No newline at end of file
diff --git a/samples/browseable/RecyclerView/src/com.example.android.common/logger/LogNode.java b/samples/browseable/RecyclerView/src/com.example.android.common/logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/RecyclerView/src/com.example.android.common/logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 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.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+ /**
+ * Instructs first LogNode in the list to print the log data provided.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/RecyclerView/src/com.example.android.common/logger/LogView.java b/samples/browseable/RecyclerView/src/com.example.android.common/logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/RecyclerView/src/com.example.android.common/logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+ public LogView(Context context) {
+ super(context);
+ }
+
+ public LogView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public LogView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * Formats the log data and prints it out to the LogView.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+
+
+ String priorityStr = null;
+
+ // For the purposes of this View, we want to print the priority as readable text.
+ switch(priority) {
+ case android.util.Log.VERBOSE:
+ priorityStr = "VERBOSE";
+ break;
+ case android.util.Log.DEBUG:
+ priorityStr = "DEBUG";
+ break;
+ case android.util.Log.INFO:
+ priorityStr = "INFO";
+ break;
+ case android.util.Log.WARN:
+ priorityStr = "WARN";
+ break;
+ case android.util.Log.ERROR:
+ priorityStr = "ERROR";
+ break;
+ case android.util.Log.ASSERT:
+ priorityStr = "ASSERT";
+ break;
+ default:
+ break;
+ }
+
+ // Handily, the Log class has a facility for converting a stack trace into a usable string.
+ String exceptionStr = null;
+ if (tr != null) {
+ exceptionStr = android.util.Log.getStackTraceString(tr);
+ }
+
+ // Take the priority, tag, message, and exception, and concatenate as necessary
+ // into one usable line of text.
+ final StringBuilder outputBuilder = new StringBuilder();
+
+ String delimiter = "\t";
+ appendIfNotNull(outputBuilder, priorityStr, delimiter);
+ appendIfNotNull(outputBuilder, tag, delimiter);
+ appendIfNotNull(outputBuilder, msg, delimiter);
+ appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+ // In case this was originally called from an AsyncTask or some other off-UI thread,
+ // make sure the update occurs within the UI thread.
+ ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+ @Override
+ public void run() {
+ // Display the text we just generated within the LogView.
+ appendToLog(outputBuilder.toString());
+ }
+ })));
+
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+ * the logger takes so many arguments that might be null, this method helps cut out some of the
+ * agonizing tedium of writing the same 3 lines over and over.
+ * @param source StringBuilder containing the text to append to.
+ * @param addStr The String to append
+ * @param delimiter The String to separate the source and appended strings. A tab or comma,
+ * for instance.
+ * @return The fully concatenated String as a StringBuilder
+ */
+ private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+ if (addStr != null) {
+ if (addStr.length() == 0) {
+ delimiter = "";
+ }
+
+ return source.append(addStr).append(delimiter);
+ }
+ return source;
+ }
+
+ // The next LogNode in the chain.
+ LogNode mNext;
+
+ /** Outputs the string as a new line of log data in the LogView. */
+ public void appendToLog(String s) {
+ append("\n" + s);
+ }
+
+
+}
diff --git a/samples/browseable/RecyclerView/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/RecyclerView/src/com.example.android.common/logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/RecyclerView/src/com.example.android.common/logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 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.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface. This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+ // For piping: The next node to receive Log data after this one has done its work.
+ private LogNode mNext;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /**
+ * Prints data out to the console using Android's native log mechanism.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ // There actually are log methods that don't take a msg parameter. For now,
+ // if that's the case, just convert null to the empty string and move on.
+ String useMsg = msg;
+ if (useMsg == null) {
+ useMsg = "";
+ }
+
+ // If an exeption was provided, convert that exception to a usable string and attach
+ // it to the end of the msg method.
+ if (tr != null) {
+ msg += "\n" + Log.getStackTraceString(tr);
+ }
+
+ // This is functionally identical to Log.x(tag, useMsg);
+ // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+ Log.println(priority, tag, useMsg);
+
+ // If this isn't the last node in the chain, move things along.
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+}
diff --git a/samples/browseable/RecyclerView/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/RecyclerView/src/com.example.android.common/logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/RecyclerView/src/com.example.android.common/logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+ LogNode mNext;
+
+ /**
+ * Takes the "next" LogNode as a parameter, to simplify chaining.
+ *
+ * @param next The next LogNode in the pipeline.
+ */
+ public MessageOnlyLogFilter(LogNode next) {
+ mNext = next;
+ }
+
+ public MessageOnlyLogFilter() {
+ }
+
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ if (mNext != null) {
+ getNext().println(Log.NONE, null, msg, null);
+ }
+ }
+
+ /**
+ * Returns the next LogNode in the chain.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+}
diff --git a/samples/browseable/RecyclerView/src/com.example.android.recyclerview/CustomAdapter.java b/samples/browseable/RecyclerView/src/com.example.android.recyclerview/CustomAdapter.java
new file mode 100644
index 0000000..f8e3bae
--- /dev/null
+++ b/samples/browseable/RecyclerView/src/com.example.android.recyclerview/CustomAdapter.java
@@ -0,0 +1,91 @@
+/*
+* Copyright (C) 2014 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.recyclerview;
+
+import com.example.android.common.logger.Log;
+
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+/**
+ * Provide views to RecyclerView with data from mDataSet.
+ */
+public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {
+ private static final String TAG = "CustomAdapter";
+
+ private String[] mDataSet;
+
+ // BEGIN_INCLUDE(recyclerViewSampleViewHolder)
+ /**
+ * Provide a reference to the type of views that you are using (custom viewholder)
+ */
+ public static class ViewHolder extends RecyclerView.ViewHolder {
+ private final TextView mTextView;
+
+ public ViewHolder(View v) {
+ super(v);
+ mTextView = (TextView) v.findViewById(R.id.textView);
+ }
+
+ public TextView getmTextView() {
+ return mTextView;
+ }
+ }
+ // END_INCLUDE(recyclerViewSampleViewHolder)
+ /**
+ * Initialize the dataset of the Adapter.
+ *
+ * @param dataSet String[] containing the data to populate views to be used by RecyclerView.
+ */
+ public CustomAdapter(String[] dataSet) {
+ mDataSet = dataSet;
+ }
+
+ // BEGIN_INCLUDE(recyclerViewOnCreateViewHolder)
+ // Create new views (invoked by the layout manager)
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int position) {
+ // Create a new view.
+ View v = LayoutInflater.from(viewGroup.getContext())
+ .inflate(R.layout.text_row_item, viewGroup, false);
+
+ ViewHolder vh = new ViewHolder(v);
+ return vh;
+ }
+ // END_INCLUDE(recyclerViewOnCreateViewHolder)
+
+ // BEGIN_INCLUDE(recyclerViewOnBindViewHolder)
+ // Replace the contents of a view (invoked by the layout manager)
+ @Override
+ public void onBindViewHolder(ViewHolder viewHolder, int position) {
+ Log.d(TAG, "Element " + position + " set.");
+
+ // Get element from your dataset at this position and replace the contents of the view
+ // with that element
+ viewHolder.getmTextView().setText(mDataSet[position]);
+ }
+ // END_INCLUDE(recyclerViewOnBindViewHolder)
+
+ // Return the size of your dataset (invoked by the layout manager)
+ @Override
+ public int getItemCount() {
+ return mDataSet.length;
+ }
+}
diff --git a/samples/browseable/RecyclerView/src/com.example.android.recyclerview/MainActivity.java b/samples/browseable/RecyclerView/src/com.example.android.recyclerview/MainActivity.java
new file mode 100644
index 0000000..7556067
--- /dev/null
+++ b/samples/browseable/RecyclerView/src/com.example.android.recyclerview/MainActivity.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.recyclerview;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ViewAnimator;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description, sample log and a custom
+ * {@link android.support.v4.app.Fragment} which can display a view.
+ * <p>
+ * For devices with displays with a width of 720dp or greater, the sample log is always visible,
+ * on other devices it's visibility is controlled by an item on the Action Bar.
+ */
+public class MainActivity extends SampleActivityBase {
+
+ public static final String TAG = "MainActivity";
+
+ // Whether the Log Fragment is currently shown
+ private boolean mLogShown;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ if (savedInstanceState == null) {
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ RecyclerViewFragment fragment = new RecyclerViewFragment();
+ transaction.replace(R.id.sample_content_fragment, fragment);
+ transaction.commit();
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
+ logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
+ logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);
+
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch(item.getItemId()) {
+ case R.id.menu_toggle_log:
+ mLogShown = !mLogShown;
+ ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);
+ if (mLogShown) {
+ output.setDisplayedChild(1);
+ } else {
+ output.setDisplayedChild(0);
+ }
+ supportInvalidateOptionsMenu();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ /** Create a chain of targets that will receive log data */
+ @Override
+ public void initializeLogging() {
+ // Wraps Android's native log framework.
+ LogWrapper logWrapper = new LogWrapper();
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ Log.setLogNode(logWrapper);
+
+ // Filter strips out everything except the message text.
+ MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+ logWrapper.setNext(msgFilter);
+
+ // On screen logging via a fragment with a TextView.
+ LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+ .findFragmentById(R.id.log_fragment);
+ msgFilter.setNext(logFragment.getLogView());
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/RecyclerView/src/com.example.android.recyclerview/RecyclerViewFragment.java b/samples/browseable/RecyclerView/src/com.example.android.recyclerview/RecyclerViewFragment.java
new file mode 100644
index 0000000..4f4a596
--- /dev/null
+++ b/samples/browseable/RecyclerView/src/com.example.android.recyclerview/RecyclerViewFragment.java
@@ -0,0 +1,81 @@
+/*
+* Copyright (C) 2014 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.recyclerview;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Demonstrates the use of RecyclerView with a LinearLayoutManager.
+ */
+public class RecyclerViewFragment extends Fragment {
+
+ private static final String TAG = "RecyclerViewFragment";
+
+ protected RecyclerView mRecyclerView;
+ protected RecyclerView.Adapter mAdapter;
+ protected RecyclerView.LayoutManager mLayoutManager;
+ protected String[] mDataset;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Initialize dataset, this data would usually come from a local content provider or
+ // remote server.
+ initDataset();
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View rootView = inflater.inflate(R.layout.recycler_view_frag, container, false);
+ rootView.setTag(TAG);
+
+ // BEGIN_INCLUDE(initializeRecyclerView)
+ mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerView);
+
+ // LinearLayoutManager is used here, this will layout the elements in a similar fashion
+ // to the way ListView would layout elements. The RecyclerView.LayoutManager defines how
+ // elements are laid out.
+ mLayoutManager = new LinearLayoutManager(getActivity());
+ mRecyclerView.setLayoutManager(mLayoutManager);
+
+ mAdapter = new CustomAdapter(mDataset);
+ // Set CustomAdapter as the adapter for RecyclerView.
+ mRecyclerView.setAdapter(mAdapter);
+ // END_INCLUDE(initializeRecyclerView)
+
+ return rootView;
+ }
+
+ /**
+ * Generates Strings for RecyclerView's adapter. This data would usually come
+ * from a local content provider or remote server.
+ */
+ private void initDataset() {
+ mDataset = new String[60];
+ for (int i=0; i < 60; i++) {
+ mDataset[i] = "This is element #" + i;
+ }
+ }
+}
diff --git a/samples/browseable/RevealEffectBasic/AndroidManifest.xml b/samples/browseable/RevealEffectBasic/AndroidManifest.xml
new file mode 100644
index 0000000..da8646b
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.revealeffectbasic"
+ android:versionCode="1"
+ android:versionName="1.0"
+ android:uiOptions="splitActionBarWhenNarrow">
+
+ <application android:allowBackup="true"
+ android:label="@string/app_name"
+ android:icon="@drawable/ic_launcher"
+ android:theme="@style/AppTheme">
+
+ <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>
+ </application>
+
+
+</manifest>
diff --git a/samples/browseable/RevealEffectBasic/_index.jd b/samples/browseable/RevealEffectBasic/_index.jd
new file mode 100644
index 0000000..c48c617
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/_index.jd
@@ -0,0 +1,9 @@
+page.tags="RevealEffectBasic"
+sample.group=UI
+@jd:body
+
+<p>
+
+ Basic sample to demonstrate the reveal effect.
+
+ </p>
diff --git a/samples/browseable/RevealEffectBasic/res/drawable-hdpi/ic_launcher.png b/samples/browseable/RevealEffectBasic/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..5acc60a
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/RevealEffectBasic/res/drawable-hdpi/tile.9.png b/samples/browseable/RevealEffectBasic/res/drawable-hdpi/tile.9.png
new file mode 100644
index 0000000..1358628
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/RevealEffectBasic/res/drawable-mdpi/ic_launcher.png b/samples/browseable/RevealEffectBasic/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..d3977a6
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/RevealEffectBasic/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/RevealEffectBasic/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..71532a7
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/RevealEffectBasic/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/RevealEffectBasic/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..33d9879
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/RevealEffectBasic/res/layout-w720dp/activity_main.xml b/samples/browseable/RevealEffectBasic/res/layout-w720dp/activity_main.xml
new file mode 100755
index 0000000..c9a52f6
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/res/layout-w720dp/activity_main.xml
@@ -0,0 +1,73 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<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/sample_main_layout">
+
+ <LinearLayout
+ android:id="@+id/sample_output"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <FrameLayout
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/margin_medium"
+ android:paddingRight="@dimen/margin_medium"
+ android:paddingTop="@dimen/margin_large"
+ android:paddingBottom="@dimen/margin_large"
+ android:text="@string/intro_message" />
+ </FrameLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1" />
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="0px"
+ android:layout_height="match_parent" />
+
+</LinearLayout>
+
+
diff --git a/samples/browseable/RevealEffectBasic/res/layout/activity_main.xml b/samples/browseable/RevealEffectBasic/res/layout/activity_main.xml
new file mode 100755
index 0000000..1ae4f98
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/res/layout/activity_main.xml
@@ -0,0 +1,65 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<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/sample_main_layout">
+
+ <ViewAnimator
+ android:id="@+id/sample_output"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1">
+
+ <ScrollView
+ style="@style/Widget.SampleMessageTile"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ style="@style/Widget.SampleMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="@dimen/horizontal_page_margin"
+ android:paddingRight="@dimen/horizontal_page_margin"
+ android:paddingTop="@dimen/vertical_page_margin"
+ android:paddingBottom="@dimen/vertical_page_margin"
+ android:text="@string/intro_message" />
+ </ScrollView>
+
+ <fragment
+ android:name="com.example.android.common.logger.LogFragment"
+ android:id="@+id/log_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ </ViewAnimator>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@android:color/darker_gray" />
+
+ <FrameLayout
+ android:id="@+id/sample_content_fragment"
+ android:layout_weight="2"
+ android:layout_width="match_parent"
+ android:layout_height="0px" />
+
+</LinearLayout>
+
diff --git a/samples/browseable/RevealEffectBasic/res/layout/reveal_effect_basic.xml b/samples/browseable/RevealEffectBasic/res/layout/reveal_effect_basic.xml
new file mode 100644
index 0000000..f7f6923
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/res/layout/reveal_effect_basic.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <View
+ android:id="@+id/circle"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_horizontal"
+ android:background="@color/color"
+ android:layout_above="@+id/button"
+ android:layout_marginTop="@dimen/margin_medium"
+ android:layout_marginRight="@dimen/margin_medium"
+ android:layout_marginLeft="@dimen/margin_medium"/>
+ <Button
+ android:id="@+id/button"
+ style="?android:attr/buttonStyleSmall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/margin_medium"
+ android:text="Reveal"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="16dp"
+ android:layout_gravity="center_horizontal|bottom"
+ android:layout_alignParentBottom="true"
+ />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/samples/browseable/RevealEffectBasic/res/menu/main.xml b/samples/browseable/RevealEffectBasic/res/menu/main.xml
new file mode 100644
index 0000000..b49c2c5
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/res/menu/main.xml
@@ -0,0 +1,21 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/menu_toggle_log"
+ android:showAsAction="always"
+ android:title="@string/sample_show_log" />
+</menu>
diff --git a/samples/browseable/RevealEffectBasic/res/values-sw600dp/template-dimens.xml b/samples/browseable/RevealEffectBasic/res/values-sw600dp/template-dimens.xml
new file mode 100644
index 0000000..22074a2
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/res/values-sw600dp/template-dimens.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/RevealEffectBasic/res/values-sw600dp/template-styles.xml b/samples/browseable/RevealEffectBasic/res/values-sw600dp/template-styles.xml
new file mode 100644
index 0000000..03d1974
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/res/values-sw600dp/template-styles.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceLarge</item>
+ <item name="android:lineSpacingMultiplier">1.2</item>
+ <item name="android:shadowDy">-6.5</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/RevealEffectBasic/res/values-v11/template-styles.xml b/samples/browseable/RevealEffectBasic/res/values-v11/template-styles.xml
new file mode 100644
index 0000000..8c1ea66
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/res/values-v11/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Holo.Light" />
+
+</resources>
diff --git a/samples/browseable/RevealEffectBasic/res/values-v21/template-styles.xml b/samples/browseable/RevealEffectBasic/res/values-v21/template-styles.xml
new file mode 100644
index 0000000..134fcd9
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/res/values-v21/template-styles.xml
@@ -0,0 +1,22 @@
+<!--
+ Copyright 2014 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>
+
+ <!-- Activity themes -->
+ <style name="Theme.Base" parent="android:Theme.Material.Light" />
+
+</resources>
diff --git a/samples/browseable/RevealEffectBasic/res/values/base-strings.xml b/samples/browseable/RevealEffectBasic/res/values/base-strings.xml
new file mode 100644
index 0000000..b4aa183
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/res/values/base-strings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">RevealEffectBasic</string>
+ <string name="intro_message">
+ <![CDATA[
+
+
+ Basic sample to demonstrate the reveal effect.
+
+
+ ]]>
+ </string>
+</resources>
diff --git a/samples/browseable/RevealEffectBasic/res/values/colors.xml b/samples/browseable/RevealEffectBasic/res/values/colors.xml
new file mode 100644
index 0000000..52150b0
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/res/values/colors.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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>
+ <color name="color">#673AB7</color>
+</resources>
diff --git a/samples/browseable/RevealEffectBasic/res/values/dimens.xml b/samples/browseable/RevealEffectBasic/res/values/dimens.xml
new file mode 100644
index 0000000..e0ffc06
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/res/values/dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 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="shape_size">128dp</dimen>
+</resources>
diff --git a/samples/browseable/RevealEffectBasic/res/values/fragmentview_strings.xml b/samples/browseable/RevealEffectBasic/res/values/fragmentview_strings.xml
new file mode 100755
index 0000000..7b9d9ec
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/res/values/fragmentview_strings.xml
@@ -0,0 +1,19 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="sample_show_log">Show Log</string>
+ <string name="sample_hide_log">Hide Log</string>
+</resources>
diff --git a/samples/browseable/RevealEffectBasic/res/values/template-dimens.xml b/samples/browseable/RevealEffectBasic/res/values/template-dimens.xml
new file mode 100644
index 0000000..39e710b
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/res/values/template-dimens.xml
@@ -0,0 +1,32 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+
+ <dimen name="margin_tiny">4dp</dimen>
+ <dimen name="margin_small">8dp</dimen>
+ <dimen name="margin_medium">16dp</dimen>
+ <dimen name="margin_large">32dp</dimen>
+ <dimen name="margin_huge">64dp</dimen>
+
+ <!-- Semantic definitions -->
+
+ <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
+ <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+
+</resources>
diff --git a/samples/browseable/RevealEffectBasic/res/values/template-styles.xml b/samples/browseable/RevealEffectBasic/res/values/template-styles.xml
new file mode 100644
index 0000000..6e7d593
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/res/values/template-styles.xml
@@ -0,0 +1,42 @@
+<!--
+ Copyright 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <!-- Activity themes -->
+
+ <style name="Theme.Base" parent="android:Theme.Light" />
+
+ <style name="Theme.Sample" parent="Theme.Base" />
+
+ <style name="AppTheme" parent="Theme.Sample" />
+ <!-- Widget styling -->
+
+ <style name="Widget" />
+
+ <style name="Widget.SampleMessage">
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:lineSpacingMultiplier">1.1</item>
+ </style>
+
+ <style name="Widget.SampleMessageTile">
+ <item name="android:background">@drawable/tile</item>
+ <item name="android:shadowColor">#7F000000</item>
+ <item name="android:shadowDy">-3.5</item>
+ <item name="android:shadowRadius">2</item>
+ </style>
+
+</resources>
diff --git a/samples/browseable/RevealEffectBasic/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/RevealEffectBasic/src/com.example.android.common/activities/SampleActivityBase.java
new file mode 100644
index 0000000..3228927
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/src/com.example.android.common/activities/SampleActivityBase.java
@@ -0,0 +1,52 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.common.activities;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogWrapper;
+
+/**
+ * Base launcher activity, to handle most of the common plumbing for samples.
+ */
+public class SampleActivityBase extends FragmentActivity {
+
+ public static final String TAG = "SampleActivityBase";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ initializeLogging();
+ }
+
+ /** Set up targets to receive log data */
+ public void initializeLogging() {
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ // Wraps Android's native log framework
+ LogWrapper logWrapper = new LogWrapper();
+ Log.setLogNode(logWrapper);
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/RevealEffectBasic/src/com.example.android.common/logger/Log.java b/samples/browseable/RevealEffectBasic/src/com.example.android.common/logger/Log.java
new file mode 100644
index 0000000..17503c5
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * <p>When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.</p>
+ */
+public class Log {
+ // Grabbing the native values from Android's native logging facilities,
+ // to make for easy migration and interop.
+ public static final int NONE = -1;
+ public static final int VERBOSE = android.util.Log.VERBOSE;
+ public static final int DEBUG = android.util.Log.DEBUG;
+ public static final int INFO = android.util.Log.INFO;
+ public static final int WARN = android.util.Log.WARN;
+ public static final int ERROR = android.util.Log.ERROR;
+ public static final int ASSERT = android.util.Log.ASSERT;
+
+ // Stores the beginning of the LogNode topology.
+ private static LogNode mLogNode;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public static LogNode getLogNode() {
+ return mLogNode;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to.
+ */
+ public static void setLogNode(LogNode node) {
+ mLogNode = node;
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void println(int priority, String tag, String msg, Throwable tr) {
+ if (mLogNode != null) {
+ mLogNode.println(priority, tag, msg, tr);
+ }
+ }
+
+ /**
+ * Instructs the LogNode to print the log data provided. Other LogNodes can
+ * be chained to the end of the LogNode as desired.
+ *
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ */
+ public static void println(int priority, String tag, String msg) {
+ println(priority, tag, msg, null);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void v(String tag, String msg, Throwable tr) {
+ println(VERBOSE, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at VERBOSE priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void v(String tag, String msg) {
+ v(tag, msg, null);
+ }
+
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void d(String tag, String msg, Throwable tr) {
+ println(DEBUG, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at DEBUG priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void d(String tag, String msg) {
+ d(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void i(String tag, String msg, Throwable tr) {
+ println(INFO, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at INFO priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void i(String tag, String msg) {
+ i(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, String msg, Throwable tr) {
+ println(WARN, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void w(String tag, String msg) {
+ w(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at WARN priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void w(String tag, Throwable tr) {
+ w(tag, null, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void e(String tag, String msg, Throwable tr) {
+ println(ERROR, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ERROR priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void e(String tag, String msg) {
+ e(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, String msg, Throwable tr) {
+ println(ASSERT, tag, msg, tr);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged.
+ */
+ public static void wtf(String tag, String msg) {
+ wtf(tag, msg, null);
+ }
+
+ /**
+ * Prints a message at ASSERT priority.
+ *
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public static void wtf(String tag, Throwable tr) {
+ wtf(tag, null, tr);
+ }
+}
diff --git a/samples/browseable/RevealEffectBasic/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/RevealEffectBasic/src/com.example.android.common/logger/LogFragment.java
new file mode 100644
index 0000000..b302acd
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/src/com.example.android.common/logger/LogFragment.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.common.logger;
+
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ScrollView;
+
+/**
+ * Simple fraggment which contains a LogView and uses is to output log data it receives
+ * through the LogNode interface.
+ */
+public class LogFragment extends Fragment {
+
+ private LogView mLogView;
+ private ScrollView mScrollView;
+
+ public LogFragment() {}
+
+ public View inflateViews() {
+ mScrollView = new ScrollView(getActivity());
+ ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ mScrollView.setLayoutParams(scrollParams);
+
+ mLogView = new LogView(getActivity());
+ ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
+ logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ mLogView.setLayoutParams(logParams);
+ mLogView.setClickable(true);
+ mLogView.setFocusable(true);
+ mLogView.setTypeface(Typeface.MONOSPACE);
+
+ // Want to set padding as 16 dips, setPadding takes pixels. Hooray math!
+ int paddingDips = 16;
+ double scale = getResources().getDisplayMetrics().density;
+ int paddingPixels = (int) ((paddingDips * (scale)) + .5);
+ mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
+ mLogView.setCompoundDrawablePadding(paddingPixels);
+
+ mLogView.setGravity(Gravity.BOTTOM);
+ mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
+
+ mScrollView.addView(mLogView);
+ return mScrollView;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+
+ View result = inflateViews();
+
+ mLogView.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
+ }
+ });
+ return result;
+ }
+
+ public LogView getLogView() {
+ return mLogView;
+ }
+}
\ No newline at end of file
diff --git a/samples/browseable/RevealEffectBasic/src/com.example.android.common/logger/LogNode.java b/samples/browseable/RevealEffectBasic/src/com.example.android.common/logger/LogNode.java
new file mode 100644
index 0000000..bc37cab
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/src/com.example.android.common/logger/LogNode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 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.common.logger;
+
+/**
+ * Basic interface for a logging system that can output to one or more targets.
+ * Note that in addition to classes that will output these logs in some format,
+ * one can also implement this interface over a filter and insert that in the chain,
+ * such that no targets further down see certain data, or see manipulated forms of the data.
+ * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
+ * it received to HTML and sent it along to the next node in the chain, without printing it
+ * anywhere.
+ */
+public interface LogNode {
+
+ /**
+ * Instructs first LogNode in the list to print the log data provided.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ public void println(int priority, String tag, String msg, Throwable tr);
+
+}
diff --git a/samples/browseable/RevealEffectBasic/src/com.example.android.common/logger/LogView.java b/samples/browseable/RevealEffectBasic/src/com.example.android.common/logger/LogView.java
new file mode 100644
index 0000000..c01542b
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/src/com.example.android.common/logger/LogView.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.*;
+import android.widget.TextView;
+
+/** Simple TextView which is used to output log data received through the LogNode interface.
+*/
+public class LogView extends TextView implements LogNode {
+
+ public LogView(Context context) {
+ super(context);
+ }
+
+ public LogView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public LogView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ /**
+ * Formats the log data and prints it out to the LogView.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+
+
+ String priorityStr = null;
+
+ // For the purposes of this View, we want to print the priority as readable text.
+ switch(priority) {
+ case android.util.Log.VERBOSE:
+ priorityStr = "VERBOSE";
+ break;
+ case android.util.Log.DEBUG:
+ priorityStr = "DEBUG";
+ break;
+ case android.util.Log.INFO:
+ priorityStr = "INFO";
+ break;
+ case android.util.Log.WARN:
+ priorityStr = "WARN";
+ break;
+ case android.util.Log.ERROR:
+ priorityStr = "ERROR";
+ break;
+ case android.util.Log.ASSERT:
+ priorityStr = "ASSERT";
+ break;
+ default:
+ break;
+ }
+
+ // Handily, the Log class has a facility for converting a stack trace into a usable string.
+ String exceptionStr = null;
+ if (tr != null) {
+ exceptionStr = android.util.Log.getStackTraceString(tr);
+ }
+
+ // Take the priority, tag, message, and exception, and concatenate as necessary
+ // into one usable line of text.
+ final StringBuilder outputBuilder = new StringBuilder();
+
+ String delimiter = "\t";
+ appendIfNotNull(outputBuilder, priorityStr, delimiter);
+ appendIfNotNull(outputBuilder, tag, delimiter);
+ appendIfNotNull(outputBuilder, msg, delimiter);
+ appendIfNotNull(outputBuilder, exceptionStr, delimiter);
+
+ // In case this was originally called from an AsyncTask or some other off-UI thread,
+ // make sure the update occurs within the UI thread.
+ ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
+ @Override
+ public void run() {
+ // Display the text we just generated within the LogView.
+ appendToLog(outputBuilder.toString());
+ }
+ })));
+
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
+ * the logger takes so many arguments that might be null, this method helps cut out some of the
+ * agonizing tedium of writing the same 3 lines over and over.
+ * @param source StringBuilder containing the text to append to.
+ * @param addStr The String to append
+ * @param delimiter The String to separate the source and appended strings. A tab or comma,
+ * for instance.
+ * @return The fully concatenated String as a StringBuilder
+ */
+ private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
+ if (addStr != null) {
+ if (addStr.length() == 0) {
+ delimiter = "";
+ }
+
+ return source.append(addStr).append(delimiter);
+ }
+ return source;
+ }
+
+ // The next LogNode in the chain.
+ LogNode mNext;
+
+ /** Outputs the string as a new line of log data in the LogView. */
+ public void appendToLog(String s) {
+ append("\n" + s);
+ }
+
+
+}
diff --git a/samples/browseable/RevealEffectBasic/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/RevealEffectBasic/src/com.example.android.common/logger/LogWrapper.java
new file mode 100644
index 0000000..16a9e7b
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/src/com.example.android.common/logger/LogWrapper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 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.common.logger;
+
+import android.util.Log;
+
+/**
+ * Helper class which wraps Android's native Log utility in the Logger interface. This way
+ * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
+ */
+public class LogWrapper implements LogNode {
+
+ // For piping: The next node to receive Log data after this one has done its work.
+ private LogNode mNext;
+
+ /**
+ * Returns the next LogNode in the linked list.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+ /**
+ * Prints data out to the console using Android's native log mechanism.
+ * @param priority Log level of the data being logged. Verbose, Error, etc.
+ * @param tag Tag for for the log data. Can be used to organize log statements.
+ * @param msg The actual message to be logged. The actual message to be logged.
+ * @param tr If an exception was thrown, this can be sent along for the logging facilities
+ * to extract and print useful information.
+ */
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ // There actually are log methods that don't take a msg parameter. For now,
+ // if that's the case, just convert null to the empty string and move on.
+ String useMsg = msg;
+ if (useMsg == null) {
+ useMsg = "";
+ }
+
+ // If an exeption was provided, convert that exception to a usable string and attach
+ // it to the end of the msg method.
+ if (tr != null) {
+ msg += "\n" + Log.getStackTraceString(tr);
+ }
+
+ // This is functionally identical to Log.x(tag, useMsg);
+ // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
+ Log.println(priority, tag, useMsg);
+
+ // If this isn't the last node in the chain, move things along.
+ if (mNext != null) {
+ mNext.println(priority, tag, msg, tr);
+ }
+ }
+}
diff --git a/samples/browseable/RevealEffectBasic/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/RevealEffectBasic/src/com.example.android.common/logger/MessageOnlyLogFilter.java
new file mode 100644
index 0000000..19967dc
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/src/com.example.android.common/logger/MessageOnlyLogFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.android.common.logger;
+
+/**
+ * Simple {@link LogNode} filter, removes everything except the message.
+ * Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
+ * just easy-to-read message updates as they're happening.
+ */
+public class MessageOnlyLogFilter implements LogNode {
+
+ LogNode mNext;
+
+ /**
+ * Takes the "next" LogNode as a parameter, to simplify chaining.
+ *
+ * @param next The next LogNode in the pipeline.
+ */
+ public MessageOnlyLogFilter(LogNode next) {
+ mNext = next;
+ }
+
+ public MessageOnlyLogFilter() {
+ }
+
+ @Override
+ public void println(int priority, String tag, String msg, Throwable tr) {
+ if (mNext != null) {
+ getNext().println(Log.NONE, null, msg, null);
+ }
+ }
+
+ /**
+ * Returns the next LogNode in the chain.
+ */
+ public LogNode getNext() {
+ return mNext;
+ }
+
+ /**
+ * Sets the LogNode data will be sent to..
+ */
+ public void setNext(LogNode node) {
+ mNext = node;
+ }
+
+}
diff --git a/samples/browseable/RevealEffectBasic/src/com.example.android.revealeffectbasic/MainActivity.java b/samples/browseable/RevealEffectBasic/src/com.example.android.revealeffectbasic/MainActivity.java
new file mode 100644
index 0000000..e9b27d9
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/src/com.example.android.revealeffectbasic/MainActivity.java
@@ -0,0 +1,109 @@
+/*
+* Copyright 2013 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.revealeffectbasic;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ViewAnimator;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description, sample log and a custom
+ * {@link android.support.v4.app.Fragment} which can display a view.
+ * <p>
+ * For devices with displays with a width of 720dp or greater, the sample log is always visible,
+ * on other devices it's visibility is controlled by an item on the Action Bar.
+ */
+public class MainActivity extends SampleActivityBase {
+
+ public static final String TAG = "MainActivity";
+
+ // Whether the Log Fragment is currently shown
+ private boolean mLogShown;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ if (savedInstanceState == null) {
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ RevealEffectBasicFragment fragment = new RevealEffectBasicFragment();
+ transaction.replace(R.id.sample_content_fragment, fragment);
+ transaction.commit();
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
+ logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
+ logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);
+
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch(item.getItemId()) {
+ case R.id.menu_toggle_log:
+ mLogShown = !mLogShown;
+ ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);
+ if (mLogShown) {
+ output.setDisplayedChild(1);
+ } else {
+ output.setDisplayedChild(0);
+ }
+ supportInvalidateOptionsMenu();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ /** Create a chain of targets that will receive log data */
+ @Override
+ public void initializeLogging() {
+ // Wraps Android's native log framework.
+ LogWrapper logWrapper = new LogWrapper();
+ // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+ Log.setLogNode(logWrapper);
+
+ // Filter strips out everything except the message text.
+ MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+ logWrapper.setNext(msgFilter);
+
+ // On screen logging via a fragment with a TextView.
+ LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+ .findFragmentById(R.id.log_fragment);
+ msgFilter.setNext(logFragment.getLogView());
+
+ Log.i(TAG, "Ready");
+ }
+}
diff --git a/samples/browseable/RevealEffectBasic/src/com.example.android.revealeffectbasic/RevealEffectBasicFragment.java b/samples/browseable/RevealEffectBasic/src/com.example.android.revealeffectbasic/RevealEffectBasicFragment.java
new file mode 100644
index 0000000..1520619
--- /dev/null
+++ b/samples/browseable/RevealEffectBasic/src/com.example.android.revealeffectbasic/RevealEffectBasicFragment.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2014 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.revealeffectbasic;
+
+import com.example.android.common.logger.Log;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.support.v4.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewAnimationUtils;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateDecelerateInterpolator;
+
+/**
+ * This sample shows a view that is revealed when a button is clicked.
+ */
+public class RevealEffectBasicFragment extends Fragment {
+
+ private final static String TAG = "RevealEffectBasicFragment";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ final View rootView = inflater.inflate(R.layout.reveal_effect_basic, container, false);
+
+ View button = rootView.findViewById(R.id.button);
+
+ // Set a listener to reveal the view when clicked.
+ button.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ View shape = rootView.findViewById(R.id.circle);
+
+ // Create a reveal {@link Animator} that starts clipping the view from
+ // the top left corner until the whole view is covered.
+ Animator animator = ViewAnimationUtils.createCircularReveal(
+ shape,
+ 0,
+ 0,
+ 0,
+ (float) Math.hypot(shape.getWidth(), shape.getHeight()));
+
+ // Set a natural ease-in/ease-out interpolator.
+ animator.setInterpolator(new AccelerateDecelerateInterpolator());
+
+ // Finally start the animation
+ animator.start();
+
+ Log.d(TAG, "Starting Reveal animation");
+ }
+ });
+
+ return rootView;
+ }
+
+}
\ No newline at end of file