am b0ab983f: am 8d594385: Updating SpeedTracker and JumpingJack for various things - icons have been updated for SpeedTracker - added two lines to application manifests in those two projects to make installation of wearable app via phone app possible
* commit 'b0ab983f7ad5f9ddedda2b29e465ada5578e797e':
Updating SpeedTracker and JumpingJack for various things - icons have been updated for SpeedTracker - added two lines to application manifests in those two projects to make installation of wearable app via phone app possible
diff --git a/ui/notifications/BasicNotifications/Application/.gitignore b/admin/AppRestrictionEnforcer/Application/.gitignore
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/.gitignore
copy to admin/AppRestrictionEnforcer/Application/.gitignore
diff --git a/ui/notifications/BasicNotifications/Application/proguard-project.txt b/admin/AppRestrictionEnforcer/Application/proguard-project.txt
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/proguard-project.txt
copy to admin/AppRestrictionEnforcer/Application/proguard-project.txt
diff --git a/admin/AppRestrictionEnforcer/Application/src/main/AndroidManifest.xml b/admin/AppRestrictionEnforcer/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..c66b4b3
--- /dev/null
+++ b/admin/AppRestrictionEnforcer/Application/src/main/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/admin/AppRestrictionEnforcer/Application/src/main/big_icon.png b/admin/AppRestrictionEnforcer/Application/src/main/big_icon.png
new file mode 100644
index 0000000..24d83d9
--- /dev/null
+++ b/admin/AppRestrictionEnforcer/Application/src/main/big_icon.png
Binary files differ
diff --git a/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/AppRestrictionEnforcerFragment.java b/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/AppRestrictionEnforcerFragment.java
new file mode 100644
index 0000000..6db54f6
--- /dev/null
+++ b/admin/AppRestrictionEnforcer/Application/src/main/java/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/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/EnableProfileActivity.java b/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/EnableProfileActivity.java
new file mode 100644
index 0000000..323ee99
--- /dev/null
+++ b/admin/AppRestrictionEnforcer/Application/src/main/java/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/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/EnforcerDeviceAdminReceiver.java b/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/EnforcerDeviceAdminReceiver.java
new file mode 100644
index 0000000..09d9e98
--- /dev/null
+++ b/admin/AppRestrictionEnforcer/Application/src/main/java/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/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/MainActivity.java b/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/MainActivity.java
new file mode 100644
index 0000000..72224e1
--- /dev/null
+++ b/admin/AppRestrictionEnforcer/Application/src/main/java/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/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/SetupProfileFragment.java b/admin/AppRestrictionEnforcer/Application/src/main/java/com/example/android/apprestrictionenforcer/SetupProfileFragment.java
new file mode 100644
index 0000000..4dbd930
--- /dev/null
+++ b/admin/AppRestrictionEnforcer/Application/src/main/java/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/admin/AppRestrictionEnforcer/Application/src/main/res/drawable-hdpi/ic_launcher.png b/admin/AppRestrictionEnforcer/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..e7bd161
--- /dev/null
+++ b/admin/AppRestrictionEnforcer/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/admin/AppRestrictionEnforcer/Application/src/main/res/drawable-mdpi/ic_launcher.png b/admin/AppRestrictionEnforcer/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..4c42c9c
--- /dev/null
+++ b/admin/AppRestrictionEnforcer/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/admin/AppRestrictionEnforcer/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/admin/AppRestrictionEnforcer/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..3ec3368
--- /dev/null
+++ b/admin/AppRestrictionEnforcer/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/admin/AppRestrictionEnforcer/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/admin/AppRestrictionEnforcer/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..730f80c
--- /dev/null
+++ b/admin/AppRestrictionEnforcer/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/admin/AppRestrictionEnforcer/Application/src/main/res/layout/activity_main_real.xml b/admin/AppRestrictionEnforcer/Application/src/main/res/layout/activity_main_real.xml
new file mode 100644
index 0000000..d36c2b6
--- /dev/null
+++ b/admin/AppRestrictionEnforcer/Application/src/main/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/admin/AppRestrictionEnforcer/Application/src/main/res/layout/fragment_app_restriction_enforcer.xml b/admin/AppRestrictionEnforcer/Application/src/main/res/layout/fragment_app_restriction_enforcer.xml
new file mode 100644
index 0000000..e6c50a2
--- /dev/null
+++ b/admin/AppRestrictionEnforcer/Application/src/main/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/admin/AppRestrictionEnforcer/Application/src/main/res/layout/fragment_setup_profile.xml b/admin/AppRestrictionEnforcer/Application/src/main/res/layout/fragment_setup_profile.xml
new file mode 100644
index 0000000..e9e9fe8
--- /dev/null
+++ b/admin/AppRestrictionEnforcer/Application/src/main/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/admin/AppRestrictionEnforcer/Application/src/main/res/values/strings.xml b/admin/AppRestrictionEnforcer/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..3029e04
--- /dev/null
+++ b/admin/AppRestrictionEnforcer/Application/src/main/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/admin/AppRestrictionEnforcer/Application/src/main/res/xml/enforcer_device_admin_receiver.xml b/admin/AppRestrictionEnforcer/Application/src/main/res/xml/enforcer_device_admin_receiver.xml
new file mode 100644
index 0000000..5e084c6
--- /dev/null
+++ b/admin/AppRestrictionEnforcer/Application/src/main/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/admin/AppRestrictionEnforcer/Application/tests/src/com/example/android/apprestrictionenforcer/tests/SampleTests.java b/admin/AppRestrictionEnforcer/Application/tests/src/com/example/android/apprestrictionenforcer/tests/SampleTests.java
new file mode 100644
index 0000000..fbed64a
--- /dev/null
+++ b/admin/AppRestrictionEnforcer/Application/tests/src/com/example/android/apprestrictionenforcer/tests/SampleTests.java
@@ -0,0 +1,79 @@
+/*
+* 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 (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.apprestrictionenforcer.tests;
+
+import com.example.android.apprestrictionenforcer.*;
+
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+* Tests for AppRestrictionEnforcer sample.
+*/
+public class SampleTests extends ActivityInstrumentationTestCase2<MainActivity> {
+
+ private MainActivity mTestActivity;
+ private AppRestrictionEnforcerFragment mTestFragment;
+
+ public SampleTests() {
+ super(MainActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // Starts the activity under test using the default Intent with:
+ // action = {@link Intent#ACTION_MAIN}
+ // flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK}
+ // All other fields are null or empty.
+ mTestActivity = getActivity();
+ mTestFragment = (AppRestrictionEnforcerFragment)
+ mTestActivity.getSupportFragmentManager().getFragments().get(1);
+ }
+
+ /**
+ * Test if the test fixture has been set up correctly.
+ */
+ public void testPreconditions() {
+ //Try to add a message to add context to your assertions. These messages will be shown if
+ //a tests fails and make it easy to understand why a test failed
+ assertNotNull("mTestActivity is null", mTestActivity);
+ assertNotNull("mTestFragment is null", mTestFragment);
+ }
+
+ /**
+ * Add more tests below.
+ */
+
+}
\ No newline at end of file
diff --git a/ui/notifications/BasicNotifications/CONTRIB.md b/admin/AppRestrictionEnforcer/CONTRIB.md
similarity index 100%
copy from ui/notifications/BasicNotifications/CONTRIB.md
copy to admin/AppRestrictionEnforcer/CONTRIB.md
diff --git a/ui/notifications/BasicNotifications/LICENSE b/admin/AppRestrictionEnforcer/LICENSE
similarity index 100%
copy from ui/notifications/BasicNotifications/LICENSE
copy to admin/AppRestrictionEnforcer/LICENSE
diff --git a/admin/AppRestrictionEnforcer/build.gradle b/admin/AppRestrictionEnforcer/build.gradle
new file mode 100644
index 0000000..f9f6f65
--- /dev/null
+++ b/admin/AppRestrictionEnforcer/build.gradle
@@ -0,0 +1,14 @@
+
+
+
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../build"
+ pathToSamplesCommon "../../common"
+}
+apply from: "../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/admin/AppRestrictionEnforcer/buildSrc/build.gradle b/admin/AppRestrictionEnforcer/buildSrc/build.gradle
new file mode 100644
index 0000000..29282af
--- /dev/null
+++ b/admin/AppRestrictionEnforcer/buildSrc/build.gradle
@@ -0,0 +1,18 @@
+
+
+
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile 'org.freemarker:freemarker:2.3.20'
+}
+
+sourceSets {
+ main {
+ groovy {
+ srcDir new File(rootDir, "../../../../../build/buildSrc/src/main/groovy")
+ }
+ }
+}
+
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/admin/AppRestrictionEnforcer/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
copy to admin/AppRestrictionEnforcer/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties b/admin/AppRestrictionEnforcer/gradle/wrapper/gradle-wrapper.properties
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties
copy to admin/AppRestrictionEnforcer/gradle/wrapper/gradle-wrapper.properties
diff --git a/ui/notifications/BasicNotifications/gradlew b/admin/AppRestrictionEnforcer/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to admin/AppRestrictionEnforcer/gradlew
diff --git a/ui/notifications/BasicNotifications/gradlew.bat b/admin/AppRestrictionEnforcer/gradlew.bat
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew.bat
copy to admin/AppRestrictionEnforcer/gradlew.bat
diff --git a/ui/notifications/BasicNotifications/settings.gradle b/admin/AppRestrictionEnforcer/settings.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/settings.gradle
copy to admin/AppRestrictionEnforcer/settings.gradle
diff --git a/admin/AppRestrictionEnforcer/template-params.xml b/admin/AppRestrictionEnforcer/template-params.xml
new file mode 100644
index 0000000..ff1a7a0
--- /dev/null
+++ b/admin/AppRestrictionEnforcer/template-params.xml
@@ -0,0 +1,38 @@
+<?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.
+-->
+
+
+
+<sample>
+ <name>AppRestrictionEnforcer</name>
+ <group>Admin</group>
+ <package>com.example.android.apprestrictionenforcer</package>
+
+ <minSdk>21</minSdk>
+ <compileSdkVersion>21</compileSdkVersion>
+
+ <strings>
+ <intro>
+ <![CDATA[
+ This sample demonstrates how to set restrictions to other apps as a profile owner.
+ Use AppRestrictionSchema sample as a app with available restrictions.
+ ]]>
+ </intro>
+ </strings>
+
+ <template src="base" />
+</sample>
diff --git a/ui/notifications/BasicNotifications/Application/.gitignore b/admin/AppRestrictionSchema/Application/.gitignore
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/.gitignore
copy to admin/AppRestrictionSchema/Application/.gitignore
diff --git a/admin/AppRestrictionSchema/Application/README-fragmentview.txt b/admin/AppRestrictionSchema/Application/README-fragmentview.txt
new file mode 100644
index 0000000..38d903f
--- /dev/null
+++ b/admin/AppRestrictionSchema/Application/README-fragmentview.txt
@@ -0,0 +1,37 @@
+<!--
+ 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.
+-->
+
+Steps to implement FragmentView template:
+-in template-params.xml.ftl:
+ -add the following line to common imports
+ <common src="activities"/>
+
+-Add a Fragment to show behavior. In your MainActivity.java class, it will reference a Fragment
+ called (yourProjectName)Fragment.java. Create that file in your project, using the "main" source
+ folder instead of "common" or "templates".
+ For instance, if your package name is com.example.foo, create the file
+ src/main/java/com/example/foo/FooFragment.java
+
+
+-Within this fragment, make sure that the onCreate method has the line
+ "setHasOptionsMenu(true);", to enable the fragment to handle menu events.
+
+-In order to override menu events, override onOptionsItemSelected.
+
+-refer to sampleSamples/fragmentViewSample for a reference implementation of a
+project built on this template.
+
+
diff --git a/ui/notifications/BasicNotifications/Application/proguard-project.txt b/admin/AppRestrictionSchema/Application/proguard-project.txt
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/proguard-project.txt
copy to admin/AppRestrictionSchema/Application/proguard-project.txt
diff --git a/admin/AppRestrictionSchema/Application/src/main/AndroidManifest.xml b/admin/AppRestrictionSchema/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..f8bbccc
--- /dev/null
+++ b/admin/AppRestrictionSchema/Application/src/main/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/admin/AppRestrictionSchema/Application/src/main/big_icon.png b/admin/AppRestrictionSchema/Application/src/main/big_icon.png
new file mode 100644
index 0000000..2115454
--- /dev/null
+++ b/admin/AppRestrictionSchema/Application/src/main/big_icon.png
Binary files differ
diff --git a/admin/AppRestrictionSchema/Application/src/main/java/com/example/android/apprestrictionschema/AppRestrictionSchemaFragment.java b/admin/AppRestrictionSchema/Application/src/main/java/com/example/android/apprestrictionschema/AppRestrictionSchemaFragment.java
new file mode 100644
index 0000000..76f024f
--- /dev/null
+++ b/admin/AppRestrictionSchema/Application/src/main/java/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/admin/AppRestrictionSchema/Application/src/main/res/drawable-hdpi/ic_launcher.png b/admin/AppRestrictionSchema/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..74344d7
--- /dev/null
+++ b/admin/AppRestrictionSchema/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/admin/AppRestrictionSchema/Application/src/main/res/drawable-mdpi/ic_launcher.png b/admin/AppRestrictionSchema/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..a01dbd7
--- /dev/null
+++ b/admin/AppRestrictionSchema/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/admin/AppRestrictionSchema/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/admin/AppRestrictionSchema/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..19bb139
--- /dev/null
+++ b/admin/AppRestrictionSchema/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/admin/AppRestrictionSchema/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/admin/AppRestrictionSchema/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..9922ae6
--- /dev/null
+++ b/admin/AppRestrictionSchema/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/admin/AppRestrictionSchema/Application/src/main/res/layout/activity_main_real.xml b/admin/AppRestrictionSchema/Application/src/main/res/layout/activity_main_real.xml
new file mode 100644
index 0000000..8aa1c8b
--- /dev/null
+++ b/admin/AppRestrictionSchema/Application/src/main/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/admin/AppRestrictionSchema/Application/src/main/res/layout/fragment_app_restriction_schema.xml b/admin/AppRestrictionSchema/Application/src/main/res/layout/fragment_app_restriction_schema.xml
new file mode 100644
index 0000000..fc5e23d
--- /dev/null
+++ b/admin/AppRestrictionSchema/Application/src/main/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/admin/AppRestrictionSchema/Application/src/main/res/values/strings.xml b/admin/AppRestrictionSchema/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..b8ef110
--- /dev/null
+++ b/admin/AppRestrictionSchema/Application/src/main/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/admin/AppRestrictionSchema/Application/src/main/res/xml/app_restrictions.xml b/admin/AppRestrictionSchema/Application/src/main/res/xml/app_restrictions.xml
new file mode 100644
index 0000000..409527f
--- /dev/null
+++ b/admin/AppRestrictionSchema/Application/src/main/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/ui/notifications/BasicNotifications/CONTRIB.md b/admin/AppRestrictionSchema/CONTRIB.md
similarity index 100%
copy from ui/notifications/BasicNotifications/CONTRIB.md
copy to admin/AppRestrictionSchema/CONTRIB.md
diff --git a/ui/notifications/BasicNotifications/LICENSE b/admin/AppRestrictionSchema/LICENSE
similarity index 100%
copy from ui/notifications/BasicNotifications/LICENSE
copy to admin/AppRestrictionSchema/LICENSE
diff --git a/admin/AppRestrictionSchema/build.gradle b/admin/AppRestrictionSchema/build.gradle
new file mode 100644
index 0000000..f9f6f65
--- /dev/null
+++ b/admin/AppRestrictionSchema/build.gradle
@@ -0,0 +1,14 @@
+
+
+
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../build"
+ pathToSamplesCommon "../../common"
+}
+apply from: "../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/admin/AppRestrictionSchema/buildSrc/build.gradle b/admin/AppRestrictionSchema/buildSrc/build.gradle
new file mode 100644
index 0000000..29282af
--- /dev/null
+++ b/admin/AppRestrictionSchema/buildSrc/build.gradle
@@ -0,0 +1,18 @@
+
+
+
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile 'org.freemarker:freemarker:2.3.20'
+}
+
+sourceSets {
+ main {
+ groovy {
+ srcDir new File(rootDir, "../../../../../build/buildSrc/src/main/groovy")
+ }
+ }
+}
+
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/admin/AppRestrictionSchema/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
copy to admin/AppRestrictionSchema/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties b/admin/AppRestrictionSchema/gradle/wrapper/gradle-wrapper.properties
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties
copy to admin/AppRestrictionSchema/gradle/wrapper/gradle-wrapper.properties
diff --git a/ui/notifications/BasicNotifications/gradlew b/admin/AppRestrictionSchema/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to admin/AppRestrictionSchema/gradlew
diff --git a/ui/notifications/BasicNotifications/gradlew.bat b/admin/AppRestrictionSchema/gradlew.bat
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew.bat
copy to admin/AppRestrictionSchema/gradlew.bat
diff --git a/ui/notifications/BasicNotifications/settings.gradle b/admin/AppRestrictionSchema/settings.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/settings.gradle
copy to admin/AppRestrictionSchema/settings.gradle
diff --git a/admin/AppRestrictionSchema/template-params.xml b/admin/AppRestrictionSchema/template-params.xml
new file mode 100644
index 0000000..c6ec4a1
--- /dev/null
+++ b/admin/AppRestrictionSchema/template-params.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.
+-->
+
+<sample>
+ <name>AppRestrictionSchema</name>
+ <group>Admin</group>
+ <package>com.example.android.apprestrictionschema</package>
+
+ <minSdk>21</minSdk>
+ <compileSdkVersion>21</compileSdkVersion>
+
+ <strings>
+ <intro>
+ <![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.
+ ]]>
+ </intro>
+ </strings>
+
+ <template src="base" />
+ <template src="FragmentView" />
+ <common src="logger" />
+ <common src="activities" />
+
+</sample>
diff --git a/admin/BasicManagedProfile/Application/.gitignore b/admin/BasicManagedProfile/Application/.gitignore
new file mode 100644
index 0000000..8fd2e1c
--- /dev/null
+++ b/admin/BasicManagedProfile/Application/.gitignore
@@ -0,0 +1,16 @@
+# 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.
+src/template/
+src/common/
+build.gradle
diff --git a/ui/notifications/BasicNotifications/Application/proguard-project.txt b/admin/BasicManagedProfile/Application/proguard-project.txt
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/proguard-project.txt
copy to admin/BasicManagedProfile/Application/proguard-project.txt
diff --git a/admin/BasicManagedProfile/Application/src/main/AndroidManifest.xml b/admin/BasicManagedProfile/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29020c3
--- /dev/null
+++ b/admin/BasicManagedProfile/Application/src/main/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/admin/BasicManagedProfile/Application/src/main/java/com/example/android/basicmanagedprofile/BasicDeviceAdminReceiver.java b/admin/BasicManagedProfile/Application/src/main/java/com/example/android/basicmanagedprofile/BasicDeviceAdminReceiver.java
new file mode 100644
index 0000000..54eee84
--- /dev/null
+++ b/admin/BasicManagedProfile/Application/src/main/java/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/admin/BasicManagedProfile/Application/src/main/java/com/example/android/basicmanagedprofile/BasicManagedProfileFragment.java b/admin/BasicManagedProfile/Application/src/main/java/com/example/android/basicmanagedprofile/BasicManagedProfileFragment.java
new file mode 100644
index 0000000..beb8d4a
--- /dev/null
+++ b/admin/BasicManagedProfile/Application/src/main/java/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/admin/BasicManagedProfile/Application/src/main/java/com/example/android/basicmanagedprofile/EnableProfileActivity.java b/admin/BasicManagedProfile/Application/src/main/java/com/example/android/basicmanagedprofile/EnableProfileActivity.java
new file mode 100644
index 0000000..deed2f6
--- /dev/null
+++ b/admin/BasicManagedProfile/Application/src/main/java/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/admin/BasicManagedProfile/Application/src/main/java/com/example/android/basicmanagedprofile/MainActivity.java b/admin/BasicManagedProfile/Application/src/main/java/com/example/android/basicmanagedprofile/MainActivity.java
new file mode 100644
index 0000000..3847fee
--- /dev/null
+++ b/admin/BasicManagedProfile/Application/src/main/java/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/admin/BasicManagedProfile/Application/src/main/java/com/example/android/basicmanagedprofile/SetupProfileFragment.java b/admin/BasicManagedProfile/Application/src/main/java/com/example/android/basicmanagedprofile/SetupProfileFragment.java
new file mode 100644
index 0000000..7da6e02
--- /dev/null
+++ b/admin/BasicManagedProfile/Application/src/main/java/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/admin/BasicManagedProfile/Application/src/main/res/drawable-hdpi/ic_launcher.png b/admin/BasicManagedProfile/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..c8feb76
--- /dev/null
+++ b/admin/BasicManagedProfile/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/admin/BasicManagedProfile/Application/src/main/res/drawable-mdpi/ic_launcher.png b/admin/BasicManagedProfile/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..4bf549e
--- /dev/null
+++ b/admin/BasicManagedProfile/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/admin/BasicManagedProfile/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/admin/BasicManagedProfile/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..33afaaa
--- /dev/null
+++ b/admin/BasicManagedProfile/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/admin/BasicManagedProfile/Application/src/main/res/drawable-xxhdpi/badge.png b/admin/BasicManagedProfile/Application/src/main/res/drawable-xxhdpi/badge.png
new file mode 100644
index 0000000..77a88cf
--- /dev/null
+++ b/admin/BasicManagedProfile/Application/src/main/res/drawable-xxhdpi/badge.png
Binary files differ
diff --git a/admin/BasicManagedProfile/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/admin/BasicManagedProfile/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..d6f927a
--- /dev/null
+++ b/admin/BasicManagedProfile/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/admin/BasicManagedProfile/Application/src/main/res/drawable/ic_launcher_badged.xml b/admin/BasicManagedProfile/Application/src/main/res/drawable/ic_launcher_badged.xml
new file mode 100644
index 0000000..b91b9bd
--- /dev/null
+++ b/admin/BasicManagedProfile/Application/src/main/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/admin/BasicManagedProfile/Application/src/main/res/layout/activity_main_real.xml b/admin/BasicManagedProfile/Application/src/main/res/layout/activity_main_real.xml
new file mode 100644
index 0000000..e09df9e
--- /dev/null
+++ b/admin/BasicManagedProfile/Application/src/main/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/admin/BasicManagedProfile/Application/src/main/res/layout/activity_setup.xml b/admin/BasicManagedProfile/Application/src/main/res/layout/activity_setup.xml
new file mode 100644
index 0000000..c52f15d
--- /dev/null
+++ b/admin/BasicManagedProfile/Application/src/main/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/admin/BasicManagedProfile/Application/src/main/res/layout/fragment_main.xml b/admin/BasicManagedProfile/Application/src/main/res/layout/fragment_main.xml
new file mode 100644
index 0000000..a5ba580
--- /dev/null
+++ b/admin/BasicManagedProfile/Application/src/main/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/admin/BasicManagedProfile/Application/src/main/res/layout/fragment_setup_profile.xml b/admin/BasicManagedProfile/Application/src/main/res/layout/fragment_setup_profile.xml
new file mode 100644
index 0000000..2aaaa93
--- /dev/null
+++ b/admin/BasicManagedProfile/Application/src/main/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/admin/BasicManagedProfile/Application/src/main/res/values-w820dp/dimens.xml b/admin/BasicManagedProfile/Application/src/main/res/values-w820dp/dimens.xml
new file mode 100644
index 0000000..146c0e1
--- /dev/null
+++ b/admin/BasicManagedProfile/Application/src/main/res/values-w820dp/dimens.xml
@@ -0,0 +1,3 @@
+<resources>
+ <dimen name="activity_horizontal_margin">64dp</dimen>
+</resources>
diff --git a/admin/BasicManagedProfile/Application/src/main/res/values/dimens.xml b/admin/BasicManagedProfile/Application/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..71c0df5
--- /dev/null
+++ b/admin/BasicManagedProfile/Application/src/main/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/admin/BasicManagedProfile/Application/src/main/res/values/strings.xml b/admin/BasicManagedProfile/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..240c7ab
--- /dev/null
+++ b/admin/BasicManagedProfile/Application/src/main/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/admin/BasicManagedProfile/Application/src/main/res/values/styles.xml b/admin/BasicManagedProfile/Application/src/main/res/values/styles.xml
new file mode 100644
index 0000000..fbf538d
--- /dev/null
+++ b/admin/BasicManagedProfile/Application/src/main/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/admin/BasicManagedProfile/Application/src/main/res/xml/basic_device_admin_receiver.xml b/admin/BasicManagedProfile/Application/src/main/res/xml/basic_device_admin_receiver.xml
new file mode 100644
index 0000000..5b876dd
--- /dev/null
+++ b/admin/BasicManagedProfile/Application/src/main/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/ui/notifications/BasicNotifications/CONTRIB.md b/admin/BasicManagedProfile/CONTRIB.md
similarity index 100%
copy from ui/notifications/BasicNotifications/CONTRIB.md
copy to admin/BasicManagedProfile/CONTRIB.md
diff --git a/ui/notifications/BasicNotifications/LICENSE b/admin/BasicManagedProfile/LICENSE
similarity index 100%
copy from ui/notifications/BasicNotifications/LICENSE
copy to admin/BasicManagedProfile/LICENSE
diff --git a/admin/BasicManagedProfile/README.md b/admin/BasicManagedProfile/README.md
new file mode 100644
index 0000000..c1e4fde
--- /dev/null
+++ b/admin/BasicManagedProfile/README.md
@@ -0,0 +1,52 @@
+Android BasicManagedProfile Sample
+==============================
+
+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.
+
+Pre-requisites
+--------------
+
+- Android SDK (L Developer Preview)
+- Android Build Tools v20
+- Android Support Repository
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-BasicManagedProfile
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2014 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements. See the NOTICE file distributed with this work for
+additional information regarding copyright ownership. The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/admin/BasicManagedProfile/build.gradle b/admin/BasicManagedProfile/build.gradle
new file mode 100644
index 0000000..f9f6f65
--- /dev/null
+++ b/admin/BasicManagedProfile/build.gradle
@@ -0,0 +1,14 @@
+
+
+
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../build"
+ pathToSamplesCommon "../../common"
+}
+apply from: "../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/admin/BasicManagedProfile/buildSrc/build.gradle b/admin/BasicManagedProfile/buildSrc/build.gradle
new file mode 100644
index 0000000..29282af
--- /dev/null
+++ b/admin/BasicManagedProfile/buildSrc/build.gradle
@@ -0,0 +1,18 @@
+
+
+
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile 'org.freemarker:freemarker:2.3.20'
+}
+
+sourceSets {
+ main {
+ groovy {
+ srcDir new File(rootDir, "../../../../../build/buildSrc/src/main/groovy")
+ }
+ }
+}
+
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/admin/BasicManagedProfile/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
copy to admin/BasicManagedProfile/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties b/admin/BasicManagedProfile/gradle/wrapper/gradle-wrapper.properties
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties
copy to admin/BasicManagedProfile/gradle/wrapper/gradle-wrapper.properties
diff --git a/ui/notifications/BasicNotifications/gradlew b/admin/BasicManagedProfile/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to admin/BasicManagedProfile/gradlew
diff --git a/ui/notifications/BasicNotifications/gradlew.bat b/admin/BasicManagedProfile/gradlew.bat
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew.bat
copy to admin/BasicManagedProfile/gradlew.bat
diff --git a/admin/BasicManagedProfile/packaging.yaml b/admin/BasicManagedProfile/packaging.yaml
new file mode 100644
index 0000000..81ec492
--- /dev/null
+++ b/admin/BasicManagedProfile/packaging.yaml
@@ -0,0 +1,15 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+
+status: PUBLISHED
+technologies: [Android]
+categories: [Admin]
+languages: [Java]
+solutions: [Mobile]
+github: googlesamples/android-BasicManagedProfile
+level: BEGINNER
+icon: BasicManagedProfileSample/src/main/res/drawable-xxhdpi/ic_launcher.png
+license: apache2
diff --git a/ui/notifications/BasicNotifications/settings.gradle b/admin/BasicManagedProfile/settings.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/settings.gradle
copy to admin/BasicManagedProfile/settings.gradle
diff --git a/admin/BasicManagedProfile/template-params.xml b/admin/BasicManagedProfile/template-params.xml
new file mode 100644
index 0000000..c1ba1cb
--- /dev/null
+++ b/admin/BasicManagedProfile/template-params.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.
+-->
+
+
+
+<sample>
+ <name>BasicManagedProfile</name>
+ <group>Admin</group>
+ <package>com.example.android.basicmanagedprofile</package>
+
+
+
+ <!-- change minSdk if needed-->
+ <minSdk>21</minSdk>
+ <compileSdkVersion>21</compileSdkVersion>
+
+
+ <strings>
+ <intro>
+ <![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.
+ ]]>
+ </intro>
+ </strings>
+ <template src="base"/>
+
+</sample>
diff --git a/ui/notifications/BasicNotifications/Application/.gitignore b/background/JobScheduler/Application/.gitignore
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/.gitignore
copy to background/JobScheduler/Application/.gitignore
diff --git a/ui/notifications/BasicNotifications/Application/proguard-project.txt b/background/JobScheduler/Application/proguard-project.txt
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/proguard-project.txt
copy to background/JobScheduler/Application/proguard-project.txt
diff --git a/background/JobScheduler/Application/src/main/AndroidManifest.xml b/background/JobScheduler/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..06a927b
--- /dev/null
+++ b/background/JobScheduler/Application/src/main/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/background/JobScheduler/Application/src/main/java/com/example/android/jobscheduler/MainActivity.java b/background/JobScheduler/Application/src/main/java/com/example/android/jobscheduler/MainActivity.java
new file mode 100644
index 0000000..624e22d
--- /dev/null
+++ b/background/JobScheduler/Application/src/main/java/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.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);
+ } else if (requiresAnyConnectivity) {
+ builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_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/background/JobScheduler/Application/src/main/java/com/example/android/jobscheduler/service/TestJobService.java b/background/JobScheduler/Application/src/main/java/com/example/android/jobscheduler/service/TestJobService.java
new file mode 100644
index 0000000..8608be5
--- /dev/null
+++ b/background/JobScheduler/Application/src/main/java/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/background/JobScheduler/Application/src/main/res/drawable-hdpi/ic_launcher.png b/background/JobScheduler/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..9cb5f74
--- /dev/null
+++ b/background/JobScheduler/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/background/JobScheduler/Application/src/main/res/drawable-mdpi/ic_launcher.png b/background/JobScheduler/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..869355b
--- /dev/null
+++ b/background/JobScheduler/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/background/JobScheduler/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/background/JobScheduler/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..679fc16
--- /dev/null
+++ b/background/JobScheduler/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/background/JobScheduler/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/background/JobScheduler/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..1734fd3
--- /dev/null
+++ b/background/JobScheduler/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/background/JobScheduler/Application/src/main/res/layout/sample_main.xml b/background/JobScheduler/Application/src/main/res/layout/sample_main.xml
new file mode 100644
index 0000000..94b1624
--- /dev/null
+++ b/background/JobScheduler/Application/src/main/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/background/JobScheduler/Application/src/main/res/values-v11/styles.xml b/background/JobScheduler/Application/src/main/res/values-v11/styles.xml
new file mode 100644
index 0000000..a181ed0
--- /dev/null
+++ b/background/JobScheduler/Application/src/main/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/background/JobScheduler/Application/src/main/res/values-v14/styles.xml b/background/JobScheduler/Application/src/main/res/values-v14/styles.xml
new file mode 100644
index 0000000..53cc49d
--- /dev/null
+++ b/background/JobScheduler/Application/src/main/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/background/JobScheduler/Application/src/main/res/values/color.xml b/background/JobScheduler/Application/src/main/res/values/color.xml
new file mode 100644
index 0000000..b1e5338
--- /dev/null
+++ b/background/JobScheduler/Application/src/main/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/background/JobScheduler/Application/src/main/res/values/strings.xml b/background/JobScheduler/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..89524b2
--- /dev/null
+++ b/background/JobScheduler/Application/src/main/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/background/JobScheduler/Application/src/main/res/values/styles.xml b/background/JobScheduler/Application/src/main/res/values/styles.xml
new file mode 100644
index 0000000..b767e51
--- /dev/null
+++ b/background/JobScheduler/Application/src/main/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/background/JobScheduler/Application/tests/AndroidManifest.xml b/background/JobScheduler/Application/tests/AndroidManifest.xml
new file mode 100644
index 0000000..bb06508
--- /dev/null
+++ b/background/JobScheduler/Application/tests/AndroidManifest.xml
@@ -0,0 +1,59 @@
+<?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.
+-->
+
+
+
+<?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.
+ -->
+<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.jobscheduler.tests"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
+ <!-- We add an application tag here just so that we can indicate that
+ this package needs to link against the android.test library,
+ which is needed when building test cases. -->
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!--
+ Specifies the instrumentation test runner used to run the tests.
+ -->
+ <instrumentation
+ android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.example.android.jobscheduler"
+ android:label="Tests for com.example.android.jobscheduler" />
+
+</manifest>
\ No newline at end of file
diff --git a/background/JobScheduler/Application/tests/src/com/example/android/jobscheduler/tests/SampleTests.java b/background/JobScheduler/Application/tests/src/com/example/android/jobscheduler/tests/SampleTests.java
new file mode 100644
index 0000000..d791b6e
--- /dev/null
+++ b/background/JobScheduler/Application/tests/src/com/example/android/jobscheduler/tests/SampleTests.java
@@ -0,0 +1,79 @@
+/*
+* 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 (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.jobscheduler.tests;
+
+import com.example.android.jobscheduler.*;
+
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+* Tests for JobScheduler sample.
+*/
+public class SampleTests extends ActivityInstrumentationTestCase2<MainActivity> {
+
+ private MainActivity mTestActivity;
+ private JobSchedulerFragment mTestFragment;
+
+ public SampleTests() {
+ super(MainActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // Starts the activity under test using the default Intent with:
+ // action = {@link Intent#ACTION_MAIN}
+ // flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK}
+ // All other fields are null or empty.
+ mTestActivity = getActivity();
+ mTestFragment = (JobSchedulerFragment)
+ mTestActivity.getSupportFragmentManager().getFragments().get(1);
+ }
+
+ /**
+ * Test if the test fixture has been set up correctly.
+ */
+ public void testPreconditions() {
+ //Try to add a message to add context to your assertions. These messages will be shown if
+ //a tests fails and make it easy to understand why a test failed
+ assertNotNull("mTestActivity is null", mTestActivity);
+ assertNotNull("mTestFragment is null", mTestFragment);
+ }
+
+ /**
+ * Add more tests below.
+ */
+
+}
\ No newline at end of file
diff --git a/ui/notifications/BasicNotifications/CONTRIB.md b/background/JobScheduler/CONTRIB.md
similarity index 100%
copy from ui/notifications/BasicNotifications/CONTRIB.md
copy to background/JobScheduler/CONTRIB.md
diff --git a/ui/notifications/BasicNotifications/LICENSE b/background/JobScheduler/LICENSE
similarity index 100%
copy from ui/notifications/BasicNotifications/LICENSE
copy to background/JobScheduler/LICENSE
diff --git a/background/JobScheduler/README.md b/background/JobScheduler/README.md
new file mode 100644
index 0000000..6b285a9
--- /dev/null
+++ b/background/JobScheduler/README.md
@@ -0,0 +1,50 @@
+Android JobScheduler Sample
+==============================
+
+Demonstration of the JobScheduler API, which provides an interface for scheduling
+background tasks when certain tasks apply.
+
+Pre-requisites
+--------------
+
+- Android SDK (L Developer Preview)
+- Android Build Tools v20
+- Android Support Repository
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-JobScheduler
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2014 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements. See the NOTICE file distributed with this work for
+additional information regarding copyright ownership. The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/background/JobScheduler/README.txt b/background/JobScheduler/README.txt
new file mode 100644
index 0000000..015d2b3
--- /dev/null
+++ b/background/JobScheduler/README.txt
@@ -0,0 +1,18 @@
+Build Instructions
+-------------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+To see a list of all available commands, run "gradlew tasks".
+
+Dependencies
+-------------
+
+- Android SDK Build-tools v20.0.0
+- Android Support Repository v2
+
+Dependencies are available for download via the Android SDK Manager.
+
+Android Studio is available for download at:
+ http://developer.android.com/sdk/installing/studio.html
diff --git a/background/JobScheduler/build.gradle b/background/JobScheduler/build.gradle
new file mode 100644
index 0000000..f9f6f65
--- /dev/null
+++ b/background/JobScheduler/build.gradle
@@ -0,0 +1,14 @@
+
+
+
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../build"
+ pathToSamplesCommon "../../common"
+}
+apply from: "../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/background/JobScheduler/buildSrc/build.gradle b/background/JobScheduler/buildSrc/build.gradle
new file mode 100644
index 0000000..29282af
--- /dev/null
+++ b/background/JobScheduler/buildSrc/build.gradle
@@ -0,0 +1,18 @@
+
+
+
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile 'org.freemarker:freemarker:2.3.20'
+}
+
+sourceSets {
+ main {
+ groovy {
+ srcDir new File(rootDir, "../../../../../build/buildSrc/src/main/groovy")
+ }
+ }
+}
+
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/background/JobScheduler/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
copy to background/JobScheduler/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties b/background/JobScheduler/gradle/wrapper/gradle-wrapper.properties
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties
copy to background/JobScheduler/gradle/wrapper/gradle-wrapper.properties
diff --git a/ui/notifications/BasicNotifications/gradlew b/background/JobScheduler/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to background/JobScheduler/gradlew
diff --git a/ui/notifications/BasicNotifications/gradlew.bat b/background/JobScheduler/gradlew.bat
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew.bat
copy to background/JobScheduler/gradlew.bat
diff --git a/background/JobScheduler/packaging.yaml b/background/JobScheduler/packaging.yaml
new file mode 100644
index 0000000..f2ea281
--- /dev/null
+++ b/background/JobScheduler/packaging.yaml
@@ -0,0 +1,15 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+
+status: PUBLISHED
+technologies: [Android]
+categories: [Background]
+languages: [Java]
+solutions: [Mobile]
+github: googlesamples/android-JobScheduler
+level: BEGINNER
+icon: JobSchedulerSample/src/main/res/drawable-xxhdpi/ic_launcher.png
+license: apache2
diff --git a/ui/notifications/BasicNotifications/settings.gradle b/background/JobScheduler/settings.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/settings.gradle
copy to background/JobScheduler/settings.gradle
diff --git a/background/JobScheduler/template-params.xml b/background/JobScheduler/template-params.xml
new file mode 100644
index 0000000..a9e06de
--- /dev/null
+++ b/background/JobScheduler/template-params.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.
+-->
+
+
+
+<sample>
+ <name>JobScheduler</name>
+ <group>Background</group>
+ <package>com.example.android.jobscheduler</package>
+
+ <!-- change minSdk if needed-->
+ <minSdk>18</minSdk>
+ <compileSdkVersion>21</compileSdkVersion>
+
+ <strings>
+ <intro>
+ <![CDATA[
+ Demonstration of the JobScheduler API, which provides an interface for scheduling
+ background tasks when certain tasks apply.
+ ]]>
+ </intro>
+ </strings>
+
+ <template src="base"/>
+ <common src="logger"/>
+
+</sample>
diff --git a/background/alarms/RepeatingAlarm/Application/src/main/AndroidManifest.xml b/background/alarms/RepeatingAlarm/Application/src/main/AndroidManifest.xml
index b7d02e5..0fbdc7a 100644
--- a/background/alarms/RepeatingAlarm/Application/src/main/AndroidManifest.xml
+++ b/background/alarms/RepeatingAlarm/Application/src/main/AndroidManifest.xml
@@ -19,7 +19,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="17" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application android:allowBackup="true"
android:label="@string/app_name"
diff --git a/build.gradle b/build.gradle
index 62ab934..740e531 100644
--- a/build.gradle
+++ b/build.gradle
@@ -24,9 +24,10 @@
"ui/actionbarcompat/ActionBarCompat-Styled",
"ui/actionbarcompat/ActionBarCompat-ListPopupMenu",
"ui/actionbarcompat/ActionBarCompat-ShareActionProvider",
-"ui/notifications/BasicNotifications",
-"ui/notifications/CustomNotifications",
+"notification/BasicNotifications",
+"notification/CustomNotifications",
"ui/actionbar/DoneBar",
+"ui/graphics/PdfRendererBasic",
"ui/window/BasicImmersiveMode",
"ui/window/AdvancedImmersiveMode",
"ui/window/ImmersiveMode",
@@ -46,9 +47,9 @@
"ui/views/SwipeRefreshLayout/SwipeRefreshLayoutBasic",
"ui/views/SwipeRefreshLayout/SwipeRefreshListFragment",
"ui/views/SwipeRefreshLayout/SwipeRefreshMultipleViews",
+"media/MediaBrowserService",
"media/MediaRouter",
"media/MediaEffects",
-"connectivity/bluetooth/BluetoothChat",
"admin/BasicManagedProfile",
"media/Camera2Basic",
"media/Camera2Video",
@@ -62,7 +63,8 @@
"background/JobScheduler",
"ui/views/RecyclerView",
"ui/views/CardView",
-"ui/notifications/LNotifications",
+"notification/LNotifications",
+"notification/MessagingService",
"ui/DrawableTinting",
"ui/Interpolator",
"media/HdrViewfinder",
@@ -70,7 +72,7 @@
"ui/activitytasks/DocumentCentricRelinquishIdentity",
"admin/AppRestrictionEnforcer",
"admin/AppRestrictionSchema",
-"bluetooth/BluetoothChat",
+"connectivity/bluetooth/BluetoothChat",
"wearable/wear/AgendaData",
"wearable/wear/DataLayer",
"wearable/wear/DelayedConfirmation",
diff --git a/common/src/java/com/example/android/common/media/MediaCodecWrapper.java b/common/src/java/com/example/android/common/media/MediaCodecWrapper.java
index a511221..a483374 100644
--- a/common/src/java/com/example/android/common/media/MediaCodecWrapper.java
+++ b/common/src/java/com/example/android/common/media/MediaCodecWrapper.java
@@ -21,6 +21,7 @@
import android.os.Looper;
import android.view.Surface;
+import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayDeque;
import java.util.Queue;
@@ -136,7 +137,7 @@
* @return
*/
public static MediaCodecWrapper fromVideoFormat(final MediaFormat trackFormat,
- Surface surface) {
+ Surface surface) throws IOException {
MediaCodecWrapper result = null;
MediaCodec videoCodec = null;
diff --git a/connectivity/bluetooth/BluetoothChat/Application/src/main/AndroidManifest.xml b/connectivity/bluetooth/BluetoothChat/Application/src/main/AndroidManifest.xml
index 99b9b12..53dc5ab 100644
--- a/connectivity/bluetooth/BluetoothChat/Application/src/main/AndroidManifest.xml
+++ b/connectivity/bluetooth/BluetoothChat/Application/src/main/AndroidManifest.xml
@@ -21,9 +21,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="11"
- android:targetSdkVersion="17"/>
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
diff --git a/connectivity/bluetooth/BluetoothLeGatt/Application/src/main/AndroidManifest.xml b/connectivity/bluetooth/BluetoothLeGatt/Application/src/main/AndroidManifest.xml
index babd6df..d3cf257 100644
--- a/connectivity/bluetooth/BluetoothLeGatt/Application/src/main/AndroidManifest.xml
+++ b/connectivity/bluetooth/BluetoothLeGatt/Application/src/main/AndroidManifest.xml
@@ -22,8 +22,8 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="18"
- android:targetSdkVersion="18"/>
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
<!-- Declare this required feature if you want to make the app available to BLE-capable
devices only. If you want to make your app available to devices that don't support BLE,
you should omit this in the manifest. Instead, determine BLE capability by using
diff --git a/connectivity/network/BasicNetworking/Application/src/main/AndroidManifest.xml b/connectivity/network/BasicNetworking/Application/src/main/AndroidManifest.xml
index 48bfeac..b512790 100644
--- a/connectivity/network/BasicNetworking/Application/src/main/AndroidManifest.xml
+++ b/connectivity/network/BasicNetworking/Application/src/main/AndroidManifest.xml
@@ -20,7 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
diff --git a/connectivity/network/BasicNetworking/Application/tests/AndroidManifest.xml b/connectivity/network/BasicNetworking/Application/tests/AndroidManifest.xml
index 293c16b..327ae46 100644
--- a/connectivity/network/BasicNetworking/Application/tests/AndroidManifest.xml
+++ b/connectivity/network/BasicNetworking/Application/tests/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/connectivity/network/NetworkConnect/Application/src/main/AndroidManifest.xml b/connectivity/network/NetworkConnect/Application/src/main/AndroidManifest.xml
index 1ae29df..00ce7f3 100644
--- a/connectivity/network/NetworkConnect/Application/src/main/AndroidManifest.xml
+++ b/connectivity/network/NetworkConnect/Application/src/main/AndroidManifest.xml
@@ -23,7 +23,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
diff --git a/connectivity/network/NetworkConnect/Application/tests/AndroidManifest.xml b/connectivity/network/NetworkConnect/Application/tests/AndroidManifest.xml
index 80fec80..2aaee3f 100644
--- a/connectivity/network/NetworkConnect/Application/tests/AndroidManifest.xml
+++ b/connectivity/network/NetworkConnect/Application/tests/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/connectivity/nfc/BeamLargeFiles/Application/src/main/AndroidManifest.xml b/connectivity/nfc/BeamLargeFiles/Application/src/main/AndroidManifest.xml
index cda0866..b084253 100644
--- a/connectivity/nfc/BeamLargeFiles/Application/src/main/AndroidManifest.xml
+++ b/connectivity/nfc/BeamLargeFiles/Application/src/main/AndroidManifest.xml
@@ -21,7 +21,7 @@
android:versionName="1.0">
<!-- Large file beam requires API 16 or above. -->
- <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="17" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- The NFC permission is required to use NfcAdapter. -->
<uses-permission android:name="android.permission.NFC" />
@@ -45,7 +45,7 @@
<!-- Content provider, used to provide images for transmission. -->
<provider
- android:name=".AssetProvider"
+ android:name="com.example.android.common.assetprovider.AssetProvider"
android:authorities="com.example.android.beamlargefiles.files"
android:exported="true"/>
diff --git a/connectivity/nfc/BeamLargeFiles/Application/src/main/res/menu/main.xml b/connectivity/nfc/BeamLargeFiles/Application/src/main/res/menu/main.xml
new file mode 100644
index 0000000..8de3baa
--- /dev/null
+++ b/connectivity/nfc/BeamLargeFiles/Application/src/main/res/menu/main.xml
@@ -0,0 +1,18 @@
+<!--
+ 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.
+ -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android" />
+
diff --git a/connectivity/nfc/BeamLargeFiles/Application/tests/AndroidManifest.xml b/connectivity/nfc/BeamLargeFiles/Application/tests/AndroidManifest.xml
index 87b785f..a046afc 100644
--- a/connectivity/nfc/BeamLargeFiles/Application/tests/AndroidManifest.xml
+++ b/connectivity/nfc/BeamLargeFiles/Application/tests/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/connectivity/nfc/BeamLargeFiles/gradle/wrapper/gradle-wrapper.properties b/connectivity/nfc/BeamLargeFiles/gradle/wrapper/gradle-wrapper.properties
index 5c22dec..d7f03cf 100644
--- a/connectivity/nfc/BeamLargeFiles/gradle/wrapper/gradle-wrapper.properties
+++ b/connectivity/nfc/BeamLargeFiles/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=http\://services.gradle.org/distributions/gradle-1.6-bin.zip
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-bin.zip
diff --git a/connectivity/nfc/BeamLargeFiles/template-params.xml b/connectivity/nfc/BeamLargeFiles/template-params.xml
index 947cf70..79142a4 100644
--- a/connectivity/nfc/BeamLargeFiles/template-params.xml
+++ b/connectivity/nfc/BeamLargeFiles/template-params.xml
@@ -16,6 +16,7 @@
-->
<sample>
<name>BeamLargeFiles</name>
+ <group>Connectivity</group>
<package>com.example.android.beamlargefiles</package>
diff --git a/connectivity/nfc/CardEmulation/Application/src/main/AndroidManifest.xml b/connectivity/nfc/CardEmulation/Application/src/main/AndroidManifest.xml
index 4a4af08..fba9a74 100644
--- a/connectivity/nfc/CardEmulation/Application/src/main/AndroidManifest.xml
+++ b/connectivity/nfc/CardEmulation/Application/src/main/AndroidManifest.xml
@@ -21,7 +21,7 @@
android:versionName="1.0">
<!-- Card emulation was introduced in API 19. -->
- <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<uses-feature android:name="android.hardware.nfc.hce" android:required="true" />
<uses-permission android:name="android.permission.NFC" />
diff --git a/connectivity/nfc/CardEmulation/Application/tests/AndroidManifest.xml b/connectivity/nfc/CardEmulation/Application/tests/AndroidManifest.xml
index 447d041..d1ec341 100644
--- a/connectivity/nfc/CardEmulation/Application/tests/AndroidManifest.xml
+++ b/connectivity/nfc/CardEmulation/Application/tests/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="19"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/connectivity/nfc/CardReader/Application/src/main/AndroidManifest.xml b/connectivity/nfc/CardReader/Application/src/main/AndroidManifest.xml
index a8ebd13..ed25c6f 100644
--- a/connectivity/nfc/CardReader/Application/src/main/AndroidManifest.xml
+++ b/connectivity/nfc/CardReader/Application/src/main/AndroidManifest.xml
@@ -21,7 +21,7 @@
android:versionName="1.0">
<!-- NFC Reader Mode was added in API 19. -->
- <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" android:required="true" />
diff --git a/connectivity/nfc/CardReader/Application/tests/AndroidManifest.xml b/connectivity/nfc/CardReader/Application/tests/AndroidManifest.xml
index 1098859..fd702fc 100644
--- a/connectivity/nfc/CardReader/Application/tests/AndroidManifest.xml
+++ b/connectivity/nfc/CardReader/Application/tests/AndroidManifest.xml
@@ -39,9 +39,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="19"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/connectivity/nfc/CardReader/gradle/wrapper/gradle-wrapper.properties b/connectivity/nfc/CardReader/gradle/wrapper/gradle-wrapper.properties
index f040b45..a7bd4a7 100644
--- a/connectivity/nfc/CardReader/gradle/wrapper/gradle-wrapper.properties
+++ b/connectivity/nfc/CardReader/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-all.zip
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip
diff --git a/connectivity/sync/BasicSyncAdapter/Application/src/main/AndroidManifest.xml b/connectivity/sync/BasicSyncAdapter/Application/src/main/AndroidManifest.xml
index dd59b06..4222b47 100644
--- a/connectivity/sync/BasicSyncAdapter/Application/src/main/AndroidManifest.xml
+++ b/connectivity/sync/BasicSyncAdapter/Application/src/main/AndroidManifest.xml
@@ -23,9 +23,7 @@
android:versionName="1.0">
<!-- SyncAdapters are available in API 5 and above. We use API 7 as a baseline for samples. -->
- <uses-sdk
- android:minSdkVersion="7"
- android:targetSdkVersion="17" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- Required for fetching feed data. -->
<uses-permission android:name="android.permission.INTERNET"/>
diff --git a/connectivity/sync/BasicSyncAdapter/Application/tests/AndroidManifest.xml b/connectivity/sync/BasicSyncAdapter/Application/tests/AndroidManifest.xml
index 44c910a..4422a8e 100644
--- a/connectivity/sync/BasicSyncAdapter/Application/tests/AndroidManifest.xml
+++ b/connectivity/sync/BasicSyncAdapter/Application/tests/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/content/LoaderCursor/AndroidManifest.xml b/content/LoaderCursor/AndroidManifest.xml
index 2305045..9dbf260 100644
--- a/content/LoaderCursor/AndroidManifest.xml
+++ b/content/LoaderCursor/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0" >
- <uses-sdk
- android:minSdkVersion="14"
- android:targetSdkVersion="17" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<application
diff --git a/content/contacts/BasicContactables/Application/src/main/AndroidManifest.xml b/content/contacts/BasicContactables/Application/src/main/AndroidManifest.xml
index 62b9812..079db23 100644
--- a/content/contacts/BasicContactables/Application/src/main/AndroidManifest.xml
+++ b/content/contacts/BasicContactables/Application/src/main/AndroidManifest.xml
@@ -23,9 +23,7 @@
<!-- BEGIN_INCLUDE(contacts_permission) -->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<!-- END_INCLUDE(contacts_permission) -->
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="18" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<permission android:name="android"></permission>
<application
diff --git a/content/contacts/BasicContactables/Application/tests/AndroidManifest.xml b/content/contacts/BasicContactables/Application/tests/AndroidManifest.xml
index 8c4af25..f8326f0 100644
--- a/content/contacts/BasicContactables/Application/tests/AndroidManifest.xml
+++ b/content/contacts/BasicContactables/Application/tests/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/content/documentsUi/StorageClient/Application/src/main/AndroidManifest.xml b/content/documentsUi/StorageClient/Application/src/main/AndroidManifest.xml
index d35a4ec..0bcfde9 100644
--- a/content/documentsUi/StorageClient/Application/src/main/AndroidManifest.xml
+++ b/content/documentsUi/StorageClient/Application/src/main/AndroidManifest.xml
@@ -19,7 +19,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application android:allowBackup="true"
android:label="@string/app_name"
diff --git a/content/documentsUi/StorageClient/Application/tests/AndroidManifest.xml b/content/documentsUi/StorageClient/Application/tests/AndroidManifest.xml
index 3f0a38f..ffcac1d 100644
--- a/content/documentsUi/StorageClient/Application/tests/AndroidManifest.xml
+++ b/content/documentsUi/StorageClient/Application/tests/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="19"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/content/documentsUi/StorageClient/template-params.xml b/content/documentsUi/StorageClient/template-params.xml
index f6843e7..0b2ddf2 100644
--- a/content/documentsUi/StorageClient/template-params.xml
+++ b/content/documentsUi/StorageClient/template-params.xml
@@ -20,7 +20,6 @@
<package>com.example.android.storageclient</package>
<!-- change minSdk if needed-->
<minSdk>4</minSdk>
- <compileSdkVersion>19</compileSdkVersion>
<strings>
<intro>
diff --git a/content/documentsUi/StorageProvider/Application/src/main/AndroidManifest.xml b/content/documentsUi/StorageProvider/Application/src/main/AndroidManifest.xml
index e4704dc..53e7819 100644
--- a/content/documentsUi/StorageProvider/Application/src/main/AndroidManifest.xml
+++ b/content/documentsUi/StorageProvider/Application/src/main/AndroidManifest.xml
@@ -21,9 +21,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="19"
- android:targetSdkVersion="19"/>
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
diff --git a/content/documentsUi/StorageProvider/template-params.xml b/content/documentsUi/StorageProvider/template-params.xml
index bda57ad..b9b5b04 100644
--- a/content/documentsUi/StorageProvider/template-params.xml
+++ b/content/documentsUi/StorageProvider/template-params.xml
@@ -22,12 +22,9 @@
<group>Content</group>
<package>com.example.android.storageprovider</package>
-
-
<!-- change minSdk if needed-->
<minSdk>19</minSdk>
-
<strings>
<intro>
<![CDATA[
diff --git a/content/multiuser/AppRestrictions/Application/src/main/AndroidManifest.xml b/content/multiuser/AppRestrictions/Application/src/main/AndroidManifest.xml
index b492bbf..ddac9cf 100644
--- a/content/multiuser/AppRestrictions/Application/src/main/AndroidManifest.xml
+++ b/content/multiuser/AppRestrictions/Application/src/main/AndroidManifest.xml
@@ -22,7 +22,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="18" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application android:label="@string/app_name"
android:icon="@drawable/ic_launcher">
diff --git a/input/gestures/BasicGestureDetect/Application/src/main/AndroidManifest.xml b/input/gestures/BasicGestureDetect/Application/src/main/AndroidManifest.xml
index 87ed603..aaa4f41 100644
--- a/input/gestures/BasicGestureDetect/Application/src/main/AndroidManifest.xml
+++ b/input/gestures/BasicGestureDetect/Application/src/main/AndroidManifest.xml
@@ -22,7 +22,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="13" android:targetSdkVersion="17" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application android:allowBackup="true"
android:label="@string/app_name"
diff --git a/input/gestures/BasicGestureDetect/Application/tests/AndroidManifest.xml b/input/gestures/BasicGestureDetect/Application/tests/AndroidManifest.xml
index 3c5487c..7014df0 100644
--- a/input/gestures/BasicGestureDetect/Application/tests/AndroidManifest.xml
+++ b/input/gestures/BasicGestureDetect/Application/tests/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/input/multitouch/BasicMultitouch/Application/src/main/AndroidManifest.xml b/input/multitouch/BasicMultitouch/Application/src/main/AndroidManifest.xml
index 043345c..fc11177 100644
--- a/input/multitouch/BasicMultitouch/Application/src/main/AndroidManifest.xml
+++ b/input/multitouch/BasicMultitouch/Application/src/main/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0" >
- <uses-sdk
- android:minSdkVersion="8"
- android:targetSdkVersion="17" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application
android:allowBackup="true"
diff --git a/media/BasicMediaDecoder/Application/src/main/AndroidManifest.xml b/media/BasicMediaDecoder/Application/src/main/AndroidManifest.xml
index d191491..02a674e 100644
--- a/media/BasicMediaDecoder/Application/src/main/AndroidManifest.xml
+++ b/media/BasicMediaDecoder/Application/src/main/AndroidManifest.xml
@@ -20,7 +20,8 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="17"/>
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
<application
android:label="@string/app_name" android:icon="@drawable/ic_launcher">
<activity
diff --git a/media/BasicMediaRouter/Application/src/main/AndroidManifest.xml b/media/BasicMediaRouter/Application/src/main/AndroidManifest.xml
index 33c20d5..f84b7df 100644
--- a/media/BasicMediaRouter/Application/src/main/AndroidManifest.xml
+++ b/media/BasicMediaRouter/Application/src/main/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0" >
- <uses-sdk
- android:minSdkVersion="17"
- android:targetSdkVersion="17" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application
android:allowBackup="true"
diff --git a/media/BasicMediaRouter/Application/tests/AndroidManifest.xml b/media/BasicMediaRouter/Application/tests/AndroidManifest.xml
index 8800232..927504e 100644
--- a/media/BasicMediaRouter/Application/tests/AndroidManifest.xml
+++ b/media/BasicMediaRouter/Application/tests/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/ui/notifications/BasicNotifications/Application/.gitignore b/media/Camera2Basic/Application/.gitignore
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/.gitignore
copy to media/Camera2Basic/Application/.gitignore
diff --git a/ui/notifications/BasicNotifications/Application/proguard-project.txt b/media/Camera2Basic/Application/proguard-project.txt
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/proguard-project.txt
copy to media/Camera2Basic/Application/proguard-project.txt
diff --git a/media/Camera2Basic/Application/src/main/AndroidManifest.xml b/media/Camera2Basic/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..87d9af1
--- /dev/null
+++ b/media/Camera2Basic/Application/src/main/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/media/Camera2Basic/Application/src/main/java/com/example/android/camera2basic/AutoFitTextureView.java b/media/Camera2Basic/Application/src/main/java/com/example/android/camera2basic/AutoFitTextureView.java
new file mode 100644
index 0000000..f4903e1
--- /dev/null
+++ b/media/Camera2Basic/Application/src/main/java/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/media/Camera2Basic/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java b/media/Camera2Basic/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java
new file mode 100644
index 0000000..f4bf220
--- /dev/null
+++ b/media/Camera2Basic/Application/src/main/java/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/media/Camera2Basic/Application/src/main/java/com/example/android/camera2basic/CameraActivity.java b/media/Camera2Basic/Application/src/main/java/com/example/android/camera2basic/CameraActivity.java
new file mode 100644
index 0000000..eb7f834
--- /dev/null
+++ b/media/Camera2Basic/Application/src/main/java/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/media/Camera2Basic/Application/src/main/res/drawable-hdpi/ic_action_info.png b/media/Camera2Basic/Application/src/main/res/drawable-hdpi/ic_action_info.png
new file mode 100644
index 0000000..32bd1aa
--- /dev/null
+++ b/media/Camera2Basic/Application/src/main/res/drawable-hdpi/ic_action_info.png
Binary files differ
diff --git a/media/Camera2Basic/Application/src/main/res/drawable-hdpi/ic_launcher.png b/media/Camera2Basic/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..ac6cf27
--- /dev/null
+++ b/media/Camera2Basic/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/media/Camera2Basic/Application/src/main/res/drawable-mdpi/ic_action_info.png b/media/Camera2Basic/Application/src/main/res/drawable-mdpi/ic_action_info.png
new file mode 100644
index 0000000..8efbbf8
--- /dev/null
+++ b/media/Camera2Basic/Application/src/main/res/drawable-mdpi/ic_action_info.png
Binary files differ
diff --git a/media/Camera2Basic/Application/src/main/res/drawable-mdpi/ic_launcher.png b/media/Camera2Basic/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..65f92a5
--- /dev/null
+++ b/media/Camera2Basic/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/media/Camera2Basic/Application/src/main/res/drawable-xhdpi/ic_action_info.png b/media/Camera2Basic/Application/src/main/res/drawable-xhdpi/ic_action_info.png
new file mode 100644
index 0000000..ba143ea
--- /dev/null
+++ b/media/Camera2Basic/Application/src/main/res/drawable-xhdpi/ic_action_info.png
Binary files differ
diff --git a/media/Camera2Basic/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/media/Camera2Basic/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..6fd1318
--- /dev/null
+++ b/media/Camera2Basic/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/media/Camera2Basic/Application/src/main/res/drawable-xxhdpi/ic_action_info.png b/media/Camera2Basic/Application/src/main/res/drawable-xxhdpi/ic_action_info.png
new file mode 100644
index 0000000..394eb7e
--- /dev/null
+++ b/media/Camera2Basic/Application/src/main/res/drawable-xxhdpi/ic_action_info.png
Binary files differ
diff --git a/media/Camera2Basic/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/media/Camera2Basic/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..4513cf2
--- /dev/null
+++ b/media/Camera2Basic/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/media/Camera2Basic/Application/src/main/res/layout-land/fragment_camera2_basic.xml b/media/Camera2Basic/Application/src/main/res/layout-land/fragment_camera2_basic.xml
new file mode 100644
index 0000000..3a3e2ff
--- /dev/null
+++ b/media/Camera2Basic/Application/src/main/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/media/Camera2Basic/Application/src/main/res/layout/activity_camera.xml b/media/Camera2Basic/Application/src/main/res/layout/activity_camera.xml
new file mode 100644
index 0000000..a86d220
--- /dev/null
+++ b/media/Camera2Basic/Application/src/main/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/media/Camera2Basic/Application/src/main/res/layout/fragment_camera2_basic.xml b/media/Camera2Basic/Application/src/main/res/layout/fragment_camera2_basic.xml
new file mode 100644
index 0000000..7d05ab3
--- /dev/null
+++ b/media/Camera2Basic/Application/src/main/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/media/Camera2Basic/Application/src/main/res/values/strings.xml b/media/Camera2Basic/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..66f1000
--- /dev/null
+++ b/media/Camera2Basic/Application/src/main/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/media/Camera2Basic/Application/src/main/res/values/styles.xml b/media/Camera2Basic/Application/src/main/res/values/styles.xml
new file mode 100644
index 0000000..3f3bdfb
--- /dev/null
+++ b/media/Camera2Basic/Application/src/main/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/media/Camera2Basic/Application/tests/AndroidManifest.xml b/media/Camera2Basic/Application/tests/AndroidManifest.xml
new file mode 100644
index 0000000..8b29c81
--- /dev/null
+++ b/media/Camera2Basic/Application/tests/AndroidManifest.xml
@@ -0,0 +1,59 @@
+<?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.
+-->
+
+
+
+<?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.
+ -->
+<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.camera2basic.tests"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
+ <!-- We add an application tag here just so that we can indicate that
+ this package needs to link against the android.test library,
+ which is needed when building test cases. -->
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!--
+ Specifies the instrumentation test runner used to run the tests.
+ -->
+ <instrumentation
+ android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.example.android.camera2basic"
+ android:label="Tests for com.example.android.camera2basic" />
+
+</manifest>
\ No newline at end of file
diff --git a/media/Camera2Basic/Application/tests/src/com/example/android/camera2basic/tests/SampleTests.java b/media/Camera2Basic/Application/tests/src/com/example/android/camera2basic/tests/SampleTests.java
new file mode 100644
index 0000000..44cdfeb
--- /dev/null
+++ b/media/Camera2Basic/Application/tests/src/com/example/android/camera2basic/tests/SampleTests.java
@@ -0,0 +1,79 @@
+/*
+* 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 (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.camera2basic.tests;
+
+import com.example.android.camera2basic.*;
+
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+* Tests for Camera2Basic sample.
+*/
+public class SampleTests extends ActivityInstrumentationTestCase2<CameraActivity> {
+
+ private CameraActivity mTestActivity;
+ private Camera2BasicFragment mTestFragment;
+
+ public SampleTests() {
+ super(CameraActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // Starts the activity under test using the default Intent with:
+ // action = {@link Intent#ACTION_MAIN}
+ // flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK}
+ // All other fields are null or empty.
+ mTestActivity = getActivity();
+ mTestFragment = (Camera2BasicFragment)
+ mTestActivity.getSupportFragmentManager().getFragments().get(1);
+ }
+
+ /**
+ * Test if the test fixture has been set up correctly.
+ */
+ public void testPreconditions() {
+ //Try to add a message to add context to your assertions. These messages will be shown if
+ //a tests fails and make it easy to understand why a test failed
+ assertNotNull("mTestActivity is null", mTestActivity);
+ assertNotNull("mTestFragment is null", mTestFragment);
+ }
+
+ /**
+ * Add more tests below.
+ */
+
+}
\ No newline at end of file
diff --git a/ui/notifications/BasicNotifications/CONTRIB.md b/media/Camera2Basic/CONTRIB.md
similarity index 100%
copy from ui/notifications/BasicNotifications/CONTRIB.md
copy to media/Camera2Basic/CONTRIB.md
diff --git a/ui/notifications/BasicNotifications/LICENSE b/media/Camera2Basic/LICENSE
similarity index 100%
copy from ui/notifications/BasicNotifications/LICENSE
copy to media/Camera2Basic/LICENSE
diff --git a/media/Camera2Basic/README.md b/media/Camera2Basic/README.md
new file mode 100644
index 0000000..73b9eac
--- /dev/null
+++ b/media/Camera2Basic/README.md
@@ -0,0 +1,50 @@
+Android Camera2Basic Sample
+==============================
+
+This sample demonstrates the basic use of Camera2 API. Check the source code to see how you can
+display camera preview and take pictures.
+
+Pre-requisites
+--------------
+
+- Android SDK (L Developer Preview)
+- Android Build Tools v20
+- Android Support Repository
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-Camera2Basic
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2014 The Android Open Source Project
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements. See the NOTICE file distributed with this work for
+additional information regarding copyright ownership. The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/media/Camera2Basic/build.gradle b/media/Camera2Basic/build.gradle
new file mode 100644
index 0000000..c7a137e
--- /dev/null
+++ b/media/Camera2Basic/build.gradle
@@ -0,0 +1,10 @@
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../build"
+ pathToSamplesCommon "../../common"
+}
+apply from: "../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/media/Camera2Basic/buildSrc/build.gradle b/media/Camera2Basic/buildSrc/build.gradle
new file mode 100644
index 0000000..29282af
--- /dev/null
+++ b/media/Camera2Basic/buildSrc/build.gradle
@@ -0,0 +1,18 @@
+
+
+
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile 'org.freemarker:freemarker:2.3.20'
+}
+
+sourceSets {
+ main {
+ groovy {
+ srcDir new File(rootDir, "../../../../../build/buildSrc/src/main/groovy")
+ }
+ }
+}
+
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/media/Camera2Basic/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
copy to media/Camera2Basic/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties b/media/Camera2Basic/gradle/wrapper/gradle-wrapper.properties
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties
copy to media/Camera2Basic/gradle/wrapper/gradle-wrapper.properties
diff --git a/ui/notifications/BasicNotifications/gradlew b/media/Camera2Basic/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to media/Camera2Basic/gradlew
diff --git a/ui/notifications/BasicNotifications/gradlew.bat b/media/Camera2Basic/gradlew.bat
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew.bat
copy to media/Camera2Basic/gradlew.bat
diff --git a/media/Camera2Basic/packaging.yaml b/media/Camera2Basic/packaging.yaml
new file mode 100644
index 0000000..d0327da
--- /dev/null
+++ b/media/Camera2Basic/packaging.yaml
@@ -0,0 +1,15 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+
+status: PUBLISHED
+technologies: [Android]
+categories: [Media]
+languages: [Java]
+solutions: [Mobile]
+github: googlesamples/android-Camera2Basic
+level: BEGINNER
+icon: Camera2BasicSample/src/main/res/drawable-xxhdpi/ic_launcher.png
+license: apache2
diff --git a/ui/notifications/BasicNotifications/settings.gradle b/media/Camera2Basic/settings.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/settings.gradle
copy to media/Camera2Basic/settings.gradle
diff --git a/media/Camera2Basic/template-params.xml b/media/Camera2Basic/template-params.xml
new file mode 100644
index 0000000..f89b6a3
--- /dev/null
+++ b/media/Camera2Basic/template-params.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.
+-->
+
+
+
+<sample>
+ <name>Camera2Basic</name>
+ <group>Media</group>
+ <package>com.example.android.camera2basic</package>
+ <minSdk>21</minSdk>
+ <compileSdkVersion>21</compileSdkVersion>
+ <strings>
+ <intro>
+ <![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.
+ ]]>
+ </intro>
+ </strings>
+
+ <template src="base"/>
+
+</sample>
diff --git a/ui/notifications/BasicNotifications/Application/.gitignore b/media/Camera2Video/Application/.gitignore
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/.gitignore
copy to media/Camera2Video/Application/.gitignore
diff --git a/ui/notifications/BasicNotifications/Application/proguard-project.txt b/media/Camera2Video/Application/proguard-project.txt
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/proguard-project.txt
copy to media/Camera2Video/Application/proguard-project.txt
diff --git a/media/Camera2Video/Application/src/main/AndroidManifest.xml b/media/Camera2Video/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..5cb5428
--- /dev/null
+++ b/media/Camera2Video/Application/src/main/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/media/Camera2Video/Application/src/main/java/com/example/android/camera2video/AutoFitTextureView.java b/media/Camera2Video/Application/src/main/java/com/example/android/camera2video/AutoFitTextureView.java
new file mode 100644
index 0000000..090f81c
--- /dev/null
+++ b/media/Camera2Video/Application/src/main/java/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/media/Camera2Video/Application/src/main/java/com/example/android/camera2video/Camera2VideoFragment.java b/media/Camera2Video/Application/src/main/java/com/example/android/camera2video/Camera2VideoFragment.java
new file mode 100644
index 0000000..78e276a
--- /dev/null
+++ b/media/Camera2Video/Application/src/main/java/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/media/Camera2Video/Application/src/main/java/com/example/android/camera2video/CameraActivity.java b/media/Camera2Video/Application/src/main/java/com/example/android/camera2video/CameraActivity.java
new file mode 100644
index 0000000..d90f227
--- /dev/null
+++ b/media/Camera2Video/Application/src/main/java/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/media/Camera2Video/Application/src/main/res/drawable-hdpi/ic_action_info.png b/media/Camera2Video/Application/src/main/res/drawable-hdpi/ic_action_info.png
new file mode 100644
index 0000000..32bd1aa
--- /dev/null
+++ b/media/Camera2Video/Application/src/main/res/drawable-hdpi/ic_action_info.png
Binary files differ
diff --git a/media/Camera2Video/Application/src/main/res/drawable-hdpi/ic_launcher.png b/media/Camera2Video/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..88bc107
--- /dev/null
+++ b/media/Camera2Video/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/media/Camera2Video/Application/src/main/res/drawable-mdpi/ic_action_info.png b/media/Camera2Video/Application/src/main/res/drawable-mdpi/ic_action_info.png
new file mode 100644
index 0000000..8efbbf8
--- /dev/null
+++ b/media/Camera2Video/Application/src/main/res/drawable-mdpi/ic_action_info.png
Binary files differ
diff --git a/media/Camera2Video/Application/src/main/res/drawable-mdpi/ic_launcher.png b/media/Camera2Video/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..28a5a42
--- /dev/null
+++ b/media/Camera2Video/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/media/Camera2Video/Application/src/main/res/drawable-xhdpi/ic_action_info.png b/media/Camera2Video/Application/src/main/res/drawable-xhdpi/ic_action_info.png
new file mode 100644
index 0000000..ba143ea
--- /dev/null
+++ b/media/Camera2Video/Application/src/main/res/drawable-xhdpi/ic_action_info.png
Binary files differ
diff --git a/media/Camera2Video/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/media/Camera2Video/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..2811666
--- /dev/null
+++ b/media/Camera2Video/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/media/Camera2Video/Application/src/main/res/drawable-xxhdpi/ic_action_info.png b/media/Camera2Video/Application/src/main/res/drawable-xxhdpi/ic_action_info.png
new file mode 100644
index 0000000..394eb7e
--- /dev/null
+++ b/media/Camera2Video/Application/src/main/res/drawable-xxhdpi/ic_action_info.png
Binary files differ
diff --git a/media/Camera2Video/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/media/Camera2Video/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..0e8ab46
--- /dev/null
+++ b/media/Camera2Video/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/media/Camera2Video/Application/src/main/res/layout-land/fragment_camera2_video.xml b/media/Camera2Video/Application/src/main/res/layout-land/fragment_camera2_video.xml
new file mode 100644
index 0000000..aa139a9
--- /dev/null
+++ b/media/Camera2Video/Application/src/main/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/media/Camera2Video/Application/src/main/res/layout/activity_camera.xml b/media/Camera2Video/Application/src/main/res/layout/activity_camera.xml
new file mode 100644
index 0000000..a86d220
--- /dev/null
+++ b/media/Camera2Video/Application/src/main/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/media/Camera2Video/Application/src/main/res/layout/fragment_camera2_video.xml b/media/Camera2Video/Application/src/main/res/layout/fragment_camera2_video.xml
new file mode 100644
index 0000000..e30009d
--- /dev/null
+++ b/media/Camera2Video/Application/src/main/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/media/Camera2Video/Application/src/main/res/values/strings.xml b/media/Camera2Video/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..bf5e439
--- /dev/null
+++ b/media/Camera2Video/Application/src/main/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/media/Camera2Video/Application/src/main/res/values/styles.xml b/media/Camera2Video/Application/src/main/res/values/styles.xml
new file mode 100644
index 0000000..841d8ce
--- /dev/null
+++ b/media/Camera2Video/Application/src/main/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/ui/notifications/BasicNotifications/CONTRIB.md b/media/Camera2Video/CONTRIB.md
similarity index 100%
copy from ui/notifications/BasicNotifications/CONTRIB.md
copy to media/Camera2Video/CONTRIB.md
diff --git a/ui/notifications/BasicNotifications/LICENSE b/media/Camera2Video/LICENSE
similarity index 100%
copy from ui/notifications/BasicNotifications/LICENSE
copy to media/Camera2Video/LICENSE
diff --git a/media/Camera2Video/README.md b/media/Camera2Video/README.md
new file mode 100644
index 0000000..543d7cd
--- /dev/null
+++ b/media/Camera2Video/README.md
@@ -0,0 +1,49 @@
+Android Camera2Video Sample
+==============================
+
+This sample demonstrates how to record video using Camera2 API.
+
+Pre-requisites
+--------------
+
+- Android SDK (L Developer Preview)
+- Android Build Tools v20
+- Android Support Repository
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-Camera2Video
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2014 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements. See the NOTICE file distributed with this work for
+additional information regarding copyright ownership. The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/media/Camera2Video/build.gradle b/media/Camera2Video/build.gradle
new file mode 100644
index 0000000..f9f6f65
--- /dev/null
+++ b/media/Camera2Video/build.gradle
@@ -0,0 +1,14 @@
+
+
+
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../build"
+ pathToSamplesCommon "../../common"
+}
+apply from: "../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/media/Camera2Video/buildSrc/build.gradle b/media/Camera2Video/buildSrc/build.gradle
new file mode 100644
index 0000000..29282af
--- /dev/null
+++ b/media/Camera2Video/buildSrc/build.gradle
@@ -0,0 +1,18 @@
+
+
+
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile 'org.freemarker:freemarker:2.3.20'
+}
+
+sourceSets {
+ main {
+ groovy {
+ srcDir new File(rootDir, "../../../../../build/buildSrc/src/main/groovy")
+ }
+ }
+}
+
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/media/Camera2Video/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
copy to media/Camera2Video/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties b/media/Camera2Video/gradle/wrapper/gradle-wrapper.properties
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties
copy to media/Camera2Video/gradle/wrapper/gradle-wrapper.properties
diff --git a/ui/notifications/BasicNotifications/gradlew b/media/Camera2Video/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to media/Camera2Video/gradlew
diff --git a/ui/notifications/BasicNotifications/gradlew.bat b/media/Camera2Video/gradlew.bat
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew.bat
copy to media/Camera2Video/gradlew.bat
diff --git a/media/Camera2Video/packaging.yaml b/media/Camera2Video/packaging.yaml
new file mode 100644
index 0000000..26270dc
--- /dev/null
+++ b/media/Camera2Video/packaging.yaml
@@ -0,0 +1,15 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+
+status: PUBLISHED
+technologies: [Android]
+categories: [Media]
+languages: [Java]
+solutions: [Mobile]
+github: googlesamples/android-Camera2Video
+level: BEGINNER
+icon: Camera2VideoSample/src/main/res/drawable-xxhdpi/ic_launcher.png
+license: apache2
diff --git a/ui/notifications/BasicNotifications/settings.gradle b/media/Camera2Video/settings.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/settings.gradle
copy to media/Camera2Video/settings.gradle
diff --git a/media/Camera2Video/template-params.xml b/media/Camera2Video/template-params.xml
new file mode 100644
index 0000000..d85ffcf
--- /dev/null
+++ b/media/Camera2Video/template-params.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.
+-->
+
+<sample>
+ <name>Camera2Video</name>
+ <group>Media</group>
+ <package>com.example.android.camera2video</package>
+
+ <minSdk>21</minSdk>
+ <compileSdkVersion>21</compileSdkVersion>
+
+ <strings>
+ <intro>
+ <![CDATA[
+ This sample demonstrates how to record video using Camera2 API.
+ ]]>
+ </intro>
+ </strings>
+
+ <template src="base"/>
+
+</sample>
diff --git a/ui/notifications/BasicNotifications/Application/.gitignore b/media/HdrViewfinder/Application/.gitignore
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/.gitignore
copy to media/HdrViewfinder/Application/.gitignore
diff --git a/media/HdrViewfinder/Application/README-singleview.txt b/media/HdrViewfinder/Application/README-singleview.txt
new file mode 100644
index 0000000..0cacd46
--- /dev/null
+++ b/media/HdrViewfinder/Application/README-singleview.txt
@@ -0,0 +1,47 @@
+<#--
+ 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.
+-->
+
+Steps to implement SingleView template:
+-in template-params.xml.ftl:
+ -add the following line to common imports
+ <common src="activities"/>
+
+ -add a string for the action button's text using the element name "sample_action".
+ This element should be a child of <strings>:
+ <strings>
+ ...
+ <sample_action>ButtonText</sample_action>
+ ...
+ </strings>
+
+
+
+-Add a Fragment to handle behavior. In your MainActivity.java class, it will reference a Fragment
+ called (yourProjectName)Fragment.java. Create that file in your project, using the "main" source
+ folder instead of "common" or "templates".
+ For instance, if your package name is com.example.foo, create the file
+ src/main/java/com/example/foo/FooFragment.java
+
+
+-Within this fragment, make sure that the onCreate method has the line
+ "setHasOptionsMenu(true);", to enable the fragment to handle menu events.
+
+-In order to override menu events, override onOptionsItemSelected.
+
+-refer to sampleSamples/singleViewSample for a reference implementation of a
+project built on this template.
+
+
diff --git a/ui/notifications/BasicNotifications/Application/proguard-project.txt b/media/HdrViewfinder/Application/proguard-project.txt
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/proguard-project.txt
copy to media/HdrViewfinder/Application/proguard-project.txt
diff --git a/media/HdrViewfinder/Application/src/main/AndroidManifest.xml b/media/HdrViewfinder/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..772b7df
--- /dev/null
+++ b/media/HdrViewfinder/Application/src/main/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/media/HdrViewfinder/Application/src/main/java/com/example/android/hdrviewfinder/CameraOps.java b/media/HdrViewfinder/Application/src/main/java/com/example/android/hdrviewfinder/CameraOps.java
new file mode 100644
index 0000000..5769760
--- /dev/null
+++ b/media/HdrViewfinder/Application/src/main/java/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/media/HdrViewfinder/Application/src/main/java/com/example/android/hdrviewfinder/FixedAspectSurfaceView.java b/media/HdrViewfinder/Application/src/main/java/com/example/android/hdrviewfinder/FixedAspectSurfaceView.java
new file mode 100644
index 0000000..48d842b
--- /dev/null
+++ b/media/HdrViewfinder/Application/src/main/java/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/media/HdrViewfinder/Application/src/main/java/com/example/android/hdrviewfinder/HdrViewfinderActivity.java b/media/HdrViewfinder/Application/src/main/java/com/example/android/hdrviewfinder/HdrViewfinderActivity.java
new file mode 100644
index 0000000..79f1bb6
--- /dev/null
+++ b/media/HdrViewfinder/Application/src/main/java/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/media/HdrViewfinder/Application/src/main/java/com/example/android/hdrviewfinder/MessageDialogFragment.java b/media/HdrViewfinder/Application/src/main/java/com/example/android/hdrviewfinder/MessageDialogFragment.java
new file mode 100644
index 0000000..b1bdf9e
--- /dev/null
+++ b/media/HdrViewfinder/Application/src/main/java/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/media/HdrViewfinder/Application/src/main/java/com/example/android/hdrviewfinder/ViewfinderProcessor.java b/media/HdrViewfinder/Application/src/main/java/com/example/android/hdrviewfinder/ViewfinderProcessor.java
new file mode 100644
index 0000000..f51dfaa
--- /dev/null
+++ b/media/HdrViewfinder/Application/src/main/java/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/media/HdrViewfinder/Application/src/main/res/drawable-hdpi/ic_action_info.png b/media/HdrViewfinder/Application/src/main/res/drawable-hdpi/ic_action_info.png
new file mode 100644
index 0000000..32bd1aa
--- /dev/null
+++ b/media/HdrViewfinder/Application/src/main/res/drawable-hdpi/ic_action_info.png
Binary files differ
diff --git a/media/HdrViewfinder/Application/src/main/res/drawable-hdpi/ic_launcher.png b/media/HdrViewfinder/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..18f79c1
--- /dev/null
+++ b/media/HdrViewfinder/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/media/HdrViewfinder/Application/src/main/res/drawable-mdpi/ic_action_info.png b/media/HdrViewfinder/Application/src/main/res/drawable-mdpi/ic_action_info.png
new file mode 100644
index 0000000..8efbbf8
--- /dev/null
+++ b/media/HdrViewfinder/Application/src/main/res/drawable-mdpi/ic_action_info.png
Binary files differ
diff --git a/media/HdrViewfinder/Application/src/main/res/drawable-mdpi/ic_launcher.png b/media/HdrViewfinder/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..e70a7dc
--- /dev/null
+++ b/media/HdrViewfinder/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/media/HdrViewfinder/Application/src/main/res/drawable-xhdpi/ic_action_info.png b/media/HdrViewfinder/Application/src/main/res/drawable-xhdpi/ic_action_info.png
new file mode 100644
index 0000000..ba143ea
--- /dev/null
+++ b/media/HdrViewfinder/Application/src/main/res/drawable-xhdpi/ic_action_info.png
Binary files differ
diff --git a/media/HdrViewfinder/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/media/HdrViewfinder/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..ed25c5a
--- /dev/null
+++ b/media/HdrViewfinder/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/media/HdrViewfinder/Application/src/main/res/drawable-xxhdpi/ic_action_info.png b/media/HdrViewfinder/Application/src/main/res/drawable-xxhdpi/ic_action_info.png
new file mode 100644
index 0000000..394eb7e
--- /dev/null
+++ b/media/HdrViewfinder/Application/src/main/res/drawable-xxhdpi/ic_action_info.png
Binary files differ
diff --git a/media/HdrViewfinder/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/media/HdrViewfinder/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..90867ff
--- /dev/null
+++ b/media/HdrViewfinder/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/media/HdrViewfinder/Application/src/main/res/layout/main.xml b/media/HdrViewfinder/Application/src/main/res/layout/main.xml
new file mode 100644
index 0000000..7507709
--- /dev/null
+++ b/media/HdrViewfinder/Application/src/main/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/media/HdrViewfinder/Application/src/main/res/menu/main.xml b/media/HdrViewfinder/Application/src/main/res/menu/main.xml
new file mode 100644
index 0000000..14b2ffa
--- /dev/null
+++ b/media/HdrViewfinder/Application/src/main/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/media/HdrViewfinder/Application/src/main/res/values/attrs.xml b/media/HdrViewfinder/Application/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..ec8a564
--- /dev/null
+++ b/media/HdrViewfinder/Application/src/main/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/media/HdrViewfinder/Application/src/main/res/values/strings.xml b/media/HdrViewfinder/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..21838d5
--- /dev/null
+++ b/media/HdrViewfinder/Application/src/main/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/media/HdrViewfinder/Application/src/main/rs/hdr_merge.rs b/media/HdrViewfinder/Application/src/main/rs/hdr_merge.rs
new file mode 100644
index 0000000..f176fd7
--- /dev/null
+++ b/media/HdrViewfinder/Application/src/main/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/ui/notifications/BasicNotifications/CONTRIB.md b/media/HdrViewfinder/CONTRIB.md
similarity index 100%
copy from ui/notifications/BasicNotifications/CONTRIB.md
copy to media/HdrViewfinder/CONTRIB.md
diff --git a/ui/notifications/BasicNotifications/LICENSE b/media/HdrViewfinder/LICENSE
similarity index 100%
copy from ui/notifications/BasicNotifications/LICENSE
copy to media/HdrViewfinder/LICENSE
diff --git a/media/HdrViewfinder/README.md b/media/HdrViewfinder/README.md
new file mode 100644
index 0000000..46adfbb
--- /dev/null
+++ b/media/HdrViewfinder/README.md
@@ -0,0 +1,82 @@
+Android HdrViewfinder Sample
+==============================
+
+This demo shows how to use Camera2 API and RenderScript to implement an HDR viewfinder.
+
+Introduction
+------------
+
+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.
+
+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.
+
+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.
+
+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.
+
+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.
+
+Pre-requisites
+--------------
+
+- Android SDK v21
+- Android Build Tools v21
+- Android Support Repository
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Screenshots
+-----------
+
+
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-HdrViewfinder
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2014 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements. See the NOTICE file distributed with this work for
+additional information regarding copyright ownership. The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/media/HdrViewfinder/big_icon.png b/media/HdrViewfinder/big_icon.png
new file mode 100644
index 0000000..b38019c
--- /dev/null
+++ b/media/HdrViewfinder/big_icon.png
Binary files differ
diff --git a/media/HdrViewfinder/build.gradle b/media/HdrViewfinder/build.gradle
new file mode 100644
index 0000000..2b8d1ef
--- /dev/null
+++ b/media/HdrViewfinder/build.gradle
@@ -0,0 +1,11 @@
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../build"
+ pathToSamplesCommon "../../common"
+}
+apply from: "../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/media/HdrViewfinder/buildSrc/build.gradle b/media/HdrViewfinder/buildSrc/build.gradle
new file mode 100644
index 0000000..8c294c2
--- /dev/null
+++ b/media/HdrViewfinder/buildSrc/build.gradle
@@ -0,0 +1,15 @@
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile 'org.freemarker:freemarker:2.3.20'
+}
+
+sourceSets {
+ main {
+ groovy {
+ srcDir new File(rootDir, "../../../../../build/buildSrc/src/main/groovy")
+ }
+ }
+}
+
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/media/HdrViewfinder/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
copy to media/HdrViewfinder/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties b/media/HdrViewfinder/gradle/wrapper/gradle-wrapper.properties
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties
copy to media/HdrViewfinder/gradle/wrapper/gradle-wrapper.properties
diff --git a/ui/notifications/BasicNotifications/gradlew b/media/HdrViewfinder/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to media/HdrViewfinder/gradlew
diff --git a/ui/notifications/BasicNotifications/gradlew.bat b/media/HdrViewfinder/gradlew.bat
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew.bat
copy to media/HdrViewfinder/gradlew.bat
diff --git a/media/HdrViewfinder/packaging.yaml b/media/HdrViewfinder/packaging.yaml
new file mode 100644
index 0000000..c13e3ed
--- /dev/null
+++ b/media/HdrViewfinder/packaging.yaml
@@ -0,0 +1,15 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+
+status: PUBLISHED
+technologies: [Android]
+categories: [Media]
+languages: [Java]
+solutions: [Mobile]
+github: googlesamples/android-HdrViewfinder
+level: INTERMEDIATE
+icon: media/HdrViewfinder/big_icon.png
+license: apache2-android
diff --git a/media/HdrViewfinder/screenshots/image1.png b/media/HdrViewfinder/screenshots/image1.png
new file mode 100755
index 0000000..75c8db1
--- /dev/null
+++ b/media/HdrViewfinder/screenshots/image1.png
Binary files differ
diff --git a/ui/notifications/BasicNotifications/settings.gradle b/media/HdrViewfinder/settings.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/settings.gradle
copy to media/HdrViewfinder/settings.gradle
diff --git a/media/HdrViewfinder/template-params.xml b/media/HdrViewfinder/template-params.xml
new file mode 100644
index 0000000..89c0056
--- /dev/null
+++ b/media/HdrViewfinder/template-params.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.
+-->
+<sample>
+ <name>HdrViewfinder</name>
+ <group>Media</group>
+ <package>com.example.android.hdrviewfinder</package>
+
+ <minSdk>21</minSdk>
+
+ <strings>
+ <intro>
+ <![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.
+ ]]>
+ </intro>
+ </strings>
+
+ <template src="base"/>
+
+</sample>
diff --git a/media/MediaEffects/MediaEffectsSample/.gitignore b/media/MediaBrowserService/Application/.gitignore
similarity index 100%
copy from media/MediaEffects/MediaEffectsSample/.gitignore
copy to media/MediaBrowserService/Application/.gitignore
diff --git a/media/MediaEffects/MediaEffectsSample/proguard-project.txt b/media/MediaBrowserService/Application/proguard-project.txt
similarity index 100%
copy from media/MediaEffects/MediaEffectsSample/proguard-project.txt
copy to media/MediaBrowserService/Application/proguard-project.txt
diff --git a/media/MediaBrowserService/Application/src/androidTest/java/com/example/android/mediabrowserservice/test/SampleTests.java b/media/MediaBrowserService/Application/src/androidTest/java/com/example/android/mediabrowserservice/test/SampleTests.java
new file mode 100644
index 0000000..7bf34eb
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/androidTest/java/com/example/android/mediabrowserservice/test/SampleTests.java
@@ -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.
+*/
+/*
+* 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.mediabrowserservice.test;
+
+import com.example.android.mediabrowserservice.*;
+
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+* Tests for MediaBrowserService sample.
+*/
+public class SampleTests extends ActivityInstrumentationTestCase2<MainActivity> {
+
+ private MainActivity mTestActivity;
+ private MediaBrowserServiceFragment mTestFragment;
+
+ public SampleTests() {
+ super(MainActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // Starts the activity under test using the default Intent with:
+ // action = {@link Intent#ACTION_MAIN}
+ // flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK}
+ // All other fields are null or empty.
+ mTestActivity = getActivity();
+ mTestFragment = (MediaBrowserServiceFragment)
+ mTestActivity.getSupportFragmentManager().getFragments().get(1);
+ }
+
+ /**
+ * Test if the test fixture has been set up correctly.
+ */
+ public void testPreconditions() {
+ //Try to add a message to add context to your assertions. These messages will be shown if
+ //a tests fails and make it easy to understand why a test failed
+ assertNotNull("mTestActivity is null", mTestActivity);
+ assertNotNull("mTestFragment is null", mTestFragment);
+ }
+
+ /**
+ * Add more tests below.
+ */
+
+}
diff --git a/media/MediaBrowserService/Application/src/main/AndroidManifest.xml b/media/MediaBrowserService/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..6d05c27
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/AndroidManifest.xml
@@ -0,0 +1,65 @@
+<?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.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.mediabrowserservice"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+ <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="com.google.android.gms.car.application"
+ android:resource="@xml/automotive_app_desc"/>
+
+
+ <activity android:name="com.example.android.mediabrowserservice.MusicPlayerActivity"
+ android:label="@string/app_name">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <!-- (OPTIONAL) use this meta data to indicate which icon should be used in media
+ notifications (for example, when the music changes and the user is
+ looking at another app) -->
+ <meta-data
+ android:name="com.google.android.gms.car.notification.SmallIcon"
+ android:resource="@drawable/ic_notification" />
+
+ <service
+ android:name="com.example.android.mediabrowserservice.MusicService"
+ android:exported="true"
+ >
+ <intent-filter>
+ <action android:name="android.media.browse.MediaBrowserService" />
+ </intent-filter>
+ </service>
+
+ </application>
+
+</manifest>
diff --git a/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/BrowseFragment.java b/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/BrowseFragment.java
new file mode 100644
index 0000000..726ae15
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/BrowseFragment.java
@@ -0,0 +1,210 @@
+/*
+ * 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.mediabrowserservice;
+
+import android.app.Fragment;
+import android.content.ComponentName;
+import android.content.Context;
+import android.media.browse.MediaBrowser;
+import android.media.session.MediaController;
+import android.os.Bundle;
+import android.util.Log;
+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.ListView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.example.android.mediabrowserservice.utils.LogHelper;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A Fragment that lists all the various browsable queues available
+ * from a {@link android.service.media.MediaBrowserService}.
+ * <p/>
+ * It uses a {@link MediaBrowser} to connect to the {@link MusicService}. Once connected,
+ * the fragment subscribes to get all the children. All {@link MediaBrowser.MediaItem}'s
+ * that can be browsed are shown in a ListView.
+ */
+public class BrowseFragment extends Fragment {
+
+ private static final String TAG = BrowseFragment.class.getSimpleName();
+
+ public static final String ARG_MEDIA_ID = "media_id";
+
+ public static interface FragmentDataHelper {
+ void onMediaItemSelected(MediaBrowser.MediaItem item);
+ }
+
+ // The mediaId to be used for subscribing for children using the MediaBrowser.
+ private String mMediaId;
+
+ private MediaBrowser mMediaBrowser;
+ private BrowseAdapter mBrowserAdapter;
+
+ private MediaBrowser.SubscriptionCallback mSubscriptionCallback = new MediaBrowser.SubscriptionCallback() {
+
+ @Override
+ public void onChildrenLoaded(String parentId, List<MediaBrowser.MediaItem> children) {
+ mBrowserAdapter.clear();
+ mBrowserAdapter.notifyDataSetInvalidated();
+ for (MediaBrowser.MediaItem item : children) {
+ mBrowserAdapter.add(item);
+ }
+ mBrowserAdapter.notifyDataSetChanged();
+ }
+
+ @Override
+ public void onError(String id) {
+ Toast.makeText(getActivity(), R.string.error_loading_media,
+ Toast.LENGTH_LONG).show();
+ }
+ };
+
+ private MediaBrowser.ConnectionCallback mConnectionCallback =
+ new MediaBrowser.ConnectionCallback() {
+ @Override
+ public void onConnected() {
+ LogHelper.d(TAG, "onConnected: session token " + mMediaBrowser.getSessionToken());
+
+ if (mMediaId == null) {
+ mMediaId = mMediaBrowser.getRoot();
+ }
+ mMediaBrowser.subscribe(mMediaId, mSubscriptionCallback);
+ if (mMediaBrowser.getSessionToken() == null) {
+ throw new IllegalArgumentException("No Session token");
+ }
+ MediaController mediaController = new MediaController(getActivity(),
+ mMediaBrowser.getSessionToken());
+ getActivity().setMediaController(mediaController);
+ }
+
+ @Override
+ public void onConnectionFailed() {
+ LogHelper.d(TAG, "onConnectionFailed");
+ }
+
+ @Override
+ public void onConnectionSuspended() {
+ LogHelper.d(TAG, "onConnectionSuspended");
+ getActivity().setMediaController(null);
+ }
+ };
+
+ public static BrowseFragment newInstance(String mediaId) {
+ Bundle args = new Bundle();
+ args.putString(ARG_MEDIA_ID, mediaId);
+ BrowseFragment fragment = new BrowseFragment();
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View rootView = inflater.inflate(R.layout.fragment_list, container, false);
+
+ mBrowserAdapter = new BrowseAdapter(getActivity());
+
+ View controls = rootView.findViewById(R.id.controls);
+ controls.setVisibility(View.GONE);
+
+ ListView listView = (ListView) rootView.findViewById(R.id.list_view);
+ listView.setAdapter(mBrowserAdapter);
+ listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ MediaBrowser.MediaItem item = mBrowserAdapter.getItem(position);
+ try {
+ FragmentDataHelper listener = (FragmentDataHelper) getActivity();
+ listener.onMediaItemSelected(item);
+ } catch (ClassCastException ex) {
+ Log.e(TAG, "Exception trying to cast to FragmentDataHelper", ex);
+ }
+ }
+ });
+
+ Bundle args = getArguments();
+ mMediaId = args.getString(ARG_MEDIA_ID, null);
+
+ mMediaBrowser = new MediaBrowser(getActivity(),
+ new ComponentName(getActivity(), MusicService.class),
+ mConnectionCallback, null);
+
+ return rootView;
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ mMediaBrowser.connect();
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ mMediaBrowser.disconnect();
+ }
+
+ // An adapter for showing the list of browsed MediaItem's
+ private static class BrowseAdapter extends ArrayAdapter<MediaBrowser.MediaItem> {
+
+ public BrowseAdapter(Context context) {
+ super(context, R.layout.media_list_item, new ArrayList<MediaBrowser.MediaItem>());
+ }
+
+ static class ViewHolder {
+ ImageView mImageView;
+ TextView mTitleView;
+ TextView mDescriptionView;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+
+ ViewHolder holder;
+
+ if (convertView == null) {
+ convertView = LayoutInflater.from(getContext())
+ .inflate(R.layout.media_list_item, parent, false);
+ holder = new ViewHolder();
+ holder.mImageView = (ImageView) convertView.findViewById(R.id.play_eq);
+ holder.mImageView.setVisibility(View.GONE);
+ holder.mTitleView = (TextView) convertView.findViewById(R.id.title);
+ holder.mDescriptionView = (TextView) convertView.findViewById(R.id.description);
+ convertView.setTag(holder);
+ } else {
+ holder = (ViewHolder) convertView.getTag();
+ }
+
+ MediaBrowser.MediaItem item = getItem(position);
+ holder.mTitleView.setText(item.getDescription().getTitle());
+ holder.mDescriptionView.setText(item.getDescription().getDescription());
+ if (item.isPlayable()) {
+ holder.mImageView.setImageDrawable(
+ getContext().getDrawable(R.drawable.ic_play_arrow_white_24dp));
+ holder.mImageView.setVisibility(View.VISIBLE);
+ }
+ return convertView;
+ }
+ }
+}
diff --git a/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/MediaNotification.java b/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/MediaNotification.java
new file mode 100644
index 0000000..7b8631a
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/MediaNotification.java
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2014 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.mediabrowserservice;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.media.MediaDescription;
+import android.media.MediaMetadata;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.media.session.PlaybackState;
+import android.os.AsyncTask;
+import android.util.LruCache;
+import android.util.SparseArray;
+
+import com.example.android.mediabrowserservice.utils.BitmapHelper;
+import com.example.android.mediabrowserservice.utils.LogHelper;
+
+import java.io.IOException;
+
+/**
+ * Keeps track of a notification and updates it automatically for a given
+ * MediaSession. Maintaining a visible notification (usually) guarantees that the music service
+ * won't be killed during playback.
+ */
+public class MediaNotification extends BroadcastReceiver {
+ private static final String TAG = "MediaNotification";
+
+ private static final int NOTIFICATION_ID = 412;
+
+ public static final String ACTION_PAUSE = "com.example.android.mediabrowserservice.pause";
+ public static final String ACTION_PLAY = "com.example.android.mediabrowserservice.play";
+ public static final String ACTION_PREV = "com.example.android.mediabrowserservice.prev";
+ public static final String ACTION_NEXT = "com.example.android.mediabrowserservice.next";
+
+ private static final int MAX_ALBUM_ART_CACHE_SIZE = 1024*1024;
+
+ private final MusicService mService;
+ private MediaSession.Token mSessionToken;
+ private MediaController mController;
+ private MediaController.TransportControls mTransportControls;
+ private final SparseArray<PendingIntent> mIntents = new SparseArray<PendingIntent>();
+ private final LruCache<String, Bitmap> mAlbumArtCache;
+
+ private PlaybackState mPlaybackState;
+ private MediaMetadata mMetadata;
+
+ private Notification.Builder mNotificationBuilder;
+ private NotificationManager mNotificationManager;
+ private Notification.Action mPlayPauseAction;
+
+ private String mCurrentAlbumArt;
+ private int mNotificationColor;
+
+ private boolean mStarted = false;
+
+ public MediaNotification(MusicService service) {
+ mService = service;
+ updateSessionToken();
+
+ // simple album art cache that holds no more than
+ // MAX_ALBUM_ART_CACHE_SIZE bytes:
+ mAlbumArtCache = new LruCache<String, Bitmap>(MAX_ALBUM_ART_CACHE_SIZE) {
+ @Override
+ protected int sizeOf(String key, Bitmap value) {
+ return value.getByteCount();
+ }
+ };
+
+ mNotificationColor = getNotificationColor();
+
+ mNotificationManager = (NotificationManager) mService
+ .getSystemService(Context.NOTIFICATION_SERVICE);
+
+ String pkg = mService.getPackageName();
+ mIntents.put(R.drawable.ic_pause_white_24dp, PendingIntent.getBroadcast(mService, 100,
+ new Intent(ACTION_PAUSE).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT));
+ mIntents.put(R.drawable.ic_play_arrow_white_24dp, PendingIntent.getBroadcast(mService, 100,
+ new Intent(ACTION_PLAY).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT));
+ mIntents.put(R.drawable.ic_skip_previous_white_24dp, PendingIntent.getBroadcast(mService, 100,
+ new Intent(ACTION_PREV).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT));
+ mIntents.put(R.drawable.ic_skip_next_white_24dp, PendingIntent.getBroadcast(mService, 100,
+ new Intent(ACTION_NEXT).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT));
+ }
+
+ protected int getNotificationColor() {
+ int notificationColor = 0;
+ String packageName = mService.getPackageName();
+ try {
+ Context packageContext = mService.createPackageContext(packageName, 0);
+ ApplicationInfo applicationInfo =
+ mService.getPackageManager().getApplicationInfo(packageName, 0);
+ packageContext.setTheme(applicationInfo.theme);
+ Resources.Theme theme = packageContext.getTheme();
+ TypedArray ta = theme.obtainStyledAttributes(
+ new int[] {android.R.attr.colorPrimary});
+ notificationColor = ta.getColor(0, Color.DKGRAY);
+ ta.recycle();
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ return notificationColor;
+ }
+
+ /**
+ * Posts the notification and starts tracking the session to keep it
+ * updated. The notification will automatically be removed if the session is
+ * destroyed before {@link #stopNotification} is called.
+ */
+ public void startNotification() {
+ if (!mStarted) {
+ mController.registerCallback(mCb);
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_NEXT);
+ filter.addAction(ACTION_PAUSE);
+ filter.addAction(ACTION_PLAY);
+ filter.addAction(ACTION_PREV);
+ mService.registerReceiver(this, filter);
+
+ mMetadata = mController.getMetadata();
+ mPlaybackState = mController.getPlaybackState();
+
+ mStarted = true;
+ // The notification must be updated after setting started to true
+ updateNotificationMetadata();
+ }
+ }
+
+ /**
+ * Removes the notification and stops tracking the session. If the session
+ * was destroyed this has no effect.
+ */
+ public void stopNotification() {
+ mStarted = false;
+ mController.unregisterCallback(mCb);
+ try {
+ mNotificationManager.cancel(NOTIFICATION_ID);
+ mService.unregisterReceiver(this);
+ } catch (IllegalArgumentException ex) {
+ // ignore if the receiver is not registered.
+ }
+ mService.stopForeground(true);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ LogHelper.d(TAG, "Received intent with action " + action);
+ if (ACTION_PAUSE.equals(action)) {
+ mTransportControls.pause();
+ } else if (ACTION_PLAY.equals(action)) {
+ mTransportControls.play();
+ } else if (ACTION_NEXT.equals(action)) {
+ mTransportControls.skipToNext();
+ } else if (ACTION_PREV.equals(action)) {
+ mTransportControls.skipToPrevious();
+ }
+ }
+
+ /**
+ * Update the state based on a change on the session token. Called either when
+ * we are running for the first time or when the media session owner has destroyed the session
+ * (see {@link android.media.session.MediaController.Callback#onSessionDestroyed()})
+ */
+ private void updateSessionToken() {
+ MediaSession.Token freshToken = mService.getSessionToken();
+ if (mSessionToken == null || !mSessionToken.equals(freshToken)) {
+ if (mController != null) {
+ mController.unregisterCallback(mCb);
+ }
+ mSessionToken = freshToken;
+ mController = new MediaController(mService, mSessionToken);
+ mTransportControls = mController.getTransportControls();
+ if (mStarted) {
+ mController.registerCallback(mCb);
+ }
+ }
+ }
+
+ private final MediaController.Callback mCb = new MediaController.Callback() {
+ @Override
+ public void onPlaybackStateChanged(PlaybackState state) {
+ mPlaybackState = state;
+ LogHelper.d(TAG, "Received new playback state", state);
+ updateNotificationPlaybackState();
+ }
+
+ @Override
+ public void onMetadataChanged(MediaMetadata metadata) {
+ mMetadata = metadata;
+ LogHelper.d(TAG, "Received new metadata ", metadata);
+ updateNotificationMetadata();
+ }
+
+ @Override
+ public void onSessionDestroyed() {
+ super.onSessionDestroyed();
+ LogHelper.d(TAG, "Session was destroyed, resetting to the new session token");
+ updateSessionToken();
+ }
+ };
+
+ private void updateNotificationMetadata() {
+ LogHelper.d(TAG, "updateNotificationMetadata. mMetadata=" + mMetadata);
+ if (mMetadata == null || mPlaybackState == null) {
+ return;
+ }
+
+ updatePlayPauseAction();
+
+ mNotificationBuilder = new Notification.Builder(mService);
+ int playPauseActionIndex = 0;
+
+ // If skip to previous action is enabled
+ if ((mPlaybackState.getActions() & PlaybackState.ACTION_SKIP_TO_PREVIOUS) != 0) {
+ mNotificationBuilder
+ .addAction(R.drawable.ic_skip_previous_white_24dp,
+ mService.getString(R.string.label_previous),
+ mIntents.get(R.drawable.ic_skip_previous_white_24dp));
+ playPauseActionIndex = 1;
+ }
+
+ mNotificationBuilder.addAction(mPlayPauseAction);
+
+ // If skip to next action is enabled
+ if ((mPlaybackState.getActions() & PlaybackState.ACTION_SKIP_TO_NEXT) != 0) {
+ mNotificationBuilder.addAction(R.drawable.ic_skip_next_white_24dp,
+ mService.getString(R.string.label_next),
+ mIntents.get(R.drawable.ic_skip_next_white_24dp));
+ }
+
+ MediaDescription description = mMetadata.getDescription();
+
+ String fetchArtUrl = null;
+ Bitmap art = description.getIconBitmap();
+ if (art == null && description.getIconUri() != null) {
+ // This sample assumes the iconUri will be a valid URL formatted String, but
+ // it can actually be any valid Android Uri formatted String.
+ // async fetch the album art icon
+ String artUrl = description.getIconUri().toString();
+ art = mAlbumArtCache.get(artUrl);
+ if (art == null) {
+ fetchArtUrl = artUrl;
+ // use a placeholder art while the remote art is being downloaded
+ art = BitmapFactory.decodeResource(mService.getResources(), R.drawable.ic_default_art);
+ }
+ }
+
+ mNotificationBuilder
+ .setStyle(new Notification.MediaStyle()
+ .setShowActionsInCompactView(playPauseActionIndex) // only show play/pause in compact view
+ .setMediaSession(mSessionToken))
+ .setColor(mNotificationColor)
+ .setSmallIcon(R.drawable.ic_notification)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setUsesChronometer(true)
+ .setContentTitle(description.getTitle())
+ .setContentText(description.getSubtitle())
+ .setLargeIcon(art);
+
+ updateNotificationPlaybackState();
+
+ mService.startForeground(NOTIFICATION_ID, mNotificationBuilder.build());
+ if (fetchArtUrl != null) {
+ fetchBitmapFromURLAsync(fetchArtUrl);
+ }
+ }
+
+ private void updatePlayPauseAction() {
+ LogHelper.d(TAG, "updatePlayPauseAction");
+ String playPauseLabel = "";
+ int playPauseIcon;
+ if (mPlaybackState.getState() == PlaybackState.STATE_PLAYING) {
+ playPauseLabel = mService.getString(R.string.label_pause);
+ playPauseIcon = R.drawable.ic_pause_white_24dp;
+ } else {
+ playPauseLabel = mService.getString(R.string.label_play);
+ playPauseIcon = R.drawable.ic_play_arrow_white_24dp;
+ }
+ if (mPlayPauseAction == null) {
+ mPlayPauseAction = new Notification.Action(playPauseIcon, playPauseLabel,
+ mIntents.get(playPauseIcon));
+ } else {
+ mPlayPauseAction.icon = playPauseIcon;
+ mPlayPauseAction.title = playPauseLabel;
+ mPlayPauseAction.actionIntent = mIntents.get(playPauseIcon);
+ }
+ }
+
+ private void updateNotificationPlaybackState() {
+ LogHelper.d(TAG, "updateNotificationPlaybackState. mPlaybackState=" + mPlaybackState);
+ if (mPlaybackState == null || !mStarted) {
+ LogHelper.d(TAG, "updateNotificationPlaybackState. cancelling notification!");
+ mService.stopForeground(true);
+ return;
+ }
+ if (mNotificationBuilder == null) {
+ LogHelper.d(TAG, "updateNotificationPlaybackState. there is no notificationBuilder. Ignoring request to update state!");
+ return;
+ }
+ if (mPlaybackState.getPosition() >= 0) {
+ LogHelper.d(TAG, "updateNotificationPlaybackState. updating playback position to ",
+ (System.currentTimeMillis() - mPlaybackState.getPosition()) / 1000, " seconds");
+ mNotificationBuilder
+ .setWhen(System.currentTimeMillis() - mPlaybackState.getPosition())
+ .setShowWhen(true)
+ .setUsesChronometer(true);
+ mNotificationBuilder.setShowWhen(true);
+ } else {
+ LogHelper.d(TAG, "updateNotificationPlaybackState. hiding playback position");
+ mNotificationBuilder
+ .setWhen(0)
+ .setShowWhen(false)
+ .setUsesChronometer(false);
+ }
+
+ updatePlayPauseAction();
+
+ // Make sure that the notification can be dismissed by the user when we are not playing:
+ mNotificationBuilder.setOngoing(mPlaybackState.getState() == PlaybackState.STATE_PLAYING);
+
+ mNotificationManager.notify(NOTIFICATION_ID, mNotificationBuilder.build());
+ }
+
+ public void fetchBitmapFromURLAsync(final String source) {
+ LogHelper.d(TAG, "getBitmapFromURLAsync: starting asynctask to fetch ", source);
+ new AsyncTask<Void, Void, Bitmap>() {
+ @Override
+ protected Bitmap doInBackground(Void[] objects) {
+ Bitmap bitmap = null;
+ try {
+ bitmap = BitmapHelper.fetchAndRescaleBitmap(source,
+ BitmapHelper.MEDIA_ART_BIG_WIDTH, BitmapHelper.MEDIA_ART_BIG_HEIGHT);
+ mAlbumArtCache.put(source, bitmap);
+ } catch (IOException e) {
+ LogHelper.e(TAG, e, "getBitmapFromURLAsync: " + source);
+ }
+ return bitmap;
+ }
+
+ @Override
+ protected void onPostExecute(Bitmap bitmap) {
+ if (bitmap != null && mMetadata != null &&
+ mNotificationBuilder != null && mMetadata.getDescription() != null &&
+ !source.equals(mMetadata.getDescription().getIconUri())) {
+ // If the media is still the same, update the notification:
+ LogHelper.d(TAG, "getBitmapFromURLAsync: set bitmap to ", source);
+ mNotificationBuilder.setLargeIcon(bitmap);
+ mNotificationManager.notify(NOTIFICATION_ID, mNotificationBuilder.build());
+ }
+ }
+ }.execute();
+ }
+
+}
diff --git a/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/MusicPlayerActivity.java b/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/MusicPlayerActivity.java
new file mode 100644
index 0000000..648d268
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/MusicPlayerActivity.java
@@ -0,0 +1,61 @@
+/*
+ * 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.mediabrowserservice;
+
+import android.app.Activity;
+import android.media.browse.MediaBrowser;
+import android.media.session.MediaController;
+import android.os.Bundle;
+
+/**
+ * Main activity for the music player.
+ */
+public class MusicPlayerActivity extends Activity
+ implements BrowseFragment.FragmentDataHelper {
+
+ private static final String TAG = MusicPlayerActivity.class.getSimpleName();
+
+ private MediaBrowser mMediaBrowser;
+ private MediaController mMediaController;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_player);
+ if (savedInstanceState == null) {
+ getFragmentManager().beginTransaction()
+ .add(R.id.container, BrowseFragment.newInstance(null))
+ .commit();
+ }
+ }
+
+ @Override
+ public void onMediaItemSelected(MediaBrowser.MediaItem item) {
+ if (item.isPlayable()) {
+ getMediaController().getTransportControls().playFromMediaId(item.getMediaId(), null);
+ QueueFragment queueFragment = QueueFragment.newInstance();
+ getFragmentManager().beginTransaction()
+ .replace(R.id.container, queueFragment)
+ .addToBackStack(null)
+ .commit();
+ } else if (item.isBrowsable()) {
+ getFragmentManager().beginTransaction()
+ .replace(R.id.container, BrowseFragment.newInstance(item.getMediaId()))
+ .addToBackStack(null)
+ .commit();
+ }
+ }
+}
diff --git a/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/MusicService.java b/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/MusicService.java
new file mode 100644
index 0000000..8e6e3f2
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/MusicService.java
@@ -0,0 +1,936 @@
+/*
+ * Copyright (C) 2014 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.mediabrowserservice;
+
+import android.content.Context;
+import android.content.Intent;
+import android.media.AudioManager;
+import android.media.MediaDescription;
+import android.media.MediaMetadata;
+import android.media.MediaPlayer;
+import android.media.MediaPlayer.OnCompletionListener;
+import android.media.MediaPlayer.OnErrorListener;
+import android.media.MediaPlayer.OnPreparedListener;
+import android.media.browse.MediaBrowser;
+import android.media.browse.MediaBrowser.MediaItem;
+import android.media.session.MediaSession;
+import android.media.session.PlaybackState;
+import android.net.Uri;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiManager.WifiLock;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.service.media.MediaBrowserService;
+
+import com.example.android.mediabrowserservice.model.MusicProvider;
+import com.example.android.mediabrowserservice.utils.LogHelper;
+import com.example.android.mediabrowserservice.utils.MediaIDHelper;
+import com.example.android.mediabrowserservice.utils.QueueHelper;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.example.android.mediabrowserservice.utils.MediaIDHelper.MEDIA_ID_MUSICS_BY_GENRE;
+import static com.example.android.mediabrowserservice.utils.MediaIDHelper.MEDIA_ID_ROOT;
+import static com.example.android.mediabrowserservice.utils.MediaIDHelper.createBrowseCategoryMediaID;
+import static com.example.android.mediabrowserservice.utils.MediaIDHelper.extractBrowseCategoryFromMediaID;
+
+/**
+ * This class provides a MediaBrowser through a service. It exposes the media library to a browsing
+ * client, through the onGetRoot and onLoadChildren methods. It also creates a MediaSession and
+ * exposes it through its MediaSession.Token, which allows the client to create a MediaController
+ * that connects to and send control commands to the MediaSession remotely. This is useful for
+ * user interfaces that need to interact with your media session, like Android Auto. You can
+ * (should) also use the same service from your app's UI, which gives a seamless playback
+ * experience to the user.
+ *
+ * To implement a MediaBrowserService, you need to:
+ *
+ * <ul>
+ *
+ * <li> Extend {@link android.service.media.MediaBrowserService}, implementing the media browsing
+ * related methods {@link android.service.media.MediaBrowserService#onGetRoot} and
+ * {@link android.service.media.MediaBrowserService#onLoadChildren};
+ * <li> In onCreate, start a new {@link android.media.session.MediaSession} and notify its parent
+ * with the session's token {@link android.service.media.MediaBrowserService#setSessionToken};
+ *
+ * <li> Set a callback on the
+ * {@link android.media.session.MediaSession#setCallback(android.media.session.MediaSession.Callback)}.
+ * The callback will receive all the user's actions, like play, pause, etc;
+ *
+ * <li> Handle all the actual music playing using any method your app prefers (for example,
+ * {@link android.media.MediaPlayer})
+ *
+ * <li> Update playbackState, "now playing" metadata and queue, using MediaSession proper methods
+ * {@link android.media.session.MediaSession#setPlaybackState(android.media.session.PlaybackState)}
+ * {@link android.media.session.MediaSession#setMetadata(android.media.MediaMetadata)} and
+ * {@link android.media.session.MediaSession#setQueue(java.util.List)})
+ *
+ * <li> Declare and export the service in AndroidManifest with an intent receiver for the action
+ * android.media.browse.MediaBrowserService
+ *
+ * </ul>
+ *
+ * To make your app compatible with Android Auto, you also need to:
+ *
+ * <ul>
+ *
+ * <li> Declare a meta-data tag in AndroidManifest.xml linking to a xml resource
+ * with a <automotiveApp> root element. For a media app, this must include
+ * an <uses name="media"/> element as a child.
+ * For example, in AndroidManifest.xml:
+ * <meta-data android:name="com.google.android.gms.car.application"
+ * android:resource="@xml/automotive_app_desc"/>
+ * And in res/values/automotive_app_desc.xml:
+ * <automotiveApp>
+ * <uses name="media"/>
+ * </automotiveApp>
+ *
+ * </ul>
+
+ * @see <a href="README.md">README.md</a> for more details.
+ *
+ */
+
+public class MusicService extends MediaBrowserService implements OnPreparedListener,
+ OnCompletionListener, OnErrorListener, AudioManager.OnAudioFocusChangeListener {
+
+ private static final String TAG = "MusicService";
+
+ // Action to thumbs up a media item
+ private static final String CUSTOM_ACTION_THUMBS_UP = "thumbs_up";
+ // Delay stopSelf by using a handler.
+ private static final int STOP_DELAY = 30000;
+
+ // The volume we set the media player to when we lose audio focus, but are
+ // allowed to reduce the volume instead of stopping playback.
+ public static final float VOLUME_DUCK = 0.2f;
+
+ // The volume we set the media player when we have audio focus.
+ public static final float VOLUME_NORMAL = 1.0f;
+ public static final String ANDROID_AUTO_PACKAGE_NAME = "com.google.android.projection.gearhead";
+ public static final String ANDROID_AUTO_SIMULATOR_PACKAGE_NAME = "com.google.android.mediasimulator";
+
+ // Music catalog manager
+ private MusicProvider mMusicProvider;
+
+ private MediaSession mSession;
+ private MediaPlayer mMediaPlayer;
+
+ // "Now playing" queue:
+ private List<MediaSession.QueueItem> mPlayingQueue;
+ private int mCurrentIndexOnQueue;
+
+ // Current local media player state
+ private int mState = PlaybackState.STATE_NONE;
+
+ // Wifi lock that we hold when streaming files from the internet, in order
+ // to prevent the device from shutting off the Wifi radio
+ private WifiLock mWifiLock;
+
+ private MediaNotification mMediaNotification;
+
+ // Indicates whether the service was started.
+ private boolean mServiceStarted;
+
+ enum AudioFocus {
+ NoFocusNoDuck, // we don't have audio focus, and can't duck
+ NoFocusCanDuck, // we don't have focus, but can play at a low volume
+ // ("ducking")
+ Focused // we have full audio focus
+ }
+
+ // Type of audio focus we have:
+ private AudioFocus mAudioFocus = AudioFocus.NoFocusNoDuck;
+ private AudioManager mAudioManager;
+
+ // Indicates if we should start playing immediately after we gain focus.
+ private boolean mPlayOnFocusGain;
+
+ private Handler mDelayedStopHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ if ((mMediaPlayer != null && mMediaPlayer.isPlaying()) ||
+ mPlayOnFocusGain) {
+ LogHelper.d(TAG, "Ignoring delayed stop since the media player is in use.");
+ return;
+ }
+ LogHelper.d(TAG, "Stopping service with delay handler.");
+ stopSelf();
+ mServiceStarted = false;
+ }
+ };
+
+ /*
+ * (non-Javadoc)
+ * @see android.app.Service#onCreate()
+ */
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ LogHelper.d(TAG, "onCreate");
+
+ mPlayingQueue = new ArrayList<>();
+
+ // Create the Wifi lock (this does not acquire the lock, this just creates it)
+ mWifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE))
+ .createWifiLock(WifiManager.WIFI_MODE_FULL, "MusicDemo_lock");
+
+
+ // Create the music catalog metadata provider
+ mMusicProvider = new MusicProvider();
+ mMusicProvider.retrieveMedia(new MusicProvider.Callback() {
+ @Override
+ public void onMusicCatalogReady(boolean success) {
+ mState = success ? PlaybackState.STATE_NONE : PlaybackState.STATE_ERROR;
+ }
+ });
+
+ mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+
+ // Start a new MediaSession
+ mSession = new MediaSession(this, "MusicService");
+ setSessionToken(mSession.getSessionToken());
+ mSession.setCallback(new MediaSessionCallback());
+ mSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS |
+ MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
+
+ // Use these extras to reserve space for the corresponding actions, even when they are disabled
+ // in the playbackstate, so the custom actions don't reflow.
+ Bundle extras = new Bundle();
+ extras.putBoolean(
+ "com.google.android.gms.car.media.ALWAYS_RESERVE_SPACE_FOR.ACTION_SKIP_TO_NEXT",
+ true);
+ extras.putBoolean(
+ "com.google.android.gms.car.media.ALWAYS_RESERVE_SPACE_FOR.ACTION_SKIP_TO_PREVIOUS",
+ true);
+ // If you want to reserve the Queue slot when there is no queue
+ // (mSession.setQueue(emptylist)), uncomment the lines below:
+ // extras.putBoolean(
+ // "com.google.android.gms.car.media.ALWAYS_RESERVE_SPACE_FOR.ACTION_QUEUE",
+ // true);
+ mSession.setExtras(extras);
+
+ updatePlaybackState(null);
+
+ mMediaNotification = new MediaNotification(this);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see android.app.Service#onDestroy()
+ */
+ @Override
+ public void onDestroy() {
+ LogHelper.d(TAG, "onDestroy");
+
+ // Service is being killed, so make sure we release our resources
+ handleStopRequest(null);
+
+ mDelayedStopHandler.removeCallbacksAndMessages(null);
+ // In particular, always release the MediaSession to clean up resources
+ // and notify associated MediaController(s).
+ mSession.release();
+ }
+
+
+ @Override
+ public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) {
+ LogHelper.d(TAG, "OnGetRoot: clientPackageName=" + clientPackageName,
+ "; clientUid=" + clientUid + " ; rootHints=", rootHints);
+ // To ensure you are not allowing any arbitrary app to browse your app's contents, you
+ // need to check the origin:
+ if (!ANDROID_AUTO_PACKAGE_NAME.equals(clientPackageName) &&
+ !ANDROID_AUTO_SIMULATOR_PACKAGE_NAME.equals(clientPackageName) &&
+ !getApplication().getPackageName().equals(clientPackageName)) {
+ // If the request comes from an untrusted package, return null. No further calls will
+ // be made to other media browsing methods.
+ LogHelper.w(TAG, "OnGetRoot: IGNORING request from untrusted package " + clientPackageName);
+ return null;
+ }
+ if (ANDROID_AUTO_PACKAGE_NAME.equals(clientPackageName)) {
+ // Optional: if your app needs to adapt ads, music library or anything else that
+ // needs to run differently when connected to the car, this is where you should handle
+ // it.
+ }
+ return new BrowserRoot(MEDIA_ID_ROOT, null);
+ }
+
+ @Override
+ public void onLoadChildren(final String parentMediaId, final Result<List<MediaItem>> result) {
+ if (!mMusicProvider.isInitialized()) {
+ // Use result.detach to allow calling result.sendResult from another thread:
+ result.detach();
+
+ mMusicProvider.retrieveMedia(new MusicProvider.Callback() {
+ @Override
+ public void onMusicCatalogReady(boolean success) {
+ if (success) {
+ loadChildrenImpl(parentMediaId, result);
+ } else {
+ updatePlaybackState(getString(R.string.error_no_metadata));
+ result.sendResult(new ArrayList<MediaItem>());
+ }
+ }
+ });
+
+ } else {
+ // If our music catalog is already loaded/cached, load them into result immediately
+ loadChildrenImpl(parentMediaId, result);
+ }
+ }
+
+ /**
+ * Actual implementation of onLoadChildren that assumes that MusicProvider is already
+ * initialized.
+ */
+ private void loadChildrenImpl(final String parentMediaId,
+ final Result<List<MediaBrowser.MediaItem>> result) {
+ LogHelper.d(TAG, "OnLoadChildren: parentMediaId=", parentMediaId);
+
+ List<MediaBrowser.MediaItem> mediaItems = new ArrayList<>();
+
+ if (MEDIA_ID_ROOT.equals(parentMediaId)) {
+ LogHelper.d(TAG, "OnLoadChildren.ROOT");
+ mediaItems.add(new MediaBrowser.MediaItem(
+ new MediaDescription.Builder()
+ .setMediaId(MEDIA_ID_MUSICS_BY_GENRE)
+ .setTitle(getString(R.string.browse_genres))
+ .setIconUri(Uri.parse("android.resource://" +
+ "com.example.android.mediabrowserservice/drawable/ic_by_genre"))
+ .setSubtitle(getString(R.string.browse_genre_subtitle))
+ .build(), MediaBrowser.MediaItem.FLAG_BROWSABLE
+ ));
+
+ } else if (MEDIA_ID_MUSICS_BY_GENRE.equals(parentMediaId)) {
+ LogHelper.d(TAG, "OnLoadChildren.GENRES");
+ for (String genre: mMusicProvider.getGenres()) {
+ MediaBrowser.MediaItem item = new MediaBrowser.MediaItem(
+ new MediaDescription.Builder()
+ .setMediaId(createBrowseCategoryMediaID(MEDIA_ID_MUSICS_BY_GENRE, genre))
+ .setTitle(genre)
+ .setSubtitle(getString(R.string.browse_musics_by_genre_subtitle, genre))
+ .build(), MediaBrowser.MediaItem.FLAG_BROWSABLE
+ );
+ mediaItems.add(item);
+ }
+
+ } else if (parentMediaId.startsWith(MEDIA_ID_MUSICS_BY_GENRE)) {
+ String genre = extractBrowseCategoryFromMediaID(parentMediaId)[1];
+ LogHelper.d(TAG, "OnLoadChildren.SONGS_BY_GENRE genre=", genre);
+ for (MediaMetadata track: mMusicProvider.getMusicsByGenre(genre)) {
+ // Since mediaMetadata fields are immutable, we need to create a copy, so we
+ // can set a hierarchy-aware mediaID. We will need to know the media hierarchy
+ // when we get a onPlayFromMusicID call, so we can create the proper queue based
+ // on where the music was selected from (by artist, by genre, random, etc)
+ String hierarchyAwareMediaID = MediaIDHelper.createTrackMediaID(
+ MEDIA_ID_MUSICS_BY_GENRE, genre, track);
+ MediaMetadata trackCopy = new MediaMetadata.Builder(track)
+ .putString(MediaMetadata.METADATA_KEY_MEDIA_ID, hierarchyAwareMediaID)
+ .build();
+ MediaBrowser.MediaItem bItem = new MediaBrowser.MediaItem(
+ trackCopy.getDescription(), MediaItem.FLAG_PLAYABLE);
+ mediaItems.add(bItem);
+ }
+ } else {
+ LogHelper.w(TAG, "Skipping unmatched parentMediaId: ", parentMediaId);
+ }
+ result.sendResult(mediaItems);
+ }
+
+
+
+ private final class MediaSessionCallback extends MediaSession.Callback {
+ @Override
+ public void onPlay() {
+ LogHelper.d(TAG, "play");
+
+ if (mPlayingQueue == null || mPlayingQueue.isEmpty()) {
+ mPlayingQueue = QueueHelper.getRandomQueue(mMusicProvider);
+ mSession.setQueue(mPlayingQueue);
+ mSession.setQueueTitle(getString(R.string.random_queue_title));
+ // start playing from the beginning of the queue
+ mCurrentIndexOnQueue = 0;
+ }
+
+ if (mPlayingQueue != null && !mPlayingQueue.isEmpty()) {
+ handlePlayRequest();
+ }
+ }
+
+ @Override
+ public void onSkipToQueueItem(long queueId) {
+ LogHelper.d(TAG, "OnSkipToQueueItem:" + queueId);
+ if (mPlayingQueue != null && !mPlayingQueue.isEmpty()) {
+
+ // set the current index on queue from the music Id:
+ mCurrentIndexOnQueue = QueueHelper.getMusicIndexOnQueue(mPlayingQueue, queueId);
+
+ // play the music
+ handlePlayRequest();
+ }
+ }
+
+ @Override
+ public void onPlayFromMediaId(String mediaId, Bundle extras) {
+ LogHelper.d(TAG, "playFromMediaId mediaId:", mediaId, " extras=", extras);
+
+ // The mediaId used here is not the unique musicId. This one comes from the
+ // MediaBrowser, and is actually a "hierarchy-aware mediaID": a concatenation of
+ // the hierarchy in MediaBrowser and the actual unique musicID. This is necessary
+ // so we can build the correct playing queue, based on where the track was
+ // selected from.
+ mPlayingQueue = QueueHelper.getPlayingQueue(mediaId, mMusicProvider);
+ mSession.setQueue(mPlayingQueue);
+ String queueTitle = getString(R.string.browse_musics_by_genre_subtitle,
+ MediaIDHelper.extractBrowseCategoryValueFromMediaID(mediaId));
+ mSession.setQueueTitle(queueTitle);
+
+ if (mPlayingQueue != null && !mPlayingQueue.isEmpty()) {
+ String uniqueMusicID = MediaIDHelper.extractMusicIDFromMediaID(mediaId);
+ // set the current index on queue from the music Id:
+ mCurrentIndexOnQueue = QueueHelper.getMusicIndexOnQueue(
+ mPlayingQueue, uniqueMusicID);
+
+ // play the music
+ handlePlayRequest();
+ }
+ }
+
+ @Override
+ public void onPause() {
+ LogHelper.d(TAG, "pause. current state=" + mState);
+ handlePauseRequest();
+ }
+
+ @Override
+ public void onStop() {
+ LogHelper.d(TAG, "stop. current state=" + mState);
+ handleStopRequest(null);
+ }
+
+ @Override
+ public void onSkipToNext() {
+ LogHelper.d(TAG, "skipToNext");
+ mCurrentIndexOnQueue++;
+ if (mPlayingQueue != null && mCurrentIndexOnQueue >= mPlayingQueue.size()) {
+ mCurrentIndexOnQueue = 0;
+ }
+ if (QueueHelper.isIndexPlayable(mCurrentIndexOnQueue, mPlayingQueue)) {
+ mState = PlaybackState.STATE_PLAYING;
+ handlePlayRequest();
+ } else {
+ LogHelper.e(TAG, "skipToNext: cannot skip to next. next Index=" +
+ mCurrentIndexOnQueue + " queue length=" +
+ (mPlayingQueue == null ? "null" : mPlayingQueue.size()));
+ handleStopRequest("Cannot skip");
+ }
+ }
+
+ @Override
+ public void onSkipToPrevious() {
+ LogHelper.d(TAG, "skipToPrevious");
+
+ mCurrentIndexOnQueue--;
+ if (mPlayingQueue != null && mCurrentIndexOnQueue < 0) {
+ // This sample's behavior: skipping to previous when in first song restarts the
+ // first song.
+ mCurrentIndexOnQueue = 0;
+ }
+ if (QueueHelper.isIndexPlayable(mCurrentIndexOnQueue, mPlayingQueue)) {
+ mState = PlaybackState.STATE_PLAYING;
+ handlePlayRequest();
+ } else {
+ LogHelper.e(TAG, "skipToPrevious: cannot skip to previous. previous Index=" +
+ mCurrentIndexOnQueue + " queue length=" +
+ (mPlayingQueue == null ? "null" : mPlayingQueue.size()));
+ handleStopRequest("Cannot skip");
+ }
+ }
+
+ @Override
+ public void onCustomAction(String action, Bundle extras) {
+ if (CUSTOM_ACTION_THUMBS_UP.equals(action)) {
+ LogHelper.i(TAG, "onCustomAction: favorite for current track");
+ MediaMetadata track = getCurrentPlayingMusic();
+ if (track != null) {
+ String mediaId = track.getString(MediaMetadata.METADATA_KEY_MEDIA_ID);
+ mMusicProvider.setFavorite(mediaId, !mMusicProvider.isFavorite(mediaId));
+ }
+ updatePlaybackState(null);
+ } else {
+ LogHelper.e(TAG, "Unsupported action: ", action);
+ }
+
+ }
+
+ @Override
+ public void onPlayFromSearch(String query, Bundle extras) {
+ LogHelper.d(TAG, "playFromSearch query=", query);
+
+ mPlayingQueue = QueueHelper.getPlayingQueueFromSearch(query, mMusicProvider);
+ LogHelper.d(TAG, "playFromSearch playqueue.length=" + mPlayingQueue.size());
+ mSession.setQueue(mPlayingQueue);
+
+ if (mPlayingQueue != null && !mPlayingQueue.isEmpty()) {
+
+ // start playing from the beginning of the queue
+ mCurrentIndexOnQueue = 0;
+
+ handlePlayRequest();
+ }
+ }
+ }
+
+
+
+ /*
+ * Called when media player is done playing current song.
+ * @see android.media.MediaPlayer.OnCompletionListener
+ */
+ @Override
+ public void onCompletion(MediaPlayer player) {
+ LogHelper.d(TAG, "onCompletion from MediaPlayer");
+ // The media player finished playing the current song, so we go ahead
+ // and start the next.
+ if (mPlayingQueue != null && !mPlayingQueue.isEmpty()) {
+ // In this sample, we restart the playing queue when it gets to the end:
+ mCurrentIndexOnQueue++;
+ if (mCurrentIndexOnQueue >= mPlayingQueue.size()) {
+ mCurrentIndexOnQueue = 0;
+ }
+ handlePlayRequest();
+ } else {
+ // If there is nothing to play, we stop and release the resources:
+ handleStopRequest(null);
+ }
+ }
+
+ /*
+ * Called when media player is done preparing.
+ * @see android.media.MediaPlayer.OnPreparedListener
+ */
+ @Override
+ public void onPrepared(MediaPlayer player) {
+ LogHelper.d(TAG, "onPrepared from MediaPlayer");
+ // The media player is done preparing. That means we can start playing if we
+ // have audio focus.
+ configMediaPlayerState();
+ }
+
+ /**
+ * Called when there's an error playing media. When this happens, the media
+ * player goes to the Error state. We warn the user about the error and
+ * reset the media player.
+ *
+ * @see android.media.MediaPlayer.OnErrorListener
+ */
+ @Override
+ public boolean onError(MediaPlayer mp, int what, int extra) {
+ LogHelper.e(TAG, "Media player error: what=" + what + ", extra=" + extra);
+ handleStopRequest("MediaPlayer error " + what + " (" + extra + ")");
+ return true; // true indicates we handled the error
+ }
+
+
+
+
+ /**
+ * Called by AudioManager on audio focus changes.
+ */
+ @Override
+ public void onAudioFocusChange(int focusChange) {
+ LogHelper.d(TAG, "onAudioFocusChange. focusChange=" + focusChange);
+ if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
+ // We have gained focus:
+ mAudioFocus = AudioFocus.Focused;
+
+ } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS ||
+ focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT ||
+ focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
+ // We have lost focus. If we can duck (low playback volume), we can keep playing.
+ // Otherwise, we need to pause the playback.
+ boolean canDuck = focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK;
+ mAudioFocus = canDuck ? AudioFocus.NoFocusCanDuck : AudioFocus.NoFocusNoDuck;
+
+ // If we are playing, we need to reset media player by calling configMediaPlayerState
+ // with mAudioFocus properly set.
+ if (mState == PlaybackState.STATE_PLAYING && !canDuck) {
+ // If we don't have audio focus and can't duck, we save the information that
+ // we were playing, so that we can resume playback once we get the focus back.
+ mPlayOnFocusGain = true;
+ }
+ } else {
+ LogHelper.e(TAG, "onAudioFocusChange: Ignoring unsupported focusChange: " + focusChange);
+ }
+
+ configMediaPlayerState();
+ }
+
+
+
+ /**
+ * Handle a request to play music
+ */
+ private void handlePlayRequest() {
+ LogHelper.d(TAG, "handlePlayRequest: mState=" + mState);
+
+ mDelayedStopHandler.removeCallbacksAndMessages(null);
+ if (!mServiceStarted) {
+ LogHelper.v(TAG, "Starting service");
+ // The MusicService needs to keep running even after the calling MediaBrowser
+ // is disconnected. Call startService(Intent) and then stopSelf(..) when we no longer
+ // need to play media.
+ startService(new Intent(getApplicationContext(), MusicService.class));
+ mServiceStarted = true;
+ }
+
+ mPlayOnFocusGain = true;
+ tryToGetAudioFocus();
+
+ if (!mSession.isActive()) {
+ mSession.setActive(true);
+ }
+
+ // actually play the song
+ if (mState == PlaybackState.STATE_PAUSED) {
+ // If we're paused, just continue playback and restore the
+ // 'foreground service' state.
+ configMediaPlayerState();
+ } else {
+ // If we're stopped or playing a song,
+ // just go ahead to the new song and (re)start playing
+ playCurrentSong();
+ }
+ }
+
+
+ /**
+ * Handle a request to pause music
+ */
+ private void handlePauseRequest() {
+ LogHelper.d(TAG, "handlePauseRequest: mState=" + mState);
+
+ if (mState == PlaybackState.STATE_PLAYING) {
+ // Pause media player and cancel the 'foreground service' state.
+ mState = PlaybackState.STATE_PAUSED;
+ if (mMediaPlayer.isPlaying()) {
+ mMediaPlayer.pause();
+ }
+ // while paused, retain the MediaPlayer but give up audio focus
+ relaxResources(false);
+ giveUpAudioFocus();
+ }
+ updatePlaybackState(null);
+ }
+
+ /**
+ * Handle a request to stop music
+ */
+ private void handleStopRequest(String withError) {
+ LogHelper.d(TAG, "handleStopRequest: mState=" + mState + " error=", withError);
+ mState = PlaybackState.STATE_STOPPED;
+
+ // let go of all resources...
+ relaxResources(true);
+ giveUpAudioFocus();
+ updatePlaybackState(withError);
+
+ mMediaNotification.stopNotification();
+
+ // service is no longer necessary. Will be started again if needed.
+ stopSelf();
+ mServiceStarted = false;
+ }
+
+ /**
+ * Releases resources used by the service for playback. This includes the
+ * "foreground service" status, the wake locks and possibly the MediaPlayer.
+ *
+ * @param releaseMediaPlayer Indicates whether the Media Player should also
+ * be released or not
+ */
+ private void relaxResources(boolean releaseMediaPlayer) {
+ LogHelper.d(TAG, "relaxResources. releaseMediaPlayer=" + releaseMediaPlayer);
+ // stop being a foreground service
+ stopForeground(true);
+
+ // reset the delayed stop handler.
+ mDelayedStopHandler.removeCallbacksAndMessages(null);
+ mDelayedStopHandler.sendEmptyMessageDelayed(0, STOP_DELAY);
+
+ // stop and release the Media Player, if it's available
+ if (releaseMediaPlayer && mMediaPlayer != null) {
+ mMediaPlayer.reset();
+ mMediaPlayer.release();
+ mMediaPlayer = null;
+ }
+
+ // we can also release the Wifi lock, if we're holding it
+ if (mWifiLock.isHeld()) {
+ mWifiLock.release();
+ }
+ }
+
+ /**
+ * Reconfigures MediaPlayer according to audio focus settings and
+ * starts/restarts it. This method starts/restarts the MediaPlayer
+ * respecting the current audio focus state. So if we have focus, it will
+ * play normally; if we don't have focus, it will either leave the
+ * MediaPlayer paused or set it to a low volume, depending on what is
+ * allowed by the current focus settings. This method assumes mPlayer !=
+ * null, so if you are calling it, you have to do so from a context where
+ * you are sure this is the case.
+ */
+ private void configMediaPlayerState() {
+ LogHelper.d(TAG, "configAndStartMediaPlayer. mAudioFocus=" + mAudioFocus);
+ if (mAudioFocus == AudioFocus.NoFocusNoDuck) {
+ // If we don't have audio focus and can't duck, we have to pause,
+ if (mState == PlaybackState.STATE_PLAYING) {
+ handlePauseRequest();
+ }
+ } else { // we have audio focus:
+ if (mAudioFocus == AudioFocus.NoFocusCanDuck) {
+ mMediaPlayer.setVolume(VOLUME_DUCK, VOLUME_DUCK); // we'll be relatively quiet
+ } else {
+ mMediaPlayer.setVolume(VOLUME_NORMAL, VOLUME_NORMAL); // we can be loud again
+ }
+ // If we were playing when we lost focus, we need to resume playing.
+ if (mPlayOnFocusGain) {
+ if (!mMediaPlayer.isPlaying()) {
+ LogHelper.d(TAG, "configAndStartMediaPlayer startMediaPlayer.");
+ mMediaPlayer.start();
+ }
+ mPlayOnFocusGain = false;
+ mState = PlaybackState.STATE_PLAYING;
+ }
+ }
+ updatePlaybackState(null);
+ }
+
+ /**
+ * Makes sure the media player exists and has been reset. This will create
+ * the media player if needed, or reset the existing media player if one
+ * already exists.
+ */
+ private void createMediaPlayerIfNeeded() {
+ LogHelper.d(TAG, "createMediaPlayerIfNeeded. needed? " + (mMediaPlayer==null));
+ if (mMediaPlayer == null) {
+ mMediaPlayer = new MediaPlayer();
+
+ // Make sure the media player will acquire a wake-lock while
+ // playing. If we don't do that, the CPU might go to sleep while the
+ // song is playing, causing playback to stop.
+ mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
+
+ // we want the media player to notify us when it's ready preparing,
+ // and when it's done playing:
+ mMediaPlayer.setOnPreparedListener(this);
+ mMediaPlayer.setOnCompletionListener(this);
+ mMediaPlayer.setOnErrorListener(this);
+ } else {
+ mMediaPlayer.reset();
+ }
+ }
+
+ /**
+ * Starts playing the current song in the playing queue.
+ */
+ void playCurrentSong() {
+ MediaMetadata track = getCurrentPlayingMusic();
+ if (track == null) {
+ LogHelper.e(TAG, "playSong: ignoring request to play next song, because cannot" +
+ " find it." +
+ " currentIndex=" + mCurrentIndexOnQueue +
+ " playQueue.size=" + (mPlayingQueue==null?"null": mPlayingQueue.size()));
+ return;
+ }
+ String source = track.getString(MusicProvider.CUSTOM_METADATA_TRACK_SOURCE);
+ LogHelper.d(TAG, "playSong: current (" + mCurrentIndexOnQueue + ") in playingQueue. " +
+ " musicId=" + track.getString(MediaMetadata.METADATA_KEY_MEDIA_ID) +
+ " source=" + source);
+
+ mState = PlaybackState.STATE_STOPPED;
+ relaxResources(false); // release everything except MediaPlayer
+
+ try {
+ createMediaPlayerIfNeeded();
+
+ mState = PlaybackState.STATE_BUFFERING;
+
+ mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
+ mMediaPlayer.setDataSource(source);
+
+ // Starts preparing the media player in the background. When
+ // it's done, it will call our OnPreparedListener (that is,
+ // the onPrepared() method on this class, since we set the
+ // listener to 'this'). Until the media player is prepared,
+ // we *cannot* call start() on it!
+ mMediaPlayer.prepareAsync();
+
+ // If we are streaming from the internet, we want to hold a
+ // Wifi lock, which prevents the Wifi radio from going to
+ // sleep while the song is playing.
+ mWifiLock.acquire();
+
+ updatePlaybackState(null);
+ updateMetadata();
+
+ } catch (IOException ex) {
+ LogHelper.e(TAG, ex, "IOException playing song");
+ updatePlaybackState(ex.getMessage());
+ }
+ }
+
+
+
+ private void updateMetadata() {
+ if (!QueueHelper.isIndexPlayable(mCurrentIndexOnQueue, mPlayingQueue)) {
+ LogHelper.e(TAG, "Can't retrieve current metadata.");
+ mState = PlaybackState.STATE_ERROR;
+ updatePlaybackState(getResources().getString(R.string.error_no_metadata));
+ return;
+ }
+ MediaSession.QueueItem queueItem = mPlayingQueue.get(mCurrentIndexOnQueue);
+ String mediaId = queueItem.getDescription().getMediaId();
+ MediaMetadata track = mMusicProvider.getMusic(mediaId);
+ String trackId = track.getString(MediaMetadata.METADATA_KEY_MEDIA_ID);
+ if (!mediaId.equals(trackId)) {
+ throw new IllegalStateException("track ID (" + trackId + ") " +
+ "should match mediaId (" + mediaId + ")");
+ }
+ LogHelper.d(TAG, "Updating metadata for MusicID= " + mediaId);
+ mSession.setMetadata(track);
+ }
+
+
+ /**
+ * Update the current media player state, optionally showing an error message.
+ *
+ * @param error if not null, error message to present to the user.
+ *
+ */
+ private void updatePlaybackState(String error) {
+
+ LogHelper.d(TAG, "updatePlaybackState, setting session playback state to " + mState);
+ long position = PlaybackState.PLAYBACK_POSITION_UNKNOWN;
+ if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
+ position = mMediaPlayer.getCurrentPosition();
+ }
+ PlaybackState.Builder stateBuilder = new PlaybackState.Builder()
+ .setActions(getAvailableActions());
+
+ setCustomAction(stateBuilder);
+
+ // If there is an error message, send it to the playback state:
+ if (error != null) {
+ // Error states are really only supposed to be used for errors that cause playback to
+ // stop unexpectedly and persist until the user takes action to fix it.
+ stateBuilder.setErrorMessage(error);
+ mState = PlaybackState.STATE_ERROR;
+ }
+ stateBuilder.setState(mState, position, 1.0f, SystemClock.elapsedRealtime());
+
+ // Set the activeQueueItemId if the current index is valid.
+ if (QueueHelper.isIndexPlayable(mCurrentIndexOnQueue, mPlayingQueue)) {
+ MediaSession.QueueItem item = mPlayingQueue.get(mCurrentIndexOnQueue);
+ stateBuilder.setActiveQueueItemId(item.getQueueId());
+ }
+
+ mSession.setPlaybackState(stateBuilder.build());
+
+ if (mState == PlaybackState.STATE_PLAYING || mState == PlaybackState.STATE_PAUSED) {
+ mMediaNotification.startNotification();
+ }
+ }
+
+ private void setCustomAction(PlaybackState.Builder stateBuilder) {
+ MediaMetadata currentMusic = getCurrentPlayingMusic();
+ if (currentMusic != null) {
+ // Set appropriate "Favorite" icon on Custom action:
+ String mediaId = currentMusic.getString(MediaMetadata.METADATA_KEY_MEDIA_ID);
+ int favoriteIcon = R.drawable.ic_star_off;
+ if (mMusicProvider.isFavorite(mediaId)) {
+ favoriteIcon = R.drawable.ic_star_on;
+ }
+ LogHelper.d(TAG, "updatePlaybackState, setting Favorite custom action of music ",
+ mediaId, " current favorite=", mMusicProvider.isFavorite(mediaId));
+ stateBuilder.addCustomAction(CUSTOM_ACTION_THUMBS_UP, getString(R.string.favorite),
+ favoriteIcon);
+ }
+ }
+
+ private long getAvailableActions() {
+ long actions = PlaybackState.ACTION_PLAY | PlaybackState.ACTION_PLAY_FROM_MEDIA_ID |
+ PlaybackState.ACTION_PLAY_FROM_SEARCH;
+ if (mPlayingQueue == null || mPlayingQueue.isEmpty()) {
+ return actions;
+ }
+ if (mState == PlaybackState.STATE_PLAYING) {
+ actions |= PlaybackState.ACTION_PAUSE;
+ }
+ if (mCurrentIndexOnQueue > 0) {
+ actions |= PlaybackState.ACTION_SKIP_TO_PREVIOUS;
+ }
+ if (mCurrentIndexOnQueue < mPlayingQueue.size() - 1) {
+ actions |= PlaybackState.ACTION_SKIP_TO_NEXT;
+ }
+ return actions;
+ }
+
+ private MediaMetadata getCurrentPlayingMusic() {
+ if (QueueHelper.isIndexPlayable(mCurrentIndexOnQueue, mPlayingQueue)) {
+ MediaSession.QueueItem item = mPlayingQueue.get(mCurrentIndexOnQueue);
+ if (item != null) {
+ LogHelper.d(TAG, "getCurrentPlayingMusic for musicId=",
+ item.getDescription().getMediaId());
+ return mMusicProvider.getMusic(item.getDescription().getMediaId());
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Try to get the system audio focus.
+ */
+ void tryToGetAudioFocus() {
+ LogHelper.d(TAG, "tryToGetAudioFocus");
+ if (mAudioFocus != AudioFocus.Focused) {
+ int result = mAudioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
+ AudioManager.AUDIOFOCUS_GAIN);
+ if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
+ mAudioFocus = AudioFocus.Focused;
+ }
+ }
+ }
+
+ /**
+ * Give up the audio focus.
+ */
+ void giveUpAudioFocus() {
+ LogHelper.d(TAG, "giveUpAudioFocus");
+ if (mAudioFocus == AudioFocus.Focused) {
+ if (mAudioManager.abandonAudioFocus(this) == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
+ mAudioFocus = AudioFocus.NoFocusNoDuck;
+ }
+ }
+ }
+}
diff --git a/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/QueueAdapter.java b/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/QueueAdapter.java
new file mode 100644
index 0000000..4f24e99
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/QueueAdapter.java
@@ -0,0 +1,82 @@
+/*
+ * 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.mediabrowserservice;
+
+import android.app.Activity;
+import android.media.session.MediaSession;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+
+/**
+ * A list adapter for items in a queue
+ */
+public class QueueAdapter extends ArrayAdapter<MediaSession.QueueItem> {
+
+ // The currently selected/active queue item Id.
+ private long mActiveQueueItemId = MediaSession.QueueItem.UNKNOWN_ID;
+
+ public QueueAdapter(Activity context) {
+ super(context, R.layout.media_list_item, new ArrayList<MediaSession.QueueItem>());
+ }
+
+ public void setActiveQueueItemId(long id) {
+ this.mActiveQueueItemId = id;
+ }
+
+ private static class ViewHolder {
+ ImageView mImageView;
+ TextView mTitleView;
+ TextView mDescriptionView;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ ViewHolder holder;
+
+ if (convertView == null) {
+ convertView = LayoutInflater.from(getContext())
+ .inflate(R.layout.media_list_item, parent, false);
+ holder = new ViewHolder();
+ holder.mImageView = (ImageView) convertView.findViewById(R.id.play_eq);
+ holder.mTitleView = (TextView) convertView.findViewById(R.id.title);
+ holder.mDescriptionView = (TextView) convertView.findViewById(R.id.description);
+ convertView.setTag(holder);
+ } else {
+ holder = (ViewHolder) convertView.getTag();
+ }
+
+ MediaSession.QueueItem item = getItem(position);
+ holder.mTitleView.setText(item.getDescription().getTitle());
+ if (item.getDescription().getDescription() != null) {
+ holder.mDescriptionView.setText(item.getDescription().getDescription());
+ }
+
+ // If the itemId matches the active Id then use a different icon
+ if (mActiveQueueItemId == item.getQueueId()) {
+ holder.mImageView.setImageDrawable(
+ getContext().getDrawable(R.drawable.ic_equalizer_white_24dp));
+ } else {
+ holder.mImageView.setImageDrawable(
+ getContext().getDrawable(R.drawable.ic_play_arrow_white_24dp));
+ }
+ return convertView;
+ }
+}
diff --git a/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/QueueFragment.java b/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/QueueFragment.java
new file mode 100644
index 0000000..f6076bc
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/QueueFragment.java
@@ -0,0 +1,295 @@
+/*
+ * 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.mediabrowserservice;
+
+import android.app.Fragment;
+import android.content.ComponentName;
+import android.media.browse.MediaBrowser;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.media.session.PlaybackState;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ImageButton;
+import android.widget.ListView;
+
+import com.example.android.mediabrowserservice.utils.LogHelper;
+
+import java.util.List;
+
+/**
+ * A class that shows the Media Queue to the user.
+ */
+public class QueueFragment extends Fragment {
+
+ private static final String TAG = QueueFragment.class.getSimpleName();
+
+ private ImageButton mSkipNext;
+ private ImageButton mSkipPrevious;
+ private ImageButton mPlayPause;
+
+ private MediaBrowser mMediaBrowser;
+ private MediaController.TransportControls mTransportControls;
+ private MediaController mMediaController;
+ private PlaybackState mPlaybackState;
+
+ private QueueAdapter mQueueAdapter;
+
+ private MediaBrowser.ConnectionCallback mConnectionCallback =
+ new MediaBrowser.ConnectionCallback() {
+ @Override
+ public void onConnected() {
+ LogHelper.d(TAG, "onConnected: session token ", mMediaBrowser.getSessionToken());
+
+ if (mMediaBrowser.getSessionToken() == null) {
+ throw new IllegalArgumentException("No Session token");
+ }
+
+ mMediaController = new MediaController(getActivity(),
+ mMediaBrowser.getSessionToken());
+ mTransportControls = mMediaController.getTransportControls();
+ mMediaController.registerCallback(mSessionCallback);
+
+ getActivity().setMediaController(mMediaController);
+ mPlaybackState = mMediaController.getPlaybackState();
+
+ List<MediaSession.QueueItem> queue = mMediaController.getQueue();
+ if (queue != null) {
+ mQueueAdapter.clear();
+ mQueueAdapter.notifyDataSetInvalidated();
+ mQueueAdapter.addAll(queue);
+ mQueueAdapter.notifyDataSetChanged();
+ }
+ onPlaybackStateChanged(mPlaybackState);
+ }
+
+ @Override
+ public void onConnectionFailed() {
+ LogHelper.d(TAG, "onConnectionFailed");
+ }
+
+ @Override
+ public void onConnectionSuspended() {
+ LogHelper.d(TAG, "onConnectionSuspended");
+ mMediaController.unregisterCallback(mSessionCallback);
+ mTransportControls = null;
+ mMediaController = null;
+ getActivity().setMediaController(null);
+ }
+ };
+
+ // Receive callbacks from the MediaController. Here we update our state such as which queue
+ // is being shown, the current title and description and the PlaybackState.
+ private MediaController.Callback mSessionCallback = new MediaController.Callback() {
+
+ @Override
+ public void onSessionDestroyed() {
+ LogHelper.d(TAG, "Session destroyed. Need to fetch a new Media Session");
+ }
+
+ @Override
+ public void onPlaybackStateChanged(PlaybackState state) {
+ if (state == null) {
+ return;
+ }
+ LogHelper.d(TAG, "Received playback state change to state ", state.getState());
+ mPlaybackState = state;
+ QueueFragment.this.onPlaybackStateChanged(state);
+ }
+
+ @Override
+ public void onQueueChanged(List<MediaSession.QueueItem> queue) {
+ LogHelper.d(TAG, "onQueueChanged ", queue);
+ if (queue != null) {
+ mQueueAdapter.clear();
+ mQueueAdapter.notifyDataSetInvalidated();
+ mQueueAdapter.addAll(queue);
+ mQueueAdapter.notifyDataSetChanged();
+ }
+ }
+ };
+
+ public static QueueFragment newInstance() {
+ return new QueueFragment();
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View rootView = inflater.inflate(R.layout.fragment_list, container, false);
+
+ mSkipPrevious = (ImageButton) rootView.findViewById(R.id.skip_previous);
+ mSkipPrevious.setEnabled(false);
+ mSkipPrevious.setOnClickListener(mButtonListener);
+
+ mSkipNext = (ImageButton) rootView.findViewById(R.id.skip_next);
+ mSkipNext.setEnabled(false);
+ mSkipNext.setOnClickListener(mButtonListener);
+
+ mPlayPause = (ImageButton) rootView.findViewById(R.id.play_pause);
+ mPlayPause.setEnabled(true);
+ mPlayPause.setOnClickListener(mButtonListener);
+
+ mQueueAdapter = new QueueAdapter(getActivity());
+
+ ListView mListView = (ListView) rootView.findViewById(R.id.list_view);
+ mListView.setAdapter(mQueueAdapter);
+ mListView.setFocusable(true);
+ mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ MediaSession.QueueItem item = mQueueAdapter.getItem(position);
+ mTransportControls.skipToQueueItem(item.getQueueId());
+ }
+ });
+
+ mMediaBrowser = new MediaBrowser(getActivity(),
+ new ComponentName(getActivity(), MusicService.class),
+ mConnectionCallback, null);
+
+ return rootView;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (mMediaBrowser != null) {
+ mMediaBrowser.connect();
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ if (mMediaController != null) {
+ mMediaController.unregisterCallback(mSessionCallback);
+ }
+ if (mMediaBrowser != null) {
+ mMediaBrowser.disconnect();
+ }
+ }
+
+
+ private void onPlaybackStateChanged(PlaybackState state) {
+ LogHelper.d(TAG, "onPlaybackStateChanged ", state);
+ if (state == null) {
+ return;
+ }
+ mQueueAdapter.setActiveQueueItemId(state.getActiveQueueItemId());
+ mQueueAdapter.notifyDataSetChanged();
+ boolean enablePlay = false;
+ StringBuilder statusBuilder = new StringBuilder();
+ switch (state.getState()) {
+ case PlaybackState.STATE_PLAYING:
+ statusBuilder.append("playing");
+ enablePlay = false;
+ break;
+ case PlaybackState.STATE_PAUSED:
+ statusBuilder.append("paused");
+ enablePlay = true;
+ break;
+ case PlaybackState.STATE_STOPPED:
+ statusBuilder.append("ended");
+ enablePlay = true;
+ break;
+ case PlaybackState.STATE_ERROR:
+ statusBuilder.append("error: ").append(state.getErrorMessage());
+ break;
+ case PlaybackState.STATE_BUFFERING:
+ statusBuilder.append("buffering");
+ break;
+ case PlaybackState.STATE_NONE:
+ statusBuilder.append("none");
+ enablePlay = false;
+ break;
+ case PlaybackState.STATE_CONNECTING:
+ statusBuilder.append("connecting");
+ break;
+ default:
+ statusBuilder.append(mPlaybackState);
+ }
+ statusBuilder.append(" -- At position: ").append(state.getPosition());
+ LogHelper.d(TAG, statusBuilder.toString());
+
+ if (enablePlay) {
+ mPlayPause.setImageDrawable(
+ getActivity().getDrawable(R.drawable.ic_play_arrow_white_24dp));
+ } else {
+ mPlayPause.setImageDrawable(getActivity().getDrawable(R.drawable.ic_pause_white_24dp));
+ }
+
+ mSkipPrevious.setEnabled((state.getActions() & PlaybackState.ACTION_SKIP_TO_PREVIOUS) != 0);
+ mSkipNext.setEnabled((state.getActions() & PlaybackState.ACTION_SKIP_TO_NEXT) != 0);
+
+ LogHelper.d(TAG, "Queue From MediaController *** Title " +
+ mMediaController.getQueueTitle() + "\n: Queue: " + mMediaController.getQueue() +
+ "\n Metadata " + mMediaController.getMetadata());
+ }
+
+ private View.OnClickListener mButtonListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ final int state = mPlaybackState == null ?
+ PlaybackState.STATE_NONE : mPlaybackState.getState();
+ switch (v.getId()) {
+ case R.id.play_pause:
+ LogHelper.d(TAG, "Play button pressed, in state " + state);
+ if (state == PlaybackState.STATE_PAUSED ||
+ state == PlaybackState.STATE_STOPPED ||
+ state == PlaybackState.STATE_NONE) {
+ playMedia();
+ } else if (state == PlaybackState.STATE_PLAYING) {
+ pauseMedia();
+ }
+ break;
+ case R.id.skip_previous:
+ LogHelper.d(TAG, "Start button pressed, in state " + state);
+ skipToPrevious();
+ break;
+ case R.id.skip_next:
+ skipToNext();
+ break;
+ }
+ }
+ };
+
+ private void playMedia() {
+ if (mTransportControls != null) {
+ mTransportControls.play();
+ }
+ }
+
+ private void pauseMedia() {
+ if (mTransportControls != null) {
+ mTransportControls.pause();
+ }
+ }
+
+ private void skipToPrevious() {
+ if (mTransportControls != null) {
+ mTransportControls.skipToPrevious();
+ }
+ }
+
+ private void skipToNext() {
+ if (mTransportControls != null) {
+ mTransportControls.skipToNext();
+ }
+ }
+}
diff --git a/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/model/MusicProvider.java b/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/model/MusicProvider.java
new file mode 100644
index 0000000..ae90fb0
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/model/MusicProvider.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2014 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.mediabrowserservice.model;
+
+import android.media.MediaMetadata;
+import android.os.AsyncTask;
+
+import com.example.android.mediabrowserservice.utils.LogHelper;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Utility class to get a list of MusicTrack's based on a server-side JSON
+ * configuration.
+ */
+public class MusicProvider {
+
+ private static final String TAG = "MusicProvider";
+
+ private static final String CATALOG_URL = "http://storage.googleapis.com/automotive-media/music.json";
+
+ public static final String CUSTOM_METADATA_TRACK_SOURCE = "__SOURCE__";
+
+ private static String JSON_MUSIC = "music";
+ private static String JSON_TITLE = "title";
+ private static String JSON_ALBUM = "album";
+ private static String JSON_ARTIST = "artist";
+ private static String JSON_GENRE = "genre";
+ private static String JSON_SOURCE = "source";
+ private static String JSON_IMAGE = "image";
+ private static String JSON_TRACK_NUMBER = "trackNumber";
+ private static String JSON_TOTAL_TRACK_COUNT = "totalTrackCount";
+ private static String JSON_DURATION = "duration";
+
+ private final ReentrantLock initializationLock = new ReentrantLock();
+
+ // Categorized caches for music track data:
+ private final HashMap<String, List<MediaMetadata>> mMusicListByGenre;
+ private final HashMap<String, MediaMetadata> mMusicListById;
+
+ private final HashSet<String> mFavoriteTracks;
+
+ enum State {
+ NON_INITIALIZED, INITIALIZING, INITIALIZED;
+ }
+
+ private State mCurrentState = State.NON_INITIALIZED;
+
+
+ public interface Callback {
+ void onMusicCatalogReady(boolean success);
+ }
+
+ public MusicProvider() {
+ mMusicListByGenre = new HashMap<>();
+ mMusicListById = new HashMap<>();
+ mFavoriteTracks = new HashSet<>();
+ }
+
+ /**
+ * Get an iterator over the list of genres
+ *
+ * @return
+ */
+ public Iterable<String> getGenres() {
+ if (mCurrentState != State.INITIALIZED) {
+ return new ArrayList<String>(0);
+ }
+ return mMusicListByGenre.keySet();
+ }
+
+ /**
+ * Get music tracks of the given genre
+ *
+ * @return
+ */
+ public Iterable<MediaMetadata> getMusicsByGenre(String genre) {
+ if (mCurrentState != State.INITIALIZED || !mMusicListByGenre.containsKey(genre)) {
+ return new ArrayList<MediaMetadata>();
+ }
+ return mMusicListByGenre.get(genre);
+ }
+
+ /**
+ * Very basic implementation of a search that filter music tracks which title containing
+ * the given query.
+ *
+ * @return
+ */
+ public Iterable<MediaMetadata> searchMusics(String titleQuery) {
+ ArrayList<MediaMetadata> result = new ArrayList<>();
+ if (mCurrentState != State.INITIALIZED) {
+ return result;
+ }
+ titleQuery = titleQuery.toLowerCase();
+ for (MediaMetadata track: mMusicListById.values()) {
+ if (track.getString(MediaMetadata.METADATA_KEY_TITLE).toLowerCase()
+ .contains(titleQuery)) {
+ result.add(track);
+ }
+ }
+ return result;
+ }
+
+ public MediaMetadata getMusic(String mediaId) {
+ return mMusicListById.get(mediaId);
+ }
+
+ public void setFavorite(String mediaId, boolean favorite) {
+ if (favorite) {
+ mFavoriteTracks.add(mediaId);
+ } else {
+ mFavoriteTracks.remove(mediaId);
+ }
+ }
+
+ public boolean isFavorite(String musicId) {
+ return mFavoriteTracks.contains(musicId);
+ }
+
+ public boolean isInitialized() {
+ return mCurrentState == State.INITIALIZED;
+ }
+
+ /**
+ * Get the list of music tracks from a server and caches the track information
+ * for future reference, keying tracks by mediaId and grouping by genre.
+ *
+ * @return
+ */
+ public void retrieveMedia(final Callback callback) {
+
+ if (mCurrentState == State.INITIALIZED) {
+ // Nothing to do, execute callback immediately
+ callback.onMusicCatalogReady(true);
+ return;
+ }
+
+ // Asynchronously load the music catalog in a separate thread
+ new AsyncTask() {
+ @Override
+ protected Object doInBackground(Object[] objects) {
+ retrieveMediaAsync(callback);
+ return null;
+ }
+ }.execute();
+ }
+
+ private void retrieveMediaAsync(Callback callback) {
+ initializationLock.lock();
+
+ try {
+ if (mCurrentState == State.NON_INITIALIZED) {
+ mCurrentState = State.INITIALIZING;
+
+ int slashPos = CATALOG_URL.lastIndexOf('/');
+ String path = CATALOG_URL.substring(0, slashPos + 1);
+ JSONObject jsonObj = parseUrl(CATALOG_URL);
+
+ JSONArray tracks = jsonObj.getJSONArray(JSON_MUSIC);
+ if (tracks != null) {
+ for (int j = 0; j < tracks.length(); j++) {
+ MediaMetadata item = buildFromJSON(tracks.getJSONObject(j), path);
+ String genre = item.getString(MediaMetadata.METADATA_KEY_GENRE);
+ List<MediaMetadata> list = mMusicListByGenre.get(genre);
+ if (list == null) {
+ list = new ArrayList<>();
+ }
+ list.add(item);
+ mMusicListByGenre.put(genre, list);
+ mMusicListById.put(item.getString(MediaMetadata.METADATA_KEY_MEDIA_ID),
+ item);
+ }
+ }
+ mCurrentState = State.INITIALIZED;
+ }
+ } catch (RuntimeException | JSONException e) {
+ LogHelper.e(TAG, e, "Could not retrieve music list");
+ } finally {
+ if (mCurrentState != State.INITIALIZED) {
+ // Something bad happened, so we reset state to NON_INITIALIZED to allow
+ // retries (eg if the network connection is temporary unavailable)
+ mCurrentState = State.NON_INITIALIZED;
+ }
+ initializationLock.unlock();
+ if (callback != null) {
+ callback.onMusicCatalogReady(mCurrentState == State.INITIALIZED);
+ }
+ }
+ }
+
+ private MediaMetadata buildFromJSON(JSONObject json, String basePath) throws JSONException {
+ String title = json.getString(JSON_TITLE);
+ String album = json.getString(JSON_ALBUM);
+ String artist = json.getString(JSON_ARTIST);
+ String genre = json.getString(JSON_GENRE);
+ String source = json.getString(JSON_SOURCE);
+ String iconUrl = json.getString(JSON_IMAGE);
+ int trackNumber = json.getInt(JSON_TRACK_NUMBER);
+ int totalTrackCount = json.getInt(JSON_TOTAL_TRACK_COUNT);
+ int duration = json.getInt(JSON_DURATION) * 1000; // ms
+
+ LogHelper.d(TAG, "Found music track: ", json);
+
+ // Media is stored relative to JSON file
+ if (!source.startsWith("http")) {
+ source = basePath + source;
+ }
+ if (!iconUrl.startsWith("http")) {
+ iconUrl = basePath + iconUrl;
+ }
+ // Since we don't have a unique ID in the server, we fake one using the hashcode of
+ // the music source. In a real world app, this could come from the server.
+ String id = String.valueOf(source.hashCode());
+
+ // Adding the music source to the MediaMetadata (and consequently using it in the
+ // mediaSession.setMetadata) is not a good idea for a real world music app, because
+ // the session metadata can be accessed by notification listeners. This is done in this
+ // sample for convenience only.
+ return new MediaMetadata.Builder()
+ .putString(MediaMetadata.METADATA_KEY_MEDIA_ID, id)
+ .putString(CUSTOM_METADATA_TRACK_SOURCE, source)
+ .putString(MediaMetadata.METADATA_KEY_ALBUM, album)
+ .putString(MediaMetadata.METADATA_KEY_ARTIST, artist)
+ .putLong(MediaMetadata.METADATA_KEY_DURATION, duration)
+ .putString(MediaMetadata.METADATA_KEY_GENRE, genre)
+ .putString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI, iconUrl)
+ .putString(MediaMetadata.METADATA_KEY_TITLE, title)
+ .putLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER, trackNumber)
+ .putLong(MediaMetadata.METADATA_KEY_NUM_TRACKS, totalTrackCount)
+ .build();
+ }
+
+ /**
+ * Download a JSON file from a server, parse the content and return the JSON
+ * object.
+ *
+ * @param urlString
+ * @return
+ */
+ private JSONObject parseUrl(String urlString) {
+ InputStream is = null;
+ try {
+ java.net.URL url = new java.net.URL(urlString);
+ URLConnection urlConnection = url.openConnection();
+ is = new BufferedInputStream(urlConnection.getInputStream());
+ BufferedReader reader = new BufferedReader(new InputStreamReader(
+ urlConnection.getInputStream(), "iso-8859-1"));
+ StringBuilder sb = new StringBuilder();
+ String line = null;
+ while ((line = reader.readLine()) != null) {
+ sb.append(line);
+ }
+ return new JSONObject(sb.toString());
+ } catch (Exception e) {
+ LogHelper.e(TAG, "Failed to parse the json for media list", e);
+ return null;
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/utils/BitmapHelper.java b/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/utils/BitmapHelper.java
new file mode 100644
index 0000000..5f0e767
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/utils/BitmapHelper.java
@@ -0,0 +1,77 @@
+/*
+ * 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.mediabrowserservice.utils;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+public class BitmapHelper {
+
+ // Bitmap size for album art in media notifications when there are more than 3 playback actions
+ public static final int MEDIA_ART_SMALL_WIDTH=64;
+ public static final int MEDIA_ART_SMALL_HEIGHT=64;
+
+ // Bitmap size for album art in media notifications when there are no more than 3 playback actions
+ public static final int MEDIA_ART_BIG_WIDTH=128;
+ public static final int MEDIA_ART_BIG_HEIGHT=128;
+
+ public static final Bitmap scaleBitmap(int scaleFactor, InputStream is) {
+ // Get the dimensions of the bitmap
+ BitmapFactory.Options bmOptions = new BitmapFactory.Options();
+
+ // Decode the image file into a Bitmap sized to fill the View
+ bmOptions.inJustDecodeBounds = false;
+ bmOptions.inSampleSize = scaleFactor;
+
+ Bitmap bitmap = BitmapFactory.decodeStream(is, null, bmOptions);
+ return bitmap;
+ }
+
+ public static final int findScaleFactor(int targetW, int targetH, InputStream is) {
+ // Get the dimensions of the bitmap
+ BitmapFactory.Options bmOptions = new BitmapFactory.Options();
+ bmOptions.inJustDecodeBounds = true;
+ BitmapFactory.decodeStream(is, null, bmOptions);
+ int actualW = bmOptions.outWidth;
+ int actualH = bmOptions.outHeight;
+
+ // Determine how much to scale down the image
+ return Math.min(actualW/targetW, actualH/targetH);
+ }
+
+ public static final Bitmap fetchAndRescaleBitmap(String uri, int width, int height)
+ throws IOException {
+ URL url = new URL(uri);
+ HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
+ httpConnection.setDoInput(true);
+ httpConnection.connect();
+ InputStream inputStream = httpConnection.getInputStream();
+ int scaleFactor = findScaleFactor(width, height, inputStream);
+
+ httpConnection = (HttpURLConnection) url.openConnection();
+ httpConnection.setDoInput(true);
+ httpConnection.connect();
+ inputStream = httpConnection.getInputStream();
+ Bitmap bitmap = scaleBitmap(scaleFactor, inputStream);
+ return bitmap;
+ }
+
+}
diff --git a/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/utils/LogHelper.java b/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/utils/LogHelper.java
new file mode 100644
index 0000000..92b2e09
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/utils/LogHelper.java
@@ -0,0 +1,67 @@
+/*
+ * 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.mediabrowserservice.utils;
+
+import android.util.Log;
+
+public class LogHelper {
+ public static void v(String tag, Object... messages) {
+ log(tag, Log.VERBOSE, null, messages);
+ }
+
+ public static void d(String tag, Object... messages) {
+ log(tag, Log.DEBUG, null, messages);
+ }
+
+ public static void i(String tag, Object... messages) {
+ log(tag, Log.INFO, null, messages);
+ }
+
+ public static void w(String tag, Object... messages) {
+ log(tag, Log.WARN, null, messages);
+ }
+
+ public static void w(String tag, Throwable t, Object... messages) {
+ log(tag, Log.WARN, t, messages);
+ }
+
+ public static void e(String tag, Object... messages) {
+ log(tag, Log.ERROR, null, messages);
+ }
+
+ public static void e(String tag, Throwable t, Object... messages) {
+ log(tag, Log.ERROR, t, messages);
+ }
+
+ public static void log(String tag, int level, Throwable t, Object... messages) {
+ if (messages != null && Log.isLoggable(tag, level)) {
+ String message;
+ if (messages.length == 1) {
+ message = messages[0] == null ? null : messages[0].toString();
+ } else {
+ StringBuilder sb = new StringBuilder();
+ for (Object m: messages) {
+ sb.append(m);
+ }
+ if (t != null) {
+ sb.append("\n").append(Log.getStackTraceString(t));
+ }
+ message = sb.toString();
+ }
+ Log.println(level, tag, message);
+ }
+ }
+}
diff --git a/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/utils/MediaIDHelper.java b/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/utils/MediaIDHelper.java
new file mode 100644
index 0000000..68e6db9
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/utils/MediaIDHelper.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2014 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.mediabrowserservice.utils;
+
+import android.media.MediaMetadata;
+
+/**
+ * Utility class to help on queue related tasks.
+ */
+public class MediaIDHelper {
+
+ private static final String TAG = "MediaIDHelper";
+
+ // Media IDs used on browseable items of MediaBrowser
+ public static final String MEDIA_ID_ROOT = "__ROOT__";
+ public static final String MEDIA_ID_MUSICS_BY_GENRE = "__BY_GENRE__";
+
+ public static final String createTrackMediaID(String categoryType, String categoryValue,
+ MediaMetadata track) {
+ // MediaIDs are of the form <categoryType>/<categoryValue>|<musicUniqueId>, to make it easy to
+ // find the category (like genre) that a music was selected from, so we
+ // can correctly build the playing queue. This is specially useful when
+ // one music can appear in more than one list, like "by genre -> genre_1"
+ // and "by artist -> artist_1".
+ return categoryType + "/" + categoryValue + "|" +
+ track.getString(MediaMetadata.METADATA_KEY_MEDIA_ID);
+ }
+
+ public static final String createBrowseCategoryMediaID(String categoryType, String categoryValue) {
+ return categoryType + "/" + categoryValue;
+ }
+
+ /**
+ * Extracts unique musicID from the mediaID. mediaID is, by this sample's convention, a
+ * concatenation of category (eg "by_genre"), categoryValue (eg "Classical") and unique
+ * musicID. This is necessary so we know where the user selected the music from, when the music
+ * exists in more than one music list, and thus we are able to correctly build the playing queue.
+ *
+ * @param musicID
+ * @return
+ */
+ public static final String extractMusicIDFromMediaID(String musicID) {
+ String[] segments = musicID.split("\\|", 2);
+ return segments.length == 2 ? segments[1] : null;
+ }
+
+ /**
+ * Extracts category and categoryValue from the mediaID. mediaID is, by this sample's
+ * convention, a concatenation of category (eg "by_genre"), categoryValue (eg "Classical") and
+ * mediaID. This is necessary so we know where the user selected the music from, when the music
+ * exists in more than one music list, and thus we are able to correctly build the playing queue.
+ *
+ * @param mediaID
+ * @return
+ */
+ public static final String[] extractBrowseCategoryFromMediaID(String mediaID) {
+ if (mediaID.indexOf('|') >= 0) {
+ mediaID = mediaID.split("\\|")[0];
+ }
+ if (mediaID.indexOf('/') == 0) {
+ return new String[]{mediaID, null};
+ } else {
+ return mediaID.split("/", 2);
+ }
+ }
+
+ public static final String extractBrowseCategoryValueFromMediaID(String mediaID) {
+ String[] categoryAndValue = extractBrowseCategoryFromMediaID(mediaID);
+ if (categoryAndValue != null && categoryAndValue.length == 2) {
+ return categoryAndValue[1];
+ }
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/utils/QueueHelper.java b/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/utils/QueueHelper.java
new file mode 100644
index 0000000..abe3d34
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/utils/QueueHelper.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2014 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.mediabrowserservice.utils;
+
+import android.media.MediaMetadata;
+import android.media.session.MediaSession;
+
+import com.example.android.mediabrowserservice.model.MusicProvider;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import static com.example.android.mediabrowserservice.utils.MediaIDHelper.MEDIA_ID_MUSICS_BY_GENRE;
+
+/**
+ * Utility class to help on queue related tasks.
+ */
+public class QueueHelper {
+
+ private static final String TAG = "QueueHelper";
+
+ public static final List<MediaSession.QueueItem> getPlayingQueue(String mediaId,
+ MusicProvider musicProvider) {
+
+ // extract the category and unique music ID from the media ID:
+ String[] category = MediaIDHelper.extractBrowseCategoryFromMediaID(mediaId);
+
+ // This sample only supports genre category.
+ if (!category[0].equals(MEDIA_ID_MUSICS_BY_GENRE) || category.length != 2) {
+ LogHelper.e(TAG, "Could not build a playing queue for this mediaId: ", mediaId);
+ return null;
+ }
+
+ String categoryValue = category[1];
+ LogHelper.e(TAG, "Creating playing queue for musics of genre ", categoryValue);
+
+ List<MediaSession.QueueItem> queue = convertToQueue(
+ musicProvider.getMusicsByGenre(categoryValue));
+
+ return queue;
+ }
+
+ public static final List<MediaSession.QueueItem> getPlayingQueueFromSearch(String query,
+ MusicProvider musicProvider) {
+
+ LogHelper.e(TAG, "Creating playing queue for musics from search ", query);
+
+ return convertToQueue(musicProvider.searchMusics(query));
+ }
+
+
+ public static final int getMusicIndexOnQueue(Iterable<MediaSession.QueueItem> queue,
+ String mediaId) {
+ int index = 0;
+ for (MediaSession.QueueItem item: queue) {
+ if (mediaId.equals(item.getDescription().getMediaId())) {
+ return index;
+ }
+ index++;
+ }
+ return -1;
+ }
+
+ public static final int getMusicIndexOnQueue(Iterable<MediaSession.QueueItem> queue,
+ long queueId) {
+ int index = 0;
+ for (MediaSession.QueueItem item: queue) {
+ if (queueId == item.getQueueId()) {
+ return index;
+ }
+ index++;
+ }
+ return -1;
+ }
+
+ private static final List<MediaSession.QueueItem> convertToQueue(
+ Iterable<MediaMetadata> tracks) {
+ List<MediaSession.QueueItem> queue = new ArrayList<>();
+ int count = 0;
+ for (MediaMetadata track : tracks) {
+ // We don't expect queues to change after created, so we use the item index as the
+ // queueId. Any other number unique in the queue would work.
+ MediaSession.QueueItem item = new MediaSession.QueueItem(
+ track.getDescription(), count++);
+ queue.add(item);
+ }
+ return queue;
+
+ }
+
+ /**
+ * Create a random queue. For simplicity sake, instead of a random queue, we create a
+ * queue using the first genre,
+ *
+ * @param musicProvider
+ * @return
+ */
+ public static final List<MediaSession.QueueItem> getRandomQueue(MusicProvider musicProvider) {
+ Iterator<String> genres = musicProvider.getGenres().iterator();
+ if (!genres.hasNext()) {
+ return new ArrayList<>();
+ }
+ String genre = genres.next();
+ Iterable<MediaMetadata> tracks = musicProvider.getMusicsByGenre(genre);
+
+ return convertToQueue(tracks);
+ }
+
+
+
+ public static final boolean isIndexPlayable(int index, List<MediaSession.QueueItem> queue) {
+ return (queue != null && index >= 0 && index < queue.size());
+ }
+}
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_launcher.png b/media/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..47d6854
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_notification.png b/media/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_notification.png
new file mode 100644
index 0000000..d8ea5a9
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_notification.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_pause_white_24dp.png b/media/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_pause_white_24dp.png
new file mode 100644
index 0000000..b4bdbb5
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_pause_white_24dp.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_play_arrow_white_24dp.png b/media/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_play_arrow_white_24dp.png
new file mode 100644
index 0000000..164385d
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_play_arrow_white_24dp.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_shuffle_white_24dp.png b/media/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_shuffle_white_24dp.png
new file mode 100644
index 0000000..3eeb0ef
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_shuffle_white_24dp.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_skip_next_white_24dp.png b/media/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_skip_next_white_24dp.png
new file mode 100644
index 0000000..4eaf7ca
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_skip_next_white_24dp.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_skip_previous_white_24dp.png b/media/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_skip_previous_white_24dp.png
new file mode 100644
index 0000000..e59dedb
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-hdpi/ic_skip_previous_white_24dp.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_launcher.png b/media/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..01b53fd
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-night-xxhdpi/ic_star_off.png b/media/MediaBrowserService/Application/src/main/res/drawable-night-xxhdpi/ic_star_off.png
new file mode 100644
index 0000000..e435d2a
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-night-xxhdpi/ic_star_off.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-night-xxhdpi/ic_star_on.png b/media/MediaBrowserService/Application/src/main/res/drawable-night-xxhdpi/ic_star_on.png
new file mode 100644
index 0000000..0c75bb6
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-night-xxhdpi/ic_star_on.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_equalizer_white_24dp.png b/media/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_equalizer_white_24dp.png
new file mode 100644
index 0000000..dbba844
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_equalizer_white_24dp.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/media/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..af762f2
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_pause_white_24dp.png b/media/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_pause_white_24dp.png
new file mode 100644
index 0000000..14b6d17
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_pause_white_24dp.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_play_arrow_white_24dp.png b/media/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_play_arrow_white_24dp.png
new file mode 100644
index 0000000..a55d199
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_play_arrow_white_24dp.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_shuffle_white_24dp.png b/media/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_shuffle_white_24dp.png
new file mode 100644
index 0000000..8ce3a60
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_shuffle_white_24dp.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_skip_next_white_24dp.png b/media/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_skip_next_white_24dp.png
new file mode 100644
index 0000000..f282b92
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_skip_next_white_24dp.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_skip_previous_white_24dp.png b/media/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_skip_previous_white_24dp.png
new file mode 100644
index 0000000..2522877
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-xhdpi/ic_skip_previous_white_24dp.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_by_genre.png b/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_by_genre.png
new file mode 100644
index 0000000..da3b4a7
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_by_genre.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_default_art.png b/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_default_art.png
new file mode 100644
index 0000000..dfb9e67
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_default_art.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_equalizer_white_24dp.png b/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_equalizer_white_24dp.png
new file mode 100644
index 0000000..b82a8d9
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_equalizer_white_24dp.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..eef47aa
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_pause_white_24dp.png b/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_pause_white_24dp.png
new file mode 100644
index 0000000..72dfa9f
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_pause_white_24dp.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_play_arrow_white_24dp.png b/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_play_arrow_white_24dp.png
new file mode 100644
index 0000000..043acd8
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_play_arrow_white_24dp.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_shuffle_white_24dp.png b/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_shuffle_white_24dp.png
new file mode 100644
index 0000000..718b6b5
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_shuffle_white_24dp.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_skip_next_white_24dp.png b/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_skip_next_white_24dp.png
new file mode 100644
index 0000000..4fe6088
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_skip_next_white_24dp.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_skip_previous_white_24dp.png b/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_skip_previous_white_24dp.png
new file mode 100644
index 0000000..2c9310a
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_skip_previous_white_24dp.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_star_off.png b/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_star_off.png
new file mode 100644
index 0000000..836085b
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_star_off.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_star_on.png b/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_star_on.png
new file mode 100644
index 0000000..7cd6cfc
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/drawable-xxhdpi/ic_star_on.png
Binary files differ
diff --git a/media/MediaBrowserService/Application/src/main/res/layout/activity_player.xml b/media/MediaBrowserService/Application/src/main/res/layout/activity_player.xml
new file mode 100644
index 0000000..21cdbbd
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/layout/activity_player.xml
@@ -0,0 +1,22 @@
+<!--
+ 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.
+ -->
+<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=".MusicPlayerActivity"
+ tools:ignore="MergeRootFrame" />
diff --git a/media/MediaBrowserService/Application/src/main/res/layout/fragment_list.xml b/media/MediaBrowserService/Application/src/main/res/layout/fragment_list.xml
new file mode 100644
index 0000000..c169fec
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/layout/fragment_list.xml
@@ -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.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="@dimen/fragment_list_padding">
+
+ <LinearLayout
+ android:id="@+id/controls"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <ImageButton
+ android:id="@+id/skip_previous"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:src="@drawable/ic_skip_previous_white_24dp"
+ android:contentDescription="@string/skip_previous"/>
+
+ <ImageButton
+ android:id="@+id/play_pause"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:src="@drawable/ic_play_arrow_white_24dp"
+ android:contentDescription="@string/play_pause"/>
+
+ <ImageButton
+ android:id="@+id/skip_next"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:src="@drawable/ic_skip_next_white_24dp"
+ android:contentDescription="@string/skip_next"/>
+
+ </LinearLayout>
+
+ <ListView
+ android:id="@+id/list_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ </ListView>
+
+</LinearLayout>
diff --git a/media/MediaBrowserService/Application/src/main/res/layout/media_list_item.xml b/media/MediaBrowserService/Application/src/main/res/layout/media_list_item.xml
new file mode 100644
index 0000000..72c0ccf
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/layout/media_list_item.xml
@@ -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.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:listPreferredItemHeight"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/play_eq"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:contentDescription="@string/play_item"
+ android:src="@drawable/ic_play_arrow_white_24dp"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:mode="twoLine"
+ android:padding="@dimen/list_item_padding"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/margin_text_view"
+ android:layout_marginTop="@dimen/margin_text_view"
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+ <TextView
+ android:id="@+id/description"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/margin_text_view"
+ android:layout_marginTop="@dimen/margin_text_view"
+ android:textAppearance="?android:attr/textAppearanceSmall"/>
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/media/MediaBrowserService/Application/src/main/res/values-v21/styles.xml b/media/MediaBrowserService/Application/src/main/res/values-v21/styles.xml
new file mode 100644
index 0000000..21bb211
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/values-v21/styles.xml
@@ -0,0 +1,33 @@
+<?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="AppBaseTheme" parent="android:Theme.Material">
+ <!-- colorPrimary is used for Notification icon and bottom facet bar icons
+ and overflow actions -->
+ <item name="android:colorPrimary">#ffff5722</item>
+
+ <!-- colorPrimaryDark is used for background -->
+ <item name="android:colorPrimaryDark">#ffbf360c</item>
+
+ <!-- colorAccent is sparingly used for accents, like floating action button highlight,
+ progress on playbar-->
+ <item name="android:colorAccent">#ffff5722</item>
+
+ </style>
+
+</resources>
diff --git a/media/MediaBrowserService/Application/src/main/res/values/dimens.xml b/media/MediaBrowserService/Application/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..e57a8c9
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/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="fragment_list_padding">16dp</dimen>
+ <dimen name="list_item_padding">4dp</dimen>
+ <dimen name="margin_text_view">6dp</dimen>
+</resources>
diff --git a/media/MediaBrowserService/Application/src/main/res/values/strings.xml b/media/MediaBrowserService/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..8c88fe3
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/values/strings.xml
@@ -0,0 +1,33 @@
+<?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>
+
+ <string name="app_name">MediaBrowserService Sample</string>
+ <string name="favorite">Favorite</string>
+ <string name="error_no_metadata">Unable to retrieve metadata.</string>
+ <string name="browse_genres">Genres</string>
+ <string name="browse_genre_subtitle">Songs by genre</string>
+ <string name="browse_musics_by_genre_subtitle">%1$s songs</string>
+ <string name="random_queue_title">Random music</string>
+ <string name="error_cannot_skip">Cannot skip</string>
+ <string name="error_loading_media">Error Loading Media</string>
+ <string name="play_item">Play item</string>
+ <string name="skip_previous">Skip to previous</string>
+ <string name="play_pause">play or pause</string>
+ <string name="skip_next">Skip to next</string>
+
+</resources>
diff --git a/media/MediaBrowserService/Application/src/main/res/values/strings_notifications.xml b/media/MediaBrowserService/Application/src/main/res/values/strings_notifications.xml
new file mode 100644
index 0000000..f406ba6
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/values/strings_notifications.xml
@@ -0,0 +1,24 @@
+<?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>
+
+ <string name="label_pause">Pause</string>
+ <string name="label_play">Play</string>
+ <string name="label_previous">Previous</string>
+ <string name="label_next">Next</string>
+ <string name="error_empty_metadata">Empty metadata!</string>
+</resources>
diff --git a/media/MediaBrowserService/Application/src/main/res/values/styles.xml b/media/MediaBrowserService/Application/src/main/res/values/styles.xml
new file mode 100644
index 0000000..3be59c1
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/values/styles.xml
@@ -0,0 +1,26 @@
+<?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="AppTheme" parent="AppBaseTheme">
+ </style>
+
+ <style name="AppBaseTheme" parent="android:Theme.Light">
+ </style>
+
+</resources>
\ No newline at end of file
diff --git a/media/MediaBrowserService/Application/src/main/res/xml/automotive_app_desc.xml b/media/MediaBrowserService/Application/src/main/res/xml/automotive_app_desc.xml
new file mode 100644
index 0000000..a84750b
--- /dev/null
+++ b/media/MediaBrowserService/Application/src/main/res/xml/automotive_app_desc.xml
@@ -0,0 +1,19 @@
+<?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.
+ -->
+<automotiveApp>
+ <uses name="media"/>
+</automotiveApp>
diff --git a/ui/notifications/BasicNotifications/CONTRIB.md b/media/MediaBrowserService/CONTRIB.md
similarity index 100%
copy from ui/notifications/BasicNotifications/CONTRIB.md
copy to media/MediaBrowserService/CONTRIB.md
diff --git a/ui/notifications/BasicNotifications/LICENSE b/media/MediaBrowserService/LICENSE
similarity index 100%
copy from ui/notifications/BasicNotifications/LICENSE
copy to media/MediaBrowserService/LICENSE
diff --git a/media/MediaBrowserService/README.md b/media/MediaBrowserService/README.md
new file mode 100644
index 0000000..b61692e
--- /dev/null
+++ b/media/MediaBrowserService/README.md
@@ -0,0 +1,123 @@
+Android MediaBrowserService Sample
+==============================
+
+This sample shows how to implement an audio media app that provides
+media library metadata and playback controls through a standard
+service. This sample is compatible with Android Auto.
+
+Introduction
+------------
+
+This sample shows how to implement an audio media app that provides
+media library metadata and playback controls through a standard
+service. It exposes a simple music library through the new
+MediaBrowserService and provides MediaSession callbacks. This allows
+it to be used in Android Auto, for example.
+When not connected to a car, the app has a very simple UI that browses
+the media library and provides simple playback controls. When
+connected to Android Auto, the same service provides data and callback
+to the Android Auto UI in the same manner as it provides them to the
+local UI.
+
+To implement a MediaBrowserService, you need to:
+
+- extend android.service.media.MediaBrowserService, implementing the media
+ browsing related methods onGetRoot and onLoadChildren;
+
+- in onCreate, start a new MediaSession and call super.setSessionToken() with
+ this MediaSession's token;
+
+- set a MediaSession.Callback class on the MediaSession. The callback class
+ will receive all the user's actions, like play, pause, etc;
+
+- handle all the actual music playing using any method your app prefers
+ (for example, the Android MediaPlayer class)
+
+- whenever it changes, update info about the playing item and the playing
+ queue using MediaSession corresponding methods (setMetadata,
+ setPlaybackState, setQueue, setQueueTitle, etc)
+
+- handle AudioManager focus change events and react appropriately
+ (e.g. pause when audio focus is lost)
+
+
+To make it compatible with Android Auto, you also need to:
+
+- declare a meta-data tag in AndroidManifest.xml linking to a xml resource
+ with a automotiveApp root element. For a media app, this must include
+ an <uses name="media"/> element as a child.
+
+ For example, in AndroidManifest.xml:
+```
+ <meta-data android:name="com.google.android.gms.car.application"
+ android:resource="@xml/automotive_app_desc"/>
+```
+
+ And in res/values/automotive\_app\_desc.xml:
+```
+ <?xml version="1.0" encoding="utf-8"?>
+ <automotiveApp>
+ <uses name="media"/>
+ </automotiveApp>
+```
+
+- declare and export the service in AndroidManifest:
+```
+ <service
+ android:name=".service.MusicService"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.media.browse.MediaBrowserService" />
+ </intent-filter>
+ </service>
+```
+
+
+Pre-requisites
+--------------
+
+- Android SDK v21
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Screenshots
+-----------
+
+<!-- Update these to point to screenshots. Add more as needed. -->
+ 
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-MediaBrowserService
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2014 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements. See the NOTICE file distributed with this work for
+additional information regarding copyright ownership. The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/media/MediaBrowserService/build.gradle b/media/MediaBrowserService/build.gradle
new file mode 100644
index 0000000..2b8d1ef
--- /dev/null
+++ b/media/MediaBrowserService/build.gradle
@@ -0,0 +1,11 @@
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../build"
+ pathToSamplesCommon "../../common"
+}
+apply from: "../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/media/MediaBrowserService/buildSrc/build.gradle b/media/MediaBrowserService/buildSrc/build.gradle
new file mode 100644
index 0000000..8c294c2
--- /dev/null
+++ b/media/MediaBrowserService/buildSrc/build.gradle
@@ -0,0 +1,15 @@
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile 'org.freemarker:freemarker:2.3.20'
+}
+
+sourceSets {
+ main {
+ groovy {
+ srcDir new File(rootDir, "../../../../../build/buildSrc/src/main/groovy")
+ }
+ }
+}
+
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/media/MediaBrowserService/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
copy to media/MediaBrowserService/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties b/media/MediaBrowserService/gradle/wrapper/gradle-wrapper.properties
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties
copy to media/MediaBrowserService/gradle/wrapper/gradle-wrapper.properties
diff --git a/ui/notifications/BasicNotifications/gradlew b/media/MediaBrowserService/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to media/MediaBrowserService/gradlew
diff --git a/ui/notifications/BasicNotifications/gradlew.bat b/media/MediaBrowserService/gradlew.bat
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew.bat
copy to media/MediaBrowserService/gradlew.bat
diff --git a/media/MediaBrowserService/packaging.yaml b/media/MediaBrowserService/packaging.yaml
new file mode 100644
index 0000000..bcd9ac5
--- /dev/null
+++ b/media/MediaBrowserService/packaging.yaml
@@ -0,0 +1,15 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+
+status: PUBLISHED
+technologies: [Android]
+categories: [None]
+languages: [Java]
+solutions: [Mobile]
+github: googlesamples/android-MediaBrowserService
+level: BEGINNER
+icon: MediaBrowserServiceSample/src/main/res/drawable-xxhdpi/ic_launcher.png
+license: apache2-android
diff --git a/media/MediaBrowserService/settings.gradle b/media/MediaBrowserService/settings.gradle
new file mode 100644
index 0000000..7f11c5f
--- /dev/null
+++ b/media/MediaBrowserService/settings.gradle
@@ -0,0 +1,2 @@
+include 'Application'
+
diff --git a/media/MediaBrowserService/template-params.xml b/media/MediaBrowserService/template-params.xml
new file mode 100644
index 0000000..c129f6a
--- /dev/null
+++ b/media/MediaBrowserService/template-params.xml
@@ -0,0 +1,36 @@
+<?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.
+-->
+<sample>
+ <name>MediaBrowserService</name>
+ <group>Media</group>
+ <package>com.example.android.mediabrowserservice</package>
+
+ <minSdk>21</minSdk>
+
+ <strings>
+ <intro>
+ <![CDATA[
+ This sample shows how to implement an audio media app that provides
+ media library metadata and playback controls through a standard
+ service.
+ ]]>
+ </intro>
+ </strings>
+
+ <!-- The basic templates have already been enabled. Uncomment more as desired. -->
+ <template src="basebuild" />
+</sample>
diff --git a/media/MediaEffects/MediaEffectsSample/.gitignore b/media/MediaEffects/Application/.gitignore
similarity index 100%
rename from media/MediaEffects/MediaEffectsSample/.gitignore
rename to media/MediaEffects/Application/.gitignore
diff --git a/media/MediaEffects/Application/README-fragmentview.txt b/media/MediaEffects/Application/README-fragmentview.txt
new file mode 100644
index 0000000..38d903f
--- /dev/null
+++ b/media/MediaEffects/Application/README-fragmentview.txt
@@ -0,0 +1,37 @@
+<!--
+ 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.
+-->
+
+Steps to implement FragmentView template:
+-in template-params.xml.ftl:
+ -add the following line to common imports
+ <common src="activities"/>
+
+-Add a Fragment to show behavior. In your MainActivity.java class, it will reference a Fragment
+ called (yourProjectName)Fragment.java. Create that file in your project, using the "main" source
+ folder instead of "common" or "templates".
+ For instance, if your package name is com.example.foo, create the file
+ src/main/java/com/example/foo/FooFragment.java
+
+
+-Within this fragment, make sure that the onCreate method has the line
+ "setHasOptionsMenu(true);", to enable the fragment to handle menu events.
+
+-In order to override menu events, override onOptionsItemSelected.
+
+-refer to sampleSamples/fragmentViewSample for a reference implementation of a
+project built on this template.
+
+
diff --git a/media/MediaEffects/MediaEffectsSample/proguard-project.txt b/media/MediaEffects/Application/proguard-project.txt
similarity index 100%
rename from media/MediaEffects/MediaEffectsSample/proguard-project.txt
rename to media/MediaEffects/Application/proguard-project.txt
diff --git a/media/MediaEffects/Application/src/main/AndroidManifest.xml b/media/MediaEffects/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..556f3c1
--- /dev/null
+++ b/media/MediaEffects/Application/src/main/AndroidManifest.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.
+-->
+
+<manifest
+ package="com.example.android.mediaeffects"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ 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>
+
+ </application>
+
+</manifest>
diff --git a/media/MediaEffects/MediaEffectsSample/src/main/java/com/example/android/mediaeffects/GLToolbox.java b/media/MediaEffects/Application/src/main/java/com/example/android/mediaeffects/GLToolbox.java
similarity index 100%
rename from media/MediaEffects/MediaEffectsSample/src/main/java/com/example/android/mediaeffects/GLToolbox.java
rename to media/MediaEffects/Application/src/main/java/com/example/android/mediaeffects/GLToolbox.java
diff --git a/media/MediaEffects/MediaEffectsSample/src/main/java/com/example/android/mediaeffects/MediaEffectsFragment.java b/media/MediaEffects/Application/src/main/java/com/example/android/mediaeffects/MediaEffectsFragment.java
similarity index 100%
rename from media/MediaEffects/MediaEffectsSample/src/main/java/com/example/android/mediaeffects/MediaEffectsFragment.java
rename to media/MediaEffects/Application/src/main/java/com/example/android/mediaeffects/MediaEffectsFragment.java
diff --git a/media/MediaEffects/MediaEffectsSample/src/main/java/com/example/android/mediaeffects/TextureRenderer.java b/media/MediaEffects/Application/src/main/java/com/example/android/mediaeffects/TextureRenderer.java
similarity index 100%
rename from media/MediaEffects/MediaEffectsSample/src/main/java/com/example/android/mediaeffects/TextureRenderer.java
rename to media/MediaEffects/Application/src/main/java/com/example/android/mediaeffects/TextureRenderer.java
diff --git a/media/MediaEffects/MediaEffectsSample/src/main/res/drawable-hdpi/ic_launcher.png b/media/MediaEffects/Application/src/main/res/drawable-hdpi/ic_launcher.png
similarity index 100%
rename from media/MediaEffects/MediaEffectsSample/src/main/res/drawable-hdpi/ic_launcher.png
rename to media/MediaEffects/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/media/MediaEffects/MediaEffectsSample/src/main/res/drawable-mdpi/ic_launcher.png b/media/MediaEffects/Application/src/main/res/drawable-mdpi/ic_launcher.png
similarity index 100%
rename from media/MediaEffects/MediaEffectsSample/src/main/res/drawable-mdpi/ic_launcher.png
rename to media/MediaEffects/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/media/MediaEffects/MediaEffectsSample/src/main/res/drawable-nodpi/puppy.jpg b/media/MediaEffects/Application/src/main/res/drawable-nodpi/puppy.jpg
similarity index 100%
rename from media/MediaEffects/MediaEffectsSample/src/main/res/drawable-nodpi/puppy.jpg
rename to media/MediaEffects/Application/src/main/res/drawable-nodpi/puppy.jpg
Binary files differ
diff --git a/media/MediaEffects/MediaEffectsSample/src/main/res/drawable-xhdpi/ic_launcher.png b/media/MediaEffects/Application/src/main/res/drawable-xhdpi/ic_launcher.png
similarity index 100%
rename from media/MediaEffects/MediaEffectsSample/src/main/res/drawable-xhdpi/ic_launcher.png
rename to media/MediaEffects/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/media/MediaEffects/MediaEffectsSample/src/main/res/drawable-xxhdpi/ic_launcher.png b/media/MediaEffects/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
similarity index 100%
rename from media/MediaEffects/MediaEffectsSample/src/main/res/drawable-xxhdpi/ic_launcher.png
rename to media/MediaEffects/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/media/MediaEffects/MediaEffectsSample/src/main/res/layout/fragment_media_effects.xml b/media/MediaEffects/Application/src/main/res/layout/fragment_media_effects.xml
similarity index 100%
rename from media/MediaEffects/MediaEffectsSample/src/main/res/layout/fragment_media_effects.xml
rename to media/MediaEffects/Application/src/main/res/layout/fragment_media_effects.xml
diff --git a/media/MediaEffects/MediaEffectsSample/src/main/res/menu/media_effects.xml b/media/MediaEffects/Application/src/main/res/menu/media_effects.xml
similarity index 100%
rename from media/MediaEffects/MediaEffectsSample/src/main/res/menu/media_effects.xml
rename to media/MediaEffects/Application/src/main/res/menu/media_effects.xml
diff --git a/media/MediaEffects/MediaEffectsSample/src/main/res/values/strings.xml b/media/MediaEffects/Application/src/main/res/values/strings.xml
similarity index 100%
rename from media/MediaEffects/MediaEffectsSample/src/main/res/values/strings.xml
rename to media/MediaEffects/Application/src/main/res/values/strings.xml
diff --git a/media/MediaEffects/MediaEffectsSample/README-fragmentview.txt b/media/MediaEffects/MediaEffectsSample/README-fragmentview.txt
deleted file mode 100644
index 8853b23..0000000
--- a/media/MediaEffects/MediaEffectsSample/README-fragmentview.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-<!--
- 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.
--->
-
-Steps to implement FragmentView template:
--in template-params.xml.ftl:
- -add the following line to common imports
- <common src="activities"/>
-
--Add a Fragment to show behavior. In your MainActivity.java class, it will reference a Fragment
- called (yourProjectName)Fragment.java. Create that file in your project, using the "main" source
- folder instead of "common" or "templates".
- For instance, if your package name is com.example.foo, create the file
- src/main/java/com/example/foo/FooFragment.java
-
-
--Within this fragment, make sure that the onCreate method has the line
- "setHasOptionsMenu(true);", to enable the fragment to handle menu events.
-
--In order to override menu events, override onOptionsItemSelected.
-
--refer to sampleSamples/fragmentViewSample for a reference implementation of a
-project built on this template.
-
-
diff --git a/media/MediaEffects/MediaEffectsSample/src/main/AndroidManifest.xml b/media/MediaEffects/MediaEffectsSample/src/main/AndroidManifest.xml
deleted file mode 100644
index 6688b4c..0000000
--- a/media/MediaEffects/MediaEffectsSample/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?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.mediaeffects"
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:versionCode="1"
- android:versionName="1.0">
-
- <uses-sdk
- android:minSdkVersion="14"
- android:targetSdkVersion="19"/>
-
- <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>
-
- </application>
-
-</manifest>
diff --git a/media/MediaEffects/settings.gradle b/media/MediaEffects/settings.gradle
index f678548..9464a35 100644
--- a/media/MediaEffects/settings.gradle
+++ b/media/MediaEffects/settings.gradle
@@ -1,4 +1 @@
-
-
-
-include 'MediaEffectsSample'
+include 'Application'
diff --git a/media/MediaRecorder/Application/src/main/AndroidManifest.xml b/media/MediaRecorder/Application/src/main/AndroidManifest.xml
index 32f88f6..539dc2c 100644
--- a/media/MediaRecorder/Application/src/main/AndroidManifest.xml
+++ b/media/MediaRecorder/Application/src/main/AndroidManifest.xml
@@ -22,9 +22,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="14"
- android:targetSdkVersion="17" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- This app records A/V content from camera and stores it to disk -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
diff --git a/media/MediaRouter/Application/src/main/AndroidManifest.xml b/media/MediaRouter/Application/src/main/AndroidManifest.xml
index 0b5bec4..1805749 100644
--- a/media/MediaRouter/Application/src/main/AndroidManifest.xml
+++ b/media/MediaRouter/Application/src/main/AndroidManifest.xml
@@ -28,9 +28,8 @@
remote display using system alert window. -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
- <uses-sdk android:targetSdkVersion="19"
- android:minSdkVersion="7"/>
-
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
<!-- The smallest screen this app works on is a phone. The app will
scale its UI to larger screens but doesn't make good use of them
so allow the compatibility mode button to be shown (mostly because
diff --git a/media/MediaRouter/Application/tests/AndroidManifest.xml b/media/MediaRouter/Application/tests/AndroidManifest.xml
index f60a1d7..0f9258a 100644
--- a/media/MediaRouter/Application/tests/AndroidManifest.xml
+++ b/media/MediaRouter/Application/tests/AndroidManifest.xml
@@ -39,9 +39,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/media/MediaRouter/gradle/wrapper/gradle-wrapper.properties b/media/MediaRouter/gradle/wrapper/gradle-wrapper.properties
index 5de946b..1e61d1f 100644
--- a/media/MediaRouter/gradle/wrapper/gradle-wrapper.properties
+++ b/media/MediaRouter/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-all.zip
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip
diff --git a/media/MediaRouter/template-params.xml b/media/MediaRouter/template-params.xml
index f43a126..d31b69f 100644
--- a/media/MediaRouter/template-params.xml
+++ b/media/MediaRouter/template-params.xml
@@ -19,16 +19,16 @@
<sample>
<name>MediaRouter</name>
- <group>NoGroup</group>
+ <group>Media</group>
<package>com.example.android.mediarouter</package>
<!-- change minSdk if needed-->
- <minSdk>4</minSdk>
+ <minSdk>13</minSdk>
- <dependency>com.android.support:appcompat-v7:+</dependency>
- <dependency>com.android.support:mediarouter-v7:+</dependency>
+ <dependency>com.android.support:appcompat-v7:20.+</dependency>
+ <dependency>com.android.support:mediarouter-v7:20.+</dependency>
<strings>
diff --git a/ui/notifications/BasicNotifications/Application/.gitignore b/notification/BasicNotifications/Application/.gitignore
similarity index 100%
rename from ui/notifications/BasicNotifications/Application/.gitignore
rename to notification/BasicNotifications/Application/.gitignore
diff --git a/ui/notifications/BasicNotifications/Application/proguard-project.txt b/notification/BasicNotifications/Application/proguard-project.txt
similarity index 100%
rename from ui/notifications/BasicNotifications/Application/proguard-project.txt
rename to notification/BasicNotifications/Application/proguard-project.txt
diff --git a/notification/BasicNotifications/Application/src/main/AndroidManifest.xml b/notification/BasicNotifications/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..01f8e3a
--- /dev/null
+++ b/notification/BasicNotifications/Application/src/main/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.basicnotifications"
+ 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>
+ </application>
+
+</manifest>
diff --git a/ui/notifications/BasicNotifications/Application/src/main/java/com/example/android/basicnotifications/MainActivity.java b/notification/BasicNotifications/Application/src/main/java/com/example/android/basicnotifications/MainActivity.java
similarity index 100%
rename from ui/notifications/BasicNotifications/Application/src/main/java/com/example/android/basicnotifications/MainActivity.java
rename to notification/BasicNotifications/Application/src/main/java/com/example/android/basicnotifications/MainActivity.java
diff --git a/ui/notifications/BasicNotifications/Application/src/main/res/drawable-hdpi-v11/ic_stat_notification.png b/notification/BasicNotifications/Application/src/main/res/drawable-hdpi-v11/ic_stat_notification.png
similarity index 100%
rename from ui/notifications/BasicNotifications/Application/src/main/res/drawable-hdpi-v11/ic_stat_notification.png
rename to notification/BasicNotifications/Application/src/main/res/drawable-hdpi-v11/ic_stat_notification.png
Binary files differ
diff --git a/ui/notifications/BasicNotifications/Application/src/main/res/drawable-hdpi-v9/ic_stat_notification.png b/notification/BasicNotifications/Application/src/main/res/drawable-hdpi-v9/ic_stat_notification.png
similarity index 100%
rename from ui/notifications/BasicNotifications/Application/src/main/res/drawable-hdpi-v9/ic_stat_notification.png
rename to notification/BasicNotifications/Application/src/main/res/drawable-hdpi-v9/ic_stat_notification.png
Binary files differ
diff --git a/ui/notifications/BasicNotifications/Application/src/main/res/drawable-hdpi/ic_launcher.png b/notification/BasicNotifications/Application/src/main/res/drawable-hdpi/ic_launcher.png
similarity index 100%
rename from ui/notifications/BasicNotifications/Application/src/main/res/drawable-hdpi/ic_launcher.png
rename to notification/BasicNotifications/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/notifications/BasicNotifications/Application/src/main/res/drawable-hdpi/ic_stat_notification.png b/notification/BasicNotifications/Application/src/main/res/drawable-hdpi/ic_stat_notification.png
similarity index 100%
rename from ui/notifications/BasicNotifications/Application/src/main/res/drawable-hdpi/ic_stat_notification.png
rename to notification/BasicNotifications/Application/src/main/res/drawable-hdpi/ic_stat_notification.png
Binary files differ
diff --git a/ui/notifications/BasicNotifications/Application/src/main/res/drawable-ldpi-v11/ic_stat_notification.png b/notification/BasicNotifications/Application/src/main/res/drawable-ldpi-v11/ic_stat_notification.png
similarity index 100%
rename from ui/notifications/BasicNotifications/Application/src/main/res/drawable-ldpi-v11/ic_stat_notification.png
rename to notification/BasicNotifications/Application/src/main/res/drawable-ldpi-v11/ic_stat_notification.png
Binary files differ
diff --git a/ui/notifications/BasicNotifications/Application/src/main/res/drawable-ldpi-v9/ic_stat_notification.png b/notification/BasicNotifications/Application/src/main/res/drawable-ldpi-v9/ic_stat_notification.png
similarity index 100%
rename from ui/notifications/BasicNotifications/Application/src/main/res/drawable-ldpi-v9/ic_stat_notification.png
rename to notification/BasicNotifications/Application/src/main/res/drawable-ldpi-v9/ic_stat_notification.png
Binary files differ
diff --git a/ui/notifications/BasicNotifications/Application/src/main/res/drawable-mdpi-v11/ic_stat_notification.png b/notification/BasicNotifications/Application/src/main/res/drawable-mdpi-v11/ic_stat_notification.png
similarity index 100%
rename from ui/notifications/BasicNotifications/Application/src/main/res/drawable-mdpi-v11/ic_stat_notification.png
rename to notification/BasicNotifications/Application/src/main/res/drawable-mdpi-v11/ic_stat_notification.png
Binary files differ
diff --git a/ui/notifications/BasicNotifications/Application/src/main/res/drawable-mdpi-v9/ic_stat_notification.png b/notification/BasicNotifications/Application/src/main/res/drawable-mdpi-v9/ic_stat_notification.png
similarity index 100%
rename from ui/notifications/BasicNotifications/Application/src/main/res/drawable-mdpi-v9/ic_stat_notification.png
rename to notification/BasicNotifications/Application/src/main/res/drawable-mdpi-v9/ic_stat_notification.png
Binary files differ
diff --git a/ui/notifications/BasicNotifications/Application/src/main/res/drawable-mdpi/ic_launcher.png b/notification/BasicNotifications/Application/src/main/res/drawable-mdpi/ic_launcher.png
similarity index 100%
rename from ui/notifications/BasicNotifications/Application/src/main/res/drawable-mdpi/ic_launcher.png
rename to notification/BasicNotifications/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/notifications/BasicNotifications/Application/src/main/res/drawable-mdpi/ic_stat_notification.png b/notification/BasicNotifications/Application/src/main/res/drawable-mdpi/ic_stat_notification.png
similarity index 100%
rename from ui/notifications/BasicNotifications/Application/src/main/res/drawable-mdpi/ic_stat_notification.png
rename to notification/BasicNotifications/Application/src/main/res/drawable-mdpi/ic_stat_notification.png
Binary files differ
diff --git a/ui/notifications/BasicNotifications/Application/src/main/res/drawable-xhdpi-v11/ic_stat_notification.png b/notification/BasicNotifications/Application/src/main/res/drawable-xhdpi-v11/ic_stat_notification.png
similarity index 100%
rename from ui/notifications/BasicNotifications/Application/src/main/res/drawable-xhdpi-v11/ic_stat_notification.png
rename to notification/BasicNotifications/Application/src/main/res/drawable-xhdpi-v11/ic_stat_notification.png
Binary files differ
diff --git a/ui/notifications/BasicNotifications/Application/src/main/res/drawable-xhdpi-v9/ic_stat_notification.png b/notification/BasicNotifications/Application/src/main/res/drawable-xhdpi-v9/ic_stat_notification.png
similarity index 100%
rename from ui/notifications/BasicNotifications/Application/src/main/res/drawable-xhdpi-v9/ic_stat_notification.png
rename to notification/BasicNotifications/Application/src/main/res/drawable-xhdpi-v9/ic_stat_notification.png
Binary files differ
diff --git a/ui/notifications/BasicNotifications/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/notification/BasicNotifications/Application/src/main/res/drawable-xhdpi/ic_launcher.png
similarity index 100%
rename from ui/notifications/BasicNotifications/Application/src/main/res/drawable-xhdpi/ic_launcher.png
rename to notification/BasicNotifications/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/notifications/BasicNotifications/Application/src/main/res/drawable-xhdpi/ic_stat_notification.png b/notification/BasicNotifications/Application/src/main/res/drawable-xhdpi/ic_stat_notification.png
similarity index 100%
rename from ui/notifications/BasicNotifications/Application/src/main/res/drawable-xhdpi/ic_stat_notification.png
rename to notification/BasicNotifications/Application/src/main/res/drawable-xhdpi/ic_stat_notification.png
Binary files differ
diff --git a/ui/notifications/BasicNotifications/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/notification/BasicNotifications/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
similarity index 100%
rename from ui/notifications/BasicNotifications/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
rename to notification/BasicNotifications/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/notifications/BasicNotifications/Application/src/main/res/layout/sample_layout.xml b/notification/BasicNotifications/Application/src/main/res/layout/sample_layout.xml
similarity index 100%
rename from ui/notifications/BasicNotifications/Application/src/main/res/layout/sample_layout.xml
rename to notification/BasicNotifications/Application/src/main/res/layout/sample_layout.xml
diff --git a/ui/notifications/BasicNotifications/Application/src/main/res/values/strings.xml b/notification/BasicNotifications/Application/src/main/res/values/strings.xml
similarity index 100%
rename from ui/notifications/BasicNotifications/Application/src/main/res/values/strings.xml
rename to notification/BasicNotifications/Application/src/main/res/values/strings.xml
diff --git a/notification/BasicNotifications/Application/tests/AndroidManifest.xml b/notification/BasicNotifications/Application/tests/AndroidManifest.xml
new file mode 100644
index 0000000..5b25bbe
--- /dev/null
+++ b/notification/BasicNotifications/Application/tests/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?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.
+ -->
+<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.basicnotifications.tests"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
+ <!-- We add an application tag here just so that we can indicate that
+ this package needs to link against the android.test library,
+ which is needed when building test cases. -->
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!--
+ Specifies the instrumentation test runner used to run the tests.
+ -->
+ <instrumentation
+ android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.example.android.basicnotifications"
+ android:label="Tests for com.example.android.basicnotifications" />
+
+</manifest>
\ No newline at end of file
diff --git a/ui/notifications/BasicNotifications/Application/tests/src/com/example/android/basicnotifications/tests/SampleTests.java b/notification/BasicNotifications/Application/tests/src/com/example/android/basicnotifications/tests/SampleTests.java
similarity index 100%
rename from ui/notifications/BasicNotifications/Application/tests/src/com/example/android/basicnotifications/tests/SampleTests.java
rename to notification/BasicNotifications/Application/tests/src/com/example/android/basicnotifications/tests/SampleTests.java
diff --git a/ui/notifications/BasicNotifications/CONTRIB.md b/notification/BasicNotifications/CONTRIB.md
similarity index 100%
rename from ui/notifications/BasicNotifications/CONTRIB.md
rename to notification/BasicNotifications/CONTRIB.md
diff --git a/ui/notifications/BasicNotifications/LICENSE b/notification/BasicNotifications/LICENSE
similarity index 100%
rename from ui/notifications/BasicNotifications/LICENSE
rename to notification/BasicNotifications/LICENSE
diff --git a/ui/notifications/BasicNotifications/README.md b/notification/BasicNotifications/README.md
similarity index 100%
rename from ui/notifications/BasicNotifications/README.md
rename to notification/BasicNotifications/README.md
diff --git a/notification/BasicNotifications/build.gradle b/notification/BasicNotifications/build.gradle
new file mode 100644
index 0000000..2b8d1ef
--- /dev/null
+++ b/notification/BasicNotifications/build.gradle
@@ -0,0 +1,11 @@
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../build"
+ pathToSamplesCommon "../../common"
+}
+apply from: "../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/notification/BasicNotifications/buildSrc/build.gradle b/notification/BasicNotifications/buildSrc/build.gradle
new file mode 100644
index 0000000..8c294c2
--- /dev/null
+++ b/notification/BasicNotifications/buildSrc/build.gradle
@@ -0,0 +1,15 @@
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile 'org.freemarker:freemarker:2.3.20'
+}
+
+sourceSets {
+ main {
+ groovy {
+ srcDir new File(rootDir, "../../../../../build/buildSrc/src/main/groovy")
+ }
+ }
+}
+
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/notification/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
rename from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
rename to notification/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties b/notification/BasicNotifications/gradle/wrapper/gradle-wrapper.properties
similarity index 100%
rename from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties
rename to notification/BasicNotifications/gradle/wrapper/gradle-wrapper.properties
diff --git a/ui/notifications/BasicNotifications/gradlew b/notification/BasicNotifications/gradlew
similarity index 100%
rename from ui/notifications/BasicNotifications/gradlew
rename to notification/BasicNotifications/gradlew
diff --git a/ui/notifications/BasicNotifications/gradlew.bat b/notification/BasicNotifications/gradlew.bat
similarity index 100%
rename from ui/notifications/BasicNotifications/gradlew.bat
rename to notification/BasicNotifications/gradlew.bat
diff --git a/ui/notifications/BasicNotifications/packaging.yaml b/notification/BasicNotifications/packaging.yaml
similarity index 100%
rename from ui/notifications/BasicNotifications/packaging.yaml
rename to notification/BasicNotifications/packaging.yaml
diff --git a/ui/notifications/BasicNotifications/settings.gradle b/notification/BasicNotifications/settings.gradle
similarity index 100%
rename from ui/notifications/BasicNotifications/settings.gradle
rename to notification/BasicNotifications/settings.gradle
diff --git a/notification/BasicNotifications/template-params.xml b/notification/BasicNotifications/template-params.xml
new file mode 100644
index 0000000..924a3d4
--- /dev/null
+++ b/notification/BasicNotifications/template-params.xml
@@ -0,0 +1,36 @@
+<?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.
+-->
+
+<sample>
+ <name>BasicNotifications</name>
+ <group>Notification</group>
+ <package>com.example.android.basicnotifications</package>
+ <!-- change minSdk if needed-->
+ <minSdk>8</minSdk>
+
+ <strings>
+ <intro>
+ <![CDATA[
+ This sample demonstrates how to display events in the system\'s notification bar. The
+ NotificationCompat API is used for compatibility with older devices, running Android
+ 2.2 (Froyo) or newer.
+ ]]>
+ </intro>
+ </strings>
+
+ <template src="base"/>
+</sample>
diff --git a/ui/notifications/CustomNotifications/Application/.gitignore b/notification/CustomNotifications/Application/.gitignore
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/.gitignore
rename to notification/CustomNotifications/Application/.gitignore
diff --git a/ui/notifications/CustomNotifications/Application/proguard-project.txt b/notification/CustomNotifications/Application/proguard-project.txt
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/proguard-project.txt
rename to notification/CustomNotifications/Application/proguard-project.txt
diff --git a/notification/CustomNotifications/Application/src/main/AndroidManifest.xml b/notification/CustomNotifications/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..3054ad7
--- /dev/null
+++ b/notification/CustomNotifications/Application/src/main/AndroidManifest.xml
@@ -0,0 +1,43 @@
+<?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.customnotifications"
+ 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="com.example.android.customnotifications.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/ui/notifications/CustomNotifications/Application/src/main/java/com/example/android/customnotifications/MainActivity.java b/notification/CustomNotifications/Application/src/main/java/com/example/android/customnotifications/MainActivity.java
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/java/com/example/android/customnotifications/MainActivity.java
rename to notification/CustomNotifications/Application/src/main/java/com/example/android/customnotifications/MainActivity.java
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/drawable-hdpi-v11/ic_stat_custom.png b/notification/CustomNotifications/Application/src/main/res/drawable-hdpi-v11/ic_stat_custom.png
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/drawable-hdpi-v11/ic_stat_custom.png
rename to notification/CustomNotifications/Application/src/main/res/drawable-hdpi-v11/ic_stat_custom.png
Binary files differ
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/drawable-hdpi-v9/ic_stat_custom.png b/notification/CustomNotifications/Application/src/main/res/drawable-hdpi-v9/ic_stat_custom.png
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/drawable-hdpi-v9/ic_stat_custom.png
rename to notification/CustomNotifications/Application/src/main/res/drawable-hdpi-v9/ic_stat_custom.png
Binary files differ
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/drawable-hdpi/ic_launcher.png b/notification/CustomNotifications/Application/src/main/res/drawable-hdpi/ic_launcher.png
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/drawable-hdpi/ic_launcher.png
rename to notification/CustomNotifications/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/drawable-hdpi/ic_stat_custom.png b/notification/CustomNotifications/Application/src/main/res/drawable-hdpi/ic_stat_custom.png
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/drawable-hdpi/ic_stat_custom.png
rename to notification/CustomNotifications/Application/src/main/res/drawable-hdpi/ic_stat_custom.png
Binary files differ
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/drawable-ldpi-v11/ic_stat_custom.png b/notification/CustomNotifications/Application/src/main/res/drawable-ldpi-v11/ic_stat_custom.png
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/drawable-ldpi-v11/ic_stat_custom.png
rename to notification/CustomNotifications/Application/src/main/res/drawable-ldpi-v11/ic_stat_custom.png
Binary files differ
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/drawable-ldpi-v9/ic_stat_custom.png b/notification/CustomNotifications/Application/src/main/res/drawable-ldpi-v9/ic_stat_custom.png
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/drawable-ldpi-v9/ic_stat_custom.png
rename to notification/CustomNotifications/Application/src/main/res/drawable-ldpi-v9/ic_stat_custom.png
Binary files differ
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/drawable-mdpi-v11/ic_stat_custom.png b/notification/CustomNotifications/Application/src/main/res/drawable-mdpi-v11/ic_stat_custom.png
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/drawable-mdpi-v11/ic_stat_custom.png
rename to notification/CustomNotifications/Application/src/main/res/drawable-mdpi-v11/ic_stat_custom.png
Binary files differ
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/drawable-mdpi-v9/ic_stat_custom.png b/notification/CustomNotifications/Application/src/main/res/drawable-mdpi-v9/ic_stat_custom.png
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/drawable-mdpi-v9/ic_stat_custom.png
rename to notification/CustomNotifications/Application/src/main/res/drawable-mdpi-v9/ic_stat_custom.png
Binary files differ
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/drawable-mdpi/ic_launcher.png b/notification/CustomNotifications/Application/src/main/res/drawable-mdpi/ic_launcher.png
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/drawable-mdpi/ic_launcher.png
rename to notification/CustomNotifications/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/drawable-mdpi/ic_stat_custom.png b/notification/CustomNotifications/Application/src/main/res/drawable-mdpi/ic_stat_custom.png
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/drawable-mdpi/ic_stat_custom.png
rename to notification/CustomNotifications/Application/src/main/res/drawable-mdpi/ic_stat_custom.png
Binary files differ
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/drawable-xhdpi-v11/ic_stat_custom.png b/notification/CustomNotifications/Application/src/main/res/drawable-xhdpi-v11/ic_stat_custom.png
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/drawable-xhdpi-v11/ic_stat_custom.png
rename to notification/CustomNotifications/Application/src/main/res/drawable-xhdpi-v11/ic_stat_custom.png
Binary files differ
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/drawable-xhdpi-v9/ic_stat_custom.png b/notification/CustomNotifications/Application/src/main/res/drawable-xhdpi-v9/ic_stat_custom.png
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/drawable-xhdpi-v9/ic_stat_custom.png
rename to notification/CustomNotifications/Application/src/main/res/drawable-xhdpi-v9/ic_stat_custom.png
Binary files differ
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/notification/CustomNotifications/Application/src/main/res/drawable-xhdpi/ic_launcher.png
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/drawable-xhdpi/ic_launcher.png
rename to notification/CustomNotifications/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/drawable-xhdpi/ic_stat_custom.png b/notification/CustomNotifications/Application/src/main/res/drawable-xhdpi/ic_stat_custom.png
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/drawable-xhdpi/ic_stat_custom.png
rename to notification/CustomNotifications/Application/src/main/res/drawable-xhdpi/ic_stat_custom.png
Binary files differ
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/drawable-xhdpi/robot.png b/notification/CustomNotifications/Application/src/main/res/drawable-xhdpi/robot.png
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/drawable-xhdpi/robot.png
rename to notification/CustomNotifications/Application/src/main/res/drawable-xhdpi/robot.png
Binary files differ
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/drawable-xhdpi/robot_expanded.png b/notification/CustomNotifications/Application/src/main/res/drawable-xhdpi/robot_expanded.png
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/drawable-xhdpi/robot_expanded.png
rename to notification/CustomNotifications/Application/src/main/res/drawable-xhdpi/robot_expanded.png
Binary files differ
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/notification/CustomNotifications/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
rename to notification/CustomNotifications/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/layout/notification.xml b/notification/CustomNotifications/Application/src/main/res/layout/notification.xml
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/layout/notification.xml
rename to notification/CustomNotifications/Application/src/main/res/layout/notification.xml
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/layout/notification_expanded.xml b/notification/CustomNotifications/Application/src/main/res/layout/notification_expanded.xml
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/layout/notification_expanded.xml
rename to notification/CustomNotifications/Application/src/main/res/layout/notification_expanded.xml
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/layout/sample_main.xml b/notification/CustomNotifications/Application/src/main/res/layout/sample_main.xml
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/layout/sample_main.xml
rename to notification/CustomNotifications/Application/src/main/res/layout/sample_main.xml
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/values-sw720dp-land/dimens.xml b/notification/CustomNotifications/Application/src/main/res/values-sw720dp-land/dimens.xml
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/values-sw720dp-land/dimens.xml
rename to notification/CustomNotifications/Application/src/main/res/values-sw720dp-land/dimens.xml
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/values-v9/styles.xml b/notification/CustomNotifications/Application/src/main/res/values-v9/styles.xml
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/values-v9/styles.xml
rename to notification/CustomNotifications/Application/src/main/res/values-v9/styles.xml
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/values/dimens.xml b/notification/CustomNotifications/Application/src/main/res/values/dimens.xml
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/values/dimens.xml
rename to notification/CustomNotifications/Application/src/main/res/values/dimens.xml
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/values/strings.xml b/notification/CustomNotifications/Application/src/main/res/values/strings.xml
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/values/strings.xml
rename to notification/CustomNotifications/Application/src/main/res/values/strings.xml
diff --git a/ui/notifications/CustomNotifications/Application/src/main/res/values/styles.xml b/notification/CustomNotifications/Application/src/main/res/values/styles.xml
similarity index 100%
rename from ui/notifications/CustomNotifications/Application/src/main/res/values/styles.xml
rename to notification/CustomNotifications/Application/src/main/res/values/styles.xml
diff --git a/ui/notifications/CustomNotifications/CONTRIB.md b/notification/CustomNotifications/CONTRIB.md
similarity index 100%
rename from ui/notifications/CustomNotifications/CONTRIB.md
rename to notification/CustomNotifications/CONTRIB.md
diff --git a/ui/notifications/CustomNotifications/LICENSE b/notification/CustomNotifications/LICENSE
similarity index 100%
rename from ui/notifications/CustomNotifications/LICENSE
rename to notification/CustomNotifications/LICENSE
diff --git a/ui/notifications/CustomNotifications/README.md b/notification/CustomNotifications/README.md
similarity index 100%
rename from ui/notifications/CustomNotifications/README.md
rename to notification/CustomNotifications/README.md
diff --git a/notification/CustomNotifications/build.gradle b/notification/CustomNotifications/build.gradle
new file mode 100644
index 0000000..2b8d1ef
--- /dev/null
+++ b/notification/CustomNotifications/build.gradle
@@ -0,0 +1,11 @@
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../build"
+ pathToSamplesCommon "../../common"
+}
+apply from: "../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/notification/CustomNotifications/buildSrc/build.gradle b/notification/CustomNotifications/buildSrc/build.gradle
new file mode 100644
index 0000000..8c294c2
--- /dev/null
+++ b/notification/CustomNotifications/buildSrc/build.gradle
@@ -0,0 +1,15 @@
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile 'org.freemarker:freemarker:2.3.20'
+}
+
+sourceSets {
+ main {
+ groovy {
+ srcDir new File(rootDir, "../../../../../build/buildSrc/src/main/groovy")
+ }
+ }
+}
+
diff --git a/ui/notifications/CustomNotifications/gradle/wrapper/gradle-wrapper.jar b/notification/CustomNotifications/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
rename from ui/notifications/CustomNotifications/gradle/wrapper/gradle-wrapper.jar
rename to notification/CustomNotifications/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/notifications/CustomNotifications/gradle/wrapper/gradle-wrapper.properties b/notification/CustomNotifications/gradle/wrapper/gradle-wrapper.properties
similarity index 100%
rename from ui/notifications/CustomNotifications/gradle/wrapper/gradle-wrapper.properties
rename to notification/CustomNotifications/gradle/wrapper/gradle-wrapper.properties
diff --git a/ui/notifications/CustomNotifications/gradlew b/notification/CustomNotifications/gradlew
similarity index 100%
rename from ui/notifications/CustomNotifications/gradlew
rename to notification/CustomNotifications/gradlew
diff --git a/ui/notifications/CustomNotifications/gradlew.bat b/notification/CustomNotifications/gradlew.bat
similarity index 100%
rename from ui/notifications/CustomNotifications/gradlew.bat
rename to notification/CustomNotifications/gradlew.bat
diff --git a/ui/notifications/CustomNotifications/packaging.yaml b/notification/CustomNotifications/packaging.yaml
similarity index 100%
rename from ui/notifications/CustomNotifications/packaging.yaml
rename to notification/CustomNotifications/packaging.yaml
diff --git a/ui/notifications/CustomNotifications/settings.gradle b/notification/CustomNotifications/settings.gradle
similarity index 100%
rename from ui/notifications/CustomNotifications/settings.gradle
rename to notification/CustomNotifications/settings.gradle
diff --git a/notification/CustomNotifications/template-params.xml b/notification/CustomNotifications/template-params.xml
new file mode 100644
index 0000000..1ded0d1
--- /dev/null
+++ b/notification/CustomNotifications/template-params.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.
+-->
+<sample>
+ <name>CustomNotifications</name>
+ <group>Notification</group>
+ <package>com.example.android.customnotifications</package>
+
+ <!-- change minSdk if needed-->
+ <minSdk>4</minSdk>
+
+ <strings>
+ <intro>
+ <![CDATA[
+ This sample demonstrates notifications with custom content views.
+ ]]>
+ </intro>
+ </strings>
+
+ <template src="base"/>
+
+</sample>
diff --git a/ui/notifications/BasicNotifications/Application/.gitignore b/notification/LNotifications/Application/.gitignore
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/.gitignore
copy to notification/LNotifications/Application/.gitignore
diff --git a/ui/notifications/BasicNotifications/Application/proguard-project.txt b/notification/LNotifications/Application/proguard-project.txt
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/proguard-project.txt
copy to notification/LNotifications/Application/proguard-project.txt
diff --git a/notification/LNotifications/Application/src/main/AndroidManifest.xml b/notification/LNotifications/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..816d78f
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/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/notification/LNotifications/Application/src/main/java/com/example/android/lnotifications/HeadsUpNotificationFragment.java b/notification/LNotifications/Application/src/main/java/com/example/android/lnotifications/HeadsUpNotificationFragment.java
new file mode 100644
index 0000000..d304cf4
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/java/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/notification/LNotifications/Application/src/main/java/com/example/android/lnotifications/LNotificationActivity.java b/notification/LNotifications/Application/src/main/java/com/example/android/lnotifications/LNotificationActivity.java
new file mode 100644
index 0000000..fbc3e62
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/java/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/notification/LNotifications/Application/src/main/java/com/example/android/lnotifications/OtherMetadataFragment.java b/notification/LNotifications/Application/src/main/java/com/example/android/lnotifications/OtherMetadataFragment.java
new file mode 100644
index 0000000..51616e7
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/java/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/notification/LNotifications/Application/src/main/java/com/example/android/lnotifications/VisibilityMetadataFragment.java b/notification/LNotifications/Application/src/main/java/com/example/android/lnotifications/VisibilityMetadataFragment.java
new file mode 100644
index 0000000..616632b
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/java/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/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_contact_picture.png b/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_contact_picture.png
new file mode 100644
index 0000000..00d0ec4
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_contact_picture.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_launcher.png b/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..015d248
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_launcher_notification.png b/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_launcher_notification.png
new file mode 100644
index 0000000..4b058c1
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_launcher_notification.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_private.png b/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_private.png
new file mode 100644
index 0000000..663f93e
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_private.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_private_notification.png b/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_private_notification.png
new file mode 100644
index 0000000..dbf5139
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_private_notification.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_public.png b/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_public.png
new file mode 100644
index 0000000..033281d
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_public.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_public_notification.png b/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_public_notification.png
new file mode 100644
index 0000000..fe1ee81
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_public_notification.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_secret.png b/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_secret.png
new file mode 100644
index 0000000..a22dbdf
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_secret.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_secret_notification.png b/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_secret_notification.png
new file mode 100644
index 0000000..5776624
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-hdpi/ic_secret_notification.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_contact_picture.png b/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_contact_picture.png
new file mode 100644
index 0000000..771cb6b
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_contact_picture.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_launcher.png b/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..605a256
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_launcher_notification.png b/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_launcher_notification.png
new file mode 100644
index 0000000..72cd1b3
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_launcher_notification.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_private.png b/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_private.png
new file mode 100644
index 0000000..2556153
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_private.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_private_notification.png b/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_private_notification.png
new file mode 100644
index 0000000..df93964
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_private_notification.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_public.png b/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_public.png
new file mode 100644
index 0000000..ff0c653
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_public.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_public_notification.png b/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_public_notification.png
new file mode 100644
index 0000000..7c69019
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_public_notification.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_secret.png b/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_secret.png
new file mode 100644
index 0000000..2843164
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_secret.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_secret_notification.png b/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_secret_notification.png
new file mode 100644
index 0000000..652e8b0
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-mdpi/ic_secret_notification.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_contact_picture.png b/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_contact_picture.png
new file mode 100644
index 0000000..bdba57b
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_contact_picture.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..c08bafa
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_launcher_notification.png b/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_launcher_notification.png
new file mode 100644
index 0000000..9a42c7a
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_launcher_notification.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_private.png b/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_private.png
new file mode 100644
index 0000000..823d942
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_private.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_private_notification.png b/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_private_notification.png
new file mode 100644
index 0000000..497a1ac
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_private_notification.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_public.png b/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_public.png
new file mode 100644
index 0000000..93b89ff
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_public.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_public_notification.png b/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_public_notification.png
new file mode 100644
index 0000000..1d6f1f1
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_public_notification.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_secret.png b/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_secret.png
new file mode 100644
index 0000000..5124eee
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_secret.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_secret_notification.png b/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_secret_notification.png
new file mode 100644
index 0000000..8388dd5
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-xhdpi/ic_secret_notification.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_contact_picture.png b/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_contact_picture.png
new file mode 100644
index 0000000..b36ec17
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_contact_picture.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..1224b39
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_launcher_notification.png b/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_launcher_notification.png
new file mode 100644
index 0000000..e25fff1
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_launcher_notification.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_private.png b/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_private.png
new file mode 100644
index 0000000..4e4d3d6
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_private.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_private_notification.png b/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_private_notification.png
new file mode 100644
index 0000000..dd5de27
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_private_notification.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_public.png b/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_public.png
new file mode 100644
index 0000000..6aede4e
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_public.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_public_notification.png b/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_public_notification.png
new file mode 100644
index 0000000..9b8c59f
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_public_notification.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_secret.png b/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_secret.png
new file mode 100644
index 0000000..d1e126c
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_secret.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_secret_notification.png b/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_secret_notification.png
new file mode 100644
index 0000000..be59c8f
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/res/drawable-xxhdpi/ic_secret_notification.png
Binary files differ
diff --git a/notification/LNotifications/Application/src/main/res/layout/activity_notification.xml b/notification/LNotifications/Application/src/main/res/layout/activity_notification.xml
new file mode 100644
index 0000000..cd0cd68
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/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/notification/LNotifications/Application/src/main/res/layout/contact_entry.xml b/notification/LNotifications/Application/src/main/res/layout/contact_entry.xml
new file mode 100644
index 0000000..90ab4b8
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/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/notification/LNotifications/Application/src/main/res/layout/fragment_heads_up_notification.xml b/notification/LNotifications/Application/src/main/res/layout/fragment_heads_up_notification.xml
new file mode 100644
index 0000000..bbcb84b
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/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/notification/LNotifications/Application/src/main/res/layout/fragment_other_metadata.xml b/notification/LNotifications/Application/src/main/res/layout/fragment_other_metadata.xml
new file mode 100644
index 0000000..5222302
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/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/notification/LNotifications/Application/src/main/res/layout/fragment_visibility_metadata_notification.xml b/notification/LNotifications/Application/src/main/res/layout/fragment_visibility_metadata_notification.xml
new file mode 100644
index 0000000..2a7bbca
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/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/notification/LNotifications/Application/src/main/res/values/colors.xml b/notification/LNotifications/Application/src/main/res/values/colors.xml
new file mode 100644
index 0000000..31d81ee
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/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/notification/LNotifications/Application/src/main/res/values/dimens.xml b/notification/LNotifications/Application/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..a776bac
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/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/notification/LNotifications/Application/src/main/res/values/strings.xml b/notification/LNotifications/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..e6cb124
--- /dev/null
+++ b/notification/LNotifications/Application/src/main/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/notification/LNotifications/Application/tests/AndroidManifest.xml b/notification/LNotifications/Application/tests/AndroidManifest.xml
new file mode 100644
index 0000000..46a65af
--- /dev/null
+++ b/notification/LNotifications/Application/tests/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<!--
+ 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 name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest
+ package="com.example.android.lnotifications.tests"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
+ <!-- We add an application tag here just so that we can indicate that
+ this package needs to link against the android.test library,
+ which is needed when building test cases. -->
+ <application>
+ <uses-library android:name="android.test.runner"/>
+ </application>
+
+ <!--
+ Specifies the instrumentation test runner used to run the tests.
+ -->
+ <instrumentation
+ android:name="android.test.InstrumentationTestRunner"
+ android:label="Tests for L notifications sample"
+ android:targetPackage="com.example.android.lnotifications"/>
+
+</manifest>
\ No newline at end of file
diff --git a/notification/LNotifications/Application/tests/src/com/example/android/lnotifications/HeadsUpNotificationFragmentTest.java b/notification/LNotifications/Application/tests/src/com/example/android/lnotifications/HeadsUpNotificationFragmentTest.java
new file mode 100644
index 0000000..1264c16
--- /dev/null
+++ b/notification/LNotifications/Application/tests/src/com/example/android/lnotifications/HeadsUpNotificationFragmentTest.java
@@ -0,0 +1,51 @@
+package com.example.android.lnotifications;
+
+import android.app.Notification;
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+ * Unit tests for {@link HeadsUpNotificationFragment}.
+ */
+public class HeadsUpNotificationFragmentTest extends
+ ActivityInstrumentationTestCase2<LNotificationActivity> {
+
+ private LNotificationActivity mActivity;
+ private HeadsUpNotificationFragment mFragment;
+
+ public HeadsUpNotificationFragmentTest() {
+ super(LNotificationActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mActivity = getActivity();
+ // The first tab should be {@link HeadsUpNotificationFragment}, that is tested in the
+ // {@link LNotificationActivityTest}.
+ mActivity.getActionBar().setSelectedNavigationItem(0);
+ getInstrumentation().waitForIdleSync();
+ mFragment = (HeadsUpNotificationFragment) mActivity.getFragmentManager()
+ .findFragmentById(R.id.container);
+ }
+
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mFragment);
+ assertNotNull(mActivity.findViewById(R.id.heads_up_notification_description));
+ assertNotNull(mActivity.findViewById(R.id.show_notification_button));
+ assertNotNull(mActivity.findViewById(R.id.use_heads_up_checkbox));
+ }
+
+ public void testCreateNotification_verifyFullScreenIntentIsNotNull() {
+ Notification notification = mFragment.createNotification(true);
+ assertNotNull(notification.fullScreenIntent);
+ }
+
+ public void testCreateNotification_verifyFullScreenIntentIsNull() {
+ Notification notification = mFragment.createNotification(false);
+ assertNull(notification.fullScreenIntent);
+ }
+
+ // If Mockito can be used, mock the NotificationManager and tests Notifications are actually
+ // created.
+}
diff --git a/notification/LNotifications/Application/tests/src/com/example/android/lnotifications/LNotificationActivityTest.java b/notification/LNotifications/Application/tests/src/com/example/android/lnotifications/LNotificationActivityTest.java
new file mode 100644
index 0000000..061f9e8
--- /dev/null
+++ b/notification/LNotifications/Application/tests/src/com/example/android/lnotifications/LNotificationActivityTest.java
@@ -0,0 +1,49 @@
+package com.example.android.lnotifications;
+
+import android.app.Fragment;
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+ * Unit tests for {@link LNotificationActivity}.
+ */
+public class LNotificationActivityTest extends
+ ActivityInstrumentationTestCase2<LNotificationActivity> {
+
+ private LNotificationActivity mActivity;
+
+ public LNotificationActivityTest() {
+ super(LNotificationActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mActivity = getActivity();
+ }
+
+ public void testPreconditions() {
+ assertNotNull(String.format("%s is null", LNotificationActivity.class.getSimpleName()),
+ mActivity);
+ }
+
+ public void testFirstTabInActionBarIsHeadsUpNotificationFragment() {
+ mActivity.getActionBar().setSelectedNavigationItem(0);
+ getInstrumentation().waitForIdleSync();
+ Fragment fragment = mActivity.getFragmentManager().findFragmentById(R.id.container);
+ assertTrue(fragment instanceof HeadsUpNotificationFragment);
+ }
+
+ public void testSecondtabInActionBarIsVisibilityMetadataFragment() {
+ mActivity.getActionBar().setSelectedNavigationItem(1);
+ getInstrumentation().waitForIdleSync();
+ Fragment fragment = mActivity.getFragmentManager().findFragmentById(R.id.container);
+ assertTrue(fragment instanceof VisibilityMetadataFragment);
+ }
+
+ public void testThirdtabInActionBarIsOtherMetadataFragment() {
+ mActivity.getActionBar().setSelectedNavigationItem(2);
+ getInstrumentation().waitForIdleSync();
+ Fragment fragment = mActivity.getFragmentManager().findFragmentById(R.id.container);
+ assertTrue(fragment instanceof OtherMetadataFragment);
+ }
+}
diff --git a/notification/LNotifications/Application/tests/src/com/example/android/lnotifications/OtherMetadataFragmentTest.java b/notification/LNotifications/Application/tests/src/com/example/android/lnotifications/OtherMetadataFragmentTest.java
new file mode 100644
index 0000000..11a6c81
--- /dev/null
+++ b/notification/LNotifications/Application/tests/src/com/example/android/lnotifications/OtherMetadataFragmentTest.java
@@ -0,0 +1,84 @@
+package com.example.android.lnotifications;
+
+import android.app.Activity;
+import android.app.Notification;
+import android.content.Intent;
+import android.net.Uri;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+
+/**
+ * Unit tests for {@link OtherMetadataFragment}.
+ */
+public class OtherMetadataFragmentTest extends
+ ActivityInstrumentationTestCase2<LNotificationActivity> {
+
+ private LNotificationActivity mActivity;
+ private OtherMetadataFragment mFragment;
+
+ public OtherMetadataFragmentTest() {
+ super(LNotificationActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mActivity = getActivity();
+ // The third tab should be {@link OtherMetadataFragment}, that is tested in the
+ // {@link LNotificationActivityTest}.
+ mActivity.getActionBar().setSelectedNavigationItem(2);
+ getInstrumentation().waitForIdleSync();
+ mFragment = (OtherMetadataFragment) mActivity.getFragmentManager()
+ .findFragmentById(R.id.container);
+ }
+
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mFragment);
+ assertNull(mFragment.mContactUri);
+ assertNotNull(mActivity.findViewById(R.id.attach_person));
+ assertNotNull(mActivity.findViewById(R.id.category_spinner));
+ assertNotNull(mActivity.findViewById(R.id.priority_spinner));
+ assertNotNull(mActivity.findViewById(R.id.show_notification_button));
+ }
+
+ public void testCreateNotification_verifyPriorityAndCategoryWithoutPerson() {
+ Notification notification = mFragment.createNotification(OtherMetadataFragment.Priority
+ .HIGH, OtherMetadataFragment.Category.CALL, null);
+ assertEquals(Notification.PRIORITY_HIGH, notification.priority);
+ assertEquals(Notification.CATEGORY_CALL, notification.category);
+ }
+
+ public void testCreateNotification_verifyPriorityAndCategoryWithPerson() {
+ String tel = "81 (90) 555-1212";
+ Uri dummyContactUri = Uri.fromParts("tel", tel, null);
+ Notification notification = mFragment.createNotification(OtherMetadataFragment.Priority
+ .DEFAULT, OtherMetadataFragment.Category.MESSAGE, dummyContactUri);
+ assertEquals(Notification.PRIORITY_DEFAULT, notification.priority);
+ assertEquals(Notification.CATEGORY_MESSAGE, notification.category);
+
+ String[] peopleArray = notification.extras.getStringArray(Notification.EXTRA_PEOPLE);
+ assertNotNull(peopleArray);
+ assertEquals(1, peopleArray.length);
+ }
+
+ public void testActionPickResultUpdatesContactInstanceField() {
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ String tel = "81 (90) 555-1212";
+ Uri dummyContactUri = Uri.fromParts("tel", tel, null);
+ Intent intent = new Intent(Intent.ACTION_PICK);
+ intent.setData(dummyContactUri);
+ mFragment.onActivityResult(mFragment.REQUEST_CODE_PICK_CONTACT,
+ Activity.RESULT_OK, intent);
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+ assertNotNull(mFragment.mContactUri);
+ }
+}
diff --git a/notification/LNotifications/Application/tests/src/com/example/android/lnotifications/VisibilityMetadataFragmentTest.java b/notification/LNotifications/Application/tests/src/com/example/android/lnotifications/VisibilityMetadataFragmentTest.java
new file mode 100644
index 0000000..eec62f0
--- /dev/null
+++ b/notification/LNotifications/Application/tests/src/com/example/android/lnotifications/VisibilityMetadataFragmentTest.java
@@ -0,0 +1,66 @@
+package com.example.android.lnotifications;
+
+import android.app.Notification;
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+ * Unit tests for {@link VisibilityMetadataFragment}.
+ */
+public class VisibilityMetadataFragmentTest extends
+ ActivityInstrumentationTestCase2<LNotificationActivity> {
+
+ private LNotificationActivity mActivity;
+ private VisibilityMetadataFragment mFragment;
+
+ public VisibilityMetadataFragmentTest() {
+ super(LNotificationActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mActivity = getActivity();
+ // The second tab should be {@link VisibilityMetadataFragment}, that is tested in the
+ // {@link LNotificationActivityTest}.
+ mActivity.getActionBar().setSelectedNavigationItem(1);
+ getInstrumentation().waitForIdleSync();
+ mFragment = (VisibilityMetadataFragment) mActivity.getFragmentManager()
+ .findFragmentById(R.id.container);
+ }
+
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mFragment);
+ assertNotNull(mActivity.findViewById(R.id.visibility_metadata_notification_description));
+ assertNotNull(mActivity.findViewById(R.id.visibility_radio_group));
+ assertNotNull(mActivity.findViewById(R.id.visibility_private_radio_button));
+ assertNotNull(mActivity.findViewById(R.id.visibility_secret_radio_button));
+ assertNotNull(mActivity.findViewById(R.id.visibility_public_radio_button));
+ assertNotNull(mActivity.findViewById(R.id.show_notification_button));
+ }
+
+ public void testCreateNotification_publicVisibility() {
+ Notification notification = mFragment.createNotification(VisibilityMetadataFragment
+ .NotificationVisibility.PUBLIC);
+
+ assertEquals(Notification.VISIBILITY_PUBLIC, notification.visibility);
+ assertEquals(R.drawable.ic_public_notification, notification.icon);
+ }
+
+ public void testCreateNotification_privateVisibility() {
+ Notification notification = mFragment.createNotification(VisibilityMetadataFragment
+ .NotificationVisibility.PRIVATE);
+
+ assertEquals(Notification.VISIBILITY_PRIVATE, notification.visibility);
+ assertEquals(R.drawable.ic_private_notification, notification.icon);
+ }
+
+ public void testCreateNotification_secretVisibility() {
+ Notification notification = mFragment.createNotification(VisibilityMetadataFragment
+ .NotificationVisibility.SECRET);
+
+ assertEquals(Notification.VISIBILITY_SECRET, notification.visibility);
+ assertEquals(R.drawable.ic_secret_notification, notification.icon);
+ }
+}
+
diff --git a/ui/notifications/BasicNotifications/CONTRIB.md b/notification/LNotifications/CONTRIB.md
similarity index 100%
copy from ui/notifications/BasicNotifications/CONTRIB.md
copy to notification/LNotifications/CONTRIB.md
diff --git a/ui/notifications/BasicNotifications/LICENSE b/notification/LNotifications/LICENSE
similarity index 100%
copy from ui/notifications/BasicNotifications/LICENSE
copy to notification/LNotifications/LICENSE
diff --git a/notification/LNotifications/README.md b/notification/LNotifications/README.md
new file mode 100644
index 0000000..56f330b
--- /dev/null
+++ b/notification/LNotifications/README.md
@@ -0,0 +1,51 @@
+Android RecyclerView Sample
+===========================
+
+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).
+
+Pre-requisites
+--------------
+
+- Android SDK (L Developer Preview)
+- Android Build Tools v20
+- Android Support Repository
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-BasicAndroidKeyStore
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2014 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements. See the NOTICE file distributed with this work for
+additional information regarding copyright ownership. The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/notification/LNotifications/build.gradle b/notification/LNotifications/build.gradle
new file mode 100644
index 0000000..2b8d1ef
--- /dev/null
+++ b/notification/LNotifications/build.gradle
@@ -0,0 +1,11 @@
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../build"
+ pathToSamplesCommon "../../common"
+}
+apply from: "../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/notification/LNotifications/buildSrc/build.gradle b/notification/LNotifications/buildSrc/build.gradle
new file mode 100644
index 0000000..8c294c2
--- /dev/null
+++ b/notification/LNotifications/buildSrc/build.gradle
@@ -0,0 +1,15 @@
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile 'org.freemarker:freemarker:2.3.20'
+}
+
+sourceSets {
+ main {
+ groovy {
+ srcDir new File(rootDir, "../../../../../build/buildSrc/src/main/groovy")
+ }
+ }
+}
+
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/notification/LNotifications/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
copy to notification/LNotifications/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/notification/LNotifications/gradle/wrapper/gradle-wrapper.properties b/notification/LNotifications/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..fbe0ffd
--- /dev/null
+++ b/notification/LNotifications/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Aug 06 17:33:35 JST 2014
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-all.zip
diff --git a/ui/notifications/BasicNotifications/gradlew b/notification/LNotifications/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to notification/LNotifications/gradlew
diff --git a/ui/notifications/BasicNotifications/gradlew.bat b/notification/LNotifications/gradlew.bat
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew.bat
copy to notification/LNotifications/gradlew.bat
diff --git a/notification/LNotifications/packaging.yaml b/notification/LNotifications/packaging.yaml
new file mode 100644
index 0000000..23d65ba
--- /dev/null
+++ b/notification/LNotifications/packaging.yaml
@@ -0,0 +1,16 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+status: PUBLISHED
+technologies: [Android]
+categories: [UI]
+languages: [Java]
+solutions: [Mobile]
+github: googlesamples/android-LNotifications
+level: INTERMEDIATE
+icon: LNotificationsSample/src/main/res/drawable-xxhdpi/ic_launcher.png
+doc_refs:
+ - android:preview/notifications.html
+license: apache2
diff --git a/ui/notifications/BasicNotifications/settings.gradle b/notification/LNotifications/settings.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/settings.gradle
copy to notification/LNotifications/settings.gradle
diff --git a/notification/LNotifications/template-params.xml b/notification/LNotifications/template-params.xml
new file mode 100644
index 0000000..6257c81
--- /dev/null
+++ b/notification/LNotifications/template-params.xml
@@ -0,0 +1,38 @@
+<?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.
+-->
+
+<sample>
+ <name>LNotifications Sample</name>
+ <group>Notification</group>
+ <package>com.example.android.lnotifications</package>
+
+ <!-- change minSdk if needed-->
+ <minSdk>21</minSdk>
+
+ <strings>
+ <intro>
+ <![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).
+ ]]>
+ </intro>
+ </strings>
+
+ <template src="base"/>
+
+</sample>
diff --git a/ui/notifications/BasicNotifications/Application/.gitignore b/notification/MessagingService/Application/.gitignore
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/.gitignore
copy to notification/MessagingService/Application/.gitignore
diff --git a/ui/notifications/BasicNotifications/Application/proguard-project.txt b/notification/MessagingService/Application/proguard-project.txt
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/proguard-project.txt
copy to notification/MessagingService/Application/proguard-project.txt
diff --git a/notification/MessagingService/Application/src/androidTest/java/com/example/android/messagingservice/test/SampleTests.java b/notification/MessagingService/Application/src/androidTest/java/com/example/android/messagingservice/test/SampleTests.java
new file mode 100644
index 0000000..79d618b
--- /dev/null
+++ b/notification/MessagingService/Application/src/androidTest/java/com/example/android/messagingservice/test/SampleTests.java
@@ -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.
+*/
+/*
+* 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.messagingservice.test;
+
+import com.example.android.messagingservice.*;
+
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+* Tests for MessagingService sample.
+*/
+public class SampleTests extends ActivityInstrumentationTestCase2<MainActivity> {
+
+ private MainActivity mTestActivity;
+ private MessagingServiceFragment mTestFragment;
+
+ public SampleTests() {
+ super(MainActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // Starts the activity under test using the default Intent with:
+ // action = {@link Intent#ACTION_MAIN}
+ // flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK}
+ // All other fields are null or empty.
+ mTestActivity = getActivity();
+ mTestFragment = (MessagingServiceFragment)
+ mTestActivity.getSupportFragmentManager().getFragments().get(1);
+ }
+
+ /**
+ * Test if the test fixture has been set up correctly.
+ */
+ public void testPreconditions() {
+ //Try to add a message to add context to your assertions. These messages will be shown if
+ //a tests fails and make it easy to understand why a test failed
+ assertNotNull("mTestActivity is null", mTestActivity);
+ assertNotNull("mTestFragment is null", mTestFragment);
+ }
+
+ /**
+ * Add more tests below.
+ */
+
+}
diff --git a/notification/MessagingService/Application/src/main/AndroidManifest.xml b/notification/MessagingService/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..f8a5850
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/AndroidManifest.xml
@@ -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.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.messagingservice">
+
+ <application android:allowBackup="true"
+ android:label="@string/app_name"
+ android:icon="@drawable/ic_launcher"
+ android:theme="@style/AppTheme">
+
+ <meta-data android:name="com.google.android.gms.car.application"
+ android:resource="@xml/automotive_app_desc"/>
+
+ <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>
+
+ <service android:name=".MessagingService">
+ </service>
+
+ <receiver android:name=".MessageReadReceiver">
+ <intent-filter>
+ <action android:name="com.example.android.messagingservice.ACTION_MESSAGE_READ"/>
+ </intent-filter>
+ </receiver>
+
+ <receiver android:name=".MessageReplyReceiver">
+ <intent-filter>
+ <action android:name="com.example.android.messagingservice.ACTION_MESSAGE_REPLY"/>
+ </intent-filter>
+ </receiver>
+ </application>
+</manifest>
diff --git a/notification/MessagingService/Application/src/main/java/com/example/android/messagingservice/Conversations.java b/notification/MessagingService/Application/src/main/java/com/example/android/messagingservice/Conversations.java
new file mode 100644
index 0000000..210e061
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/java/com/example/android/messagingservice/Conversations.java
@@ -0,0 +1,126 @@
+/*
+ * 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.messagingservice;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * A simple class that denotes unread conversations and messages. In a real world application,
+ * this would be replaced by a content provider that actually gets the unread messages to be
+ * shown to the user.
+ */
+public class Conversations {
+
+ /**
+ * Set of strings used as messages by the sample.
+ */
+ private static final String[] MESSAGES = new String[]{
+ "Are you at home?",
+ "Can you give me a call?",
+ "Hey yt?",
+ "Don't forget to get some milk on your way back home",
+ "Is that project done?",
+ "Did you finish the Messaging app yet?"
+ };
+
+ /**
+ * Senders of the said messages.
+ */
+ private static final String[] PARTICIPANTS = new String[]{
+ "John Rambo",
+ "Han Solo",
+ "Rocky Balboa",
+ "Lara Croft"
+ };
+
+ static class Conversation {
+
+ private final int conversationId;
+
+ private final String participantName;
+
+ /**
+ * A given conversation can have a single or multiple messages.
+ * Note that the messages are sorted from *newest* to *oldest*
+ */
+ private final List<String> messages;
+
+ private final long timestamp;
+
+ public Conversation(int conversationId, String participantName,
+ List<String> messages) {
+ this.conversationId = conversationId;
+ this.participantName = participantName;
+ this.messages = messages == null ? Collections.<String>emptyList() : messages;
+ this.timestamp = System.currentTimeMillis();
+ }
+
+ public int getConversationId() {
+ return conversationId;
+ }
+
+ public String getParticipantName() {
+ return participantName;
+ }
+
+ public List<String> getMessages() {
+ return messages;
+ }
+
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ public String toString() {
+ return "[Conversation: conversationId=" + conversationId +
+ ", participantName=" + participantName +
+ ", messages=" + messages +
+ ", timestamp=" + timestamp + "]";
+ }
+ }
+
+ private Conversations() {
+ }
+
+ public static Conversation[] getUnreadConversations(int howManyConversations,
+ int messagesPerConversation) {
+ Conversation[] conversations = new Conversation[howManyConversations];
+ for (int i = 0; i < howManyConversations; i++) {
+ conversations[i] = new Conversation(
+ ThreadLocalRandom.current().nextInt(),
+ name(), makeMessages(messagesPerConversation));
+ }
+ return conversations;
+ }
+
+ private static List<String> makeMessages(int messagesPerConversation) {
+ int maxLen = MESSAGES.length;
+ List<String> messages = new ArrayList<>(messagesPerConversation);
+ for (int i = 0; i < messagesPerConversation; i++) {
+ messages.add(MESSAGES[ThreadLocalRandom.current().nextInt(0, maxLen)]);
+ }
+ return messages;
+ }
+
+ private static String name() {
+ return PARTICIPANTS[ThreadLocalRandom.current().nextInt(0, PARTICIPANTS.length)];
+ }
+}
diff --git a/notification/MessagingService/Application/src/main/java/com/example/android/messagingservice/MainActivity.java b/notification/MessagingService/Application/src/main/java/com/example/android/messagingservice/MainActivity.java
new file mode 100644
index 0000000..e558a64
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/java/com/example/android/messagingservice/MainActivity.java
@@ -0,0 +1,34 @@
+/*
+ * 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.messagingservice;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class MainActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ if (savedInstanceState == null) {
+ getFragmentManager().beginTransaction()
+ .add(R.id.container, new MessagingFragment())
+ .commit();
+ }
+ }
+}
diff --git a/notification/MessagingService/Application/src/main/java/com/example/android/messagingservice/MessageLogger.java b/notification/MessagingService/Application/src/main/java/com/example/android/messagingservice/MessageLogger.java
new file mode 100644
index 0000000..d1007b5
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/java/com/example/android/messagingservice/MessageLogger.java
@@ -0,0 +1,57 @@
+/*
+ * 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.messagingservice;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * A simple logger that uses shared preferences to log messages, their reads
+ * and replies. Don't use this in a real world application. This logger is only
+ * used for displaying the messages in the text view.
+ */
+public class MessageLogger {
+
+ private static final String PREF_MESSAGE = "MESSAGE_LOGGER";
+ private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+ public static final String LOG_KEY = "message_data";
+ public static final String LINE_BREAKS = "\n\n";
+
+ public static void logMessage(Context context, String message) {
+ SharedPreferences prefs = getPrefs(context);
+ message = DATE_FORMAT.format(new Date(System.currentTimeMillis())) + ": " + message;
+ prefs.edit()
+ .putString(LOG_KEY, prefs.getString(LOG_KEY, "") + LINE_BREAKS + message)
+ .apply();
+ }
+
+ public static SharedPreferences getPrefs(Context context) {
+ return context.getSharedPreferences(PREF_MESSAGE, Context.MODE_PRIVATE);
+ }
+
+ public static String getAllMessages(Context context) {
+ return getPrefs(context).getString(LOG_KEY, "");
+ }
+
+ public static void clear(Context context) {
+ getPrefs(context).edit().remove(LOG_KEY).apply();
+ }
+}
diff --git a/notification/MessagingService/Application/src/main/java/com/example/android/messagingservice/MessageReadReceiver.java b/notification/MessagingService/Application/src/main/java/com/example/android/messagingservice/MessageReadReceiver.java
new file mode 100644
index 0000000..f28a3a7
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/java/com/example/android/messagingservice/MessageReadReceiver.java
@@ -0,0 +1,42 @@
+/*
+ * 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.messagingservice;
+
+import android.app.NotificationManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.support.v4.app.NotificationManagerCompat;
+import android.util.Log;
+
+public class MessageReadReceiver extends BroadcastReceiver {
+ private static final String TAG = MessageReadReceiver.class.getSimpleName();
+
+ private static final String CONVERSATION_ID = "conversation_id";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.d(TAG, "onReceive");
+ int conversationId = intent.getIntExtra(CONVERSATION_ID, -1);
+ if (conversationId != -1) {
+ Log.d(TAG, "Conversation " + conversationId + " was read");
+ MessageLogger.logMessage(context, "Conversation " + conversationId + " was read.");
+ NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
+ notificationManager.cancel(conversationId);
+ }
+ }
+}
diff --git a/notification/MessagingService/Application/src/main/java/com/example/android/messagingservice/MessageReplyReceiver.java b/notification/MessagingService/Application/src/main/java/com/example/android/messagingservice/MessageReplyReceiver.java
new file mode 100644
index 0000000..0a3eba6
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/java/com/example/android/messagingservice/MessageReplyReceiver.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.messagingservice;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.RemoteInput;
+import android.util.Log;
+
+/**
+ * A receiver that gets called when a reply is sent to a given conversationId
+ */
+public class MessageReplyReceiver extends BroadcastReceiver {
+
+ private static final String TAG = MessageReplyReceiver.class.getSimpleName();
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (MessagingService.REPLY_ACTION.equals(intent.getAction())) {
+ int conversationId = intent.getIntExtra(MessagingService.CONVERSATION_ID, -1);
+ CharSequence reply = getMessageText(intent);
+ if (conversationId != -1) {
+ Log.d(TAG, "Got reply (" + reply + ") for ConversationId " + conversationId);
+ MessageLogger.logMessage(context, "ConversationId: " + conversationId +
+ " received a reply: [" + reply + "]");
+ }
+ }
+ }
+
+ /**
+ * Get the message text from the intent.
+ * Note that you should call {@code RemoteInput#getResultsFromIntent(intent)} to process
+ * the RemoteInput.
+ */
+ private CharSequence getMessageText(Intent intent) {
+ Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
+ if (remoteInput != null) {
+ return remoteInput.getCharSequence(MessagingService.EXTRA_VOICE_REPLY);
+ }
+ return null;
+ }
+}
diff --git a/notification/MessagingService/Application/src/main/java/com/example/android/messagingservice/MessagingFragment.java b/notification/MessagingService/Application/src/main/java/com/example/android/messagingservice/MessagingFragment.java
new file mode 100644
index 0000000..f8efcc0
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/java/com/example/android/messagingservice/MessagingFragment.java
@@ -0,0 +1,170 @@
+/*
+ * 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.messagingservice;
+
+import android.app.Fragment;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.text.method.ScrollingMovementMethod;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+
+/**
+ * The main fragment that shows the buttons and the text view containing the log.
+ */
+public class MessagingFragment extends Fragment implements View.OnClickListener {
+
+ private static final String TAG = MessagingFragment.class.getSimpleName();
+
+ private Button mSendSingleConversation;
+ private Button mSendTwoConversations;
+ private Button mSendConversationWithThreeMessages;
+ private TextView mDataPortView;
+ private Button mClearLogButton;
+
+ private Messenger mService;
+ private boolean mBound;
+
+ private ServiceConnection mConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName componentName, IBinder service) {
+ mService = new Messenger(service);
+ mBound = true;
+ setButtonsState(true);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName componentName) {
+ mService = null;
+ mBound = false;
+ setButtonsState(false);
+ }
+ };
+
+ private SharedPreferences.OnSharedPreferenceChangeListener listener =
+ new SharedPreferences.OnSharedPreferenceChangeListener() {
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ if (MessageLogger.LOG_KEY.equals(key)) {
+ mDataPortView.setText(MessageLogger.getAllMessages(getActivity()));
+ }
+ }
+ };
+
+ public MessagingFragment() {
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View rootView = inflater.inflate(R.layout.fragment_message_me, container, false);
+
+ mSendSingleConversation = (Button) rootView.findViewById(R.id.send_1_conversation);
+ mSendSingleConversation.setOnClickListener(this);
+
+ mSendTwoConversations = (Button) rootView.findViewById(R.id.send_2_conversations);
+ mSendTwoConversations.setOnClickListener(this);
+
+ mSendConversationWithThreeMessages =
+ (Button) rootView.findViewById(R.id.send_1_conversation_3_messages);
+ mSendConversationWithThreeMessages.setOnClickListener(this);
+
+ mDataPortView = (TextView) rootView.findViewById(R.id.data_port);
+ mDataPortView.setMovementMethod(new ScrollingMovementMethod());
+
+ mClearLogButton = (Button) rootView.findViewById(R.id.clear);
+ mClearLogButton.setOnClickListener(this);
+
+ setButtonsState(false);
+
+ return rootView;
+ }
+
+ @Override
+ public void onClick(View view) {
+ if (view == mSendSingleConversation) {
+ sendMsg(1, 1);
+ } else if (view == mSendTwoConversations) {
+ sendMsg(2, 1);
+ } else if (view == mSendConversationWithThreeMessages) {
+ sendMsg(1, 3);
+ } else if (view == mClearLogButton) {
+ MessageLogger.clear(getActivity());
+ mDataPortView.setText(MessageLogger.getAllMessages(getActivity()));
+ }
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ getActivity().bindService(new Intent(getActivity(), MessagingService.class), mConnection,
+ Context.BIND_AUTO_CREATE);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ MessageLogger.getPrefs(getActivity()).unregisterOnSharedPreferenceChangeListener(listener);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mDataPortView.setText(MessageLogger.getAllMessages(getActivity()));
+ MessageLogger.getPrefs(getActivity()).registerOnSharedPreferenceChangeListener(listener);
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ if (mBound) {
+ getActivity().unbindService(mConnection);
+ mBound = false;
+ }
+ }
+
+ private void sendMsg(int howManyConversations, int messagesPerConversation) {
+ if (mBound) {
+ Message msg = Message.obtain(null, MessagingService.MSG_SEND_NOTIFICATION,
+ howManyConversations, messagesPerConversation);
+ try {
+ mService.send(msg);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error sending a message", e);
+ MessageLogger.logMessage(getActivity(), "Error occurred while sending a message.");
+ }
+ }
+ }
+
+ private void setButtonsState(boolean enable) {
+ mSendSingleConversation.setEnabled(enable);
+ mSendTwoConversations.setEnabled(enable);
+ mSendConversationWithThreeMessages.setEnabled(enable);
+ }
+}
diff --git a/notification/MessagingService/Application/src/main/java/com/example/android/messagingservice/MessagingService.java b/notification/MessagingService/Application/src/main/java/com/example/android/messagingservice/MessagingService.java
new file mode 100644
index 0000000..f590061
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/java/com/example/android/messagingservice/MessagingService.java
@@ -0,0 +1,174 @@
+/*
+ * 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.messagingservice;
+
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Intent;
+import android.graphics.BitmapFactory;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.support.v4.app.NotificationCompat.CarExtender;
+import android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation;
+import android.support.v4.app.NotificationCompat;
+import android.support.v4.app.NotificationManagerCompat;
+import android.support.v4.app.RemoteInput;
+import android.util.Log;
+
+import java.util.Iterator;
+
+public class MessagingService extends Service {
+ private static final String TAG = MessagingService.class.getSimpleName();
+
+ public static final String READ_ACTION =
+ "com.example.android.messagingservice.ACTION_MESSAGE_READ";
+ public static final String REPLY_ACTION =
+ "com.example.android.messagingservice.ACTION_MESSAGE_REPLY";
+ public static final String CONVERSATION_ID = "conversation_id";
+ public static final String EXTRA_VOICE_REPLY = "extra_voice_reply";
+ public static final int MSG_SEND_NOTIFICATION = 1;
+ public static final String EOL = "\n";
+
+ private NotificationManagerCompat mNotificationManager;
+
+ private final Messenger mMessenger = new Messenger(new IncomingHandler());
+
+ /**
+ * Handler of incoming messages from clients.
+ */
+ class IncomingHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SEND_NOTIFICATION:
+ int howManyConversations = msg.arg1 <= 0 ? 1 : msg.arg1;
+ int messagesPerConv = msg.arg2 <= 0 ? 1 : msg.arg2;
+ sendNotification(howManyConversations, messagesPerConv);
+ break;
+ default:
+ super.handleMessage(msg);
+ }
+ }
+ }
+
+ @Override
+ public void onCreate() {
+ Log.d(TAG, "onCreate");
+ mNotificationManager = NotificationManagerCompat.from(getApplicationContext());
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ Log.d(TAG, "onBind");
+ return mMessenger.getBinder();
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ Log.d(TAG, "onStartCommand");
+ return START_STICKY;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ Log.d(TAG, "onDestroy");
+ }
+
+ // Creates an intent that will be triggered when a message is marked as read.
+ private Intent getMessageReadIntent(int id) {
+ return new Intent()
+ .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
+ .setAction(READ_ACTION)
+ .putExtra(CONVERSATION_ID, id);
+ }
+
+ // Creates an Intent that will be triggered when a voice reply is received.
+ private Intent getMessageReplyIntent(int conversationId) {
+ return new Intent()
+ .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
+ .setAction(REPLY_ACTION)
+ .putExtra(CONVERSATION_ID, conversationId);
+ }
+
+ private void sendNotification(int howManyConversations, int messagesPerConversation) {
+ Conversations.Conversation[] conversations = Conversations.getUnreadConversations(
+ howManyConversations, messagesPerConversation);
+ for (Conversations.Conversation conv : conversations) {
+ sendNotificationForConversation(conv);
+ }
+ }
+
+ private void sendNotificationForConversation(Conversations.Conversation conversation) {
+ // A pending Intent for reads
+ PendingIntent readPendingIntent = PendingIntent.getBroadcast(getApplicationContext(),
+ conversation.getConversationId(),
+ getMessageReadIntent(conversation.getConversationId()),
+ PendingIntent.FLAG_UPDATE_CURRENT);
+
+ // Build a RemoteInput for receiving voice input in a Car Notification
+ RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)
+ .setLabel(getApplicationContext().getString(R.string.notification_reply))
+ .build();
+
+ // Building a Pending Intent for the reply action to trigger
+ PendingIntent replyIntent = PendingIntent.getBroadcast(getApplicationContext(),
+ conversation.getConversationId(),
+ getMessageReplyIntent(conversation.getConversationId()),
+ PendingIntent.FLAG_UPDATE_CURRENT);
+
+ // Create the UnreadConversation and populate it with the participant name,
+ // read and reply intents.
+ UnreadConversation.Builder unreadConvBuilder =
+ new UnreadConversation.Builder(conversation.getParticipantName())
+ .setLatestTimestamp(conversation.getTimestamp())
+ .setReadPendingIntent(readPendingIntent)
+ .setReplyAction(replyIntent, remoteInput);
+
+ // Note: Add messages from oldest to newest to the UnreadConversation.Builder
+ StringBuilder messageForNotification = new StringBuilder();
+ for (Iterator<String> messages = conversation.getMessages().iterator();
+ messages.hasNext(); ) {
+ String message = messages.next();
+ unreadConvBuilder.addMessage(message);
+ messageForNotification.append(message);
+ if (messages.hasNext()) {
+ messageForNotification.append(EOL);
+ }
+ }
+
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext())
+ .setSmallIcon(R.drawable.notification_icon)
+ .setLargeIcon(BitmapFactory.decodeResource(
+ getApplicationContext().getResources(), R.drawable.android_contact))
+ .setContentText(messageForNotification.toString())
+ .setWhen(conversation.getTimestamp())
+ .setContentTitle(conversation.getParticipantName())
+ .setContentIntent(readPendingIntent)
+ .extend(new CarExtender()
+ .setUnreadConversation(unreadConvBuilder.build())
+ .setColor(getApplicationContext()
+ .getResources().getColor(R.color.default_color_light)));
+
+ MessageLogger.logMessage(getApplicationContext(), "Sending notification "
+ + conversation.getConversationId() + " conversation: " + conversation);
+
+ mNotificationManager.notify(conversation.getConversationId(), builder.build());
+ }
+}
diff --git a/notification/MessagingService/Application/src/main/res/drawable-hdpi/android_contact.png b/notification/MessagingService/Application/src/main/res/drawable-hdpi/android_contact.png
new file mode 100644
index 0000000..00d0ec4
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/res/drawable-hdpi/android_contact.png
Binary files differ
diff --git a/notification/MessagingService/Application/src/main/res/drawable-hdpi/ic_launcher.png b/notification/MessagingService/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..06d85f1
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/notification/MessagingService/Application/src/main/res/drawable-hdpi/notification_icon.png b/notification/MessagingService/Application/src/main/res/drawable-hdpi/notification_icon.png
new file mode 100644
index 0000000..9cdfca1
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/res/drawable-hdpi/notification_icon.png
Binary files differ
diff --git a/notification/MessagingService/Application/src/main/res/drawable-mdpi/android_contact.png b/notification/MessagingService/Application/src/main/res/drawable-mdpi/android_contact.png
new file mode 100644
index 0000000..771cb6b
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/res/drawable-mdpi/android_contact.png
Binary files differ
diff --git a/notification/MessagingService/Application/src/main/res/drawable-mdpi/ic_launcher.png b/notification/MessagingService/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..4e1cc86
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/notification/MessagingService/Application/src/main/res/drawable-mdpi/notification_icon.png b/notification/MessagingService/Application/src/main/res/drawable-mdpi/notification_icon.png
new file mode 100644
index 0000000..d6069eb
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/res/drawable-mdpi/notification_icon.png
Binary files differ
diff --git a/notification/MessagingService/Application/src/main/res/drawable-xhdpi/android_contact.png b/notification/MessagingService/Application/src/main/res/drawable-xhdpi/android_contact.png
new file mode 100644
index 0000000..bdba57b
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/res/drawable-xhdpi/android_contact.png
Binary files differ
diff --git a/notification/MessagingService/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/notification/MessagingService/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..92f1e2d
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/notification/MessagingService/Application/src/main/res/drawable-xhdpi/notification_icon.png b/notification/MessagingService/Application/src/main/res/drawable-xhdpi/notification_icon.png
new file mode 100644
index 0000000..786ed17
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/res/drawable-xhdpi/notification_icon.png
Binary files differ
diff --git a/notification/MessagingService/Application/src/main/res/drawable-xxhdpi/android_contact.png b/notification/MessagingService/Application/src/main/res/drawable-xxhdpi/android_contact.png
new file mode 100644
index 0000000..b36ec17
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/res/drawable-xxhdpi/android_contact.png
Binary files differ
diff --git a/notification/MessagingService/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/notification/MessagingService/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..2476cbd
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/notification/MessagingService/Application/src/main/res/drawable-xxhdpi/notification_icon.png b/notification/MessagingService/Application/src/main/res/drawable-xxhdpi/notification_icon.png
new file mode 100644
index 0000000..005207c
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/res/drawable-xxhdpi/notification_icon.png
Binary files differ
diff --git a/notification/MessagingService/Application/src/main/res/layout-land/fragment_message_me.xml b/notification/MessagingService/Application/src/main/res/layout-land/fragment_message_me.xml
new file mode 100644
index 0000000..8f7b60a
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/res/layout-land/fragment_message_me.xml
@@ -0,0 +1,67 @@
+<!--
+ 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="match_parent"
+ android:gravity="center_horizontal"
+ android:orientation="horizontal"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin">
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+ <Button
+ android:id="@+id/send_1_conversation"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/send_1_conversation"/>
+
+ <Button
+ android:id="@+id/send_2_conversations"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/send_2_conversations"/>
+
+ <Button
+ android:id="@+id/send_1_conversation_3_messages"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/send_1_conv_3_messages"/>
+ </LinearLayout>
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="2">
+ <Button
+ android:id="@+id/clear"
+ android:layout_alignParentBottom="true"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/clear_log"/>
+
+ <TextView
+ android:id="@+id/data_port"
+ android:layout_above="@id/clear"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:maxLines="20"
+ android:scrollbars="vertical"/>
+ </RelativeLayout>
+</LinearLayout>
diff --git a/notification/MessagingService/Application/src/main/res/layout/activity_main.xml b/notification/MessagingService/Application/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..59eec80
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/res/layout/activity_main.xml
@@ -0,0 +1,22 @@
+<!--
+ 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.
+ -->
+<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=".MainActivity"
+ tools:ignore="MergeRootFrame" />
diff --git a/notification/MessagingService/Application/src/main/res/layout/fragment_message_me.xml b/notification/MessagingService/Application/src/main/res/layout/fragment_message_me.xml
new file mode 100644
index 0000000..d01c513
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/res/layout/fragment_message_me.xml
@@ -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.
+ -->
+<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"
+ android:gravity="center_horizontal"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin">
+
+ <Button
+ android:id="@+id/send_1_conversation"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/send_1_conversation"/>
+
+ <Button
+ android:id="@+id/send_2_conversations"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/send_2_conversations"/>
+
+ <Button
+ android:id="@+id/send_1_conversation_3_messages"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/send_1_conv_3_messages"/>
+
+ <TextView
+ android:id="@+id/data_port"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:maxLines="20"
+ android:scrollbars="vertical"/>
+ <Button
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/clear"
+ android:text="@string/clear_log"/>
+
+</LinearLayout>
diff --git a/notification/MessagingService/Application/src/main/res/values-v21/styles.xml b/notification/MessagingService/Application/src/main/res/values-v21/styles.xml
new file mode 100644
index 0000000..f30c97a
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/res/values-v21/styles.xml
@@ -0,0 +1,22 @@
+<?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="AppTheme" parent="android:Theme.Material.Light">
+ <item name="android:colorPrimary">@color/default_color_light</item>
+ <item name="android:colorPrimaryDark">@color/default_color_dark</item>
+ </style>
+</resources>
diff --git a/notification/MessagingService/Application/src/main/res/values/colors.xml b/notification/MessagingService/Application/src/main/res/values/colors.xml
new file mode 100644
index 0000000..0e6825b
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/res/values/colors.xml
@@ -0,0 +1,20 @@
+<?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>
+ <color name="default_color_light">#ff4092c3</color>
+ <color name="default_color_dark">#ff241c99</color>
+</resources>
diff --git a/notification/MessagingService/Application/src/main/res/values/dimens.xml b/notification/MessagingService/Application/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..574a35d
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/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>
+ <!-- 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/notification/MessagingService/Application/src/main/res/values/strings.xml b/notification/MessagingService/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..001b10e
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/res/values/strings.xml
@@ -0,0 +1,26 @@
+<?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>
+ <string name="app_name">Messaging Sample</string>
+ <string name="action_settings">Settings</string>
+ <string name="title">Messaging Sample</string>
+ <string name="notification_reply">Reply by Voice</string>
+ <string name="send_2_conversations">Send 2 conversations with 1 message</string>
+ <string name="send_1_conversation">Send 1 conversation with 1 message</string>
+ <string name="send_1_conv_3_messages">Send 1 conversation with 3 messages</string>
+ <string name="clear_log">Clear Log</string>
+</resources>
diff --git a/notification/MessagingService/Application/src/main/res/values/styles.xml b/notification/MessagingService/Application/src/main/res/values/styles.xml
new file mode 100644
index 0000000..3f1a6af
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/res/values/styles.xml
@@ -0,0 +1,20 @@
+<?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="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+ </style>
+</resources>
diff --git a/notification/MessagingService/Application/src/main/res/xml/automotive_app_desc.xml b/notification/MessagingService/Application/src/main/res/xml/automotive_app_desc.xml
new file mode 100644
index 0000000..9e9f174
--- /dev/null
+++ b/notification/MessagingService/Application/src/main/res/xml/automotive_app_desc.xml
@@ -0,0 +1,19 @@
+<?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.
+ -->
+<automotiveApp>
+ <uses name="notification"/>
+</automotiveApp>
diff --git a/ui/notifications/BasicNotifications/CONTRIB.md b/notification/MessagingService/CONTRIB.md
similarity index 100%
copy from ui/notifications/BasicNotifications/CONTRIB.md
copy to notification/MessagingService/CONTRIB.md
diff --git a/ui/notifications/BasicNotifications/LICENSE b/notification/MessagingService/LICENSE
similarity index 100%
copy from ui/notifications/BasicNotifications/LICENSE
copy to notification/MessagingService/LICENSE
diff --git a/notification/MessagingService/README.md b/notification/MessagingService/README.md
new file mode 100644
index 0000000..4cb5bb8
--- /dev/null
+++ b/notification/MessagingService/README.md
@@ -0,0 +1,88 @@
+Android MessagingService Sample
+==============================
+
+This sample shows a simple service that sends notifications using
+NotificationCompat. In addition to sending a notification, it also extends
+the notification with a CarExtender to make it compatible with Android Auto.
+Each unread conversation from a user is sent as a distinct notification.
+
+CheckList while building a messaging app that supports Android Auto:
+-------------------------------------------------------------------
+1. Add or import the android-auto-sdk.jar into your app.
+2. Ensure that Message notifications are extended using
+NotificationCompat.Builder.extend(new CarExtender()...)
+3. Add meta-data to your AndroidManifest.xml to specify that your app
+is automotive enabled.
+```
+ <meta-data android:name="com.google.android.gms.car.application"
+ android:resource="@xml/automotive_app_desc"/>
+```
+and include the following to indicate that the application wants to show notifications on
+the Android Auto overview screen.
+res/xml/automotive\_app\_desc.xml
+```
+<automotiveApp>
+ <uses name="notification"/>
+</automotiveApp>
+```
+
+Flow
+-----
+MessagingFragment is shown to the user. Depending on the button clicked, the MessagingService is
+sent a message. MessagingService inturn creates notifications which can be viewed either on the
+emulator or in a car.
+When a message is read, the associated PendingIntent is called and MessageReadReceiver is called
+with the appropriate conversationId. Similarly, when a reply is received, the MessageReplyReceiver
+is called with the appropriate conversationId. MessageLogger logs each event and shows them in a
+TextView in MessagingFragment for correlation.
+
+
+Pre-requisites
+--------------
+
+- Android SDK v21
+- Android Support Repository
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Screenshots
+-----------
+
+<!-- Update these to point to screenshots. Add more as needed. -->
+ 
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-MessagingService
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2014 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements. See the NOTICE file distributed with this work for
+additional information regarding copyright ownership. The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/notification/MessagingService/build.gradle b/notification/MessagingService/build.gradle
new file mode 100644
index 0000000..2b8d1ef
--- /dev/null
+++ b/notification/MessagingService/build.gradle
@@ -0,0 +1,11 @@
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../build"
+ pathToSamplesCommon "../../common"
+}
+apply from: "../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/notification/MessagingService/buildSrc/build.gradle b/notification/MessagingService/buildSrc/build.gradle
new file mode 100644
index 0000000..8c294c2
--- /dev/null
+++ b/notification/MessagingService/buildSrc/build.gradle
@@ -0,0 +1,15 @@
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile 'org.freemarker:freemarker:2.3.20'
+}
+
+sourceSets {
+ main {
+ groovy {
+ srcDir new File(rootDir, "../../../../../build/buildSrc/src/main/groovy")
+ }
+ }
+}
+
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/notification/MessagingService/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
copy to notification/MessagingService/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties b/notification/MessagingService/gradle/wrapper/gradle-wrapper.properties
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties
copy to notification/MessagingService/gradle/wrapper/gradle-wrapper.properties
diff --git a/ui/notifications/BasicNotifications/gradlew b/notification/MessagingService/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to notification/MessagingService/gradlew
diff --git a/ui/notifications/BasicNotifications/gradlew.bat b/notification/MessagingService/gradlew.bat
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew.bat
copy to notification/MessagingService/gradlew.bat
diff --git a/notification/MessagingService/packaging.yaml b/notification/MessagingService/packaging.yaml
new file mode 100644
index 0000000..38733c7
--- /dev/null
+++ b/notification/MessagingService/packaging.yaml
@@ -0,0 +1,15 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+
+status: PUBLISHED
+technologies: [Android]
+categories: [None]
+languages: [Java]
+solutions: [Mobile]
+github: googlesamples/android-MessagingService
+level: BEGINNER
+icon: MessagingServiceSample/src/main/res/drawable-xxhdpi/ic_launcher.png
+license: apache2-android
diff --git a/ui/notifications/BasicNotifications/settings.gradle b/notification/MessagingService/settings.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/settings.gradle
copy to notification/MessagingService/settings.gradle
diff --git a/notification/MessagingService/template-params.xml b/notification/MessagingService/template-params.xml
new file mode 100644
index 0000000..7866642
--- /dev/null
+++ b/notification/MessagingService/template-params.xml
@@ -0,0 +1,36 @@
+<?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.
+-->
+<sample>
+ <name>MessagingService</name>
+ <group>Notification</group>
+ <package>com.example.android.messagingservice</package>
+
+ <minSdk>21</minSdk>
+
+ <strings>
+ <intro>
+ <![CDATA[
+This sample shows a simple service that sends notifications using
+NotificationCompat. In addition to sending a notification, it also extends
+the notification with a CarExtender to make it compatible with Android Auto.
+Each unread conversation from a user is sent as a distinct notification.
+ ]]>
+ </intro>
+ </strings>
+
+ <template src="basebuild" />
+</sample>
diff --git a/renderScript/BasicRenderScript/Application/AndroidManifest.xml b/renderScript/BasicRenderScript/Application/AndroidManifest.xml
index 1e35dc3..21c3a62 100644
--- a/renderScript/BasicRenderScript/Application/AndroidManifest.xml
+++ b/renderScript/BasicRenderScript/Application/AndroidManifest.xml
@@ -4,9 +4,7 @@
android:versionCode="1"
android:versionName="1.0" >
- <uses-sdk
- android:minSdkVersion="8"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application
android:allowBackup="true"
diff --git a/renderScript/BasicRenderScript/Application/src/main/AndroidManifest.xml b/renderScript/BasicRenderScript/Application/src/main/AndroidManifest.xml
index e1e2dfc..3bc65ff 100644
--- a/renderScript/BasicRenderScript/Application/src/main/AndroidManifest.xml
+++ b/renderScript/BasicRenderScript/Application/src/main/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="8"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application
android:allowBackup="true"
diff --git a/renderScript/BasicRenderScript/Application/tests/AndroidManifest.xml b/renderScript/BasicRenderScript/Application/tests/AndroidManifest.xml
index 02a8db3..34eca02 100644
--- a/renderScript/BasicRenderScript/Application/tests/AndroidManifest.xml
+++ b/renderScript/BasicRenderScript/Application/tests/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="8"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/renderScript/RenderScriptIntrinsic/Application/src/main/AndroidManifest.xml b/renderScript/RenderScriptIntrinsic/Application/src/main/AndroidManifest.xml
index 566ef8a..e108aff 100644
--- a/renderScript/RenderScriptIntrinsic/Application/src/main/AndroidManifest.xml
+++ b/renderScript/RenderScriptIntrinsic/Application/src/main/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="8"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application
android:allowBackup="true"
diff --git a/renderScript/RenderScriptIntrinsic/Application/tests/AndroidManifest.xml b/renderScript/RenderScriptIntrinsic/Application/tests/AndroidManifest.xml
index 96fa207..72f0969 100644
--- a/renderScript/RenderScriptIntrinsic/Application/tests/AndroidManifest.xml
+++ b/renderScript/RenderScriptIntrinsic/Application/tests/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="8"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/security/keystore/BasicAndroidKeyStore/Application/src/main/AndroidManifest.xml b/security/keystore/BasicAndroidKeyStore/Application/src/main/AndroidManifest.xml
index 28d256c..1c3b255 100644
--- a/security/keystore/BasicAndroidKeyStore/Application/src/main/AndroidManifest.xml
+++ b/security/keystore/BasicAndroidKeyStore/Application/src/main/AndroidManifest.xml
@@ -22,7 +22,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="18" android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application android:allowBackup="true"
android:label="@string/app_name"
diff --git a/security/keystore/BasicAndroidKeyStore/Application/tests/AndroidManifest.xml b/security/keystore/BasicAndroidKeyStore/Application/tests/AndroidManifest.xml
index eb8b7b8..3ebff98 100644
--- a/security/keystore/BasicAndroidKeyStore/Application/tests/AndroidManifest.xml
+++ b/security/keystore/BasicAndroidKeyStore/Application/tests/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/sensors/BatchStepSensor/Application/src/main/AndroidManifest.xml b/sensors/BatchStepSensor/Application/src/main/AndroidManifest.xml
index 2c4e4f2..9063770 100644
--- a/sensors/BatchStepSensor/Application/src/main/AndroidManifest.xml
+++ b/sensors/BatchStepSensor/Application/src/main/AndroidManifest.xml
@@ -23,7 +23,7 @@
android:versionName="1.0">
<!-- This sample requires at least Android KitKat for sensor batching support -->
- <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- Require the step counter and step detector sensors.
See the method BatchStepSensorFragment#isKitkatWithStepSensor() for a programmatic check if
diff --git a/testing/ActivityInstrumentation/Application/src/main/AndroidManifest.xml b/testing/ActivityInstrumentation/Application/src/main/AndroidManifest.xml
index 547d95e..da5c824 100644
--- a/testing/ActivityInstrumentation/Application/src/main/AndroidManifest.xml
+++ b/testing/ActivityInstrumentation/Application/src/main/AndroidManifest.xml
@@ -22,7 +22,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="17" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application android:allowBackup="true"
android:label="@string/app_name"
diff --git a/testing/ActivityInstrumentation/Application/tests/AndroidManifest.xml b/testing/ActivityInstrumentation/Application/tests/AndroidManifest.xml
index ad20a2a..4c24a6f 100644
--- a/testing/ActivityInstrumentation/Application/tests/AndroidManifest.xml
+++ b/testing/ActivityInstrumentation/Application/tests/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/ui/notifications/BasicNotifications/Application/.gitignore b/ui/DrawableTinting/Application/.gitignore
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/.gitignore
copy to ui/DrawableTinting/Application/.gitignore
diff --git a/ui/DrawableTinting/Application/README-fragmentview.txt b/ui/DrawableTinting/Application/README-fragmentview.txt
new file mode 100644
index 0000000..38d903f
--- /dev/null
+++ b/ui/DrawableTinting/Application/README-fragmentview.txt
@@ -0,0 +1,37 @@
+<!--
+ 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.
+-->
+
+Steps to implement FragmentView template:
+-in template-params.xml.ftl:
+ -add the following line to common imports
+ <common src="activities"/>
+
+-Add a Fragment to show behavior. In your MainActivity.java class, it will reference a Fragment
+ called (yourProjectName)Fragment.java. Create that file in your project, using the "main" source
+ folder instead of "common" or "templates".
+ For instance, if your package name is com.example.foo, create the file
+ src/main/java/com/example/foo/FooFragment.java
+
+
+-Within this fragment, make sure that the onCreate method has the line
+ "setHasOptionsMenu(true);", to enable the fragment to handle menu events.
+
+-In order to override menu events, override onOptionsItemSelected.
+
+-refer to sampleSamples/fragmentViewSample for a reference implementation of a
+project built on this template.
+
+
diff --git a/ui/DrawableTinting/Application/build.gradle b/ui/DrawableTinting/Application/build.gradle
new file mode 100644
index 0000000..5fa47b7
--- /dev/null
+++ b/ui/DrawableTinting/Application/build.gradle
@@ -0,0 +1,59 @@
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:0.12.+'
+ }
+}
+
+apply plugin: 'com.android.application'
+
+
+dependencies {
+
+ compile "com.android.support:support-v4:20.+"
+ compile "com.android.support:support-v13:20.+"
+
+}
+
+// The sample build uses multiple directories to
+// keep boilerplate and common code separate from
+// the main sample code.
+List<String> dirs = [
+ 'main', // main sample code; look here for the interesting stuff.
+ 'common', // components that are reused by multiple samples
+ 'template'] // boilerplate code that is generated by the sample template process
+
+android {
+ compileSdkVersion "android-L"
+
+ buildToolsVersion "20.0.0"
+
+ sourceSets {
+ main {
+ dirs.each { dir ->
+ java.srcDirs "src/${dir}/java"
+ res.srcDirs "src/${dir}/res"
+ }
+ }
+
+ }
+
+}
+// BEGIN_EXCLUDE
+// Tasks below this line will be hidden from release output
+
+task preflight (dependsOn: parent.preflight) {
+ project.afterEvaluate {
+ // Inject a preflight task into each variant so we have a place to hook tasks
+ // that need to run before any of the android build tasks.
+ //
+ android.applicationVariants.each { variant ->
+ tasks.getByPath("prepare${variant.name.capitalize()}Dependencies").dependsOn preflight
+ }
+ }
+}
+
+// END_EXCLUDE
diff --git a/ui/DrawableTinting/Application/src/main/AndroidManifest.xml b/ui/DrawableTinting/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..9aa3976
--- /dev/null
+++ b/ui/DrawableTinting/Application/src/main/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/ui/DrawableTinting/Application/src/main/java/com/example/android/drawabletinting/DrawableTintingFragment.java b/ui/DrawableTinting/Application/src/main/java/com/example/android/drawabletinting/DrawableTintingFragment.java
new file mode 100644
index 0000000..cd46fb9
--- /dev/null
+++ b/ui/DrawableTinting/Application/src/main/java/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/ui/DrawableTinting/Application/src/main/res/color/custom_tint.xml b/ui/DrawableTinting/Application/src/main/res/color/custom_tint.xml
new file mode 100644
index 0000000..983880a
--- /dev/null
+++ b/ui/DrawableTinting/Application/src/main/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/ui/DrawableTinting/Application/src/main/res/drawable-hdpi/btn_default_normal_holo.9.png b/ui/DrawableTinting/Application/src/main/res/drawable-hdpi/btn_default_normal_holo.9.png
new file mode 100644
index 0000000..dbcede7
--- /dev/null
+++ b/ui/DrawableTinting/Application/src/main/res/drawable-hdpi/btn_default_normal_holo.9.png
Binary files differ
diff --git a/ui/DrawableTinting/Application/src/main/res/drawable-hdpi/ic_launcher.png b/ui/DrawableTinting/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a8cb237
--- /dev/null
+++ b/ui/DrawableTinting/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/DrawableTinting/Application/src/main/res/drawable-mdpi/btn_default_normal_holo.9.png b/ui/DrawableTinting/Application/src/main/res/drawable-mdpi/btn_default_normal_holo.9.png
new file mode 100644
index 0000000..0e0da34
--- /dev/null
+++ b/ui/DrawableTinting/Application/src/main/res/drawable-mdpi/btn_default_normal_holo.9.png
Binary files differ
diff --git a/ui/DrawableTinting/Application/src/main/res/drawable-mdpi/ic_launcher.png b/ui/DrawableTinting/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..9249aa2
--- /dev/null
+++ b/ui/DrawableTinting/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/DrawableTinting/Application/src/main/res/drawable-xhdpi/btn_default_normal_holo.9.png b/ui/DrawableTinting/Application/src/main/res/drawable-xhdpi/btn_default_normal_holo.9.png
new file mode 100644
index 0000000..92a49db
--- /dev/null
+++ b/ui/DrawableTinting/Application/src/main/res/drawable-xhdpi/btn_default_normal_holo.9.png
Binary files differ
diff --git a/ui/DrawableTinting/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/ui/DrawableTinting/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..5d57004
--- /dev/null
+++ b/ui/DrawableTinting/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/DrawableTinting/Application/src/main/res/drawable-xxhdpi/btn_default_normal_holo.9.png b/ui/DrawableTinting/Application/src/main/res/drawable-xxhdpi/btn_default_normal_holo.9.png
new file mode 100644
index 0000000..c1632c8
--- /dev/null
+++ b/ui/DrawableTinting/Application/src/main/res/drawable-xxhdpi/btn_default_normal_holo.9.png
Binary files differ
diff --git a/ui/DrawableTinting/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/ui/DrawableTinting/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..9ceea0e
--- /dev/null
+++ b/ui/DrawableTinting/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/DrawableTinting/Application/src/main/res/drawable/buttonbackground.xml b/ui/DrawableTinting/Application/src/main/res/drawable/buttonbackground.xml
new file mode 100644
index 0000000..060c5c7
--- /dev/null
+++ b/ui/DrawableTinting/Application/src/main/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/ui/DrawableTinting/Application/src/main/res/layout/tinting_fragment.xml b/ui/DrawableTinting/Application/src/main/res/layout/tinting_fragment.xml
new file mode 100644
index 0000000..0a3bfa7
--- /dev/null
+++ b/ui/DrawableTinting/Application/src/main/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/ui/DrawableTinting/Application/src/main/res/values/color.xml b/ui/DrawableTinting/Application/src/main/res/values/color.xml
new file mode 100644
index 0000000..86a2db7
--- /dev/null
+++ b/ui/DrawableTinting/Application/src/main/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/ui/DrawableTinting/Application/src/main/res/values/strings.xml b/ui/DrawableTinting/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..4a517d1
--- /dev/null
+++ b/ui/DrawableTinting/Application/src/main/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/ui/notifications/BasicNotifications/Application/proguard-project.txt b/ui/DrawableTinting/Application/src/proguard-project.txt
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/proguard-project.txt
copy to ui/DrawableTinting/Application/src/proguard-project.txt
diff --git a/ui/DrawableTinting/Application/src/test/SampleTests.java b/ui/DrawableTinting/Application/src/test/SampleTests.java
new file mode 100644
index 0000000..534ad12
--- /dev/null
+++ b/ui/DrawableTinting/Application/src/test/SampleTests.java
@@ -0,0 +1,158 @@
+/*
+* 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 android.ui.DrawableTinting.Application.src.test;
+
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.ui.DrawableTinting.Application.src.main.java.com.example.android.drawabletinting.DrawableTintingFragment;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.SeekBar;
+import android.widget.Spinner;
+
+import com.example.android.drawabletinting.MainActivity;
+import com.example.android.drawabletinting.R;
+
+/**
+ * Tests for drawabletinting sample.
+ */
+public class SampleTests extends ActivityInstrumentationTestCase2<MainActivity> {
+
+ private MainActivity mTestActivity;
+ private DrawableTintingFragment mTestFragment;
+
+ View mFragmentView;
+ SeekBar mAlpha;
+ SeekBar mRed;
+ SeekBar mGreen;
+ SeekBar mBlue;
+ Spinner mBlendMode;
+ ImageView mImage;
+
+ public SampleTests() {
+ super(MainActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // Starts the activity under test using the default Intent with:
+ // action = {@link Intent#ACTION_MAIN}
+ // flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK}
+ // All other fields are null or empty.
+ mTestActivity = getActivity();
+ mTestFragment = (DrawableTintingFragment)
+ mTestActivity.getSupportFragmentManager().getFragments().get(1);
+
+ final View fragmentView = mTestFragment.getView();
+ mAlpha = (SeekBar) fragmentView.findViewById(R.id.alphaSeek);
+ mRed = (SeekBar) fragmentView.findViewById(R.id.redSeek);
+ mGreen = (SeekBar) fragmentView.findViewById(R.id.greenSeek);
+ mBlue = (SeekBar) fragmentView.findViewById(R.id.blueSeek);
+ mBlendMode = (Spinner) fragmentView.findViewById(R.id.blendSpinner);
+ mImage = (ImageView) fragmentView.findViewById(R.id.image);
+ }
+
+ /**
+ * Test if the test fixture has been set up correctly.
+ */
+ public void testPreconditions() {
+ //Try to add a message to add context to your assertions. These messages will be shown if
+ //a tests fails and make it easy to understand why a test failed
+ assertNotNull("mTestActivity is null", mTestActivity);
+ assertNotNull("mTestFragment is null", mTestFragment);
+ }
+
+ /**
+ * Test the initial state of all UI elements, color and blend mode.
+ */
+ public void testInitialState() {
+ assertEquals(255, mAlpha.getProgress());
+ assertEquals(0, mRed.getProgress());
+ assertEquals(0, mGreen.getProgress());
+ assertEquals(0, mBlue.getProgress());
+ assertEquals("Add", (String) mBlendMode.getSelectedItem());
+
+ PorterDuffColorFilter colorFilter = (PorterDuffColorFilter) mImage.getColorFilter();
+ assertNotNull(colorFilter);
+ int initialColor = Color.BLACK;
+ assertEquals(initialColor, colorFilter.getColor());
+ assertEquals(PorterDuff.Mode.ADD, colorFilter.getMode());
+ }
+
+ /**
+ * Test application of blend modes.
+ */
+ @UiThreadTest
+ public void testModes() {
+ final int testColor = Color.GREEN;
+ // Test that each tint mode can be successfully applied and matches a valid PorterDuff mode
+ final PorterDuff.Mode[] modes = PorterDuff.Mode.values();
+
+ // Test that each blend mode can be applied
+ for (PorterDuff.Mode m : modes) {
+ mTestFragment.updateTint(testColor, m);
+ final PorterDuffColorFilter filter = (PorterDuffColorFilter) mImage.getColorFilter();
+ assertEquals(m, filter.getMode());
+ assertEquals(testColor, filter.getColor());
+ }
+ }
+
+ /**
+ * Test the color computation from ARGB Seekbars.
+ */
+ public void testColor() {
+ // Red
+ mAlpha.setProgress(255);
+ mRed.setProgress(255);
+ mBlue.setProgress(0);
+ mGreen.setProgress(0);
+ assertEquals(Color.RED, mTestFragment.getColor());
+
+ // Blue
+ mAlpha.setProgress(255);
+ mRed.setProgress(0);
+ mBlue.setProgress(255);
+ mGreen.setProgress(0);
+ assertEquals(Color.BLUE, mTestFragment.getColor());
+
+ // Green
+ mAlpha.setProgress(255);
+ mRed.setProgress(0);
+ mBlue.setProgress(0);
+ mGreen.setProgress(255);
+ assertEquals(Color.GREEN, mTestFragment.getColor());
+
+ // Black
+ mAlpha.setProgress(255);
+ mRed.setProgress(0);
+ mBlue.setProgress(0);
+ mGreen.setProgress(0);
+ assertEquals(Color.BLACK, mTestFragment.getColor());
+
+ // Transparent
+ mAlpha.setProgress(0);
+ mRed.setProgress(0);
+ mBlue.setProgress(0);
+ mGreen.setProgress(0);
+ assertEquals(Color.TRANSPARENT, mTestFragment.getColor());
+ }
+
+}
diff --git a/ui/notifications/BasicNotifications/CONTRIB.md b/ui/DrawableTinting/CONTRIB.md
similarity index 100%
copy from ui/notifications/BasicNotifications/CONTRIB.md
copy to ui/DrawableTinting/CONTRIB.md
diff --git a/ui/notifications/BasicNotifications/LICENSE b/ui/DrawableTinting/LICENSE
similarity index 100%
copy from ui/notifications/BasicNotifications/LICENSE
copy to ui/DrawableTinting/LICENSE
diff --git a/ui/DrawableTinting/README.md b/ui/DrawableTinting/README.md
new file mode 100644
index 0000000..db2efaa
--- /dev/null
+++ b/ui/DrawableTinting/README.md
@@ -0,0 +1,61 @@
+Android DrawableTinting Sample
+==============================
+
+Sample that shows applying tinting and color filters to Drawables both programmatically
+and as Drawable resources in XML.
+
+Introduction
+------------
+
+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 to see the effect of different options.
+
+Pre-requisites
+--------------
+
+- Android SDK (L Developer Preview)
+- Android Build Tools v20
+- Android Support Repository
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-DrawableTinting
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2014 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements. See the NOTICE file distributed with this work for
+additional information regarding copyright ownership. The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/ui/DrawableTinting/build.gradle b/ui/DrawableTinting/build.gradle
new file mode 100644
index 0000000..c7a137e
--- /dev/null
+++ b/ui/DrawableTinting/build.gradle
@@ -0,0 +1,10 @@
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../build"
+ pathToSamplesCommon "../../common"
+}
+apply from: "../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/ui/DrawableTinting/buildSrc/build.gradle b/ui/DrawableTinting/buildSrc/build.gradle
new file mode 100644
index 0000000..29282af
--- /dev/null
+++ b/ui/DrawableTinting/buildSrc/build.gradle
@@ -0,0 +1,18 @@
+
+
+
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile 'org.freemarker:freemarker:2.3.20'
+}
+
+sourceSets {
+ main {
+ groovy {
+ srcDir new File(rootDir, "../../../../../build/buildSrc/src/main/groovy")
+ }
+ }
+}
+
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/ui/DrawableTinting/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
copy to ui/DrawableTinting/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/DrawableTinting/gradle/wrapper/gradle-wrapper.properties b/ui/DrawableTinting/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..56f685a
--- /dev/null
+++ b/ui/DrawableTinting/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Apr 10 15:27:10 PDT 2013
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-bin.zip
diff --git a/ui/notifications/BasicNotifications/gradlew b/ui/DrawableTinting/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to ui/DrawableTinting/gradlew
diff --git a/ui/DrawableTinting/gradlew.bat b/ui/DrawableTinting/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/ui/DrawableTinting/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/ui/DrawableTinting/packaging.yaml b/ui/DrawableTinting/packaging.yaml
new file mode 100644
index 0000000..67e603d
--- /dev/null
+++ b/ui/DrawableTinting/packaging.yaml
@@ -0,0 +1,15 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+
+status: PUBLISHED
+technologies: [Android]
+categories: [UI]
+languages: [Java]
+solutions: [Mobile]
+github: googlesamples/android-DrawableTinting
+level: BEGINNER
+icon: DrawableTintingSample/src/main/res/drawable-xxhdpi/ic_launcher.png
+license: apache2
diff --git a/ui/notifications/BasicNotifications/settings.gradle b/ui/DrawableTinting/settings.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/settings.gradle
copy to ui/DrawableTinting/settings.gradle
diff --git a/ui/DrawableTinting/template-params.xml b/ui/DrawableTinting/template-params.xml
new file mode 100644
index 0000000..dfc3960
--- /dev/null
+++ b/ui/DrawableTinting/template-params.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.
+-->
+<sample>
+ <name>DrawableTinting</name>
+ <group>UI</group>
+ <package>com.example.android.drawabletinting</package>
+ <!-- change minSdk if needed-->
+ <minSdk>21</minSdk>
+ <strings>
+ <intro>
+ <![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.
+ ]]>
+ </intro>
+ </strings>
+ <template src="base"/>
+ <template src="FragmentView"/>
+ <common src="logger"/>
+ <common src="activities"/>
+</sample>
\ No newline at end of file
diff --git a/ui/notifications/BasicNotifications/Application/.gitignore b/ui/Interpolator/Application/.gitignore
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/.gitignore
copy to ui/Interpolator/Application/.gitignore
diff --git a/ui/notifications/BasicNotifications/Application/proguard-project.txt b/ui/Interpolator/Application/proguard-project.txt
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/proguard-project.txt
copy to ui/Interpolator/Application/proguard-project.txt
diff --git a/ui/Interpolator/Application/src/main/AndroidManifest.xml b/ui/Interpolator/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..85f50b2
--- /dev/null
+++ b/ui/Interpolator/Application/src/main/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/ui/Interpolator/Application/src/main/java/com/example/android/interpolator/InterpolatorFragment.java b/ui/Interpolator/Application/src/main/java/com/example/android/interpolator/InterpolatorFragment.java
new file mode 100644
index 0000000..07ecc95
--- /dev/null
+++ b/ui/Interpolator/Application/src/main/java/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/ui/Interpolator/Application/src/main/res/drawable-hdpi/ic_launcher.png b/ui/Interpolator/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..14a1e3a
--- /dev/null
+++ b/ui/Interpolator/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/Interpolator/Application/src/main/res/drawable-mdpi/ic_launcher.png b/ui/Interpolator/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..e328c42
--- /dev/null
+++ b/ui/Interpolator/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/Interpolator/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/ui/Interpolator/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..c78e0c4
--- /dev/null
+++ b/ui/Interpolator/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/Interpolator/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/ui/Interpolator/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..0be3d8b
--- /dev/null
+++ b/ui/Interpolator/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/Interpolator/Application/src/main/res/layout/interpolator_fragment.xml b/ui/Interpolator/Application/src/main/res/layout/interpolator_fragment.xml
new file mode 100644
index 0000000..6e1cb04
--- /dev/null
+++ b/ui/Interpolator/Application/src/main/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/ui/Interpolator/Application/src/main/res/values/color.xml b/ui/Interpolator/Application/src/main/res/values/color.xml
new file mode 100644
index 0000000..aa18437
--- /dev/null
+++ b/ui/Interpolator/Application/src/main/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/ui/Interpolator/Application/src/main/res/values/strings.xml b/ui/Interpolator/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..e2cfb2a
--- /dev/null
+++ b/ui/Interpolator/Application/src/main/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/ui/Interpolator/Application/tests/AndroidManifest.xml b/ui/Interpolator/Application/tests/AndroidManifest.xml
new file mode 100644
index 0000000..5e43ab9
--- /dev/null
+++ b/ui/Interpolator/Application/tests/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.
+-->
+
+<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.interpolatorplayground.tests"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
+ <!-- We add an application tag here just so that we can indicate that
+ this package needs to link against the android.test library,
+ which is needed when building test cases. -->
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!--
+ Specifies the instrumentation test runner used to run the tests.
+ -->
+ <instrumentation
+ android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.example.android.interpolatorplayground"
+ android:label="Tests for com.example.android.interpolatorplayground" />
+
+</manifest>
\ No newline at end of file
diff --git a/ui/Interpolator/Application/tests/src/com/example/android/interpolatorplayground/tests/SampleTests.java b/ui/Interpolator/Application/tests/src/com/example/android/interpolatorplayground/tests/SampleTests.java
new file mode 100644
index 0000000..7a0264b
--- /dev/null
+++ b/ui/Interpolator/Application/tests/src/com/example/android/interpolatorplayground/tests/SampleTests.java
@@ -0,0 +1,115 @@
+/*
+* 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.interpolatorplayground.tests;
+
+import com.example.android.interpolator.InterpolatorFragment;
+import com.example.android.interpolatorplayground.*;
+
+import android.animation.ObjectAnimator;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.view.animation.Interpolator;
+import android.widget.SeekBar;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+/**
+ * Tests for interpolatorplayground sample.
+ */
+public class SampleTests extends ActivityInstrumentationTestCase2<MainActivity> {
+
+ private MainActivity mTestActivity;
+ private InterpolatorFragment mTestFragment;
+
+ public SampleTests() {
+ super(MainActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ setActivityInitialTouchMode(true);
+
+ // Starts the activity under test using the default Intent with:
+ // action = {@link Intent#ACTION_MAIN}
+ // flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK}
+ // All other fields are null or empty.
+ mTestActivity = getActivity();
+ mTestFragment = (InterpolatorFragment)
+ mTestActivity.getSupportFragmentManager().getFragments().get(1);
+ }
+
+ /**
+ * Test if the test fixture has been set up correctly.
+ */
+ public void testPreconditions() {
+ //Try to add a message to add context to your assertions. These messages will be shown if
+ //a tests fails and make it easy to understand why a test failed
+ assertNotNull("mTestActivity is null", mTestActivity);
+ assertNotNull("mTestFragment is null", mTestFragment);
+ }
+
+ /**
+ * Test if all UI elements have been set up correctly.
+ */
+ public void testInitialisation() {
+ final int initialDuration = 750;
+ final String initialInterpolator = "Linear";
+
+ SeekBar durationBar = (SeekBar) getActivity().findViewById(R.id.durationSeek);
+ TextView durationLabel = (TextView) getActivity().findViewById(R.id.durationLabel);
+ Spinner interpolateSpinner = (Spinner) getActivity().findViewById(R.id.interpolatorSpinner);
+ Interpolator[] interpolators = mTestFragment.getInterpolators();
+
+ // Duration in progress bar
+ assertEquals(durationBar.getProgress(), initialDuration);
+ // Duration label
+ assertEquals(durationLabel.getText().toString(), getActivity().getResources().getString(R.string.animation_duration, initialDuration));
+ // Initial Interpolator
+ assertEquals((String) interpolateSpinner.getSelectedItem(), initialInterpolator);
+
+ // The number of loaded interpolators has to match the number of entries in the spinner
+ assertEquals(interpolators.length, interpolateSpinner.getCount());
+ // Test that all interpolators have been loaded
+ for (Interpolator i : interpolators) {
+ assertNotNull(i);
+ }
+
+ }
+
+ /**
+ * Test if all Interpolators can be used to start an animation.
+ */
+ @UiThreadTest
+ public void testStartInterpolators() {
+
+ // Start an animation for each interpolator
+ final Interpolator[] interpolators = mTestFragment.getInterpolators();
+
+ for (final Interpolator i : interpolators) {
+ // Start the animation
+ ObjectAnimator animator = mTestFragment.startAnimation(i, 1000L, mTestFragment.getPathIn());
+ // Check that the correct interpolator is used for the animation
+ assertEquals(i, animator.getInterpolator());
+ // Verify the animation has started
+ assertTrue(animator.isStarted());
+ // Cancel before starting the next animation
+ animator.cancel();
+ }
+ }
+}
\ No newline at end of file
diff --git a/ui/notifications/BasicNotifications/CONTRIB.md b/ui/Interpolator/CONTRIB.md
similarity index 100%
copy from ui/notifications/BasicNotifications/CONTRIB.md
copy to ui/Interpolator/CONTRIB.md
diff --git a/ui/notifications/BasicNotifications/LICENSE b/ui/Interpolator/LICENSE
similarity index 100%
copy from ui/notifications/BasicNotifications/LICENSE
copy to ui/Interpolator/LICENSE
diff --git a/ui/Interpolator/README.md b/ui/Interpolator/README.md
new file mode 100644
index 0000000..faf9086
--- /dev/null
+++ b/ui/Interpolator/README.md
@@ -0,0 +1,51 @@
+Android Interpolator Sample
+==============================
+
+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.
+
+Pre-requisites
+--------------
+
+- Android SDK (L Developer Preview)
+- Android Build Tools v20
+- Android Support Repository
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-Interpolator
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2014 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements. See the NOTICE file distributed with this work for
+additional information regarding copyright ownership. The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/ui/Interpolator/build.gradle b/ui/Interpolator/build.gradle
new file mode 100644
index 0000000..f9f6f65
--- /dev/null
+++ b/ui/Interpolator/build.gradle
@@ -0,0 +1,14 @@
+
+
+
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../build"
+ pathToSamplesCommon "../../common"
+}
+apply from: "../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/ui/Interpolator/buildSrc/build.gradle b/ui/Interpolator/buildSrc/build.gradle
new file mode 100644
index 0000000..29282af
--- /dev/null
+++ b/ui/Interpolator/buildSrc/build.gradle
@@ -0,0 +1,18 @@
+
+
+
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile 'org.freemarker:freemarker:2.3.20'
+}
+
+sourceSets {
+ main {
+ groovy {
+ srcDir new File(rootDir, "../../../../../build/buildSrc/src/main/groovy")
+ }
+ }
+}
+
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/ui/Interpolator/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
copy to ui/Interpolator/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/Interpolator/gradle/wrapper/gradle-wrapper.properties b/ui/Interpolator/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..56f685a
--- /dev/null
+++ b/ui/Interpolator/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Apr 10 15:27:10 PDT 2013
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-bin.zip
diff --git a/ui/notifications/BasicNotifications/gradlew b/ui/Interpolator/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to ui/Interpolator/gradlew
diff --git a/ui/Interpolator/gradlew.bat b/ui/Interpolator/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/ui/Interpolator/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/ui/Interpolator/packaging.yaml b/ui/Interpolator/packaging.yaml
new file mode 100644
index 0000000..962ed1b
--- /dev/null
+++ b/ui/Interpolator/packaging.yaml
@@ -0,0 +1,15 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+
+status: PUBLISHED
+technologies: [Android]
+categories: [UI]
+languages: [Java]
+solutions: [Mobile]
+github: googlesamples/android-Interpolator
+level: BEGINNER
+icon: InterpolatorSample/src/main/res/drawable-xxhdpi/ic_launcher.png
+license: apache2
diff --git a/ui/notifications/BasicNotifications/settings.gradle b/ui/Interpolator/settings.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/settings.gradle
copy to ui/Interpolator/settings.gradle
diff --git a/ui/Interpolator/template-params.xml b/ui/Interpolator/template-params.xml
new file mode 100644
index 0000000..268ee8a
--- /dev/null
+++ b/ui/Interpolator/template-params.xml
@@ -0,0 +1,44 @@
+<?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.
+-->
+
+
+
+<sample>
+ <name>Interpolator</name>
+ <group>UI</group>
+ <package>com.example.android.interpolator</package>
+
+ <!-- change minSdk if needed-->
+ <minSdk>21</minSdk>
+
+ <strings>
+ <intro>
+ <![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.
+ ]]>
+ </intro>
+ </strings>
+
+ <template src="base"/>
+ <template src="FragmentView"/>
+
+ <common src="logger"/>
+ <common src="activities"/>
+
+</sample>
diff --git a/ui/accessibility/BasicAccessibility/Application/src/main/AndroidManifest.xml b/ui/accessibility/BasicAccessibility/Application/src/main/AndroidManifest.xml
index d61d789..281114d 100644
--- a/ui/accessibility/BasicAccessibility/Application/src/main/AndroidManifest.xml
+++ b/ui/accessibility/BasicAccessibility/Application/src/main/AndroidManifest.xml
@@ -22,9 +22,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="11"
- android:targetSdkVersion="16" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application
android:allowBackup="true"
diff --git a/ui/accessibility/BasicAccessibility/Application/tests/AndroidManifest.xml b/ui/accessibility/BasicAccessibility/Application/tests/AndroidManifest.xml
index 8dc47be..e7c7840 100644
--- a/ui/accessibility/BasicAccessibility/Application/tests/AndroidManifest.xml
+++ b/ui/accessibility/BasicAccessibility/Application/tests/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/ui/actionbar/DoneBar/Application/src/main/AndroidManifest.xml b/ui/actionbar/DoneBar/Application/src/main/AndroidManifest.xml
index 4731114..820fae5 100644
--- a/ui/actionbar/DoneBar/Application/src/main/AndroidManifest.xml
+++ b/ui/actionbar/DoneBar/Application/src/main/AndroidManifest.xml
@@ -22,7 +22,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application android:label="@string/app_name"
android:icon="@drawable/ic_launcher"
diff --git a/ui/actionbar/DoneBar/Application/tests/AndroidManifest.xml b/ui/actionbar/DoneBar/Application/tests/AndroidManifest.xml
index 40eb5e1..6e910c7 100644
--- a/ui/actionbar/DoneBar/Application/tests/AndroidManifest.xml
+++ b/ui/actionbar/DoneBar/Application/tests/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/ui/actionbarcompat/ActionBarCompat-Basic/Application/src/main/AndroidManifest.xml b/ui/actionbarcompat/ActionBarCompat-Basic/Application/src/main/AndroidManifest.xml
index 332c055..2e19220 100644
--- a/ui/actionbarcompat/ActionBarCompat-Basic/Application/src/main/AndroidManifest.xml
+++ b/ui/actionbarcompat/ActionBarCompat-Basic/Application/src/main/AndroidManifest.xml
@@ -21,9 +21,7 @@
android:versionName="1.0">
<!-- ActionBarCompat provides an Action Bar from API v7 onwards -->
- <uses-sdk
- android:minSdkVersion="7"
- android:targetSdkVersion="17" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application
android:icon="@drawable/ic_launcher"
diff --git a/ui/actionbarcompat/ActionBarCompat-Basic/Application/tests/AndroidManifest.xml b/ui/actionbarcompat/ActionBarCompat-Basic/Application/tests/AndroidManifest.xml
index a2f7cfc..b73eb7f 100644
--- a/ui/actionbarcompat/ActionBarCompat-Basic/Application/tests/AndroidManifest.xml
+++ b/ui/actionbarcompat/ActionBarCompat-Basic/Application/tests/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/ui/actionbarcompat/ActionBarCompat-ListPopupMenu/Application/src/main/AndroidManifest.xml b/ui/actionbarcompat/ActionBarCompat-ListPopupMenu/Application/src/main/AndroidManifest.xml
index 114053e..695d4e0 100644
--- a/ui/actionbarcompat/ActionBarCompat-ListPopupMenu/Application/src/main/AndroidManifest.xml
+++ b/ui/actionbarcompat/ActionBarCompat-ListPopupMenu/Application/src/main/AndroidManifest.xml
@@ -21,9 +21,7 @@
android:versionName="1.0">
<!-- ActionBarCompat provides an implementation of Popup Menu from API v7 onwards -->
- <uses-sdk
- android:minSdkVersion="7"
- android:targetSdkVersion="17" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application
android:icon="@drawable/ic_launcher"
diff --git a/ui/actionbarcompat/ActionBarCompat-ListPopupMenu/Application/tests/AndroidManifest.xml b/ui/actionbarcompat/ActionBarCompat-ListPopupMenu/Application/tests/AndroidManifest.xml
index d23ab10..955a51a 100644
--- a/ui/actionbarcompat/ActionBarCompat-ListPopupMenu/Application/tests/AndroidManifest.xml
+++ b/ui/actionbarcompat/ActionBarCompat-ListPopupMenu/Application/tests/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/ui/actionbarcompat/ActionBarCompat-ListViewModalSelect/Application/src/main/AndroidManifest.xml b/ui/actionbarcompat/ActionBarCompat-ListViewModalSelect/Application/src/main/AndroidManifest.xml
index 800118c..5ee7466 100644
--- a/ui/actionbarcompat/ActionBarCompat-ListViewModalSelect/Application/src/main/AndroidManifest.xml
+++ b/ui/actionbarcompat/ActionBarCompat-ListViewModalSelect/Application/src/main/AndroidManifest.xml
@@ -25,9 +25,7 @@
<!--
ActionBarCompat provides an Action Bar from API v7 onwards
-->
- <uses-sdk
- android:minSdkVersion="7"
- android:targetSdkVersion="17" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application
android:icon="@drawable/ic_launcher"
diff --git a/ui/actionbarcompat/ActionBarCompat-ListViewModalSelect/Application/tests/AndroidManifest.xml b/ui/actionbarcompat/ActionBarCompat-ListViewModalSelect/Application/tests/AndroidManifest.xml
index d4a31c9..979b955 100644
--- a/ui/actionbarcompat/ActionBarCompat-ListViewModalSelect/Application/tests/AndroidManifest.xml
+++ b/ui/actionbarcompat/ActionBarCompat-ListViewModalSelect/Application/tests/AndroidManifest.xml
@@ -39,9 +39,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/ui/actionbarcompat/ActionBarCompat-SearchView/src/main/AndroidManifest.xml b/ui/actionbarcompat/ActionBarCompat-SearchView/src/main/AndroidManifest.xml
index b2554d6..30e4e97 100644
--- a/ui/actionbarcompat/ActionBarCompat-SearchView/src/main/AndroidManifest.xml
+++ b/ui/actionbarcompat/ActionBarCompat-SearchView/src/main/AndroidManifest.xml
@@ -23,9 +23,7 @@
ActionBarCompat provides an Action Bar with compatible SearchView
from API v7 onwards
-->
- <uses-sdk
- android:minSdkVersion="7"
- android:targetSdkVersion="17" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application
android:icon="@drawable/ic_launcher"
diff --git a/ui/actionbarcompat/ActionBarCompat-ShareActionProvider/Application/src/main/AndroidManifest.xml b/ui/actionbarcompat/ActionBarCompat-ShareActionProvider/Application/src/main/AndroidManifest.xml
index be1ed49..18dfc27 100644
--- a/ui/actionbarcompat/ActionBarCompat-ShareActionProvider/Application/src/main/AndroidManifest.xml
+++ b/ui/actionbarcompat/ActionBarCompat-ShareActionProvider/Application/src/main/AndroidManifest.xml
@@ -23,9 +23,7 @@
<!--
ActionBarCompat provides an Action Bar from API v7 onwards
-->
- <uses-sdk
- android:minSdkVersion="7"
- android:targetSdkVersion="17" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application
android:icon="@drawable/ic_launcher"
diff --git a/ui/actionbarcompat/ActionBarCompat-ShareActionProvider/Application/tests/AndroidManifest.xml b/ui/actionbarcompat/ActionBarCompat-ShareActionProvider/Application/tests/AndroidManifest.xml
index c52949c..e750ac3 100644
--- a/ui/actionbarcompat/ActionBarCompat-ShareActionProvider/Application/tests/AndroidManifest.xml
+++ b/ui/actionbarcompat/ActionBarCompat-ShareActionProvider/Application/tests/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/ui/actionbarcompat/ActionBarCompat-Styled/Application/src/main/AndroidManifest.xml b/ui/actionbarcompat/ActionBarCompat-Styled/Application/src/main/AndroidManifest.xml
index 06394c7..b9d266c 100644
--- a/ui/actionbarcompat/ActionBarCompat-Styled/Application/src/main/AndroidManifest.xml
+++ b/ui/actionbarcompat/ActionBarCompat-Styled/Application/src/main/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0" >
- <uses-sdk
- android:minSdkVersion="7"
- android:targetSdkVersion="17" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!--
Theme is set on the application so that our custom theme is used by
diff --git a/ui/actionbarcompat/ActionBarCompat-Styled/Application/tests/AndroidManifest.xml b/ui/actionbarcompat/ActionBarCompat-Styled/Application/tests/AndroidManifest.xml
index a990607..bf2fab4 100644
--- a/ui/actionbarcompat/ActionBarCompat-Styled/Application/tests/AndroidManifest.xml
+++ b/ui/actionbarcompat/ActionBarCompat-Styled/Application/tests/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/ui/notifications/BasicNotifications/Application/.gitignore b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/.gitignore
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/.gitignore
copy to ui/activityscenetransition/ActivitySceneTransitionBasic/Application/.gitignore
diff --git a/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/libs/volley.jar b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/libs/volley.jar
new file mode 100644
index 0000000..a38dac4
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/libs/volley.jar
Binary files differ
diff --git a/ui/notifications/BasicNotifications/Application/proguard-project.txt b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/proguard-project.txt
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/proguard-project.txt
copy to ui/activityscenetransition/ActivitySceneTransitionBasic/Application/proguard-project.txt
diff --git a/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/AndroidManifest.xml b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..ae64d6f
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/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/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/java/com/example/android/activityscenetransitionbasic/DetailActivity.java b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/java/com/example/android/activityscenetransitionbasic/DetailActivity.java
new file mode 100644
index 0000000..9589008
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/java/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.setTransitionName(VIEW_NAME_HEADER_IMAGE);
+ mHeaderTitle.setTransitionName(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/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/java/com/example/android/activityscenetransitionbasic/ImageMemoryCache.java b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/java/com/example/android/activityscenetransitionbasic/ImageMemoryCache.java
new file mode 100644
index 0000000..53d47ba
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/java/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/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/java/com/example/android/activityscenetransitionbasic/Item.java b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/java/com/example/android/activityscenetransitionbasic/Item.java
new file mode 100644
index 0000000..e211886
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/java/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/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/java/com/example/android/activityscenetransitionbasic/MainActivity.java b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/java/com/example/android/activityscenetransitionbasic/MainActivity.java
new file mode 100644
index 0000000..9c51789
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/java/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.setTransitionName("grid:image:" + item.getId());
+ name.setTransitionName("grid:name:" + item.getId());
+ // END_INCLUDE(grid_set_view_name)
+
+ return view;
+ }
+ }
+}
diff --git a/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/java/com/example/android/activityscenetransitionbasic/SquareFrameLayout.java b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/java/com/example/android/activityscenetransitionbasic/SquareFrameLayout.java
new file mode 100644
index 0000000..eece73e
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/java/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/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/drawable-hdpi/ic_launcher.png b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a598447
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/drawable-mdpi/ic_launcher.png b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..8aaa6c9
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..3667baa
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..e3c4a32
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/layout/details.xml b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/layout/details.xml
new file mode 100644
index 0000000..e61212e
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/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/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/layout/grid.xml b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/layout/grid.xml
new file mode 100644
index 0000000..4dded95
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/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/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/layout/grid_item.xml b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/layout/grid_item.xml
new file mode 100644
index 0000000..1d28dba
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/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/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/transition/grid_detail_transition.xml b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/transition/grid_detail_transition.xml
new file mode 100644
index 0000000..40be3d4
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/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/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/values-v21/styles.xml b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/values-v21/styles.xml
new file mode 100644
index 0000000..fd212b3
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/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/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/values/dimens.xml b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..b8e2e56
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/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/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/values/strings.xml b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..2aa0d3b
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/src/main/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/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/tests/AndroidManifest.xml b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/tests/AndroidManifest.xml
new file mode 100644
index 0000000..65521e6
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/tests/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?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.
+ -->
+<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.activityscenetransitionbasic.tests"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
+ <!-- We add an application tag here just so that we can indicate that
+ this package needs to link against the android.test library,
+ which is needed when building test cases. -->
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!--
+ Specifies the instrumentation test runner used to run the tests.
+ -->
+ <instrumentation
+ android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.example.android.activityscenetransitionbasic"
+ android:label="Tests for com.example.android.activityscenetransitionbasic" />
+
+</manifest>
diff --git a/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/tests/src/com/example/android/activityscenetransitionbasic/tests/SampleTests.java b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/tests/src/com/example/android/activityscenetransitionbasic/tests/SampleTests.java
new file mode 100644
index 0000000..f06d1ae
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/Application/tests/src/com/example/android/activityscenetransitionbasic/tests/SampleTests.java
@@ -0,0 +1,61 @@
+/*
+ * 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.tests;
+
+import com.example.android.activityscenetransitionbasic.*;
+
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+* Tests for ActivitySceneTransitionBasic sample.
+*/
+public class SampleTests extends ActivityInstrumentationTestCase2<MainActivity> {
+
+ private MainActivity mTestActivity;
+ private ActivitySceneTransitionBasicFragment mTestFragment;
+
+ public SampleTests() {
+ super(MainActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // Starts the activity under test using the default Intent with:
+ // action = {@link Intent#ACTION_MAIN}
+ // flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK}
+ // All other fields are null or empty.
+ mTestActivity = getActivity();
+ mTestFragment = (ActivitySceneTransitionBasicFragment)
+ mTestActivity.getSupportFragmentManager().getFragments().get(1);
+ }
+
+ /**
+ * Test if the test fixture has been set up correctly.
+ */
+ public void testPreconditions() {
+ //Try to add a message to add context to your assertions. These messages will be shown if
+ //a tests fails and make it easy to understand why a test failed
+ assertNotNull("mTestActivity is null", mTestActivity);
+ assertNotNull("mTestFragment is null", mTestFragment);
+ }
+
+ /**
+ * Add more tests below.
+ */
+
+}
diff --git a/ui/notifications/BasicNotifications/CONTRIB.md b/ui/activityscenetransition/ActivitySceneTransitionBasic/CONTRIB.md
similarity index 100%
copy from ui/notifications/BasicNotifications/CONTRIB.md
copy to ui/activityscenetransition/ActivitySceneTransitionBasic/CONTRIB.md
diff --git a/ui/notifications/BasicNotifications/LICENSE b/ui/activityscenetransition/ActivitySceneTransitionBasic/LICENSE
similarity index 100%
copy from ui/notifications/BasicNotifications/LICENSE
copy to ui/activityscenetransition/ActivitySceneTransitionBasic/LICENSE
diff --git a/ui/activityscenetransition/ActivitySceneTransitionBasic/README.md b/ui/activityscenetransition/ActivitySceneTransitionBasic/README.md
new file mode 100644
index 0000000..afb91ce
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/README.md
@@ -0,0 +1,51 @@
+Android ActivitySceneTransitionBasic Sample
+==============================
+
+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.
+
+Pre-requisites
+--------------
+
+- Android SDK (L Developer Preview)
+- Android Build Tools v20
+- Android Support Repository
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-ActivitySceneTransitionBasic
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2014 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements. See the NOTICE file distributed with this work for
+additional information regarding copyright ownership. The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/ui/activityscenetransition/ActivitySceneTransitionBasic/build.gradle b/ui/activityscenetransition/ActivitySceneTransitionBasic/build.gradle
new file mode 100644
index 0000000..be1fa82
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/build.gradle
@@ -0,0 +1,14 @@
+
+
+
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../../build"
+ pathToSamplesCommon "../../../common"
+}
+apply from: "../../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/ui/notifications/BasicNotifications/buildSrc/build.gradle b/ui/activityscenetransition/ActivitySceneTransitionBasic/buildSrc/build.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/buildSrc/build.gradle
copy to ui/activityscenetransition/ActivitySceneTransitionBasic/buildSrc/build.gradle
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/ui/activityscenetransition/ActivitySceneTransitionBasic/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
copy to ui/activityscenetransition/ActivitySceneTransitionBasic/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/activityscenetransition/ActivitySceneTransitionBasic/gradle/wrapper/gradle-wrapper.properties b/ui/activityscenetransition/ActivitySceneTransitionBasic/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..eca7f2f
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Fri Jun 13 16:21:29 BST 2014
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip
diff --git a/ui/notifications/BasicNotifications/gradlew b/ui/activityscenetransition/ActivitySceneTransitionBasic/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to ui/activityscenetransition/ActivitySceneTransitionBasic/gradlew
diff --git a/ui/activityscenetransition/ActivitySceneTransitionBasic/gradlew.bat b/ui/activityscenetransition/ActivitySceneTransitionBasic/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/ui/activityscenetransition/ActivitySceneTransitionBasic/packaging.yaml b/ui/activityscenetransition/ActivitySceneTransitionBasic/packaging.yaml
new file mode 100644
index 0000000..0d1188d
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/packaging.yaml
@@ -0,0 +1,15 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+
+status: PUBLISHED
+technologies: [Android]
+categories: [UI]
+languages: [Java]
+solutions: [Mobile]
+github: googlesamples/android-ActivitySceneTransitionBasic
+level: BEGINNER
+icon: ActivitySceneTransitionBasicSample/src/main/res/drawable-xxhdpi/ic_launcher.png
+license: apache2
diff --git a/ui/notifications/BasicNotifications/settings.gradle b/ui/activityscenetransition/ActivitySceneTransitionBasic/settings.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/settings.gradle
copy to ui/activityscenetransition/ActivitySceneTransitionBasic/settings.gradle
diff --git a/ui/activityscenetransition/ActivitySceneTransitionBasic/template-params.xml b/ui/activityscenetransition/ActivitySceneTransitionBasic/template-params.xml
new file mode 100644
index 0000000..ae954d4
--- /dev/null
+++ b/ui/activityscenetransition/ActivitySceneTransitionBasic/template-params.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.
+-->
+
+
+
+<sample>
+ <name>ActivitySceneTransitionBasic</name>
+ <group>UI</group>
+ <package>com.example.android.activityscenetransitionbasic</package>
+
+ <minSdk>21</minSdk>
+ <compileSdkVersion>21</compileSdkVersion>
+
+ <dependency_external>'libs/volley.jar'</dependency_external>
+
+ <strings>
+ <intro>
+ <![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.
+ ]]>
+ </intro>
+ </strings>
+
+ <template src="base"/>
+ <common src="logger"/>
+
+</sample>
diff --git a/ui/notifications/BasicNotifications/Application/.gitignore b/ui/activitytasks/DocumentCentricApps/Application/.gitignore
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/.gitignore
copy to ui/activitytasks/DocumentCentricApps/Application/.gitignore
diff --git a/ui/notifications/BasicNotifications/Application/proguard-project.txt b/ui/activitytasks/DocumentCentricApps/Application/proguard-project.txt
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/proguard-project.txt
copy to ui/activitytasks/DocumentCentricApps/Application/proguard-project.txt
diff --git a/ui/activitytasks/DocumentCentricApps/Application/src/main/AndroidManifest.xml b/ui/activitytasks/DocumentCentricApps/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..a1378ef
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricApps/Application/src/main/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/ui/activitytasks/DocumentCentricApps/Application/src/main/java/com/example/android/documentcentricapps/DocumentCentricActivity.java b/ui/activitytasks/DocumentCentricApps/Application/src/main/java/com/example/android/documentcentricapps/DocumentCentricActivity.java
new file mode 100644
index 0000000..92b5b43
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricApps/Application/src/main/java/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/ui/activitytasks/DocumentCentricApps/Application/src/main/java/com/example/android/documentcentricapps/NewDocumentActivity.java b/ui/activitytasks/DocumentCentricApps/Application/src/main/java/com/example/android/documentcentricapps/NewDocumentActivity.java
new file mode 100644
index 0000000..ac5e4f3
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricApps/Application/src/main/java/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/ui/activitytasks/DocumentCentricApps/Application/src/main/res/drawable-hdpi/ic_launcher.png b/ui/activitytasks/DocumentCentricApps/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..b1efaf4
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricApps/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/activitytasks/DocumentCentricApps/Application/src/main/res/drawable-mdpi/ic_launcher.png b/ui/activitytasks/DocumentCentricApps/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f5f9244
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricApps/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/activitytasks/DocumentCentricApps/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/ui/activitytasks/DocumentCentricApps/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..5d07b3f
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricApps/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/activitytasks/DocumentCentricApps/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/ui/activitytasks/DocumentCentricApps/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..6ef21e1
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricApps/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/activitytasks/DocumentCentricApps/Application/src/main/res/layout/activity_document_centric_main.xml b/ui/activitytasks/DocumentCentricApps/Application/src/main/res/layout/activity_document_centric_main.xml
new file mode 100755
index 0000000..5f62415
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricApps/Application/src/main/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/ui/activitytasks/DocumentCentricApps/Application/src/main/res/layout/activity_new_document.xml b/ui/activitytasks/DocumentCentricApps/Application/src/main/res/layout/activity_new_document.xml
new file mode 100644
index 0000000..2a6c58a
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricApps/Application/src/main/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/ui/activitytasks/DocumentCentricApps/Application/src/main/res/values/dimens.xml b/ui/activitytasks/DocumentCentricApps/Application/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..061387a
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricApps/Application/src/main/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/ui/activitytasks/DocumentCentricApps/Application/src/main/res/values/strings.xml b/ui/activitytasks/DocumentCentricApps/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..5f0e3f0
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricApps/Application/src/main/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/ui/activitytasks/DocumentCentricApps/Application/tests/src/com/example/android/documentcentricapps/tests/DocumentCentricAppsInstrumentationTest.java b/ui/activitytasks/DocumentCentricApps/Application/tests/src/com/example/android/documentcentricapps/tests/DocumentCentricAppsInstrumentationTest.java
new file mode 100644
index 0000000..3701f22
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricApps/Application/tests/src/com/example/android/documentcentricapps/tests/DocumentCentricAppsInstrumentationTest.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.tests;
+
+import com.example.android.documentcentricapps.DocumentCentricActivity;
+import com.example.android.documentcentricapps.R;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.TouchUtils;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.widget.Button;
+
+import java.util.List;
+
+/**
+ * Instrumentation tests for DocumentCentricApps sample.
+ */
+@LargeTest
+public class DocumentCentricAppsInstrumentationTest extends
+ ActivityInstrumentationTestCase2<DocumentCentricActivity> {
+
+ private DocumentCentricActivity mDocumentCentricActivity;
+
+ public DocumentCentricAppsInstrumentationTest() {
+ super(DocumentCentricActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mDocumentCentricActivity = getActivity();
+ }
+
+ public void testNewDocument_CreatesOverviewEntry() {
+ // Given a initialized Activity
+ assertNotNull("mDocumentCentricActivity is null", mDocumentCentricActivity);
+ final Button createNewDocumentButton = (Button) mDocumentCentricActivity
+ .findViewById(R.id.new_document_button);
+ assertNotNull(createNewDocumentButton);
+
+ // When "Create new Document" Button is clicked
+ TouchUtils.clickView(this, createNewDocumentButton);
+
+ // Then a entry in overview app tasks is created.
+ List<ActivityManager.AppTask> recentAppTasks = getRecentAppTasks();
+ assertEquals("# of recentAppTasks does not match", 2, recentAppTasks.size());
+ }
+
+ private List<ActivityManager.AppTask> getRecentAppTasks() {
+ ActivityManager activityManager = (ActivityManager) getInstrumentation().getTargetContext()
+ .getSystemService(Context.ACTIVITY_SERVICE);
+ List<ActivityManager.AppTask> appTasks = activityManager.getAppTasks();
+ return appTasks;
+ }
+
+}
\ No newline at end of file
diff --git a/ui/activitytasks/DocumentCentricApps/Application/tests/src/com/example/android/documentcentricapps/tests/DocumentCentricAppsUnitTest.java b/ui/activitytasks/DocumentCentricApps/Application/tests/src/com/example/android/documentcentricapps/tests/DocumentCentricAppsUnitTest.java
new file mode 100644
index 0000000..b3da974
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricApps/Application/tests/src/com/example/android/documentcentricapps/tests/DocumentCentricAppsUnitTest.java
@@ -0,0 +1,88 @@
+/*
+* 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.tests;
+
+import com.example.android.documentcentricapps.DocumentCentricActivity;
+import com.example.android.documentcentricapps.R;
+
+import android.content.Intent;
+import android.test.ActivityUnitTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.Button;
+import android.widget.CheckBox;
+
+/**
+ * Unit tests for DocumentCentricApps sample.
+ */
+@MediumTest
+public class DocumentCentricAppsUnitTest extends ActivityUnitTestCase<DocumentCentricActivity> {
+
+ private DocumentCentricActivity mDocumentCentricActivity;
+
+ public DocumentCentricAppsUnitTest() {
+ super(DocumentCentricActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ final Intent launchIntent = new Intent(getInstrumentation()
+ .getTargetContext(), DocumentCentricActivity.class);
+ mDocumentCentricActivity = startActivity(launchIntent, null, null);
+ }
+
+ public void testNewDocumentButton_IntentIsSentOnClick() {
+ // Given a initialized Activity
+ assertNotNull("mDocumentCentricActivity is null", mDocumentCentricActivity);
+ final Button createNewDocumentButton = (Button) mDocumentCentricActivity
+ .findViewById(R.id.new_document_button);
+ assertNotNull(createNewDocumentButton);
+
+ // When "Create new Document" Button is clicked
+ createNewDocumentButton.performClick();
+
+ // Then NewDocumentActivity is started with the correct flags
+ final Intent newDocumentIntent = getStartedActivityIntent();
+ assertNotNull("newDocumentIntent is null", newDocumentIntent);
+ assertEquals("intent is missing flag FLAG_ACTIVITY_NEW_DOCUMENT", Intent.FLAG_ACTIVITY_NEW_DOCUMENT,
+ newDocumentIntent.getFlags() & Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+ }
+
+ public void testNewDocumentButton_FlagMultipleSetWhenCheckboxIsChecked() {
+ // Given a initialized Activity and ticked "Create new task" checkbox
+ assertNotNull("mDocumentCentricActivity is null", mDocumentCentricActivity);
+ final Button createNewDocumentButton = (Button) mDocumentCentricActivity
+ .findViewById(R.id.new_document_button);
+ assertNotNull(createNewDocumentButton);
+ final CheckBox newTaskCheckbox = (CheckBox) mDocumentCentricActivity
+ .findViewById(R.id.multiple_task_checkbox);
+ assertNotNull(newTaskCheckbox);
+ newTaskCheckbox.setChecked(true);
+
+ // When "Create new Document" Button is clicked
+ createNewDocumentButton.performClick();
+
+ // Then NewDocumentActivity is started with the new document and multiple task flags
+ final Intent newDocumentIntent = getStartedActivityIntent();
+ assertNotNull("newDocumentIntent is null", newDocumentIntent);
+ assertEquals("intent is missing flag FLAG_ACTIVITY_NEW_DOCUMENT", Intent.FLAG_ACTIVITY_NEW_DOCUMENT,
+ newDocumentIntent.getFlags() & Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+ assertEquals("intent is missing flag FLAG_ACTIVITY_MULTIPLE_TASK", Intent.FLAG_ACTIVITY_MULTIPLE_TASK,
+ newDocumentIntent.getFlags() & Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ }
+
+}
\ No newline at end of file
diff --git a/ui/notifications/BasicNotifications/CONTRIB.md b/ui/activitytasks/DocumentCentricApps/CONTRIB.md
similarity index 100%
copy from ui/notifications/BasicNotifications/CONTRIB.md
copy to ui/activitytasks/DocumentCentricApps/CONTRIB.md
diff --git a/ui/notifications/BasicNotifications/LICENSE b/ui/activitytasks/DocumentCentricApps/LICENSE
similarity index 100%
copy from ui/notifications/BasicNotifications/LICENSE
copy to ui/activitytasks/DocumentCentricApps/LICENSE
diff --git a/ui/activitytasks/DocumentCentricApps/build.gradle b/ui/activitytasks/DocumentCentricApps/build.gradle
new file mode 100644
index 0000000..be1fa82
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricApps/build.gradle
@@ -0,0 +1,14 @@
+
+
+
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../../build"
+ pathToSamplesCommon "../../../common"
+}
+apply from: "../../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/ui/notifications/BasicNotifications/buildSrc/build.gradle b/ui/activitytasks/DocumentCentricApps/buildSrc/build.gradle
similarity index 100%
rename from ui/notifications/BasicNotifications/buildSrc/build.gradle
rename to ui/activitytasks/DocumentCentricApps/buildSrc/build.gradle
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/ui/activitytasks/DocumentCentricApps/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
copy to ui/activitytasks/DocumentCentricApps/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/activitytasks/DocumentCentricApps/gradle/wrapper/gradle-wrapper.properties b/ui/activitytasks/DocumentCentricApps/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..56f685a
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricApps/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Apr 10 15:27:10 PDT 2013
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-bin.zip
diff --git a/ui/notifications/BasicNotifications/gradlew b/ui/activitytasks/DocumentCentricApps/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to ui/activitytasks/DocumentCentricApps/gradlew
diff --git a/ui/notifications/BasicNotifications/gradlew.bat b/ui/activitytasks/DocumentCentricApps/gradlew.bat
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew.bat
copy to ui/activitytasks/DocumentCentricApps/gradlew.bat
diff --git a/ui/activitytasks/DocumentCentricApps/settings.gradle b/ui/activitytasks/DocumentCentricApps/settings.gradle
new file mode 100644
index 0000000..aa94981
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricApps/settings.gradle
@@ -0,0 +1 @@
+include 'Application'
\ No newline at end of file
diff --git a/ui/activitytasks/DocumentCentricApps/template-params.xml b/ui/activitytasks/DocumentCentricApps/template-params.xml
new file mode 100644
index 0000000..589e9f1
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricApps/template-params.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.
+-->
+
+
+
+<sample>
+ <name>DocumentCentricRecents</name>
+ <group>UI</group>
+ <package>com.example.android.documentcentricapps</package>
+
+ <!-- change minSdk if needed-->
+ <minSdk>21</minSdk>
+
+ <strings>
+ <intro>
+ <![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.
+ ]]>
+ </intro>
+ </strings>
+
+ <template src="base"/>
+
+</sample>
diff --git a/ui/notifications/BasicNotifications/Application/.gitignore b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/.gitignore
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/.gitignore
copy to ui/activitytasks/DocumentCentricRelinquishIdentity/Application/.gitignore
diff --git a/ui/notifications/BasicNotifications/Application/proguard-project.txt b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/proguard-project.txt
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/proguard-project.txt
copy to ui/activitytasks/DocumentCentricRelinquishIdentity/Application/proguard-project.txt
diff --git a/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/AndroidManifest.xml b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..00cfd13
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/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/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/java/com/example/android/documentcentricrelinquishidentity/NewDocumentActivity.java b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/java/com/example/android/documentcentricrelinquishidentity/NewDocumentActivity.java
new file mode 100644
index 0000000..c3037d6
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/java/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/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/java/com/example/android/documentcentricrelinquishidentity/RelinquishIdentityActivity.java b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/java/com/example/android/documentcentricrelinquishidentity/RelinquishIdentityActivity.java
new file mode 100644
index 0000000..d2ce228
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/java/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/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/drawable-hdpi/ic_launcher.png b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..b1efaf4
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/drawable-hdpi/new_icon.png b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/drawable-hdpi/new_icon.png
new file mode 100755
index 0000000..34767f3
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/drawable-hdpi/new_icon.png
Binary files differ
diff --git a/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/drawable-mdpi/ic_launcher.png b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f5f9244
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/drawable-mdpi/new_icon.png b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/drawable-mdpi/new_icon.png
new file mode 100755
index 0000000..f1b91b9
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/drawable-mdpi/new_icon.png
Binary files differ
diff --git a/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..5d07b3f
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/drawable-xhdpi/new_icon.png b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/drawable-xhdpi/new_icon.png
new file mode 100755
index 0000000..412a06d
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/drawable-xhdpi/new_icon.png
Binary files differ
diff --git a/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..6ef21e1
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/drawable-xxhdpi/new_icon.png b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/drawable-xxhdpi/new_icon.png
new file mode 100755
index 0000000..a159b16
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/drawable-xxhdpi/new_icon.png
Binary files differ
diff --git a/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/layout/activity_document.xml b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/layout/activity_document.xml
new file mode 100644
index 0000000..b9f6755
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/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/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/layout/activity_relinquish_identity.xml b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/layout/activity_relinquish_identity.xml
new file mode 100755
index 0000000..7552eae
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/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/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/values/dimens.xml b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..061387a
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/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/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/values/strings.xml b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..4ddf4c7
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricRelinquishIdentity/Application/src/main/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/ui/activitytasks/DocumentCentricRelinquishIdentity/build.gradle b/ui/activitytasks/DocumentCentricRelinquishIdentity/build.gradle
new file mode 100644
index 0000000..be1fa82
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricRelinquishIdentity/build.gradle
@@ -0,0 +1,14 @@
+
+
+
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../../build"
+ pathToSamplesCommon "../../../common"
+}
+apply from: "../../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/ui/notifications/BasicNotifications/buildSrc/build.gradle b/ui/activitytasks/DocumentCentricRelinquishIdentity/buildSrc/build.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/buildSrc/build.gradle
copy to ui/activitytasks/DocumentCentricRelinquishIdentity/buildSrc/build.gradle
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/ui/activitytasks/DocumentCentricRelinquishIdentity/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
copy to ui/activitytasks/DocumentCentricRelinquishIdentity/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/activitytasks/DocumentCentricRelinquishIdentity/gradle/wrapper/gradle-wrapper.properties b/ui/activitytasks/DocumentCentricRelinquishIdentity/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..56f685a
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricRelinquishIdentity/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Apr 10 15:27:10 PDT 2013
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-bin.zip
diff --git a/ui/notifications/BasicNotifications/gradlew b/ui/activitytasks/DocumentCentricRelinquishIdentity/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to ui/activitytasks/DocumentCentricRelinquishIdentity/gradlew
diff --git a/ui/notifications/BasicNotifications/gradlew.bat b/ui/activitytasks/DocumentCentricRelinquishIdentity/gradlew.bat
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew.bat
copy to ui/activitytasks/DocumentCentricRelinquishIdentity/gradlew.bat
diff --git a/ui/notifications/BasicNotifications/settings.gradle b/ui/activitytasks/DocumentCentricRelinquishIdentity/settings.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/settings.gradle
copy to ui/activitytasks/DocumentCentricRelinquishIdentity/settings.gradle
diff --git a/ui/activitytasks/DocumentCentricRelinquishIdentity/template-params.xml b/ui/activitytasks/DocumentCentricRelinquishIdentity/template-params.xml
new file mode 100644
index 0000000..8364071
--- /dev/null
+++ b/ui/activitytasks/DocumentCentricRelinquishIdentity/template-params.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.
+-->
+
+
+
+<sample>
+ <name>DocumentCentricRelinquishIdentity</name>
+ <group>UI</group>
+ <package>com.example.android.documentcentricrelinquishidentity</package>
+
+ <!-- change minSdk if needed-->
+ <minSdk>21</minSdk>
+
+ <strings>
+ <intro>
+ <![CDATA[
+ This sample shows how to relinquish identity to activities above it in the task stack.
+ ]]>
+ </intro>
+ </strings>
+
+ <template src="base"/>
+
+</sample>
diff --git a/ui/graphics/DisplayingBitmaps/Application/src/main/AndroidManifest.xml b/ui/graphics/DisplayingBitmaps/Application/src/main/AndroidManifest.xml
index 23db308..a580277 100644
--- a/ui/graphics/DisplayingBitmaps/Application/src/main/AndroidManifest.xml
+++ b/ui/graphics/DisplayingBitmaps/Application/src/main/AndroidManifest.xml
@@ -20,7 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
diff --git a/ui/graphics/DisplayingBitmaps/Application/tests/AndroidManifest.xml b/ui/graphics/DisplayingBitmaps/Application/tests/AndroidManifest.xml
index 4ddcbbb..a93e21f 100644
--- a/ui/graphics/DisplayingBitmaps/Application/tests/AndroidManifest.xml
+++ b/ui/graphics/DisplayingBitmaps/Application/tests/AndroidManifest.xml
@@ -39,9 +39,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/ui/notifications/BasicNotifications/Application/.gitignore b/ui/graphics/PdfRendererBasic/Application/.gitignore
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/.gitignore
copy to ui/graphics/PdfRendererBasic/Application/.gitignore
diff --git a/ui/graphics/PdfRendererBasic/Application/README-fragmentview.txt b/ui/graphics/PdfRendererBasic/Application/README-fragmentview.txt
new file mode 100644
index 0000000..38d903f
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/Application/README-fragmentview.txt
@@ -0,0 +1,37 @@
+<!--
+ 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.
+-->
+
+Steps to implement FragmentView template:
+-in template-params.xml.ftl:
+ -add the following line to common imports
+ <common src="activities"/>
+
+-Add a Fragment to show behavior. In your MainActivity.java class, it will reference a Fragment
+ called (yourProjectName)Fragment.java. Create that file in your project, using the "main" source
+ folder instead of "common" or "templates".
+ For instance, if your package name is com.example.foo, create the file
+ src/main/java/com/example/foo/FooFragment.java
+
+
+-Within this fragment, make sure that the onCreate method has the line
+ "setHasOptionsMenu(true);", to enable the fragment to handle menu events.
+
+-In order to override menu events, override onOptionsItemSelected.
+
+-refer to sampleSamples/fragmentViewSample for a reference implementation of a
+project built on this template.
+
+
diff --git a/ui/notifications/BasicNotifications/Application/proguard-project.txt b/ui/graphics/PdfRendererBasic/Application/proguard-project.txt
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/proguard-project.txt
copy to ui/graphics/PdfRendererBasic/Application/proguard-project.txt
diff --git a/ui/graphics/PdfRendererBasic/Application/src/main/AndroidManifest.xml b/ui/graphics/PdfRendererBasic/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..2287067
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/Application/src/main/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.pdfrendererbasic"
+ 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/ui/graphics/PdfRendererBasic/Application/src/main/assets/sample.pdf b/ui/graphics/PdfRendererBasic/Application/src/main/assets/sample.pdf
new file mode 100644
index 0000000..73f68b1
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/Application/src/main/assets/sample.pdf
Binary files differ
diff --git a/ui/graphics/PdfRendererBasic/Application/src/main/java/com/example/android/pdfrendererbasic/MainActivity.java b/ui/graphics/PdfRendererBasic/Application/src/main/java/com/example/android/pdfrendererbasic/MainActivity.java
new file mode 100644
index 0000000..6b7e8b4
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/Application/src/main/java/com/example/android/pdfrendererbasic/MainActivity.java
@@ -0,0 +1,59 @@
+/*
+ * 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.pdfrendererbasic;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+
+public class MainActivity extends Activity {
+
+ public static final String FRAGMENT_PDF_RENDERER_BASIC = "pdf_renderer_basic";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main_real);
+ if (savedInstanceState == null) {
+ getFragmentManager().beginTransaction()
+ .add(R.id.container, new PdfRendererBasicFragment(),
+ FRAGMENT_PDF_RENDERER_BASIC)
+ .commit();
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.action_info:
+ new AlertDialog.Builder(this)
+ .setMessage(R.string.intro_message)
+ .setPositiveButton(android.R.string.ok, null)
+ .show();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+}
diff --git a/ui/graphics/PdfRendererBasic/Application/src/main/java/com/example/android/pdfrendererbasic/PdfRendererBasicFragment.java b/ui/graphics/PdfRendererBasic/Application/src/main/java/com/example/android/pdfrendererbasic/PdfRendererBasicFragment.java
new file mode 100644
index 0000000..e413c65
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/Application/src/main/java/com/example/android/pdfrendererbasic/PdfRendererBasicFragment.java
@@ -0,0 +1,221 @@
+/*
+ * 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.pdfrendererbasic;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.pdf.PdfRenderer;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.Toast;
+
+import java.io.IOException;
+
+/**
+ * This fragment has a big {@ImageView} that shows PDF pages, and 2 {@link android.widget.Button}s to move between
+ * pages. We use a {@link android.graphics.pdf.PdfRenderer} to render PDF pages as {@link android.graphics.Bitmap}s.
+ */
+public class PdfRendererBasicFragment extends Fragment implements View.OnClickListener {
+
+ /**
+ * Key string for saving the state of current page index.
+ */
+ private static final String STATE_CURRENT_PAGE_INDEX = "current_page_index";
+
+ /**
+ * File descriptor of the PDF.
+ */
+ private ParcelFileDescriptor mFileDescriptor;
+
+ /**
+ * {@link android.graphics.pdf.PdfRenderer} to render the PDF.
+ */
+ private PdfRenderer mPdfRenderer;
+
+ /**
+ * Page that is currently shown on the screen.
+ */
+ private PdfRenderer.Page mCurrentPage;
+
+ /**
+ * {@link android.widget.ImageView} that shows a PDF page as a {@link android.graphics.Bitmap}
+ */
+ private ImageView mImageView;
+
+ /**
+ * {@link android.widget.Button} to move to the previous page.
+ */
+ private Button mButtonPrevious;
+
+ /**
+ * {@link android.widget.Button} to move to the next page.
+ */
+ private Button mButtonNext;
+
+ public PdfRendererBasicFragment() {
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_pdf_renderer_basic, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ // Retain view references.
+ mImageView = (ImageView) view.findViewById(R.id.image);
+ mButtonPrevious = (Button) view.findViewById(R.id.previous);
+ mButtonNext = (Button) view.findViewById(R.id.next);
+ // Bind events.
+ mButtonPrevious.setOnClickListener(this);
+ mButtonNext.setOnClickListener(this);
+ // Show the first page by default.
+ int index = 0;
+ // If there is a savedInstanceState (screen orientations, etc.), we restore the page index.
+ if (null != savedInstanceState) {
+ index = savedInstanceState.getInt(STATE_CURRENT_PAGE_INDEX, 0);
+ }
+ showPage(index);
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ try {
+ openRenderer(activity);
+ } catch (IOException e) {
+ e.printStackTrace();
+ Toast.makeText(activity, "Error! " + e.getMessage(), Toast.LENGTH_SHORT).show();
+ activity.finish();
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ try {
+ closeRenderer();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ super.onDetach();
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ if (null != mCurrentPage) {
+ outState.putInt(STATE_CURRENT_PAGE_INDEX, mCurrentPage.getIndex());
+ }
+ }
+
+ /**
+ * Sets up a {@link android.graphics.pdf.PdfRenderer} and related resources.
+ */
+ private void openRenderer(Context context) throws IOException {
+ // In this sample, we read a PDF from the assets directory.
+ mFileDescriptor = context.getAssets().openFd("sample.pdf").getParcelFileDescriptor();
+ // This is the PdfRenderer we use to render the PDF.
+ mPdfRenderer = new PdfRenderer(mFileDescriptor);
+ }
+
+ /**
+ * Closes the {@link android.graphics.pdf.PdfRenderer} and related resources.
+ *
+ * @throws java.io.IOException When the PDF file cannot be closed.
+ */
+ private void closeRenderer() throws IOException {
+ if (null != mCurrentPage) {
+ mCurrentPage.close();
+ }
+ mPdfRenderer.close();
+ mFileDescriptor.close();
+ }
+
+ /**
+ * Shows the specified page of PDF to the screen.
+ *
+ * @param index The page index.
+ */
+ private void showPage(int index) {
+ if (mPdfRenderer.getPageCount() <= index) {
+ return;
+ }
+ // Make sure to close the current page before opening another one.
+ if (null != mCurrentPage) {
+ mCurrentPage.close();
+ }
+ // Use `openPage` to open a specific page in PDF.
+ mCurrentPage = mPdfRenderer.openPage(index);
+ // Important: the destination bitmap must be ARGB (not RGB).
+ Bitmap bitmap = Bitmap.createBitmap(mCurrentPage.getWidth(), mCurrentPage.getHeight(),
+ Bitmap.Config.ARGB_8888);
+ // Here, we render the page onto the Bitmap.
+ // To render a portion of the page, use the second and third parameter. Pass nulls to get
+ // the default result.
+ // Pass either RENDER_MODE_FOR_DISPLAY or RENDER_MODE_FOR_PRINT for the last parameter.
+ mCurrentPage.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
+ // We are ready to show the Bitmap to user.
+ mImageView.setImageBitmap(bitmap);
+ updateUi();
+ }
+
+ /**
+ * Updates the state of 2 control buttons in response to the current page index.
+ */
+ private void updateUi() {
+ int index = mCurrentPage.getIndex();
+ int pageCount = mPdfRenderer.getPageCount();
+ mButtonPrevious.setEnabled(0 != index);
+ mButtonNext.setEnabled(index + 1 < pageCount);
+ getActivity().setTitle(getString(R.string.app_name_with_index, index + 1, pageCount));
+ }
+
+ /**
+ * Gets the number of pages in the PDF. This method is marked as public for testing.
+ *
+ * @return The number of pages.
+ */
+ public int getPageCount() {
+ return mPdfRenderer.getPageCount();
+ }
+
+ @Override
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.previous: {
+ // Move to the previous page
+ showPage(mCurrentPage.getIndex() - 1);
+ break;
+ }
+ case R.id.next: {
+ // Move to the next page
+ showPage(mCurrentPage.getIndex() + 1);
+ break;
+ }
+ }
+ }
+
+}
diff --git a/ui/graphics/PdfRendererBasic/Application/src/main/res/drawable-hdpi/ic_action_info.png b/ui/graphics/PdfRendererBasic/Application/src/main/res/drawable-hdpi/ic_action_info.png
new file mode 100644
index 0000000..32bd1aa
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/Application/src/main/res/drawable-hdpi/ic_action_info.png
Binary files differ
diff --git a/ui/graphics/PdfRendererBasic/Application/src/main/res/drawable-hdpi/ic_launcher.png b/ui/graphics/PdfRendererBasic/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..0c9b694
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/graphics/PdfRendererBasic/Application/src/main/res/drawable-mdpi/ic_action_info.png b/ui/graphics/PdfRendererBasic/Application/src/main/res/drawable-mdpi/ic_action_info.png
new file mode 100644
index 0000000..8efbbf8
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/Application/src/main/res/drawable-mdpi/ic_action_info.png
Binary files differ
diff --git a/ui/graphics/PdfRendererBasic/Application/src/main/res/drawable-mdpi/ic_launcher.png b/ui/graphics/PdfRendererBasic/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..1a6c3d0
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/graphics/PdfRendererBasic/Application/src/main/res/drawable-xhdpi/ic_action_info.png b/ui/graphics/PdfRendererBasic/Application/src/main/res/drawable-xhdpi/ic_action_info.png
new file mode 100644
index 0000000..ba143ea
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/Application/src/main/res/drawable-xhdpi/ic_action_info.png
Binary files differ
diff --git a/ui/graphics/PdfRendererBasic/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/ui/graphics/PdfRendererBasic/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..2081f40
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/graphics/PdfRendererBasic/Application/src/main/res/drawable-xxhdpi/ic_action_info.png b/ui/graphics/PdfRendererBasic/Application/src/main/res/drawable-xxhdpi/ic_action_info.png
new file mode 100644
index 0000000..394eb7e
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/Application/src/main/res/drawable-xxhdpi/ic_action_info.png
Binary files differ
diff --git a/ui/graphics/PdfRendererBasic/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/ui/graphics/PdfRendererBasic/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b506de4
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/graphics/PdfRendererBasic/Application/src/main/res/layout/activity_main_real.xml b/ui/graphics/PdfRendererBasic/Application/src/main/res/layout/activity_main_real.xml
new file mode 100644
index 0000000..dcd52be
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/Application/src/main/res/layout/activity_main_real.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+<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=".MainActivity"
+ tools:ignore="MergeRootFrame" />
diff --git a/ui/graphics/PdfRendererBasic/Application/src/main/res/layout/fragment_pdf_renderer_basic.xml b/ui/graphics/PdfRendererBasic/Application/src/main/res/layout/fragment_pdf_renderer_basic.xml
new file mode 100644
index 0000000..4a7799b
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/Application/src/main/res/layout/fragment_pdf_renderer_basic.xml
@@ -0,0 +1,56 @@
+<?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"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ tools:context=".MainActivity$PlaceholderFragment">
+
+ <ImageView
+ android:id="@+id/image"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:background="@android:color/white"
+ android:scaleType="fitCenter" />
+
+ <LinearLayout
+ style="?android:attr/buttonBarStyle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:measureWithLargestChild="true"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/previous"
+ style="?android:attr/buttonBarButtonStyle"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/previous" />
+
+ <Button
+ android:id="@+id/next"
+ style="?android:attr/buttonBarButtonStyle"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/next" />
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/ui/graphics/PdfRendererBasic/Application/src/main/res/menu/main.xml b/ui/graphics/PdfRendererBasic/Application/src/main/res/menu/main.xml
new file mode 100644
index 0000000..fa452e1
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/Application/src/main/res/menu/main.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:id="@+id/action_info"
+ android:icon="@drawable/ic_action_info"
+ android:showAsAction="always"
+ android:title="@string/info" />
+
+</menu>
\ No newline at end of file
diff --git a/ui/graphics/PdfRendererBasic/Application/src/main/res/values/strings.xml b/ui/graphics/PdfRendererBasic/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..e0182fd
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/Application/src/main/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?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>
+
+ <string name="app_name_with_index">PdfRendererBasic (%1$d/%2$d)</string>
+ <string name="info">Info</string>
+ <string name="previous">Previous</string>
+ <string name="next">Next</string>
+
+</resources>
diff --git a/ui/graphics/PdfRendererBasic/Application/tests/AndroidManifest.xml b/ui/graphics/PdfRendererBasic/Application/tests/AndroidManifest.xml
new file mode 100644
index 0000000..54829c7
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/Application/tests/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?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.
+ -->
+<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest
+ package="com.example.android.pdfrendererbasic.tests"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
+ <!-- We add an application tag here just so that we can indicate that
+ this package needs to link against the android.test library,
+ which is needed when building test cases. -->
+ <application>
+ <uses-library android:name="android.test.runner"/>
+ </application>
+
+ <!--
+ Specifies the instrumentation test runner used to run the tests.
+ -->
+ <instrumentation
+ android:name="android.test.InstrumentationTestRunner"
+ android:label="Tests for com.example.android.pdfrendererbasic"
+ android:targetPackage="com.example.android.pdfrendererbasic"/>
+
+</manifest>
diff --git a/ui/graphics/PdfRendererBasic/Application/tests/src/com/example/android/pdfrendererbasic/tests/PdfRendererBasicFragmentTests.java b/ui/graphics/PdfRendererBasic/Application/tests/src/com/example/android/pdfrendererbasic/tests/PdfRendererBasicFragmentTests.java
new file mode 100644
index 0000000..0f94cbf
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/Application/tests/src/com/example/android/pdfrendererbasic/tests/PdfRendererBasicFragmentTests.java
@@ -0,0 +1,132 @@
+/*
+ * 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.pdfrendererbasic.tests;
+
+import android.content.pm.ActivityInfo;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.TouchUtils;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+import android.widget.Button;
+
+import com.example.android.pdfrendererbasic.MainActivity;
+import com.example.android.pdfrendererbasic.PdfRendererBasicFragment;
+import com.example.android.pdfrendererbasic.R;
+
+/**
+ * Tests for PdfRendererBasic sample.
+ */
+public class PdfRendererBasicFragmentTests extends ActivityInstrumentationTestCase2<MainActivity> {
+
+ private MainActivity mActivity;
+ private PdfRendererBasicFragment mFragment;
+
+ private Button mButtonPrevious;
+ private Button mButtonNext;
+
+ public PdfRendererBasicFragmentTests() {
+ super(MainActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mActivity = getActivity();
+ mFragment = (PdfRendererBasicFragment) mActivity.getFragmentManager()
+ .findFragmentByTag(MainActivity.FRAGMENT_PDF_RENDERER_BASIC);
+ }
+
+ @LargeTest
+ public void testActivityTitle() {
+ // The title of the activity should be "PdfRendererBasic (1/10)" at first
+ String expectedActivityTitle = mActivity.getString(R.string.app_name_with_index, 1,
+ mFragment.getPageCount());
+ assertEquals(expectedActivityTitle, mActivity.getTitle());
+ }
+
+ @LargeTest
+ public void testButtons_previousDisabledAtFirst() {
+ setUpButtons();
+ // Check that the previous button is disabled at first
+ assertFalse(mButtonPrevious.isEnabled());
+ // The next button should be enabled
+ assertTrue(mButtonNext.isEnabled());
+ }
+
+ @LargeTest
+ public void testButtons_bothEnabledInMiddle() {
+ setUpButtons();
+ turnPages(1);
+ // Two buttons should be both enabled
+ assertTrue(mButtonPrevious.isEnabled());
+ assertTrue(mButtonNext.isEnabled());
+ }
+
+ @LargeTest
+ public void testButtons_nextDisabledLastPage() {
+ setUpButtons();
+ int pageCount = mFragment.getPageCount();
+ // Click till it reaches the last page
+ turnPages(pageCount - 1);
+ // Check the page count
+ String expectedActivityTitle = mActivity.getString(R.string.app_name_with_index,
+ pageCount, pageCount);
+ assertEquals(expectedActivityTitle, mActivity.getTitle());
+ // The previous button should be enabled
+ assertTrue(mButtonPrevious.isEnabled());
+ // Check that the next button is disabled
+ assertFalse(mButtonNext.isEnabled());
+ }
+
+ @LargeTest
+ public void testOrientationChangePreserveState() {
+ mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+ setUpButtons();
+ turnPages(1);
+ int pageCount = mFragment.getPageCount();
+ String expectedActivityTitle = mActivity.getString(R.string.app_name_with_index,
+ 2, pageCount);
+ assertEquals(expectedActivityTitle, mActivity.getTitle());
+ mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+ // Check that the title is the same after orientation change
+ assertEquals(expectedActivityTitle, mActivity.getTitle());
+ }
+
+ /**
+ * Prepares references to the buttons "Previous" and "Next".
+ */
+ private void setUpButtons() {
+ View view = mFragment.getView();
+ assertNotNull(view);
+ mButtonPrevious = (Button) view.findViewById(R.id.previous);
+ assertNotNull(mButtonPrevious);
+ mButtonNext = (Button) view.findViewById(R.id.next);
+ assertNotNull(mButtonNext);
+ }
+
+ /**
+ * Click the "Next" button to turn the pages.
+ *
+ * @param count The number of times to turn pages.
+ */
+ private void turnPages(int count) {
+ for (int i = 0; i < count; ++i) {
+ TouchUtils.clickView(this, mButtonNext);
+ }
+ }
+
+}
diff --git a/ui/notifications/BasicNotifications/CONTRIB.md b/ui/graphics/PdfRendererBasic/CONTRIB.md
similarity index 100%
copy from ui/notifications/BasicNotifications/CONTRIB.md
copy to ui/graphics/PdfRendererBasic/CONTRIB.md
diff --git a/ui/notifications/BasicNotifications/LICENSE b/ui/graphics/PdfRendererBasic/LICENSE
similarity index 100%
copy from ui/notifications/BasicNotifications/LICENSE
copy to ui/graphics/PdfRendererBasic/LICENSE
diff --git a/ui/graphics/PdfRendererBasic/build.gradle b/ui/graphics/PdfRendererBasic/build.gradle
new file mode 100644
index 0000000..be1fa82
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/build.gradle
@@ -0,0 +1,14 @@
+
+
+
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../../build"
+ pathToSamplesCommon "../../../common"
+}
+apply from: "../../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/ui/notifications/BasicNotifications/buildSrc/build.gradle b/ui/graphics/PdfRendererBasic/buildSrc/build.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/buildSrc/build.gradle
copy to ui/graphics/PdfRendererBasic/buildSrc/build.gradle
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/ui/graphics/PdfRendererBasic/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
copy to ui/graphics/PdfRendererBasic/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties b/ui/graphics/PdfRendererBasic/gradle/wrapper/gradle-wrapper.properties
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties
copy to ui/graphics/PdfRendererBasic/gradle/wrapper/gradle-wrapper.properties
diff --git a/ui/notifications/BasicNotifications/gradlew b/ui/graphics/PdfRendererBasic/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to ui/graphics/PdfRendererBasic/gradlew
diff --git a/ui/notifications/BasicNotifications/gradlew.bat b/ui/graphics/PdfRendererBasic/gradlew.bat
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew.bat
copy to ui/graphics/PdfRendererBasic/gradlew.bat
diff --git a/ui/notifications/BasicNotifications/settings.gradle b/ui/graphics/PdfRendererBasic/settings.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/settings.gradle
copy to ui/graphics/PdfRendererBasic/settings.gradle
diff --git a/ui/graphics/PdfRendererBasic/template-params.xml b/ui/graphics/PdfRendererBasic/template-params.xml
new file mode 100644
index 0000000..a87261d
--- /dev/null
+++ b/ui/graphics/PdfRendererBasic/template-params.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.
+-->
+
+
+
+<sample>
+ <name>PdfRendererBasic</name>
+ <group>UI</group>
+ <package>com.example.android.pdfrendererbasic</package>
+
+
+
+ <!-- change minSdk if needed-->
+ <minSdk>21</minSdk>
+ <compileSdkVersion>21</compileSdkVersion>
+
+
+ <strings>
+ <intro>
+ <![CDATA[
+ This sample demonstrates how to use PdfRenderer to display PDF documents on the screen.
+ ]]>
+ </intro>
+ </strings>
+
+ <aapt>
+ <noCompress>pdf</noCompress>
+ </aapt>
+
+ <template src="base"/>
+
+</sample>
diff --git a/ui/holo/BorderlessButtons/Application/src/main/AndroidManifest.xml b/ui/holo/BorderlessButtons/Application/src/main/AndroidManifest.xml
index 34b2898..90b92cf 100644
--- a/ui/holo/BorderlessButtons/Application/src/main/AndroidManifest.xml
+++ b/ui/holo/BorderlessButtons/Application/src/main/AndroidManifest.xml
@@ -28,7 +28,7 @@
This sample requires API 14 for use of theme attributes such as
?android:listPreferredItemPaddingLeft.
-->
- <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application android:label="@string/app_name"
android:icon="@drawable/ic_launcher"
diff --git a/ui/lists/CustomChoiceList/Application/src/main/AndroidManifest.xml b/ui/lists/CustomChoiceList/Application/src/main/AndroidManifest.xml
index 8c194f5..8b0653e 100644
--- a/ui/lists/CustomChoiceList/Application/src/main/AndroidManifest.xml
+++ b/ui/lists/CustomChoiceList/Application/src/main/AndroidManifest.xml
@@ -19,7 +19,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="17" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application android:label="@string/app_name"
android:icon="@drawable/ic_launcher"
diff --git a/ui/lists/CustomChoiceList/template-params.xml b/ui/lists/CustomChoiceList/template-params.xml
index b58c0ac..407aa0b 100644
--- a/ui/lists/CustomChoiceList/template-params.xml
+++ b/ui/lists/CustomChoiceList/template-params.xml
@@ -20,7 +20,7 @@
<package>com.example.android.customchoicelist</package>
<!-- change minSdk if needed-->
- <minSdk>3</minSdk>
+ <minSdk>4</minSdk>
<strings>
<intro>
diff --git a/ui/notifications/BasicNotifications/Application/src/main/AndroidManifest.xml b/ui/notifications/BasicNotifications/Application/src/main/AndroidManifest.xml
deleted file mode 100644
index 1e37d0b..0000000
--- a/ui/notifications/BasicNotifications/Application/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?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.basicnotifications"
- android:versionCode="1"
- android:versionName="1.0">
-
- <uses-sdk
- android:minSdkVersion="8"
- android:targetSdkVersion="17"/>
-
- <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>
- </application>
-
-</manifest>
diff --git a/ui/notifications/BasicNotifications/Application/tests/AndroidManifest.xml b/ui/notifications/BasicNotifications/Application/tests/AndroidManifest.xml
deleted file mode 100644
index 62c01e8..0000000
--- a/ui/notifications/BasicNotifications/Application/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?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.
- -->
-<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.android.basicnotifications.tests"
- android:versionCode="1"
- android:versionName="1.0">
-
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
-
- <!-- We add an application tag here just so that we can indicate that
- this package needs to link against the android.test library,
- which is needed when building test cases. -->
- <application>
- <uses-library android:name="android.test.runner" />
- </application>
-
- <!--
- Specifies the instrumentation test runner used to run the tests.
- -->
- <instrumentation
- android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.example.android.basicnotifications"
- android:label="Tests for com.example.android.basicnotifications" />
-
-</manifest>
\ No newline at end of file
diff --git a/ui/notifications/BasicNotifications/build.gradle b/ui/notifications/BasicNotifications/build.gradle
deleted file mode 100644
index cca9ac3..0000000
--- a/ui/notifications/BasicNotifications/build.gradle
+++ /dev/null
@@ -1,10 +0,0 @@
-// BEGIN_EXCLUDE
-import com.example.android.samples.build.SampleGenPlugin
-apply plugin: SampleGenPlugin
-
-samplegen {
- pathToBuild "../../../../../build"
- pathToSamplesCommon "../../../common"
-}
-apply from: "../../../../../build/build.gradle"
-// END_EXCLUDE
diff --git a/ui/notifications/BasicNotifications/template-params.xml b/ui/notifications/BasicNotifications/template-params.xml
deleted file mode 100644
index 7118c24..0000000
--- a/ui/notifications/BasicNotifications/template-params.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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.
--->
-
-<sample>
- <name>BasicNotifications</name>
- <group>UI</group>
- <package>com.example.android.basicnotifications</package>
- <!-- change minSdk if needed-->
- <minSdk>8</minSdk>
-
- <strings>
- <intro>
- <![CDATA[
- This sample demonstrates how to display events in the system\'s notification bar. The
- NotificationCompat API is used for compatibility with older devices, running Android
- 2.2 (Froyo) or newer.
- ]]>
- </intro>
- </strings>
-
- <template src="base"/>
-</sample>
diff --git a/ui/notifications/CustomNotifications/Application/src/main/AndroidManifest.xml b/ui/notifications/CustomNotifications/Application/src/main/AndroidManifest.xml
deleted file mode 100644
index b20a411..0000000
--- a/ui/notifications/CustomNotifications/Application/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?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.customnotifications"
- android:versionCode="1"
- android:versionName="1.0">
-
- <uses-sdk
- android:minSdkVersion="4"
- android:targetSdkVersion="18" />
-
- <application
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:theme="@style/AppTheme" >
- <activity
- android:name="com.example.android.customnotifications.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/ui/notifications/CustomNotifications/build.gradle b/ui/notifications/CustomNotifications/build.gradle
deleted file mode 100644
index cca9ac3..0000000
--- a/ui/notifications/CustomNotifications/build.gradle
+++ /dev/null
@@ -1,10 +0,0 @@
-// BEGIN_EXCLUDE
-import com.example.android.samples.build.SampleGenPlugin
-apply plugin: SampleGenPlugin
-
-samplegen {
- pathToBuild "../../../../../build"
- pathToSamplesCommon "../../../common"
-}
-apply from: "../../../../../build/build.gradle"
-// END_EXCLUDE
diff --git a/ui/notifications/CustomNotifications/buildSrc/build.gradle b/ui/notifications/CustomNotifications/buildSrc/build.gradle
deleted file mode 100644
index e344a8c..0000000
--- a/ui/notifications/CustomNotifications/buildSrc/build.gradle
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-repositories {
- mavenCentral()
-}
-dependencies {
- compile 'org.freemarker:freemarker:2.3.20'
-}
-
-sourceSets {
- main {
- groovy {
- srcDir new File(rootDir, "../../../../../../build/buildSrc/src/main/groovy")
- }
- }
-}
-
diff --git a/ui/notifications/CustomNotifications/template-params.xml b/ui/notifications/CustomNotifications/template-params.xml
deleted file mode 100644
index ff90ca3..0000000
--- a/ui/notifications/CustomNotifications/template-params.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
--->
-<sample>
- <name>CustomNotifications</name>
- <group>UI</group>
- <package>com.example.android.customnotifications</package>
-
- <!-- change minSdk if needed-->
- <minSdk>4</minSdk>
-
- <strings>
- <intro>
- <![CDATA[
- This sample demonstrates notifications with custom content views.
- ]]>
- </intro>
- </strings>
-
- <template src="base"/>
-
-</sample>
diff --git a/ui/transition/AdapterTransition/Application/src/main/AndroidManifest.xml b/ui/transition/AdapterTransition/Application/src/main/AndroidManifest.xml
index 01b414d..a998a4c 100644
--- a/ui/transition/AdapterTransition/Application/src/main/AndroidManifest.xml
+++ b/ui/transition/AdapterTransition/Application/src/main/AndroidManifest.xml
@@ -19,9 +19,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="19"
- android:targetSdkVersion="19"/>
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application
android:allowBackup="true"
diff --git a/ui/transition/BasicTransition/Application/src/main/AndroidManifest.xml b/ui/transition/BasicTransition/Application/src/main/AndroidManifest.xml
index b4698d6..435f5e0 100644
--- a/ui/transition/BasicTransition/Application/src/main/AndroidManifest.xml
+++ b/ui/transition/BasicTransition/Application/src/main/AndroidManifest.xml
@@ -19,7 +19,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application
android:allowBackup="true"
diff --git a/ui/transition/BasicTransition/template-params.xml b/ui/transition/BasicTransition/template-params.xml
index 0da7567..2bacb7a 100644
--- a/ui/transition/BasicTransition/template-params.xml
+++ b/ui/transition/BasicTransition/template-params.xml
@@ -21,7 +21,6 @@
<!-- change minSdk if needed-->
<minSdk>19</minSdk>
- <compileSdkVersion>19</compileSdkVersion>
<strings>
<intro>
diff --git a/ui/transition/CustomTransition/Application/src/main/AndroidManifest.xml b/ui/transition/CustomTransition/Application/src/main/AndroidManifest.xml
index b3328f1..010cf78 100644
--- a/ui/transition/CustomTransition/Application/src/main/AndroidManifest.xml
+++ b/ui/transition/CustomTransition/Application/src/main/AndroidManifest.xml
@@ -22,7 +22,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application android:allowBackup="true"
android:label="@string/app_name"
diff --git a/ui/transition/FragmentTransition/Application/src/main/AndroidManifest.xml b/ui/transition/FragmentTransition/Application/src/main/AndroidManifest.xml
index 8d02eb0..2cfe406 100644
--- a/ui/transition/FragmentTransition/Application/src/main/AndroidManifest.xml
+++ b/ui/transition/FragmentTransition/Application/src/main/AndroidManifest.xml
@@ -19,7 +19,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application
android:allowBackup="true"
diff --git a/ui/notifications/BasicNotifications/Application/.gitignore b/ui/views/CardView/Application/.gitignore
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/.gitignore
copy to ui/views/CardView/Application/.gitignore
diff --git a/ui/notifications/BasicNotifications/Application/proguard-project.txt b/ui/views/CardView/Application/proguard-project.txt
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/proguard-project.txt
copy to ui/views/CardView/Application/proguard-project.txt
diff --git a/ui/views/CardView/Application/src/main/AndroidManifest.xml b/ui/views/CardView/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..6c4a9d9
--- /dev/null
+++ b/ui/views/CardView/Application/src/main/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/ui/views/CardView/Application/src/main/java/com/example/android/cardview/CardViewActivity.java b/ui/views/CardView/Application/src/main/java/com/example/android/cardview/CardViewActivity.java
new file mode 100644
index 0000000..0153f56
--- /dev/null
+++ b/ui/views/CardView/Application/src/main/java/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/ui/views/CardView/Application/src/main/java/com/example/android/cardview/CardViewFragment.java b/ui/views/CardView/Application/src/main/java/com/example/android/cardview/CardViewFragment.java
new file mode 100644
index 0000000..46ba6b0
--- /dev/null
+++ b/ui/views/CardView/Application/src/main/java/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/ui/views/CardView/Application/src/main/res/drawable-hdpi/ic_launcher.png b/ui/views/CardView/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..36f4db5
--- /dev/null
+++ b/ui/views/CardView/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/CardView/Application/src/main/res/drawable-mdpi/ic_launcher.png b/ui/views/CardView/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f4ca065
--- /dev/null
+++ b/ui/views/CardView/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/CardView/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/ui/views/CardView/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..6464a93
--- /dev/null
+++ b/ui/views/CardView/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/CardView/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/ui/views/CardView/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..5a017ba
--- /dev/null
+++ b/ui/views/CardView/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/CardView/Application/src/main/res/layout/activity_card_view.xml b/ui/views/CardView/Application/src/main/res/layout/activity_card_view.xml
new file mode 100644
index 0000000..e32b7a6
--- /dev/null
+++ b/ui/views/CardView/Application/src/main/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/ui/views/CardView/Application/src/main/res/layout/fragment_card_view.xml b/ui/views/CardView/Application/src/main/res/layout/fragment_card_view.xml
new file mode 100644
index 0000000..432c524
--- /dev/null
+++ b/ui/views/CardView/Application/src/main/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/ui/views/CardView/Application/src/main/res/values/colors.xml b/ui/views/CardView/Application/src/main/res/values/colors.xml
new file mode 100644
index 0000000..71d15f7
--- /dev/null
+++ b/ui/views/CardView/Application/src/main/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/ui/views/CardView/Application/src/main/res/values/dimens.xml b/ui/views/CardView/Application/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..9133662
--- /dev/null
+++ b/ui/views/CardView/Application/src/main/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/ui/views/CardView/Application/src/main/res/values/strings.xml b/ui/views/CardView/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..c995595
--- /dev/null
+++ b/ui/views/CardView/Application/src/main/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/ui/views/CardView/Application/tests/AndroidManifest.xml b/ui/views/CardView/Application/tests/AndroidManifest.xml
new file mode 100644
index 0000000..92cfd40
--- /dev/null
+++ b/ui/views/CardView/Application/tests/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<!--
+ 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 name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest
+ package="com.example.android.cardview.tests"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
+ <!-- We add an application tag here just so that we can indicate that
+ this package needs to link against the android.test library,
+ which is needed when building test cases. -->
+ <application>
+ <uses-library android:name="android.test.runner"/>
+ </application>
+
+ <!--
+ Specifies the instrumentation test runner used to run the tests.
+ -->
+ <instrumentation
+ android:name="android.test.InstrumentationTestRunner"
+ android:label="Tests for CardView sample"
+ android:targetPackage="com.example.android.cardview"/>
+
+</manifest>
\ No newline at end of file
diff --git a/ui/views/CardView/Application/tests/src/com/example/android/cardview/SampleTests.java b/ui/views/CardView/Application/tests/src/com/example/android/cardview/SampleTests.java
new file mode 100644
index 0000000..87b2588
--- /dev/null
+++ b/ui/views/CardView/Application/tests/src/com/example/android/cardview/SampleTests.java
@@ -0,0 +1,70 @@
+/*
+* 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.test.ActivityInstrumentationTestCase2;
+
+/**
+ * Unit tests for CardView samples.
+ */
+public class SampleTests extends ActivityInstrumentationTestCase2<CardViewActivity> {
+
+ private CardViewActivity mActivity;
+ private CardViewFragment mFragment;
+
+ public SampleTests() {
+ super(CardViewActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mActivity = getActivity();
+ mFragment = (CardViewFragment) mActivity.getFragmentManager().findFragmentById(R.id
+ .container);
+ }
+
+ public void testPreconditions() {
+ assertNotNull(String.format("%s is null", CardViewActivity.class.getSimpleName()),
+ mActivity);
+ assertNotNull(String.format("%s is null", CardViewFragment.class.getSimpleName()),
+ mFragment);
+ assertNotNull("SeekBar for Radius is null", mFragment.mRadiusSeekBar);
+ assertNotNull("SeekBar for Elevation is null", mFragment.mElevationSeekBar);
+ }
+
+ public void testRadiusSeekbarChangesRadiusOfCardView() {
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ float radius = 50.0f;
+ mFragment.mRadiusSeekBar.setProgress((int) radius);
+ assertEquals(radius, mFragment.mCardView.getRadius());
+ }
+ });
+ }
+
+ public void testElevationSeekbarChangesElevationOfCardView() {
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ float elevation = 40.0f;
+ mFragment.mElevationSeekBar.setProgress((int) elevation);
+ assertEquals(elevation, mFragment.mCardView.getElevation());
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/ui/views/CardView/CONTRIB.md b/ui/views/CardView/CONTRIB.md
new file mode 100644
index 0000000..8ddb52d
--- /dev/null
+++ b/ui/views/CardView/CONTRIB.md
@@ -0,0 +1,35 @@
+# How to become a contributor and submit your own code
+
+## Contributor License Agreements
+
+We'd love to accept your sample apps and patches! Before we can take them, we
+have to jump a couple of legal hurdles.
+
+Please fill out either the individual or corporate Contributor License Agreement (CLA).
+
+ * If you are an individual writing original source code and you're sure you
+ own the intellectual property, then you'll need to sign an [individual CLA]
+ (https://developers.google.com/open-source/cla/individual).
+ * If you work for a company that wants to allow you to contribute your work,
+ then you'll need to sign a [corporate CLA]
+ (https://developers.google.com/open-source/cla/corporate).
+
+Follow either of the two links above to access the appropriate CLA and
+instructions for how to sign and return it. Once we receive it, we'll be able to
+accept your pull requests.
+
+## Contributing A Patch
+
+1. Submit an issue describing your proposed change to the repo in question.
+1. The repo owner will respond to your issue promptly.
+1. If your proposed change is accepted, and you haven't already done so, sign a
+ Contributor License Agreement (see details above).
+1. Fork the desired repo, develop and test your code changes.
+1. Ensure that your code adheres to the existing style in the sample to which
+ you are contributing. Refer to the
+ [Google Cloud Platform Samples Style Guide]
+ (https://github.com/GoogleCloudPlatform/Template/wiki/style.html) for the
+ recommended coding standards for this organization.
+1. Ensure that your code has an appropriate set of unit tests which all pass.
+1. Submit a pull request.
+
diff --git a/ui/views/CardView/LICENSE b/ui/views/CardView/LICENSE
new file mode 100644
index 0000000..c02ca2f
--- /dev/null
+++ b/ui/views/CardView/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ 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.
diff --git a/ui/views/CardView/README.md b/ui/views/CardView/README.md
new file mode 100644
index 0000000..afa2483
--- /dev/null
+++ b/ui/views/CardView/README.md
@@ -0,0 +1,49 @@
+Android CardView Sample
+=======================
+
+Demonstration of the CardView API introduced in Android L.
+
+Pre-requisites
+--------------
+
+- Android SDK (L Developer Preview)
+- Android Build Tools v20
+- Android Support Repository
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-BasicAndroidKeyStore
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2014 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements. See the NOTICE file distributed with this work for
+additional information regarding copyright ownership. The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/ui/views/CardView/build.gradle b/ui/views/CardView/build.gradle
new file mode 100644
index 0000000..be1fa82
--- /dev/null
+++ b/ui/views/CardView/build.gradle
@@ -0,0 +1,14 @@
+
+
+
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../../build"
+ pathToSamplesCommon "../../../common"
+}
+apply from: "../../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/ui/notifications/BasicNotifications/buildSrc/build.gradle b/ui/views/CardView/buildSrc/build.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/buildSrc/build.gradle
copy to ui/views/CardView/buildSrc/build.gradle
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/ui/views/CardView/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
copy to ui/views/CardView/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/views/CardView/gradle/wrapper/gradle-wrapper.properties b/ui/views/CardView/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..588fabb
--- /dev/null
+++ b/ui/views/CardView/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Fri Aug 22 14:55:27 JST 2014
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip
diff --git a/ui/notifications/BasicNotifications/gradlew b/ui/views/CardView/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to ui/views/CardView/gradlew
diff --git a/ui/notifications/BasicNotifications/gradlew.bat b/ui/views/CardView/gradlew.bat
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew.bat
copy to ui/views/CardView/gradlew.bat
diff --git a/ui/views/CardView/packaging.yaml b/ui/views/CardView/packaging.yaml
new file mode 100644
index 0000000..1dbd957
--- /dev/null
+++ b/ui/views/CardView/packaging.yaml
@@ -0,0 +1,16 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+status: PUBLISHED
+technologies: [Android]
+categories: [UI]
+languages: [Java]
+solutions: [Mobile]
+github: googlesamples/android-CardView
+level: INTERMEDIATE
+icon: CardViewSample/src/main/res/drawable-xxhdpi/ic_launcher.png
+doc_refs:
+ - android:preview/material/ui-widgets.html
+license: apache2
diff --git a/ui/notifications/BasicNotifications/settings.gradle b/ui/views/CardView/settings.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/settings.gradle
copy to ui/views/CardView/settings.gradle
diff --git a/ui/views/CardView/template-params.xml b/ui/views/CardView/template-params.xml
new file mode 100644
index 0000000..6ff29b1
--- /dev/null
+++ b/ui/views/CardView/template-params.xml
@@ -0,0 +1,44 @@
+<?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.
+-->
+
+
+
+<sample>
+ <name>CardView Sample</name>
+ <group>UI</group>
+ <package>com.example.android.cardview</package>
+
+ <auto_add_support_lib>false</auto_add_support_lib>
+
+ <!-- change minSdk if needed-->
+ <minSdk>21</minSdk>
+ <compileSdkVersion>21</compileSdkVersion>
+
+ <dependency>com.android.support:cardview-v7:21.+</dependency>
+
+ <strings>
+ <intro>
+ <![CDATA[
+ This sample demonstrates how to use CardView introduced in the support library for the
+ Android L preview.
+ ]]>
+ </intro>
+ </strings>
+
+ <template src="base"/>
+
+</sample>
diff --git a/ui/notifications/BasicNotifications/Application/.gitignore b/ui/views/Clipping/ClippingBasic/Application/.gitignore
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/.gitignore
copy to ui/views/Clipping/ClippingBasic/Application/.gitignore
diff --git a/ui/views/Clipping/ClippingBasic/Application/README-fragmentview.txt b/ui/views/Clipping/ClippingBasic/Application/README-fragmentview.txt
new file mode 100644
index 0000000..38d903f
--- /dev/null
+++ b/ui/views/Clipping/ClippingBasic/Application/README-fragmentview.txt
@@ -0,0 +1,37 @@
+<!--
+ 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.
+-->
+
+Steps to implement FragmentView template:
+-in template-params.xml.ftl:
+ -add the following line to common imports
+ <common src="activities"/>
+
+-Add a Fragment to show behavior. In your MainActivity.java class, it will reference a Fragment
+ called (yourProjectName)Fragment.java. Create that file in your project, using the "main" source
+ folder instead of "common" or "templates".
+ For instance, if your package name is com.example.foo, create the file
+ src/main/java/com/example/foo/FooFragment.java
+
+
+-Within this fragment, make sure that the onCreate method has the line
+ "setHasOptionsMenu(true);", to enable the fragment to handle menu events.
+
+-In order to override menu events, override onOptionsItemSelected.
+
+-refer to sampleSamples/fragmentViewSample for a reference implementation of a
+project built on this template.
+
+
diff --git a/ui/notifications/BasicNotifications/Application/proguard-project.txt b/ui/views/Clipping/ClippingBasic/Application/proguard-project.txt
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/proguard-project.txt
copy to ui/views/Clipping/ClippingBasic/Application/proguard-project.txt
diff --git a/ui/views/Clipping/ClippingBasic/Application/src/main/AndroidManifest.xml b/ui/views/Clipping/ClippingBasic/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..282d089
--- /dev/null
+++ b/ui/views/Clipping/ClippingBasic/Application/src/main/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/ui/views/Clipping/ClippingBasic/Application/src/main/java/com/example/android/clippingbasic/ClippingBasicFragment.java b/ui/views/Clipping/ClippingBasic/Application/src/main/java/com/example/android/clippingbasic/ClippingBasicFragment.java
new file mode 100644
index 0000000..295a474
--- /dev/null
+++ b/ui/views/Clipping/ClippingBasic/Application/src/main/java/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/ui/views/Clipping/ClippingBasic/Application/src/main/res/drawable-hdpi/ic_launcher.png b/ui/views/Clipping/ClippingBasic/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..d79207b
--- /dev/null
+++ b/ui/views/Clipping/ClippingBasic/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/Clipping/ClippingBasic/Application/src/main/res/drawable-mdpi/ic_launcher.png b/ui/views/Clipping/ClippingBasic/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..3ee83ad
--- /dev/null
+++ b/ui/views/Clipping/ClippingBasic/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/Clipping/ClippingBasic/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/ui/views/Clipping/ClippingBasic/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..3b1ae0a
--- /dev/null
+++ b/ui/views/Clipping/ClippingBasic/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/Clipping/ClippingBasic/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/ui/views/Clipping/ClippingBasic/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..64b728d
--- /dev/null
+++ b/ui/views/Clipping/ClippingBasic/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/Clipping/ClippingBasic/Application/src/main/res/drawable/gradient_drawable.xml b/ui/views/Clipping/ClippingBasic/Application/src/main/res/drawable/gradient_drawable.xml
new file mode 100644
index 0000000..c6377cc
--- /dev/null
+++ b/ui/views/Clipping/ClippingBasic/Application/src/main/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/ui/views/Clipping/ClippingBasic/Application/src/main/res/layout/clipping_basic_fragment.xml b/ui/views/Clipping/ClippingBasic/Application/src/main/res/layout/clipping_basic_fragment.xml
new file mode 100644
index 0000000..44efedc
--- /dev/null
+++ b/ui/views/Clipping/ClippingBasic/Application/src/main/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/ui/views/Clipping/ClippingBasic/Application/src/main/res/values/strings.xml b/ui/views/Clipping/ClippingBasic/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..b01a168
--- /dev/null
+++ b/ui/views/Clipping/ClippingBasic/Application/src/main/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/ui/views/Clipping/ClippingBasic/Application/tests/AndroidManifest.xml b/ui/views/Clipping/ClippingBasic/Application/tests/AndroidManifest.xml
new file mode 100644
index 0000000..28aa52a
--- /dev/null
+++ b/ui/views/Clipping/ClippingBasic/Application/tests/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.
+-->
+<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.clippingbasic.tests"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
+ <!-- We add an application tag here just so that we can indicate that
+ this package needs to link against the android.test library,
+ which is needed when building test cases. -->
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!--
+ Specifies the instrumentation test runner used to run the tests.
+ -->
+ <instrumentation
+ android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.example.android.clippingbasic"
+ android:label="Tests for com.example.android.clippingbasic" />
+
+</manifest>
\ No newline at end of file
diff --git a/ui/views/Clipping/ClippingBasic/Application/tests/src/com/example/android/clippingbasic/tests/SampleTests.java b/ui/views/Clipping/ClippingBasic/Application/tests/src/com/example/android/clippingbasic/tests/SampleTests.java
new file mode 100644
index 0000000..69d40b2
--- /dev/null
+++ b/ui/views/Clipping/ClippingBasic/Application/tests/src/com/example/android/clippingbasic/tests/SampleTests.java
@@ -0,0 +1,74 @@
+/*
+* 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.tests;
+
+import com.example.android.clippingbasic.*;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.TouchUtils;
+import android.view.View;
+
+/**
+* Tests for ClippingBasic sample.
+*/
+public class SampleTests extends ActivityInstrumentationTestCase2<MainActivity> {
+
+ private MainActivity mTestActivity;
+ private ClippingBasicFragment mTestFragment;
+
+ public SampleTests() {
+ super(MainActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // Starts the activity under test using the default Intent with:
+ // action = {@link Intent#ACTION_MAIN}
+ // flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK}
+ // All other fields are null or empty.
+ mTestActivity = getActivity();
+ mTestFragment = (ClippingBasicFragment)
+ mTestActivity.getSupportFragmentManager().getFragments().get(1);
+ }
+
+ /**
+ * Test if the test fixture has been set up correctly.
+ */
+ public void testPreconditions() {
+ assertNotNull("mTestActivity is null", mTestActivity);
+ assertNotNull("mTestFragment is null", mTestFragment);
+ assertNotNull("Clipped frame is null", mTestActivity.findViewById(R.id.frame));
+ assertNotNull("Text view is null", mTestActivity.findViewById(R.id.text_view));
+ }
+
+ /**
+ * Triggers a click on the button and tests if the view is clipped afterwards.
+ */
+ public void testClipping() {
+ View clippedView = mTestActivity.findViewById(R.id.frame);
+
+ // Initially, the view is not clipped.
+ assertFalse(clippedView.getClipToOutline());
+
+ // Trigger a click on the button to activate clipping.
+ TouchUtils.clickView(this, mTestActivity.findViewById(R.id.button));
+
+ // Check that the view has been clipped.
+ assertTrue(clippedView.getClipToOutline());
+ }
+}
\ No newline at end of file
diff --git a/ui/notifications/BasicNotifications/CONTRIB.md b/ui/views/Clipping/ClippingBasic/CONTRIB.md
similarity index 100%
copy from ui/notifications/BasicNotifications/CONTRIB.md
copy to ui/views/Clipping/ClippingBasic/CONTRIB.md
diff --git a/ui/notifications/BasicNotifications/LICENSE b/ui/views/Clipping/ClippingBasic/LICENSE
similarity index 100%
copy from ui/notifications/BasicNotifications/LICENSE
copy to ui/views/Clipping/ClippingBasic/LICENSE
diff --git a/ui/views/Clipping/ClippingBasic/README.md b/ui/views/Clipping/ClippingBasic/README.md
new file mode 100644
index 0000000..f6347ea
--- /dev/null
+++ b/ui/views/Clipping/ClippingBasic/README.md
@@ -0,0 +1,49 @@
+Android ClippingBasic Sample
+==============================
+
+Basic sample to demonstrate clipping on a View.
+
+Pre-requisites
+--------------
+
+- Android SDK (L Developer Preview)
+- Android Build Tools v20
+- Android Support Repository
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-ClippingBasic
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2014 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements. See the NOTICE file distributed with this work for
+additional information regarding copyright ownership. The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/ui/views/Clipping/ClippingBasic/build.gradle b/ui/views/Clipping/ClippingBasic/build.gradle
new file mode 100644
index 0000000..cda9c5c
--- /dev/null
+++ b/ui/views/Clipping/ClippingBasic/build.gradle
@@ -0,0 +1,14 @@
+
+
+
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../../../build"
+ pathToSamplesCommon "../../../../common"
+}
+apply from: "../../../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/ui/views/Clipping/ClippingBasic/buildSrc/build.gradle b/ui/views/Clipping/ClippingBasic/buildSrc/build.gradle
new file mode 100644
index 0000000..81f445f
--- /dev/null
+++ b/ui/views/Clipping/ClippingBasic/buildSrc/build.gradle
@@ -0,0 +1,18 @@
+
+
+
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile 'org.freemarker:freemarker:2.3.20'
+}
+
+sourceSets {
+ main {
+ groovy {
+ srcDir new File(rootDir, "../../../../../../../build/buildSrc/src/main/groovy")
+ }
+ }
+}
+
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/ui/views/Clipping/ClippingBasic/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
copy to ui/views/Clipping/ClippingBasic/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties b/ui/views/Clipping/ClippingBasic/gradle/wrapper/gradle-wrapper.properties
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties
copy to ui/views/Clipping/ClippingBasic/gradle/wrapper/gradle-wrapper.properties
diff --git a/ui/notifications/BasicNotifications/gradlew b/ui/views/Clipping/ClippingBasic/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to ui/views/Clipping/ClippingBasic/gradlew
diff --git a/ui/notifications/BasicNotifications/gradlew.bat b/ui/views/Clipping/ClippingBasic/gradlew.bat
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew.bat
copy to ui/views/Clipping/ClippingBasic/gradlew.bat
diff --git a/ui/views/Clipping/ClippingBasic/packaging.yaml b/ui/views/Clipping/ClippingBasic/packaging.yaml
new file mode 100644
index 0000000..2e26f7d
--- /dev/null
+++ b/ui/views/Clipping/ClippingBasic/packaging.yaml
@@ -0,0 +1,15 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+
+status: PUBLISHED
+technologies: [Android]
+categories: [UI]
+languages: [Java]
+solutions: [Mobile]
+github: googlesamples/android-ClippingBasic
+level: BEGINNER
+icon: ClippingBasicSample/src/main/res/drawable-xxhdpi/ic_launcher.png
+license: apache2
diff --git a/ui/notifications/BasicNotifications/settings.gradle b/ui/views/Clipping/ClippingBasic/settings.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/settings.gradle
copy to ui/views/Clipping/ClippingBasic/settings.gradle
diff --git a/ui/views/Clipping/ClippingBasic/template-params.xml b/ui/views/Clipping/ClippingBasic/template-params.xml
new file mode 100644
index 0000000..957a591
--- /dev/null
+++ b/ui/views/Clipping/ClippingBasic/template-params.xml
@@ -0,0 +1,43 @@
+<?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.
+-->
+
+
+
+<sample>
+ <name>ClippingBasic</name>
+ <group>UI</group>
+ <package>com.example.android.clippingbasic</package>
+
+
+ <minSdk>21</minSdk>
+ <compileSdkVersion>21</compileSdkVersion>
+
+
+ <strings>
+ <intro>
+ <![CDATA[
+ Basic sample to demonstrate clipping on a View.
+ ]]>
+ </intro>
+ </strings>
+
+ <template src="base"/>
+ <template src="FragmentView"/>
+ <common src="logger"/>
+ <common src="activities"/>
+
+</sample>
diff --git a/ui/notifications/BasicNotifications/Application/.gitignore b/ui/views/Elevation/ElevationBasic/Application/.gitignore
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/.gitignore
copy to ui/views/Elevation/ElevationBasic/Application/.gitignore
diff --git a/ui/views/Elevation/ElevationBasic/Application/README-singleview.txt b/ui/views/Elevation/ElevationBasic/Application/README-singleview.txt
new file mode 100644
index 0000000..0cacd46
--- /dev/null
+++ b/ui/views/Elevation/ElevationBasic/Application/README-singleview.txt
@@ -0,0 +1,47 @@
+<#--
+ 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.
+-->
+
+Steps to implement SingleView template:
+-in template-params.xml.ftl:
+ -add the following line to common imports
+ <common src="activities"/>
+
+ -add a string for the action button's text using the element name "sample_action".
+ This element should be a child of <strings>:
+ <strings>
+ ...
+ <sample_action>ButtonText</sample_action>
+ ...
+ </strings>
+
+
+
+-Add a Fragment to handle behavior. In your MainActivity.java class, it will reference a Fragment
+ called (yourProjectName)Fragment.java. Create that file in your project, using the "main" source
+ folder instead of "common" or "templates".
+ For instance, if your package name is com.example.foo, create the file
+ src/main/java/com/example/foo/FooFragment.java
+
+
+-Within this fragment, make sure that the onCreate method has the line
+ "setHasOptionsMenu(true);", to enable the fragment to handle menu events.
+
+-In order to override menu events, override onOptionsItemSelected.
+
+-refer to sampleSamples/singleViewSample for a reference implementation of a
+project built on this template.
+
+
diff --git a/ui/notifications/BasicNotifications/Application/proguard-project.txt b/ui/views/Elevation/ElevationBasic/Application/proguard-project.txt
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/proguard-project.txt
copy to ui/views/Elevation/ElevationBasic/Application/proguard-project.txt
diff --git a/ui/views/Elevation/ElevationBasic/Application/src/main/AndroidManifest.xml b/ui/views/Elevation/ElevationBasic/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..a70cd85
--- /dev/null
+++ b/ui/views/Elevation/ElevationBasic/Application/src/main/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/ui/views/Elevation/ElevationBasic/Application/src/main/java/com/example/android/elevationbasic/ElevationBasicFragment.java b/ui/views/Elevation/ElevationBasic/Application/src/main/java/com/example/android/elevationbasic/ElevationBasicFragment.java
new file mode 100644
index 0000000..71edea5
--- /dev/null
+++ b/ui/views/Elevation/ElevationBasic/Application/src/main/java/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/ui/views/Elevation/ElevationBasic/Application/src/main/res/drawable-hdpi/ic_launcher.png b/ui/views/Elevation/ElevationBasic/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..c28e40d
--- /dev/null
+++ b/ui/views/Elevation/ElevationBasic/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/Elevation/ElevationBasic/Application/src/main/res/drawable-mdpi/ic_launcher.png b/ui/views/Elevation/ElevationBasic/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..71738ff
--- /dev/null
+++ b/ui/views/Elevation/ElevationBasic/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/Elevation/ElevationBasic/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/ui/views/Elevation/ElevationBasic/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..788ac1f
--- /dev/null
+++ b/ui/views/Elevation/ElevationBasic/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/Elevation/ElevationBasic/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/ui/views/Elevation/ElevationBasic/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..72359c3
--- /dev/null
+++ b/ui/views/Elevation/ElevationBasic/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/Elevation/ElevationBasic/Application/src/main/res/drawable/shape.xml b/ui/views/Elevation/ElevationBasic/Application/src/main/res/drawable/shape.xml
new file mode 100644
index 0000000..22ffe05
--- /dev/null
+++ b/ui/views/Elevation/ElevationBasic/Application/src/main/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/ui/views/Elevation/ElevationBasic/Application/src/main/res/drawable/shape2.xml b/ui/views/Elevation/ElevationBasic/Application/src/main/res/drawable/shape2.xml
new file mode 100644
index 0000000..7060f58
--- /dev/null
+++ b/ui/views/Elevation/ElevationBasic/Application/src/main/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/ui/views/Elevation/ElevationBasic/Application/src/main/res/layout/elevation_basic.xml b/ui/views/Elevation/ElevationBasic/Application/src/main/res/layout/elevation_basic.xml
new file mode 100644
index 0000000..83ab1d2
--- /dev/null
+++ b/ui/views/Elevation/ElevationBasic/Application/src/main/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/ui/views/Elevation/ElevationBasic/Application/src/main/res/values/colors.xml b/ui/views/Elevation/ElevationBasic/Application/src/main/res/values/colors.xml
new file mode 100644
index 0000000..b5782df
--- /dev/null
+++ b/ui/views/Elevation/ElevationBasic/Application/src/main/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/ui/views/Elevation/ElevationBasic/Application/tests/AndroidManifest.xml b/ui/views/Elevation/ElevationBasic/Application/tests/AndroidManifest.xml
new file mode 100644
index 0000000..800c0ba
--- /dev/null
+++ b/ui/views/Elevation/ElevationBasic/Application/tests/AndroidManifest.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.
+-->
+
+<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.elevationbasic.tests"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
+ <!-- We add an application tag here just so that we can indicate that
+ this package needs to link against the android.test library,
+ which is needed when building test cases. -->
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!--
+ Specifies the instrumentation test runner used to run the tests.
+ -->
+ <instrumentation
+ android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.example.android.elevationbasic"
+ android:label="Tests for com.example.android.elevationbasic" />
+
+</manifest>
\ No newline at end of file
diff --git a/ui/views/Elevation/ElevationBasic/Application/tests/src/com/example/android/elevationbasic/tests/SampleTests.java b/ui/views/Elevation/ElevationBasic/Application/tests/src/com/example/android/elevationbasic/tests/SampleTests.java
new file mode 100644
index 0000000..0da03c6
--- /dev/null
+++ b/ui/views/Elevation/ElevationBasic/Application/tests/src/com/example/android/elevationbasic/tests/SampleTests.java
@@ -0,0 +1,70 @@
+/*
+* 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.elevationbasic.tests;
+
+import com.example.android.elevationbasic.ElevationBasicFragment;
+import com.example.android.elevationbasic.MainActivity;
+import com.example.android.elevationbasic.R;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.view.View;
+
+/**
+* Tests for ElevationBasic sample.
+*/
+public class SampleTests extends ActivityInstrumentationTestCase2<MainActivity> {
+
+ private MainActivity mTestActivity;
+ private ElevationBasicFragment mTestFragment;
+
+ private View mShape1;
+ private View mShape2;
+
+ public SampleTests() {
+ super(MainActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // Starts the activity under test using the default Intent with:
+ // action = {@link Intent#ACTION_MAIN}
+ // flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK}
+ // All other fields are null or empty.
+ mTestActivity = getActivity();
+ mTestFragment = (ElevationBasicFragment)
+ mTestActivity.getSupportFragmentManager().getFragments().get(1);
+ mShape1 = mTestActivity.findViewById(R.id.floating_shape);
+ mShape2 = mTestActivity.findViewById(R.id.floating_shape_2);
+ }
+
+ /**
+ * Test if the test fixture has been set up correctly.
+ */
+ public void testPreconditions() {
+ assertNotNull("mTestActivity is null", mTestActivity);
+ assertNotNull("mTestFragment is null", mTestFragment);
+ }
+
+ /**
+ * Test if the initial Z values of the shapes are correct.
+ */
+ public void testInitialShapeZ() {
+ assertTrue(mShape1.getZ() > 0f);
+ assertEquals(mShape2.getZ(), 0f);
+ }
+}
\ No newline at end of file
diff --git a/ui/notifications/BasicNotifications/CONTRIB.md b/ui/views/Elevation/ElevationBasic/CONTRIB.md
similarity index 100%
copy from ui/notifications/BasicNotifications/CONTRIB.md
copy to ui/views/Elevation/ElevationBasic/CONTRIB.md
diff --git a/ui/notifications/BasicNotifications/LICENSE b/ui/views/Elevation/ElevationBasic/LICENSE
similarity index 100%
copy from ui/notifications/BasicNotifications/LICENSE
copy to ui/views/Elevation/ElevationBasic/LICENSE
diff --git a/ui/views/Elevation/ElevationBasic/README.md b/ui/views/Elevation/ElevationBasic/README.md
new file mode 100644
index 0000000..b40a734
--- /dev/null
+++ b/ui/views/Elevation/ElevationBasic/README.md
@@ -0,0 +1,51 @@
+Android ElevationBasic Sample
+==============================
+
+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().
+
+Pre-requisites
+--------------
+
+- Android SDK (L Developer Preview)
+- Android Build Tools v20
+- Android Support Repository
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-ElevationBasic
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2014 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements. See the NOTICE file distributed with this work for
+additional information regarding copyright ownership. The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/ui/views/Elevation/ElevationBasic/build.gradle b/ui/views/Elevation/ElevationBasic/build.gradle
new file mode 100644
index 0000000..cda9c5c
--- /dev/null
+++ b/ui/views/Elevation/ElevationBasic/build.gradle
@@ -0,0 +1,14 @@
+
+
+
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../../../build"
+ pathToSamplesCommon "../../../../common"
+}
+apply from: "../../../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/ui/views/Elevation/ElevationBasic/buildSrc/build.gradle b/ui/views/Elevation/ElevationBasic/buildSrc/build.gradle
new file mode 100644
index 0000000..81f445f
--- /dev/null
+++ b/ui/views/Elevation/ElevationBasic/buildSrc/build.gradle
@@ -0,0 +1,18 @@
+
+
+
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile 'org.freemarker:freemarker:2.3.20'
+}
+
+sourceSets {
+ main {
+ groovy {
+ srcDir new File(rootDir, "../../../../../../../build/buildSrc/src/main/groovy")
+ }
+ }
+}
+
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/ui/views/Elevation/ElevationBasic/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
copy to ui/views/Elevation/ElevationBasic/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/views/Elevation/ElevationBasic/gradle/wrapper/gradle-wrapper.properties b/ui/views/Elevation/ElevationBasic/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..fe5a0cf
--- /dev/null
+++ b/ui/views/Elevation/ElevationBasic/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon May 19 15:36:48 BST 2014
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.11-all.zip
diff --git a/ui/notifications/BasicNotifications/gradlew b/ui/views/Elevation/ElevationBasic/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to ui/views/Elevation/ElevationBasic/gradlew
diff --git a/ui/notifications/BasicNotifications/gradlew.bat b/ui/views/Elevation/ElevationBasic/gradlew.bat
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew.bat
copy to ui/views/Elevation/ElevationBasic/gradlew.bat
diff --git a/ui/views/Elevation/ElevationBasic/packaging.yaml b/ui/views/Elevation/ElevationBasic/packaging.yaml
new file mode 100644
index 0000000..cb6d6c2
--- /dev/null
+++ b/ui/views/Elevation/ElevationBasic/packaging.yaml
@@ -0,0 +1,15 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+
+status: PUBLISHED
+technologies: [Android]
+categories: [NoGroup]
+languages: [Java]
+solutions: [Mobile]
+github: googlesamples/android-ElevationBasic
+level: BEGINNER
+icon: ElevationBasicSample/src/main/res/drawable-xxhdpi/ic_launcher.png
+license: apache2
diff --git a/ui/notifications/BasicNotifications/settings.gradle b/ui/views/Elevation/ElevationBasic/settings.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/settings.gradle
copy to ui/views/Elevation/ElevationBasic/settings.gradle
diff --git a/ui/views/Elevation/ElevationBasic/template-params.xml b/ui/views/Elevation/ElevationBasic/template-params.xml
new file mode 100644
index 0000000..3ef4ec2
--- /dev/null
+++ b/ui/views/Elevation/ElevationBasic/template-params.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.
+-->
+
+
+
+<sample>
+ <name>ElevationBasic</name>
+ <group>UI</group>
+ <package>com.example.android.elevationbasic</package>
+
+
+
+ <!-- change minSdk if needed-->
+ <minSdk>21</minSdk>
+ <compileSdkVersion>21</compileSdkVersion>
+
+
+ <strings>
+ <intro>
+ <![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().
+ ]]>
+ </intro>
+ <sample_action>Elevation Basic</sample_action>
+ </strings>
+
+ <template src="base"/>
+ <template src="FragmentView"/>
+ <common src="logger"/>
+ <common src="activities"/>
+
+</sample>
diff --git a/ui/notifications/BasicNotifications/Application/.gitignore b/ui/views/Elevation/ElevationDrag/Application/.gitignore
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/.gitignore
copy to ui/views/Elevation/ElevationDrag/Application/.gitignore
diff --git a/ui/views/Elevation/ElevationDrag/Application/README-fragmentview.txt b/ui/views/Elevation/ElevationDrag/Application/README-fragmentview.txt
new file mode 100644
index 0000000..38d903f
--- /dev/null
+++ b/ui/views/Elevation/ElevationDrag/Application/README-fragmentview.txt
@@ -0,0 +1,37 @@
+<!--
+ 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.
+-->
+
+Steps to implement FragmentView template:
+-in template-params.xml.ftl:
+ -add the following line to common imports
+ <common src="activities"/>
+
+-Add a Fragment to show behavior. In your MainActivity.java class, it will reference a Fragment
+ called (yourProjectName)Fragment.java. Create that file in your project, using the "main" source
+ folder instead of "common" or "templates".
+ For instance, if your package name is com.example.foo, create the file
+ src/main/java/com/example/foo/FooFragment.java
+
+
+-Within this fragment, make sure that the onCreate method has the line
+ "setHasOptionsMenu(true);", to enable the fragment to handle menu events.
+
+-In order to override menu events, override onOptionsItemSelected.
+
+-refer to sampleSamples/fragmentViewSample for a reference implementation of a
+project built on this template.
+
+
diff --git a/ui/notifications/BasicNotifications/Application/proguard-project.txt b/ui/views/Elevation/ElevationDrag/Application/proguard-project.txt
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/proguard-project.txt
copy to ui/views/Elevation/ElevationDrag/Application/proguard-project.txt
diff --git a/ui/views/Elevation/ElevationDrag/Application/src/main/AndroidManifest.xml b/ui/views/Elevation/ElevationDrag/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..9fd7d53
--- /dev/null
+++ b/ui/views/Elevation/ElevationDrag/Application/src/main/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/ui/views/Elevation/ElevationDrag/Application/src/main/java/com/example/android/elevationdrag/DragFrameLayout.java b/ui/views/Elevation/ElevationDrag/Application/src/main/java/com/example/android/elevationdrag/DragFrameLayout.java
new file mode 100644
index 0000000..0b2a8d2
--- /dev/null
+++ b/ui/views/Elevation/ElevationDrag/Application/src/main/java/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/ui/views/Elevation/ElevationDrag/Application/src/main/java/com/example/android/elevationdrag/ElevationDragFragment.java b/ui/views/Elevation/ElevationDrag/Application/src/main/java/com/example/android/elevationdrag/ElevationDragFragment.java
new file mode 100644
index 0000000..9d14206
--- /dev/null
+++ b/ui/views/Elevation/ElevationDrag/Application/src/main/java/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/ui/views/Elevation/ElevationDrag/Application/src/main/res/drawable-hdpi/ic_launcher.png b/ui/views/Elevation/ElevationDrag/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..8d34f6a
--- /dev/null
+++ b/ui/views/Elevation/ElevationDrag/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/Elevation/ElevationDrag/Application/src/main/res/drawable-mdpi/ic_launcher.png b/ui/views/Elevation/ElevationDrag/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..8d9cd3e
--- /dev/null
+++ b/ui/views/Elevation/ElevationDrag/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/Elevation/ElevationDrag/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/ui/views/Elevation/ElevationDrag/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..09e4c8d
--- /dev/null
+++ b/ui/views/Elevation/ElevationDrag/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/Elevation/ElevationDrag/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/ui/views/Elevation/ElevationDrag/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..232dc77
--- /dev/null
+++ b/ui/views/Elevation/ElevationDrag/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/Elevation/ElevationDrag/Application/src/main/res/layout/ztranslation.xml b/ui/views/Elevation/ElevationDrag/Application/src/main/res/layout/ztranslation.xml
new file mode 100644
index 0000000..2ae3926
--- /dev/null
+++ b/ui/views/Elevation/ElevationDrag/Application/src/main/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/ui/views/Elevation/ElevationDrag/Application/src/main/res/values/colors.xml b/ui/views/Elevation/ElevationDrag/Application/src/main/res/values/colors.xml
new file mode 100644
index 0000000..d563796
--- /dev/null
+++ b/ui/views/Elevation/ElevationDrag/Application/src/main/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/ui/views/Elevation/ElevationDrag/Application/src/main/res/values/dimens.xml b/ui/views/Elevation/ElevationDrag/Application/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..778d8de
--- /dev/null
+++ b/ui/views/Elevation/ElevationDrag/Application/src/main/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/ui/views/Elevation/ElevationDrag/Application/tests/AndroidManifest.xml b/ui/views/Elevation/ElevationDrag/Application/tests/AndroidManifest.xml
new file mode 100644
index 0000000..60c9a19
--- /dev/null
+++ b/ui/views/Elevation/ElevationDrag/Application/tests/AndroidManifest.xml
@@ -0,0 +1,59 @@
+<?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.
+-->
+
+
+
+<?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.
+ -->
+<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.elevationdrag.tests"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
+ <!-- We add an application tag here just so that we can indicate that
+ this package needs to link against the android.test library,
+ which is needed when building test cases. -->
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!--
+ Specifies the instrumentation test runner used to run the tests.
+ -->
+ <instrumentation
+ android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.example.android.elevationdrag"
+ android:label="Tests for com.example.android.elevationdrag" />
+
+</manifest>
\ No newline at end of file
diff --git a/ui/views/Elevation/ElevationDrag/Application/tests/src/com/example/android/elevationdrag/tests/SampleTests.java b/ui/views/Elevation/ElevationDrag/Application/tests/src/com/example/android/elevationdrag/tests/SampleTests.java
new file mode 100644
index 0000000..5e7acc0
--- /dev/null
+++ b/ui/views/Elevation/ElevationDrag/Application/tests/src/com/example/android/elevationdrag/tests/SampleTests.java
@@ -0,0 +1,113 @@
+/*
+* 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 (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.elevationdrag.tests;
+
+import com.example.android.elevationdrag.*;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.TouchUtils;
+import android.view.Gravity;
+import android.view.View;
+
+/**
+* Tests for ElevationDrag sample.
+*/
+public class SampleTests extends ActivityInstrumentationTestCase2<MainActivity> {
+
+ private MainActivity mTestActivity;
+ private ElevationDragFragment mTestFragment;
+
+ private View mFloatingShape;
+ private View mDragFrame;
+
+ public SampleTests() {
+ super(MainActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // Starts the activity under test using the default Intent with:
+ // action = {@link Intent#ACTION_MAIN}
+ // flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK}
+ // All other fields are null or empty.
+ mTestActivity = getActivity();
+ mTestFragment = (ElevationDragFragment)
+ mTestActivity.getSupportFragmentManager().getFragments().get(1);
+
+ mFloatingShape = mTestActivity.findViewById(R.id.circle);
+ mDragFrame = mTestActivity.findViewById(R.id.main_layout);
+ }
+
+ /**
+ * Test if the test fixture has been set up correctly.
+ */
+ public void testPreconditions() {
+ //Try to add a message to add context to your assertions. These messages will be shown if
+ //a tests fails and make it easy to understand why a test failed
+ assertNotNull("mTestActivity is null", mTestActivity);
+ assertNotNull("mTestFragment is null", mTestFragment);
+ assertNotNull("mFloatingShape is null", mFloatingShape);
+ assertNotNull("mDragFrame is null", mDragFrame);
+ // Check that the view is not raised yet.
+ assertEquals(mFloatingShape.getZ(), 0f);
+ }
+
+ /**
+ * Test that the floating shape can be dragged and that it's raised while dragging.
+ */
+ public void testDrag() {
+ final float initialX = mFloatingShape.getX();
+ // Drag the shape to the left edge.
+ TouchUtils.dragViewToX(this,
+ mFloatingShape,
+ Gravity.CENTER,
+ 0);
+
+ // Check that the view is dragging and that it's been raised.
+ // We need to use runOnMainSync here as fake dragging uses waitForIdleSync().
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ // Check that the view has moved.
+ float deltaX = mFloatingShape.getX() - initialX;
+ assertTrue(Math.abs(deltaX) > 0f);
+
+ // Check that the view is raised.
+ assertTrue(mFloatingShape.getZ() > 0f);
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/ui/notifications/BasicNotifications/CONTRIB.md b/ui/views/Elevation/ElevationDrag/CONTRIB.md
similarity index 100%
copy from ui/notifications/BasicNotifications/CONTRIB.md
copy to ui/views/Elevation/ElevationDrag/CONTRIB.md
diff --git a/ui/notifications/BasicNotifications/LICENSE b/ui/views/Elevation/ElevationDrag/LICENSE
similarity index 100%
copy from ui/notifications/BasicNotifications/LICENSE
copy to ui/views/Elevation/ElevationDrag/LICENSE
diff --git a/ui/views/Elevation/ElevationDrag/README.md b/ui/views/Elevation/ElevationDrag/README.md
new file mode 100644
index 0000000..f3c2129
--- /dev/null
+++ b/ui/views/Elevation/ElevationDrag/README.md
@@ -0,0 +1,51 @@
+Android ElevationDrag Sample
+==============================
+
+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.
+
+Pre-requisites
+--------------
+
+- Android SDK (L Developer Preview)
+- Android Build Tools v20
+- Android Support Repository
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-ElevationDrag
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2014 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements. See the NOTICE file distributed with this work for
+additional information regarding copyright ownership. The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/ui/views/Elevation/ElevationDrag/build.gradle b/ui/views/Elevation/ElevationDrag/build.gradle
new file mode 100644
index 0000000..cda9c5c
--- /dev/null
+++ b/ui/views/Elevation/ElevationDrag/build.gradle
@@ -0,0 +1,14 @@
+
+
+
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../../../build"
+ pathToSamplesCommon "../../../../common"
+}
+apply from: "../../../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/ui/views/Elevation/ElevationDrag/buildSrc/build.gradle b/ui/views/Elevation/ElevationDrag/buildSrc/build.gradle
new file mode 100644
index 0000000..81f445f
--- /dev/null
+++ b/ui/views/Elevation/ElevationDrag/buildSrc/build.gradle
@@ -0,0 +1,18 @@
+
+
+
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile 'org.freemarker:freemarker:2.3.20'
+}
+
+sourceSets {
+ main {
+ groovy {
+ srcDir new File(rootDir, "../../../../../../../build/buildSrc/src/main/groovy")
+ }
+ }
+}
+
diff --git a/ui/views/Elevation/ElevationDrag/gradle/gradle/wrapper/gradle-wrapper.jar b/ui/views/Elevation/ElevationDrag/gradle/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..5838598
--- /dev/null
+++ b/ui/views/Elevation/ElevationDrag/gradle/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/views/Elevation/ElevationDrag/gradle/gradle/wrapper/gradle-wrapper.properties b/ui/views/Elevation/ElevationDrag/gradle/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..eefbc0a
--- /dev/null
+++ b/ui/views/Elevation/ElevationDrag/gradle/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue May 20 13:33:02 BST 2014
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-bin.zip
diff --git a/ui/notifications/BasicNotifications/gradlew b/ui/views/Elevation/ElevationDrag/gradle/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to ui/views/Elevation/ElevationDrag/gradle/gradlew
diff --git a/ui/notifications/BasicNotifications/gradlew.bat b/ui/views/Elevation/ElevationDrag/gradle/gradlew.bat
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew.bat
copy to ui/views/Elevation/ElevationDrag/gradle/gradlew.bat
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/ui/views/Elevation/ElevationDrag/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
copy to ui/views/Elevation/ElevationDrag/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties b/ui/views/Elevation/ElevationDrag/gradle/wrapper/gradle-wrapper.properties
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.properties
copy to ui/views/Elevation/ElevationDrag/gradle/wrapper/gradle-wrapper.properties
diff --git a/ui/notifications/BasicNotifications/gradlew b/ui/views/Elevation/ElevationDrag/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to ui/views/Elevation/ElevationDrag/gradlew
diff --git a/ui/notifications/BasicNotifications/gradlew.bat b/ui/views/Elevation/ElevationDrag/gradlew.bat
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew.bat
copy to ui/views/Elevation/ElevationDrag/gradlew.bat
diff --git a/ui/views/Elevation/ElevationDrag/packaging.yaml b/ui/views/Elevation/ElevationDrag/packaging.yaml
new file mode 100644
index 0000000..044a7d3
--- /dev/null
+++ b/ui/views/Elevation/ElevationDrag/packaging.yaml
@@ -0,0 +1,15 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+
+status: PUBLISHED
+technologies: [Android]
+categories: [UI]
+languages: [Java]
+solutions: [Mobile]
+github: googlesamples/android-ElevationDrag
+level: BEGINNER
+icon: ElevationDragSample/src/main/res/drawable-xxhdpi/ic_launcher.png
+license: apache2
diff --git a/ui/notifications/BasicNotifications/settings.gradle b/ui/views/Elevation/ElevationDrag/settings.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/settings.gradle
copy to ui/views/Elevation/ElevationDrag/settings.gradle
diff --git a/ui/views/Elevation/ElevationDrag/template-params.xml b/ui/views/Elevation/ElevationDrag/template-params.xml
new file mode 100644
index 0000000..2c62cb2
--- /dev/null
+++ b/ui/views/Elevation/ElevationDrag/template-params.xml
@@ -0,0 +1,47 @@
+<?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.
+-->
+
+
+
+<sample>
+ <name>ElevationDrag</name>
+ <group>UI</group>
+ <package>com.example.android.elevationdrag</package>
+
+
+ <!-- change minSdk if needed-->
+ <minSdk>21</minSdk>
+ <compileSdkVersion>21</compileSdkVersion>
+
+
+ <strings>
+ <intro>
+ <![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.
+ ]]>
+ </intro>
+ <sample_action>Elevation Drag</sample_action>
+ </strings>
+
+ <template src="base"/>
+ <template src="FragmentView"/>
+ <common src="logger"/>
+ <common src="activities"/>
+
+</sample>
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/.gitignore b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/.gitignore
new file mode 100644
index 0000000..0349d31
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/.gitignore
@@ -0,0 +1,17 @@
+# 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.
+src/template/
+src/common/
+build.gradle
+*.iml
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/README-fragmentview.txt b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/README-fragmentview.txt
new file mode 100644
index 0000000..38d903f
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/README-fragmentview.txt
@@ -0,0 +1,37 @@
+<!--
+ 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.
+-->
+
+Steps to implement FragmentView template:
+-in template-params.xml.ftl:
+ -add the following line to common imports
+ <common src="activities"/>
+
+-Add a Fragment to show behavior. In your MainActivity.java class, it will reference a Fragment
+ called (yourProjectName)Fragment.java. Create that file in your project, using the "main" source
+ folder instead of "common" or "templates".
+ For instance, if your package name is com.example.foo, create the file
+ src/main/java/com/example/foo/FooFragment.java
+
+
+-Within this fragment, make sure that the onCreate method has the line
+ "setHasOptionsMenu(true);", to enable the fragment to handle menu events.
+
+-In order to override menu events, override onOptionsItemSelected.
+
+-refer to sampleSamples/fragmentViewSample for a reference implementation of a
+project built on this template.
+
+
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/proguard-project.txt b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/proguard-project.txt
new file mode 100644
index 0000000..f2fe155
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/proguard-project.txt
@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/AndroidManifest.xml b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..8f26c99
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/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/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/java/com/example/android/floatingactionbuttonbasic/FloatingActionButton.java b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/java/com/example/android/floatingactionbuttonbasic/FloatingActionButton.java
new file mode 100644
index 0000000..12fdd1c
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/java/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/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/java/com/example/android/floatingactionbuttonbasic/FloatingActionButtonBasicFragment.java b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/java/com/example/android/floatingactionbuttonbasic/FloatingActionButtonBasicFragment.java
new file mode 100644
index 0000000..817cfb7
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/java/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/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/animator/fab_anim.xml b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/animator/fab_anim.xml
new file mode 100644
index 0000000..dd83cd3
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/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/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable-hdpi/ic_launcher.png b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..5832eda
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable-mdpi/ic_launcher.png b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..08e272e
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..7803f2d
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable-xxhdpi/ic_add.png b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable-xxhdpi/ic_add.png
new file mode 100644
index 0000000..f3166df
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable-xxhdpi/ic_add.png
Binary files differ
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..a1f819c
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable-xxhdpi/ic_tick.png b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable-xxhdpi/ic_tick.png
new file mode 100644
index 0000000..56f0454
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable-xxhdpi/ic_tick.png
Binary files differ
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable/fab_background.xml b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable/fab_background.xml
new file mode 100644
index 0000000..e5e7dbc
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/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/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable/fab_icons.xml b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/drawable/fab_icons.xml
new file mode 100644
index 0000000..daf1d24
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/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/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/layout/fab_layout.xml b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/layout/fab_layout.xml
new file mode 100644
index 0000000..ab8c7dc
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/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/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/values/colors.xml b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/values/colors.xml
new file mode 100644
index 0000000..141b1f5
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/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/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/values/dimens.xml b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..f063937
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/src/main/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/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/tests/AndroidManifest.xml b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/tests/AndroidManifest.xml
new file mode 100644
index 0000000..6027422
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/tests/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?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.
+ -->
+
+<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.floatingactionbuttonbasic.tests"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
+ <!-- We add an application tag here just so that we can indicate that
+ this package needs to link against the android.test library,
+ which is needed when building test cases. -->
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!--
+ Specifies the instrumentation test runner used to run the tests.
+ -->
+ <instrumentation
+ android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.example.android.floatingactionbuttonbasic"
+ android:label="Tests for com.example.android.floatingactionbuttonbasic" />
+
+</manifest>
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/tests/src/com/example/android/floatingactionbuttonbasic/tests/SampleTests.java b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/tests/src/com/example/android/floatingactionbuttonbasic/tests/SampleTests.java
new file mode 100644
index 0000000..a900485
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/Application/tests/src/com/example/android/floatingactionbuttonbasic/tests/SampleTests.java
@@ -0,0 +1,62 @@
+/*
+* 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.tests;
+
+import com.example.android.floatingactionbuttonbasic.*;
+
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+* Tests for FloatingActionButtonBasic sample.
+*/
+public class SampleTests extends ActivityInstrumentationTestCase2<MainActivity> {
+
+ private MainActivity mTestActivity;
+ private FloatingActionButton mTestFragment;
+
+ public SampleTests() {
+ super(MainActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // Starts the activity under test using the default Intent with:
+ // action = {@link Intent#ACTION_MAIN}
+ // flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK}
+ // All other fields are null or empty.
+ mTestActivity = getActivity();
+ mTestFragment = (FloatingActionButton)
+ mTestActivity.getSupportFragmentManager().getFragments().get(1);
+ }
+
+ /**
+ * Test if the test fixture has been set up correctly.
+ */
+ public void testPreconditions() {
+ //Try to add a message to add context to your assertions. These messages will be shown if
+ //a tests fails and make it easy to understand why a test failed
+ assertNotNull("mTestActivity is null", mTestActivity);
+ assertNotNull("mTestFragment is null", mTestFragment);
+ }
+
+ /**
+ * Add more tests below.
+ */
+
+}
\ No newline at end of file
diff --git a/ui/notifications/BasicNotifications/CONTRIB.md b/ui/views/FloatingActionButton/FloatingActionButtonBasic/CONTRIB.md
similarity index 100%
copy from ui/notifications/BasicNotifications/CONTRIB.md
copy to ui/views/FloatingActionButton/FloatingActionButtonBasic/CONTRIB.md
diff --git a/ui/notifications/BasicNotifications/LICENSE b/ui/views/FloatingActionButton/FloatingActionButtonBasic/LICENSE
similarity index 100%
copy from ui/notifications/BasicNotifications/LICENSE
copy to ui/views/FloatingActionButton/FloatingActionButtonBasic/LICENSE
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/build.gradle b/ui/views/FloatingActionButton/FloatingActionButtonBasic/build.gradle
new file mode 100644
index 0000000..cda9c5c
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/build.gradle
@@ -0,0 +1,14 @@
+
+
+
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../../../build"
+ pathToSamplesCommon "../../../../common"
+}
+apply from: "../../../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/buildSrc/build.gradle b/ui/views/FloatingActionButton/FloatingActionButtonBasic/buildSrc/build.gradle
new file mode 100644
index 0000000..81f445f
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/buildSrc/build.gradle
@@ -0,0 +1,18 @@
+
+
+
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile 'org.freemarker:freemarker:2.3.20'
+}
+
+sourceSets {
+ main {
+ groovy {
+ srcDir new File(rootDir, "../../../../../../../build/buildSrc/src/main/groovy")
+ }
+ }
+}
+
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/gradle/wrapper/gradle-wrapper.jar b/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..0087cd3
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/gradle/wrapper/gradle-wrapper.properties b/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..893a63e
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Oct 15 14:12:11 BST 2014
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-1.12-bin.zip
diff --git a/ui/notifications/BasicNotifications/gradlew b/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/gradlew
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/gradlew.bat b/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
copy to ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/wrapper/gradle-wrapper.properties b/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..fc0d638
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Oct 14 12:13:20 MDT 2014
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip
diff --git a/ui/notifications/BasicNotifications/gradlew b/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to ui/views/FloatingActionButton/FloatingActionButtonBasic/gradlew
diff --git a/ui/notifications/BasicNotifications/gradlew.bat b/ui/views/FloatingActionButton/FloatingActionButtonBasic/gradlew.bat
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew.bat
copy to ui/views/FloatingActionButton/FloatingActionButtonBasic/gradlew.bat
diff --git a/ui/notifications/BasicNotifications/settings.gradle b/ui/views/FloatingActionButton/FloatingActionButtonBasic/settings.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/settings.gradle
copy to ui/views/FloatingActionButton/FloatingActionButtonBasic/settings.gradle
diff --git a/ui/views/FloatingActionButton/FloatingActionButtonBasic/template-params.xml b/ui/views/FloatingActionButton/FloatingActionButtonBasic/template-params.xml
new file mode 100644
index 0000000..0e97b7a
--- /dev/null
+++ b/ui/views/FloatingActionButton/FloatingActionButtonBasic/template-params.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.
+-->
+
+
+
+<sample>
+ <name>FloatingActionButtonBasic</name>
+ <group>UI</group>
+ <package>com.example.android.floatingactionbuttonbasic</package>
+
+ <!-- change minSdk if needed-->
+ <minSdk>21</minSdk>
+ <compileSdkVersion>21</compileSdkVersion>
+
+
+ <strings>
+ <intro>
+ <![CDATA[
+ This sample shows the two sizes of Floating Action Buttons and how to interact with
+ them.
+ ]]>
+ </intro>
+ </strings>
+
+ <template src="base"/>
+ <template src="FragmentView"/>
+ <common src="logger"/>
+ <common src="activities"/>
+
+</sample>
diff --git a/ui/views/HorizontalPaging/Application/src/main/AndroidManifest.xml b/ui/views/HorizontalPaging/Application/src/main/AndroidManifest.xml
index 33b9e15..1f6fdd2 100644
--- a/ui/views/HorizontalPaging/Application/src/main/AndroidManifest.xml
+++ b/ui/views/HorizontalPaging/Application/src/main/AndroidManifest.xml
@@ -22,9 +22,7 @@
<!-- While ViewPager will work on API 4 or above, tabs require an ActionBar. ActionBar is only
available in API 11 or above. -->
- <uses-sdk
- android:minSdkVersion="11"
- android:targetSdkVersion="16" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application
android:allowBackup="true"
diff --git a/ui/views/HorizontalPaging/Application/tests/AndroidManifest.xml b/ui/views/HorizontalPaging/Application/tests/AndroidManifest.xml
index 3f35ede..a8e7be5 100644
--- a/ui/views/HorizontalPaging/Application/tests/AndroidManifest.xml
+++ b/ui/views/HorizontalPaging/Application/tests/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/ui/notifications/BasicNotifications/Application/.gitignore b/ui/views/NavigationDrawer/Application/.gitignore
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/.gitignore
copy to ui/views/NavigationDrawer/Application/.gitignore
diff --git a/ui/notifications/BasicNotifications/Application/proguard-project.txt b/ui/views/NavigationDrawer/Application/proguard-project.txt
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/proguard-project.txt
copy to ui/views/NavigationDrawer/Application/proguard-project.txt
diff --git a/ui/views/NavigationDrawer/Application/src/main/AndroidManifest.xml b/ui/views/NavigationDrawer/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..ab2e141
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/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/ui/views/NavigationDrawer/Application/src/main/java/com/example/android/navigationdrawer/NavigationDrawerActivity.java b/ui/views/NavigationDrawer/Application/src/main/java/com/example/android/navigationdrawer/NavigationDrawerActivity.java
new file mode 100644
index 0000000..1176757
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/java/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/ui/views/NavigationDrawer/Application/src/main/java/com/example/android/navigationdrawer/PlanetAdapter.java b/ui/views/NavigationDrawer/Application/src/main/java/com/example/android/navigationdrawer/PlanetAdapter.java
new file mode 100644
index 0000000..5b449d0
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/java/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/ui/views/NavigationDrawer/Application/src/main/res/drawable-hdpi/action_search.png b/ui/views/NavigationDrawer/Application/src/main/res/drawable-hdpi/action_search.png
new file mode 100755
index 0000000..f12e005
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/res/drawable-hdpi/action_search.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/Application/src/main/res/drawable-hdpi/drawer_shadow.9.png b/ui/views/NavigationDrawer/Application/src/main/res/drawable-hdpi/drawer_shadow.9.png
new file mode 100644
index 0000000..224cc4f
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/res/drawable-hdpi/drawer_shadow.9.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/Application/src/main/res/drawable-hdpi/ic_drawer.png b/ui/views/NavigationDrawer/Application/src/main/res/drawable-hdpi/ic_drawer.png
new file mode 100644
index 0000000..ff7b1de
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/res/drawable-hdpi/ic_drawer.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/Application/src/main/res/drawable-hdpi/ic_launcher.png b/ui/views/NavigationDrawer/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100755
index 0000000..b460d60
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/Application/src/main/res/drawable-mdpi/action_search.png b/ui/views/NavigationDrawer/Application/src/main/res/drawable-mdpi/action_search.png
new file mode 100755
index 0000000..587d9e0
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/res/drawable-mdpi/action_search.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/Application/src/main/res/drawable-mdpi/drawer_shadow.9.png b/ui/views/NavigationDrawer/Application/src/main/res/drawable-mdpi/drawer_shadow.9.png
new file mode 100644
index 0000000..3797f99
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/res/drawable-mdpi/drawer_shadow.9.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/Application/src/main/res/drawable-mdpi/ic_drawer.png b/ui/views/NavigationDrawer/Application/src/main/res/drawable-mdpi/ic_drawer.png
new file mode 100644
index 0000000..fb681ba
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/res/drawable-mdpi/ic_drawer.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/Application/src/main/res/drawable-mdpi/ic_launcher.png b/ui/views/NavigationDrawer/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100755
index 0000000..dee53f4
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/Application/src/main/res/drawable-xhdpi/action_search.png b/ui/views/NavigationDrawer/Application/src/main/res/drawable-xhdpi/action_search.png
new file mode 100755
index 0000000..3549f84
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/res/drawable-xhdpi/action_search.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/Application/src/main/res/drawable-xhdpi/drawer_shadow.9.png b/ui/views/NavigationDrawer/Application/src/main/res/drawable-xhdpi/drawer_shadow.9.png
new file mode 100644
index 0000000..fa3d853
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/res/drawable-xhdpi/drawer_shadow.9.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/Application/src/main/res/drawable-xhdpi/ic_drawer.png b/ui/views/NavigationDrawer/Application/src/main/res/drawable-xhdpi/ic_drawer.png
new file mode 100644
index 0000000..b9bc3d7
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/res/drawable-xhdpi/ic_drawer.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/ui/views/NavigationDrawer/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100755
index 0000000..d4e1215
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/ui/views/NavigationDrawer/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..6ef21e1
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/NavigationDrawer/Application/src/main/res/drawable/earth.jpg b/ui/views/NavigationDrawer/Application/src/main/res/drawable/earth.jpg
new file mode 100644
index 0000000..6cabbf4
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/res/drawable/earth.jpg
Binary files differ
diff --git a/ui/views/NavigationDrawer/Application/src/main/res/drawable/jupiter.jpg b/ui/views/NavigationDrawer/Application/src/main/res/drawable/jupiter.jpg
new file mode 100644
index 0000000..24e8eea
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/res/drawable/jupiter.jpg
Binary files differ
diff --git a/ui/views/NavigationDrawer/Application/src/main/res/drawable/mars.jpg b/ui/views/NavigationDrawer/Application/src/main/res/drawable/mars.jpg
new file mode 100644
index 0000000..db253ef
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/res/drawable/mars.jpg
Binary files differ
diff --git a/ui/views/NavigationDrawer/Application/src/main/res/drawable/mercury.jpg b/ui/views/NavigationDrawer/Application/src/main/res/drawable/mercury.jpg
new file mode 100644
index 0000000..531790b
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/res/drawable/mercury.jpg
Binary files differ
diff --git a/ui/views/NavigationDrawer/Application/src/main/res/drawable/neptune.jpg b/ui/views/NavigationDrawer/Application/src/main/res/drawable/neptune.jpg
new file mode 100644
index 0000000..88467c5
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/res/drawable/neptune.jpg
Binary files differ
diff --git a/ui/views/NavigationDrawer/Application/src/main/res/drawable/saturn.jpg b/ui/views/NavigationDrawer/Application/src/main/res/drawable/saturn.jpg
new file mode 100644
index 0000000..8219d18
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/res/drawable/saturn.jpg
Binary files differ
diff --git a/ui/views/NavigationDrawer/Application/src/main/res/drawable/uranus.jpg b/ui/views/NavigationDrawer/Application/src/main/res/drawable/uranus.jpg
new file mode 100644
index 0000000..fa32e37
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/res/drawable/uranus.jpg
Binary files differ
diff --git a/ui/views/NavigationDrawer/Application/src/main/res/drawable/venus.jpg b/ui/views/NavigationDrawer/Application/src/main/res/drawable/venus.jpg
new file mode 100644
index 0000000..e04f078
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/res/drawable/venus.jpg
Binary files differ
diff --git a/ui/views/NavigationDrawer/Application/src/main/res/layout/activity_navigation_drawer.xml b/ui/views/NavigationDrawer/Application/src/main/res/layout/activity_navigation_drawer.xml
new file mode 100644
index 0000000..4e61639
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/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/ui/views/NavigationDrawer/Application/src/main/res/layout/drawer_list_item.xml b/ui/views/NavigationDrawer/Application/src/main/res/layout/drawer_list_item.xml
new file mode 100644
index 0000000..6d059ca
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/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/ui/views/NavigationDrawer/Application/src/main/res/layout/fragment_planet.xml b/ui/views/NavigationDrawer/Application/src/main/res/layout/fragment_planet.xml
new file mode 100644
index 0000000..7471a8f
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/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/ui/views/NavigationDrawer/Application/src/main/res/menu/navigation_drawer.xml b/ui/views/NavigationDrawer/Application/src/main/res/menu/navigation_drawer.xml
new file mode 100644
index 0000000..2549927
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/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/ui/views/NavigationDrawer/Application/src/main/res/values-v20/styles.xml b/ui/views/NavigationDrawer/Application/src/main/res/values-v20/styles.xml
new file mode 100644
index 0000000..01a2e28
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/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/ui/views/NavigationDrawer/Application/src/main/res/values/strings.xml b/ui/views/NavigationDrawer/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..7f8de63
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/src/main/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/ui/views/NavigationDrawer/Application/tests/AndroidManifest.xml b/ui/views/NavigationDrawer/Application/tests/AndroidManifest.xml
new file mode 100644
index 0000000..6a651a5
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/tests/AndroidManifest.xml
@@ -0,0 +1,59 @@
+<?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.
+-->
+
+
+
+<?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.
+ -->
+<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.navigationdrawer.tests"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
+ <!-- We add an application tag here just so that we can indicate that
+ this package needs to link against the android.test library,
+ which is needed when building test cases. -->
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!--
+ Specifies the instrumentation test runner used to run the tests.
+ -->
+ <instrumentation
+ android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.example.android.navigationdrawer"
+ android:label="Tests for com.example.android.navigationdrawer" />
+
+</manifest>
\ No newline at end of file
diff --git a/ui/views/NavigationDrawer/Application/tests/src/com/example/android/navigationdrawer/tests/SampleTests.java b/ui/views/NavigationDrawer/Application/tests/src/com/example/android/navigationdrawer/tests/SampleTests.java
new file mode 100644
index 0000000..eca6b61
--- /dev/null
+++ b/ui/views/NavigationDrawer/Application/tests/src/com/example/android/navigationdrawer/tests/SampleTests.java
@@ -0,0 +1,79 @@
+/*
+* 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 (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.navigationdrawer.tests;
+
+import com.example.android.navigationdrawer.*;
+
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+* Tests for NavigationDrawer sample.
+*/
+public class SampleTests extends ActivityInstrumentationTestCase2<MainActivity> {
+
+ private MainActivity mTestActivity;
+ private NavigationDrawerFragment mTestFragment;
+
+ public SampleTests() {
+ super(MainActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // Starts the activity under test using the default Intent with:
+ // action = {@link Intent#ACTION_MAIN}
+ // flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK}
+ // All other fields are null or empty.
+ mTestActivity = getActivity();
+ mTestFragment = (NavigationDrawerFragment)
+ mTestActivity.getSupportFragmentManager().getFragments().get(1);
+ }
+
+ /**
+ * Test if the test fixture has been set up correctly.
+ */
+ public void testPreconditions() {
+ //Try to add a message to add context to your assertions. These messages will be shown if
+ //a tests fails and make it easy to understand why a test failed
+ assertNotNull("mTestActivity is null", mTestActivity);
+ assertNotNull("mTestFragment is null", mTestFragment);
+ }
+
+ /**
+ * Add more tests below.
+ */
+
+}
\ No newline at end of file
diff --git a/ui/notifications/BasicNotifications/CONTRIB.md b/ui/views/NavigationDrawer/CONTRIB.md
similarity index 100%
copy from ui/notifications/BasicNotifications/CONTRIB.md
copy to ui/views/NavigationDrawer/CONTRIB.md
diff --git a/ui/notifications/BasicNotifications/LICENSE b/ui/views/NavigationDrawer/LICENSE
similarity index 100%
copy from ui/notifications/BasicNotifications/LICENSE
copy to ui/views/NavigationDrawer/LICENSE
diff --git a/ui/views/NavigationDrawer/README.md b/ui/views/NavigationDrawer/README.md
new file mode 100644
index 0000000..26fb4d9
--- /dev/null
+++ b/ui/views/NavigationDrawer/README.md
@@ -0,0 +1,50 @@
+Android Navigation Drawer Sample
+==============================
+
+This example illustrates a common usage of the DrawerLayout widget in the Android
+support library.
+
+Pre-requisites
+--------------
+
+- Android SDK (L Developer Preview)
+- Android Build Tools v20
+- Android Support Repository
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-Navigation Drawer
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2014 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements. See the NOTICE file distributed with this work for
+additional information regarding copyright ownership. The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/ui/views/NavigationDrawer/build.gradle b/ui/views/NavigationDrawer/build.gradle
new file mode 100644
index 0000000..be1fa82
--- /dev/null
+++ b/ui/views/NavigationDrawer/build.gradle
@@ -0,0 +1,14 @@
+
+
+
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../../build"
+ pathToSamplesCommon "../../../common"
+}
+apply from: "../../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/ui/notifications/BasicNotifications/buildSrc/build.gradle b/ui/views/NavigationDrawer/buildSrc/build.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/buildSrc/build.gradle
copy to ui/views/NavigationDrawer/buildSrc/build.gradle
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/ui/views/NavigationDrawer/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
copy to ui/views/NavigationDrawer/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/views/NavigationDrawer/gradle/wrapper/gradle-wrapper.properties b/ui/views/NavigationDrawer/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..c819e62
--- /dev/null
+++ b/ui/views/NavigationDrawer/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Jun 09 15:04:51 BST 2014
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip
diff --git a/ui/notifications/BasicNotifications/gradlew b/ui/views/NavigationDrawer/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to ui/views/NavigationDrawer/gradlew
diff --git a/ui/notifications/BasicNotifications/gradlew.bat b/ui/views/NavigationDrawer/gradlew.bat
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew.bat
copy to ui/views/NavigationDrawer/gradlew.bat
diff --git a/ui/views/NavigationDrawer/packaging.yaml b/ui/views/NavigationDrawer/packaging.yaml
new file mode 100644
index 0000000..f66fb11
--- /dev/null
+++ b/ui/views/NavigationDrawer/packaging.yaml
@@ -0,0 +1,15 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+
+status: PUBLISHED
+technologies: [Android]
+categories: [UI]
+languages: [Java]
+solutions: [Mobile]
+github: googlesamples/android-Navigation Drawer
+level: BEGINNER
+icon: Navigation DrawerSample/src/main/res/drawable-xxhdpi/ic_launcher.png
+license: apache2
diff --git a/ui/notifications/BasicNotifications/settings.gradle b/ui/views/NavigationDrawer/settings.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/settings.gradle
copy to ui/views/NavigationDrawer/settings.gradle
diff --git a/ui/views/NavigationDrawer/template-params.xml b/ui/views/NavigationDrawer/template-params.xml
new file mode 100644
index 0000000..2553ce9
--- /dev/null
+++ b/ui/views/NavigationDrawer/template-params.xml
@@ -0,0 +1,57 @@
+<?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.
+-->
+
+
+
+<sample>
+ <name>Navigation Drawer</name>
+ <group>UI</group>
+ <package>com.example.android.navigationdrawer</package>
+
+ <auto_add_support_lib>false</auto_add_support_lib>
+
+ <!-- change minSdk if needed-->
+ <minSdk>14</minSdk>
+ <compileSdkVersion>21</compileSdkVersion>
+
+
+ <dependency>com.android.support:support-v13:20.+</dependency>
+ <dependency>com.android.support:appcompat-v7:20.+</dependency>
+ <dependency>com.android.support:recyclerview-v7:+</dependency>
+ <dependency>com.android.support:cardview-v7:21.+</dependency>
+
+ <strings>
+ <intro>
+ <![CDATA[
+ This example illustrates a common usage of the DrawerLayout widget in the Android
+ support library.
+ ]]>
+ </intro>
+ </strings>
+
+ <activity>
+ <class>NavigationDrawerActivity</class>
+ <title>Navigation Drawer Example</title>
+ <description>This example illustrates a common usage of the DrawerLayout widget in the Android
+ support library.</description>
+ </activity>
+
+ <template src="base"/>
+ <template src="ActivityCards"/>
+ <common src="logger"/>
+
+</sample>
diff --git a/ui/notifications/BasicNotifications/Application/.gitignore b/ui/views/RecyclerView/Application/.gitignore
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/.gitignore
copy to ui/views/RecyclerView/Application/.gitignore
diff --git a/ui/notifications/BasicNotifications/Application/proguard-project.txt b/ui/views/RecyclerView/Application/proguard-project.txt
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/proguard-project.txt
copy to ui/views/RecyclerView/Application/proguard-project.txt
diff --git a/ui/views/RecyclerView/Application/src/androidTest/java/com/example/android/recyclerview/test/RecyclerViewSampleTests.java b/ui/views/RecyclerView/Application/src/androidTest/java/com/example/android/recyclerview/test/RecyclerViewSampleTests.java
new file mode 100644
index 0000000..6e63120
--- /dev/null
+++ b/ui/views/RecyclerView/Application/src/androidTest/java/com/example/android/recyclerview/test/RecyclerViewSampleTests.java
@@ -0,0 +1,70 @@
+/*
+* 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.test;
+
+import com.example.android.recyclerview.MainActivity;
+import com.example.android.recyclerview.R;
+import com.example.android.recyclerview.RecyclerViewFragment;
+
+import android.support.v4.app.Fragment;
+import android.support.v7.widget.RecyclerView;
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+* Tests for RecyclerView sample.
+*/
+public class RecyclerViewSampleTests extends ActivityInstrumentationTestCase2<MainActivity> {
+
+ private MainActivity mTestActivity;
+ private RecyclerViewFragment mTestFragment;
+
+ public RecyclerViewSampleTests() {
+ super(MainActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // Starts the activity under test using the default Intent with:
+ // action = {@link Intent#ACTION_MAIN}
+ // flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK}
+ // All other fields are null or empty.
+ mTestActivity = getActivity();
+ mTestFragment = (RecyclerViewFragment)
+ mTestActivity.getSupportFragmentManager().getFragments().get(1);
+ }
+
+ /**
+ * Test if the test fixture has been set up correctly.
+ */
+ public void testPreconditions() {
+ //Try to add a message to add context to your assertions. These messages will be shown if
+ //a tests fails and make it easy to understand why a test failed
+ assertNotNull("mTestActivity is null", mTestActivity);
+ assertNotNull("mTestFragment is null", mTestFragment);
+ }
+
+ public void testRecyclerViewElementCount() {
+ RecyclerView recyclerView =
+ (RecyclerView) mTestFragment.getView().findViewById(R.id.recyclerView);
+ int elementCount = recyclerView.getAdapter().getItemCount();
+ // There should be 60 elements in the RecyclerView's adapter.
+ assertEquals(60, elementCount);
+ }
+
+}
diff --git a/ui/views/RecyclerView/Application/src/main/AndroidManifest.xml b/ui/views/RecyclerView/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..2870f1e
--- /dev/null
+++ b/ui/views/RecyclerView/Application/src/main/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/ui/views/RecyclerView/Application/src/main/java/com/example/android/recyclerview/CustomAdapter.java b/ui/views/RecyclerView/Application/src/main/java/com/example/android/recyclerview/CustomAdapter.java
new file mode 100644
index 0000000..f8e3bae
--- /dev/null
+++ b/ui/views/RecyclerView/Application/src/main/java/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/ui/views/RecyclerView/Application/src/main/java/com/example/android/recyclerview/RecyclerViewFragment.java b/ui/views/RecyclerView/Application/src/main/java/com/example/android/recyclerview/RecyclerViewFragment.java
new file mode 100644
index 0000000..4f4a596
--- /dev/null
+++ b/ui/views/RecyclerView/Application/src/main/java/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/ui/views/RecyclerView/Application/src/main/res/drawable-hdpi/ic_launcher.png b/ui/views/RecyclerView/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..bcb72b1
--- /dev/null
+++ b/ui/views/RecyclerView/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/RecyclerView/Application/src/main/res/drawable-mdpi/ic_launcher.png b/ui/views/RecyclerView/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..37e5bce
--- /dev/null
+++ b/ui/views/RecyclerView/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/RecyclerView/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/ui/views/RecyclerView/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..1c4a85a
--- /dev/null
+++ b/ui/views/RecyclerView/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/RecyclerView/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/ui/views/RecyclerView/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b26545c
--- /dev/null
+++ b/ui/views/RecyclerView/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/RecyclerView/Application/src/main/res/layout/recycler_view_frag.xml b/ui/views/RecyclerView/Application/src/main/res/layout/recycler_view_frag.xml
new file mode 100644
index 0000000..6682468
--- /dev/null
+++ b/ui/views/RecyclerView/Application/src/main/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/ui/views/RecyclerView/Application/src/main/res/layout/text_row_item.xml b/ui/views/RecyclerView/Application/src/main/res/layout/text_row_item.xml
new file mode 100644
index 0000000..d552e0e
--- /dev/null
+++ b/ui/views/RecyclerView/Application/src/main/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/ui/views/RecyclerView/Application/src/main/res/values/strings.xml b/ui/views/RecyclerView/Application/src/main/res/values/strings.xml
new file mode 100644
index 0000000..179529c
--- /dev/null
+++ b/ui/views/RecyclerView/Application/src/main/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/ui/views/RecyclerView/CONTRIB.md b/ui/views/RecyclerView/CONTRIB.md
new file mode 100644
index 0000000..8ddb52d
--- /dev/null
+++ b/ui/views/RecyclerView/CONTRIB.md
@@ -0,0 +1,35 @@
+# How to become a contributor and submit your own code
+
+## Contributor License Agreements
+
+We'd love to accept your sample apps and patches! Before we can take them, we
+have to jump a couple of legal hurdles.
+
+Please fill out either the individual or corporate Contributor License Agreement (CLA).
+
+ * If you are an individual writing original source code and you're sure you
+ own the intellectual property, then you'll need to sign an [individual CLA]
+ (https://developers.google.com/open-source/cla/individual).
+ * If you work for a company that wants to allow you to contribute your work,
+ then you'll need to sign a [corporate CLA]
+ (https://developers.google.com/open-source/cla/corporate).
+
+Follow either of the two links above to access the appropriate CLA and
+instructions for how to sign and return it. Once we receive it, we'll be able to
+accept your pull requests.
+
+## Contributing A Patch
+
+1. Submit an issue describing your proposed change to the repo in question.
+1. The repo owner will respond to your issue promptly.
+1. If your proposed change is accepted, and you haven't already done so, sign a
+ Contributor License Agreement (see details above).
+1. Fork the desired repo, develop and test your code changes.
+1. Ensure that your code adheres to the existing style in the sample to which
+ you are contributing. Refer to the
+ [Google Cloud Platform Samples Style Guide]
+ (https://github.com/GoogleCloudPlatform/Template/wiki/style.html) for the
+ recommended coding standards for this organization.
+1. Ensure that your code has an appropriate set of unit tests which all pass.
+1. Submit a pull request.
+
diff --git a/ui/views/RecyclerView/LICENSE b/ui/views/RecyclerView/LICENSE
new file mode 100644
index 0000000..c02ca2f
--- /dev/null
+++ b/ui/views/RecyclerView/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ 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.
diff --git a/ui/views/RecyclerView/README.md b/ui/views/RecyclerView/README.md
new file mode 100644
index 0000000..fdfa4f1
--- /dev/null
+++ b/ui/views/RecyclerView/README.md
@@ -0,0 +1,49 @@
+Android RecyclerView Sample
+===========================
+
+Demonstration of using RecyclerView with a LinearLayoutManager to create a vertical ListView.
+
+Pre-requisites
+--------------
+
+- Android SDK (L Developer Preview)
+- Android Build Tools v20
+- Android Support Repository
+
+Getting Started
+---------------
+
+This sample uses the Gradle build system. To build this project, use the
+"gradlew build" command or use "Import Project" in Android Studio.
+
+Support
+-------
+
+- Google+ Community: https://plus.google.com/communities/105153134372062985968
+- Stack Overflow: http://stackoverflow.com/questions/tagged/android
+
+If you've found an error in this sample, please file an issue:
+https://github.com/googlesamples/android-BasicAndroidKeyStore
+
+Patches are encouraged, and may be submitted by forking this project and
+submitting a pull request through GitHub. Please see CONTRIBUTING.md for more details.
+
+License
+-------
+
+Copyright 2014 The Android Open Source Project, Inc.
+
+Licensed to the Apache Software Foundation (ASF) under one or more contributor
+license agreements. See the NOTICE file distributed with this work for
+additional information regarding copyright ownership. The ASF licenses this
+file to you under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
diff --git a/ui/views/RecyclerView/build.gradle b/ui/views/RecyclerView/build.gradle
new file mode 100644
index 0000000..be1fa82
--- /dev/null
+++ b/ui/views/RecyclerView/build.gradle
@@ -0,0 +1,14 @@
+
+
+
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../../build"
+ pathToSamplesCommon "../../../common"
+}
+apply from: "../../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/ui/notifications/BasicNotifications/buildSrc/build.gradle b/ui/views/RecyclerView/buildSrc/build.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/buildSrc/build.gradle
copy to ui/views/RecyclerView/buildSrc/build.gradle
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/ui/views/RecyclerView/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
copy to ui/views/RecyclerView/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/views/RecyclerView/gradle/wrapper/gradle-wrapper.properties b/ui/views/RecyclerView/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..65fb80a
--- /dev/null
+++ b/ui/views/RecyclerView/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Sep 08 13:53:18 PDT 2014
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-all.zip
diff --git a/ui/notifications/BasicNotifications/gradlew b/ui/views/RecyclerView/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to ui/views/RecyclerView/gradlew
diff --git a/ui/notifications/BasicNotifications/gradlew.bat b/ui/views/RecyclerView/gradlew.bat
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew.bat
copy to ui/views/RecyclerView/gradlew.bat
diff --git a/ui/views/RecyclerView/packaging.yaml b/ui/views/RecyclerView/packaging.yaml
new file mode 100644
index 0000000..8554a96
--- /dev/null
+++ b/ui/views/RecyclerView/packaging.yaml
@@ -0,0 +1,16 @@
+# GOOGLE SAMPLE PACKAGING DATA
+#
+# This file is used by Google as part of our samples packaging process.
+# End users may safely ignore this file. It has no relevance to other systems.
+---
+status: PUBLISHED
+technologies: [Android]
+categories: [UI]
+languages: [Java]
+solutions: [Mobile]
+github: googlesamples/android-RecyclerView
+level: INTERMEDIATE
+icon: RecyclerViewSample/src/main/res/drawable-xxhdpi/ic_launcher.png
+doc_refs:
+ - android:preview/material/ui-widgets.html
+license: apache2
diff --git a/ui/notifications/BasicNotifications/settings.gradle b/ui/views/RecyclerView/settings.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/settings.gradle
copy to ui/views/RecyclerView/settings.gradle
diff --git a/ui/views/RecyclerView/template-params.xml b/ui/views/RecyclerView/template-params.xml
new file mode 100644
index 0000000..76fbd83
--- /dev/null
+++ b/ui/views/RecyclerView/template-params.xml
@@ -0,0 +1,43 @@
+<?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.
+-->
+
+
+
+<sample>
+ <name>RecyclerView</name>
+ <group>UI</group>
+ <package>com.example.android.recyclerview</package>
+
+ <dependency>com.android.support:recyclerview-v7:+</dependency>
+
+ <!-- change minSdk if needed-->
+ <minSdk>7</minSdk>
+
+
+ <strings>
+ <intro>
+ <![CDATA[
+ Demonstration of using RecyclerView with a LayoutManager to create a vertical ListView.
+ ]]>
+ </intro>
+ </strings>
+
+ <template src="base"/>
+ <template src="FragmentView"/>
+ <common src="logger"/>
+ <common src="activities"/>
+</sample>
diff --git a/ui/notifications/BasicNotifications/Application/.gitignore b/ui/views/RevealEffect/RevealEffectBasic/Application/.gitignore
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/.gitignore
copy to ui/views/RevealEffect/RevealEffectBasic/Application/.gitignore
diff --git a/ui/views/RevealEffect/RevealEffectBasic/Application/README-fragmentview.txt b/ui/views/RevealEffect/RevealEffectBasic/Application/README-fragmentview.txt
new file mode 100644
index 0000000..38d903f
--- /dev/null
+++ b/ui/views/RevealEffect/RevealEffectBasic/Application/README-fragmentview.txt
@@ -0,0 +1,37 @@
+<!--
+ 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.
+-->
+
+Steps to implement FragmentView template:
+-in template-params.xml.ftl:
+ -add the following line to common imports
+ <common src="activities"/>
+
+-Add a Fragment to show behavior. In your MainActivity.java class, it will reference a Fragment
+ called (yourProjectName)Fragment.java. Create that file in your project, using the "main" source
+ folder instead of "common" or "templates".
+ For instance, if your package name is com.example.foo, create the file
+ src/main/java/com/example/foo/FooFragment.java
+
+
+-Within this fragment, make sure that the onCreate method has the line
+ "setHasOptionsMenu(true);", to enable the fragment to handle menu events.
+
+-In order to override menu events, override onOptionsItemSelected.
+
+-refer to sampleSamples/fragmentViewSample for a reference implementation of a
+project built on this template.
+
+
diff --git a/ui/notifications/BasicNotifications/Application/proguard-project.txt b/ui/views/RevealEffect/RevealEffectBasic/Application/proguard-project.txt
similarity index 100%
copy from ui/notifications/BasicNotifications/Application/proguard-project.txt
copy to ui/views/RevealEffect/RevealEffectBasic/Application/proguard-project.txt
diff --git a/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/AndroidManifest.xml b/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..da8646b
--- /dev/null
+++ b/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/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/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/java/com/example/android/revealeffectbasic/RevealEffectBasicFragment.java b/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/java/com/example/android/revealeffectbasic/RevealEffectBasicFragment.java
new file mode 100644
index 0000000..1520619
--- /dev/null
+++ b/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/java/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
diff --git a/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/drawable-hdpi/ic_launcher.png b/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..5acc60a
--- /dev/null
+++ b/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/drawable-mdpi/ic_launcher.png b/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..d3977a6
--- /dev/null
+++ b/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/drawable-xhdpi/ic_launcher.png b/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..71532a7
--- /dev/null
+++ b/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/drawable-xxhdpi/ic_launcher.png b/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..33d9879
--- /dev/null
+++ b/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/layout/reveal_effect_basic.xml b/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/layout/reveal_effect_basic.xml
new file mode 100644
index 0000000..f7f6923
--- /dev/null
+++ b/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/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/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/values/colors.xml b/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/values/colors.xml
new file mode 100644
index 0000000..52150b0
--- /dev/null
+++ b/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/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/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/values/dimens.xml b/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..e0ffc06
--- /dev/null
+++ b/ui/views/RevealEffect/RevealEffectBasic/Application/src/main/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/ui/views/RevealEffect/RevealEffectBasic/Application/tests/AndroidManifest.xml b/ui/views/RevealEffect/RevealEffectBasic/Application/tests/AndroidManifest.xml
new file mode 100644
index 0000000..a0d25c1
--- /dev/null
+++ b/ui/views/RevealEffect/RevealEffectBasic/Application/tests/AndroidManifest.xml
@@ -0,0 +1,59 @@
+<?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.
+-->
+
+
+
+<?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.
+ -->
+<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.revealeffectbasic.tests"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
+
+ <!-- We add an application tag here just so that we can indicate that
+ this package needs to link against the android.test library,
+ which is needed when building test cases. -->
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!--
+ Specifies the instrumentation test runner used to run the tests.
+ -->
+ <instrumentation
+ android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.example.android.revealeffectbasic"
+ android:label="Tests for com.example.android.revealeffectbasic" />
+
+</manifest>
\ No newline at end of file
diff --git a/ui/views/RevealEffect/RevealEffectBasic/Application/tests/src/com/example/android/revealeffectbasic/tests/SampleTests.java b/ui/views/RevealEffect/RevealEffectBasic/Application/tests/src/com/example/android/revealeffectbasic/tests/SampleTests.java
new file mode 100644
index 0000000..249f1ef
--- /dev/null
+++ b/ui/views/RevealEffect/RevealEffectBasic/Application/tests/src/com/example/android/revealeffectbasic/tests/SampleTests.java
@@ -0,0 +1,75 @@
+/*
+* 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 (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.revealeffectbasic.tests;
+
+import com.example.android.revealeffectbasic.*;
+
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+* Tests for RevealEffectBasic sample.
+*/
+public class SampleTests extends ActivityInstrumentationTestCase2<MainActivity> {
+
+ private MainActivity mTestActivity;
+ private RevealEffectBasicFragment mTestFragment;
+
+ public SampleTests() {
+ super(MainActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // Starts the activity under test using the default Intent with:
+ // action = {@link Intent#ACTION_MAIN}
+ // flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK}
+ // All other fields are null or empty.
+ mTestActivity = getActivity();
+ mTestFragment = (RevealEffectBasicFragment)
+ mTestActivity.getSupportFragmentManager().getFragments().get(1);
+ }
+
+ /**
+ * Test if the test fixture has been set up correctly.
+ */
+ public void testPreconditions() {
+ //Try to add a message to add context to your assertions. These messages will be shown if
+ //a tests fails and make it easy to understand why a test failed
+ assertNotNull("mTestActivity is null", mTestActivity);
+ assertNotNull("mTestFragment is null", mTestFragment);
+ assertNotNull("Circle view is null", mTestActivity.findViewById(R.id.circle));
+ }
+}
\ No newline at end of file
diff --git a/ui/notifications/BasicNotifications/CONTRIB.md b/ui/views/RevealEffect/RevealEffectBasic/CONTRIB.md
similarity index 100%
copy from ui/notifications/BasicNotifications/CONTRIB.md
copy to ui/views/RevealEffect/RevealEffectBasic/CONTRIB.md
diff --git a/ui/notifications/BasicNotifications/LICENSE b/ui/views/RevealEffect/RevealEffectBasic/LICENSE
similarity index 100%
copy from ui/notifications/BasicNotifications/LICENSE
copy to ui/views/RevealEffect/RevealEffectBasic/LICENSE
diff --git a/ui/views/RevealEffect/RevealEffectBasic/build.gradle b/ui/views/RevealEffect/RevealEffectBasic/build.gradle
new file mode 100644
index 0000000..cda9c5c
--- /dev/null
+++ b/ui/views/RevealEffect/RevealEffectBasic/build.gradle
@@ -0,0 +1,14 @@
+
+
+
+
+// BEGIN_EXCLUDE
+import com.example.android.samples.build.SampleGenPlugin
+apply plugin: SampleGenPlugin
+
+samplegen {
+ pathToBuild "../../../../../../build"
+ pathToSamplesCommon "../../../../common"
+}
+apply from: "../../../../../../build/build.gradle"
+// END_EXCLUDE
diff --git a/ui/views/RevealEffect/RevealEffectBasic/buildSrc/build.gradle b/ui/views/RevealEffect/RevealEffectBasic/buildSrc/build.gradle
new file mode 100644
index 0000000..81f445f
--- /dev/null
+++ b/ui/views/RevealEffect/RevealEffectBasic/buildSrc/build.gradle
@@ -0,0 +1,18 @@
+
+
+
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile 'org.freemarker:freemarker:2.3.20'
+}
+
+sourceSets {
+ main {
+ groovy {
+ srcDir new File(rootDir, "../../../../../../../build/buildSrc/src/main/groovy")
+ }
+ }
+}
+
diff --git a/ui/views/RevealEffect/RevealEffectBasic/gradle/gradle/wrapper/gradle-wrapper.jar b/ui/views/RevealEffect/RevealEffectBasic/gradle/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..5838598
--- /dev/null
+++ b/ui/views/RevealEffect/RevealEffectBasic/gradle/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/views/RevealEffect/RevealEffectBasic/gradle/gradle/wrapper/gradle-wrapper.properties b/ui/views/RevealEffect/RevealEffectBasic/gradle/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..02df8c4
--- /dev/null
+++ b/ui/views/RevealEffect/RevealEffectBasic/gradle/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Fri May 23 13:44:29 BST 2014
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-bin.zip
diff --git a/ui/notifications/BasicNotifications/gradlew b/ui/views/RevealEffect/RevealEffectBasic/gradle/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to ui/views/RevealEffect/RevealEffectBasic/gradle/gradlew
diff --git a/ui/notifications/BasicNotifications/gradlew.bat b/ui/views/RevealEffect/RevealEffectBasic/gradle/gradlew.bat
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew.bat
copy to ui/views/RevealEffect/RevealEffectBasic/gradle/gradlew.bat
diff --git a/ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar b/ui/views/RevealEffect/RevealEffectBasic/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
copy from ui/notifications/BasicNotifications/gradle/wrapper/gradle-wrapper.jar
copy to ui/views/RevealEffect/RevealEffectBasic/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/ui/views/RevealEffect/RevealEffectBasic/gradle/wrapper/gradle-wrapper.properties b/ui/views/RevealEffect/RevealEffectBasic/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..19c6ed1
--- /dev/null
+++ b/ui/views/RevealEffect/RevealEffectBasic/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Apr 10 15:27:10 PDT 2013
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.11-bin.zip
diff --git a/ui/notifications/BasicNotifications/gradlew b/ui/views/RevealEffect/RevealEffectBasic/gradlew
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew
copy to ui/views/RevealEffect/RevealEffectBasic/gradlew
diff --git a/ui/notifications/BasicNotifications/gradlew.bat b/ui/views/RevealEffect/RevealEffectBasic/gradlew.bat
similarity index 100%
copy from ui/notifications/BasicNotifications/gradlew.bat
copy to ui/views/RevealEffect/RevealEffectBasic/gradlew.bat
diff --git a/ui/notifications/BasicNotifications/settings.gradle b/ui/views/RevealEffect/RevealEffectBasic/settings.gradle
similarity index 100%
copy from ui/notifications/BasicNotifications/settings.gradle
copy to ui/views/RevealEffect/RevealEffectBasic/settings.gradle
diff --git a/ui/views/RevealEffect/RevealEffectBasic/template-params.xml b/ui/views/RevealEffect/RevealEffectBasic/template-params.xml
new file mode 100644
index 0000000..dea5695
--- /dev/null
+++ b/ui/views/RevealEffect/RevealEffectBasic/template-params.xml
@@ -0,0 +1,44 @@
+<?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.
+-->
+
+
+
+<sample>
+ <name>RevealEffectBasic</name>
+ <group>UI</group>
+ <package>com.example.android.revealeffectbasic</package>
+
+
+
+ <minSdk>21</minSdk>
+ <compileSdkVersion>21</compileSdkVersion>
+
+
+ <strings>
+ <intro>
+ <![CDATA[
+ Basic sample to demonstrate the reveal effect.
+ ]]>
+ </intro>
+ </strings>
+
+ <template src="base"/>
+ <template src="FragmentView"/>
+ <common src="logger"/>
+ <common src="activities"/>
+
+</sample>
diff --git a/ui/views/SlidingTabs/SlidingTabsBasic/Application/src/main/AndroidManifest.xml b/ui/views/SlidingTabs/SlidingTabsBasic/Application/src/main/AndroidManifest.xml
index 31cbfb8..441c3de 100644
--- a/ui/views/SlidingTabs/SlidingTabsBasic/Application/src/main/AndroidManifest.xml
+++ b/ui/views/SlidingTabs/SlidingTabsBasic/Application/src/main/AndroidManifest.xml
@@ -22,7 +22,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application android:allowBackup="true"
android:label="@string/app_name"
diff --git a/ui/views/SlidingTabs/SlidingTabsBasic/Application/tests/AndroidManifest.xml b/ui/views/SlidingTabs/SlidingTabsBasic/Application/tests/AndroidManifest.xml
index 8d8fa2b..3b7394c 100644
--- a/ui/views/SlidingTabs/SlidingTabsBasic/Application/tests/AndroidManifest.xml
+++ b/ui/views/SlidingTabs/SlidingTabsBasic/Application/tests/AndroidManifest.xml
@@ -39,9 +39,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="4"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/ui/views/SlidingTabs/SlidingTabsBasic/gradle/wrapper/gradle-wrapper.properties b/ui/views/SlidingTabs/SlidingTabsBasic/gradle/wrapper/gradle-wrapper.properties
index d647dee..7dc3dff 100644
--- a/ui/views/SlidingTabs/SlidingTabsBasic/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/views/SlidingTabs/SlidingTabsBasic/gradle/wrapper/gradle-wrapper.properties
@@ -3,5 +3,5 @@
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-all.zip
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip
diff --git a/ui/views/SlidingTabs/SlidingTabsColors/Application/src/main/AndroidManifest.xml b/ui/views/SlidingTabs/SlidingTabsColors/Application/src/main/AndroidManifest.xml
index be4a43a..5ff4240 100644
--- a/ui/views/SlidingTabs/SlidingTabsColors/Application/src/main/AndroidManifest.xml
+++ b/ui/views/SlidingTabs/SlidingTabsColors/Application/src/main/AndroidManifest.xml
@@ -22,7 +22,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application android:allowBackup="true"
android:label="@string/app_name"
diff --git a/ui/views/SlidingTabs/SlidingTabsColors/Application/tests/AndroidManifest.xml b/ui/views/SlidingTabs/SlidingTabsColors/Application/tests/AndroidManifest.xml
index f9fcf3e..b018f6c 100644
--- a/ui/views/SlidingTabs/SlidingTabsColors/Application/tests/AndroidManifest.xml
+++ b/ui/views/SlidingTabs/SlidingTabsColors/Application/tests/AndroidManifest.xml
@@ -21,9 +21,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="4"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/ui/views/SlidingTabs/SlidingTabsColors/gradle/wrapper/gradle-wrapper.properties b/ui/views/SlidingTabs/SlidingTabsColors/gradle/wrapper/gradle-wrapper.properties
index 2ea0b84..5fbce39 100644
--- a/ui/views/SlidingTabs/SlidingTabsColors/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/views/SlidingTabs/SlidingTabsColors/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-all.zip
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip
diff --git a/ui/views/SwipeRefreshLayout/SwipeRefreshLayoutBasic/Application/src/main/AndroidManifest.xml b/ui/views/SwipeRefreshLayout/SwipeRefreshLayoutBasic/Application/src/main/AndroidManifest.xml
index fa75453..245097d 100644
--- a/ui/views/SwipeRefreshLayout/SwipeRefreshLayoutBasic/Application/src/main/AndroidManifest.xml
+++ b/ui/views/SwipeRefreshLayout/SwipeRefreshLayoutBasic/Application/src/main/AndroidManifest.xml
@@ -22,7 +22,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="17" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application android:allowBackup="true"
android:label="@string/app_name"
diff --git a/ui/views/SwipeRefreshLayout/SwipeRefreshLayoutBasic/Application/tests/AndroidManifest.xml b/ui/views/SwipeRefreshLayout/SwipeRefreshLayoutBasic/Application/tests/AndroidManifest.xml
index 0da53b7..9455da6 100644
--- a/ui/views/SwipeRefreshLayout/SwipeRefreshLayoutBasic/Application/tests/AndroidManifest.xml
+++ b/ui/views/SwipeRefreshLayout/SwipeRefreshLayoutBasic/Application/tests/AndroidManifest.xml
@@ -39,9 +39,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/ui/views/SwipeRefreshLayout/SwipeRefreshLayoutBasic/gradle/wrapper/gradle-wrapper.properties b/ui/views/SwipeRefreshLayout/SwipeRefreshLayoutBasic/gradle/wrapper/gradle-wrapper.properties
index f699501..a9085ca 100644
--- a/ui/views/SwipeRefreshLayout/SwipeRefreshLayoutBasic/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/views/SwipeRefreshLayout/SwipeRefreshLayoutBasic/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-all.zip
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip
diff --git a/ui/views/SwipeRefreshLayout/SwipeRefreshListFragment/Application/src/main/AndroidManifest.xml b/ui/views/SwipeRefreshLayout/SwipeRefreshListFragment/Application/src/main/AndroidManifest.xml
index be44930..48f1a8d 100644
--- a/ui/views/SwipeRefreshLayout/SwipeRefreshListFragment/Application/src/main/AndroidManifest.xml
+++ b/ui/views/SwipeRefreshLayout/SwipeRefreshListFragment/Application/src/main/AndroidManifest.xml
@@ -22,7 +22,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application android:allowBackup="true"
android:label="@string/app_name"
diff --git a/ui/views/SwipeRefreshLayout/SwipeRefreshListFragment/Application/tests/AndroidManifest.xml b/ui/views/SwipeRefreshLayout/SwipeRefreshListFragment/Application/tests/AndroidManifest.xml
index a1f8f9b..8326b36 100644
--- a/ui/views/SwipeRefreshLayout/SwipeRefreshListFragment/Application/tests/AndroidManifest.xml
+++ b/ui/views/SwipeRefreshLayout/SwipeRefreshListFragment/Application/tests/AndroidManifest.xml
@@ -39,9 +39,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/ui/views/SwipeRefreshLayout/SwipeRefreshMultipleViews/Application/src/main/AndroidManifest.xml b/ui/views/SwipeRefreshLayout/SwipeRefreshMultipleViews/Application/src/main/AndroidManifest.xml
index aba15e0..b987db4 100644
--- a/ui/views/SwipeRefreshLayout/SwipeRefreshMultipleViews/Application/src/main/AndroidManifest.xml
+++ b/ui/views/SwipeRefreshLayout/SwipeRefreshMultipleViews/Application/src/main/AndroidManifest.xml
@@ -22,7 +22,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="17" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application android:allowBackup="true"
android:label="@string/app_name"
diff --git a/ui/views/SwipeRefreshLayout/SwipeRefreshMultipleViews/Application/tests/AndroidManifest.xml b/ui/views/SwipeRefreshLayout/SwipeRefreshMultipleViews/Application/tests/AndroidManifest.xml
index 8c9b277..dea1d96 100644
--- a/ui/views/SwipeRefreshLayout/SwipeRefreshMultipleViews/Application/tests/AndroidManifest.xml
+++ b/ui/views/SwipeRefreshLayout/SwipeRefreshMultipleViews/Application/tests/AndroidManifest.xml
@@ -39,9 +39,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/ui/views/TextSwitcher/Application/src/main/AndroidManifest.xml b/ui/views/TextSwitcher/Application/src/main/AndroidManifest.xml
index 7f512a3..70884cd 100644
--- a/ui/views/TextSwitcher/Application/src/main/AndroidManifest.xml
+++ b/ui/views/TextSwitcher/Application/src/main/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0" >
- <uses-sdk
- android:minSdkVersion="4"
- android:targetSdkVersion="17" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application
android:allowBackup="true"
diff --git a/ui/window/AdvancedImmersiveMode/Application/README-singleview.txt b/ui/window/AdvancedImmersiveMode/Application/README-singleview.txt
new file mode 100644
index 0000000..0cacd46
--- /dev/null
+++ b/ui/window/AdvancedImmersiveMode/Application/README-singleview.txt
@@ -0,0 +1,47 @@
+<#--
+ 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.
+-->
+
+Steps to implement SingleView template:
+-in template-params.xml.ftl:
+ -add the following line to common imports
+ <common src="activities"/>
+
+ -add a string for the action button's text using the element name "sample_action".
+ This element should be a child of <strings>:
+ <strings>
+ ...
+ <sample_action>ButtonText</sample_action>
+ ...
+ </strings>
+
+
+
+-Add a Fragment to handle behavior. In your MainActivity.java class, it will reference a Fragment
+ called (yourProjectName)Fragment.java. Create that file in your project, using the "main" source
+ folder instead of "common" or "templates".
+ For instance, if your package name is com.example.foo, create the file
+ src/main/java/com/example/foo/FooFragment.java
+
+
+-Within this fragment, make sure that the onCreate method has the line
+ "setHasOptionsMenu(true);", to enable the fragment to handle menu events.
+
+-In order to override menu events, override onOptionsItemSelected.
+
+-refer to sampleSamples/singleViewSample for a reference implementation of a
+project built on this template.
+
+
diff --git a/ui/window/AdvancedImmersiveMode/Application/src/main/AndroidManifest.xml b/ui/window/AdvancedImmersiveMode/Application/src/main/AndroidManifest.xml
index 1d01856..a96ebb4 100644
--- a/ui/window/AdvancedImmersiveMode/Application/src/main/AndroidManifest.xml
+++ b/ui/window/AdvancedImmersiveMode/Application/src/main/AndroidManifest.xml
@@ -27,7 +27,7 @@
<!-- This sample is to demonstrate features released in API 19.
So while it would technically run on an earlier version of Android,
there wouldn't be much point) -->
- <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- allowBackup declares if the app can be part of device-wide backups such as "adb backup" -->
<!-- theme is a way of applying UI decisions across your entire application. You can also
define it on a per-application basis. -->
diff --git a/ui/window/AdvancedImmersiveMode/Application/tests/AndroidManifest.xml b/ui/window/AdvancedImmersiveMode/Application/tests/AndroidManifest.xml
index 7117969..bb8c97e 100644
--- a/ui/window/AdvancedImmersiveMode/Application/tests/AndroidManifest.xml
+++ b/ui/window/AdvancedImmersiveMode/Application/tests/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="19"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/ui/window/AdvancedImmersiveMode/buildSrc/build.gradle b/ui/window/AdvancedImmersiveMode/buildSrc/build.gradle
index 490642d..e344a8c 100644
--- a/ui/window/AdvancedImmersiveMode/buildSrc/build.gradle
+++ b/ui/window/AdvancedImmersiveMode/buildSrc/build.gradle
@@ -1,8 +1,18 @@
+
+
+
repositories {
mavenCentral()
}
-
dependencies {
compile 'org.freemarker:freemarker:2.3.20'
- compile files("libs/buildSrc.jar")
}
+
+sourceSets {
+ main {
+ groovy {
+ srcDir new File(rootDir, "../../../../../../build/buildSrc/src/main/groovy")
+ }
+ }
+}
+
diff --git a/ui/window/AdvancedImmersiveMode/buildSrc/libs/buildSrc.jar b/ui/window/AdvancedImmersiveMode/buildSrc/libs/buildSrc.jar
deleted file mode 100644
index 8154696..0000000
--- a/ui/window/AdvancedImmersiveMode/buildSrc/libs/buildSrc.jar
+++ /dev/null
Binary files differ
diff --git a/ui/window/AdvancedImmersiveMode/gradle/wrapper/gradle-wrapper.properties b/ui/window/AdvancedImmersiveMode/gradle/wrapper/gradle-wrapper.properties
index 9e133a0..7817462 100644
--- a/ui/window/AdvancedImmersiveMode/gradle/wrapper/gradle-wrapper.properties
+++ b/ui/window/AdvancedImmersiveMode/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-all.zip
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip
diff --git a/ui/window/AdvancedImmersiveMode/template-params.xml b/ui/window/AdvancedImmersiveMode/template-params.xml
index c081c66..2ed54fd 100644
--- a/ui/window/AdvancedImmersiveMode/template-params.xml
+++ b/ui/window/AdvancedImmersiveMode/template-params.xml
@@ -22,7 +22,6 @@
<!-- change minSdk if needed-->
<minSdk>4</minSdk>
- <compileSdkVersion>19</compileSdkVersion>
<strings>
<intro>
diff --git a/ui/window/BasicImmersiveMode/Application/src/main/AndroidManifest.xml b/ui/window/BasicImmersiveMode/Application/src/main/AndroidManifest.xml
index 00b4e3c..d483d5b 100644
--- a/ui/window/BasicImmersiveMode/Application/src/main/AndroidManifest.xml
+++ b/ui/window/BasicImmersiveMode/Application/src/main/AndroidManifest.xml
@@ -19,7 +19,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application android:allowBackup="true"
android:label="@string/app_name"
diff --git a/ui/window/BasicImmersiveMode/Application/tests/AndroidManifest.xml b/ui/window/BasicImmersiveMode/Application/tests/AndroidManifest.xml
index 070368c..844c34d 100644
--- a/ui/window/BasicImmersiveMode/Application/tests/AndroidManifest.xml
+++ b/ui/window/BasicImmersiveMode/Application/tests/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="19"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/ui/window/BasicImmersiveMode/template-params.xml b/ui/window/BasicImmersiveMode/template-params.xml
index 1335908..cc663ab 100644
--- a/ui/window/BasicImmersiveMode/template-params.xml
+++ b/ui/window/BasicImmersiveMode/template-params.xml
@@ -19,11 +19,8 @@
<group>UI</group>
<package>com.example.android.basicimmersivemode</package>
-
-
<!-- change minSdk if needed-->
<minSdk>19</minSdk>
- <compileSdkVersion>19</compileSdkVersion>
<strings>
<intro>
diff --git a/ui/window/ImmersiveMode/Application/src/main/AndroidManifest.xml b/ui/window/ImmersiveMode/Application/src/main/AndroidManifest.xml
index 72a60ce..b558db6 100644
--- a/ui/window/ImmersiveMode/Application/src/main/AndroidManifest.xml
+++ b/ui/window/ImmersiveMode/Application/src/main/AndroidManifest.xml
@@ -19,7 +19,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application android:allowBackup="true"
android:label="@string/app_name"
diff --git a/ui/window/ImmersiveMode/Application/tests/AndroidManifest.xml b/ui/window/ImmersiveMode/Application/tests/AndroidManifest.xml
index b090189..9125fed 100644
--- a/ui/window/ImmersiveMode/Application/tests/AndroidManifest.xml
+++ b/ui/window/ImmersiveMode/Application/tests/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/ui/window/ImmersiveMode/template-params.xml b/ui/window/ImmersiveMode/template-params.xml
index e053d26..8959099 100644
--- a/ui/window/ImmersiveMode/template-params.xml
+++ b/ui/window/ImmersiveMode/template-params.xml
@@ -19,8 +19,6 @@
<group>UI</group>
<package>com.example.android.immersivemode</package>
- <compileSdkVersion>19</compileSdkVersion>
-
<!--TODO: change minSdk if needed-->
<minSdk>4</minSdk>
diff --git a/views/TextLinkify/Application/src/main/AndroidManifest.xml b/views/TextLinkify/Application/src/main/AndroidManifest.xml
index 49b4eae..eb55f20 100644
--- a/views/TextLinkify/Application/src/main/AndroidManifest.xml
+++ b/views/TextLinkify/Application/src/main/AndroidManifest.xml
@@ -22,9 +22,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="4"
- android:targetSdkVersion="17" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application
android:allowBackup="true"
diff --git a/views/TextLinkify/Application/tests/AndroidManifest.xml b/views/TextLinkify/Application/tests/AndroidManifest.xml
index e368f05..9a4dd16 100644
--- a/views/TextLinkify/Application/tests/AndroidManifest.xml
+++ b/views/TextLinkify/Application/tests/AndroidManifest.xml
@@ -20,9 +20,7 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="18"
- android:targetSdkVersion="19" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
diff --git a/wearable/wear/EmbeddedApp/Application/src/main/AndroidManifest.xml b/wearable/wear/EmbeddedApp/Application/src/main/AndroidManifest.xml
index eb2e01c..ee47ffe 100644
--- a/wearable/wear/EmbeddedApp/Application/src/main/AndroidManifest.xml
+++ b/wearable/wear/EmbeddedApp/Application/src/main/AndroidManifest.xml
@@ -16,7 +16,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.wearable.embeddedapp" >
- <uses-sdk android:minSdkVersion="18" android:targetSdkVersion="20" />
+ <!-- Min/target SDK versions (<uses-sdk>) managed by build.gradle -->
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
diff --git a/wearable/wear/SynchronizedNotifications/README-wear.txt b/wearable/wear/SynchronizedNotifications/README-wear.txt
index 033cde3..17523d7 100644
--- a/wearable/wear/SynchronizedNotifications/README-wear.txt
+++ b/wearable/wear/SynchronizedNotifications/README-wear.txt
@@ -1,5 +1,5 @@
<#--
- Copyright 2013 The Android Open Source Project
+ 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.
diff --git a/wearable/wear/SynchronizedNotifications/Shared/build.gradle b/wearable/wear/SynchronizedNotifications/Shared/build.gradle
index ebdb54b..dda6f07 100644
--- a/wearable/wear/SynchronizedNotifications/Shared/build.gradle
+++ b/wearable/wear/SynchronizedNotifications/Shared/build.gradle
@@ -22,7 +22,7 @@
'template'] // boilerplate code that is generated by the sample template process
android {
- compileSdkVersion 19
+ compileSdkVersion "android-L"
buildToolsVersion '20'
@@ -35,6 +35,4 @@
}
}
- productFlavors {
- }
}
diff --git a/wearable/wear/SynchronizedNotifications/Wearable/build.gradle b/wearable/wear/SynchronizedNotifications/Wearable/build.gradle
index 476fa4a..529a093 100644
--- a/wearable/wear/SynchronizedNotifications/Wearable/build.gradle
+++ b/wearable/wear/SynchronizedNotifications/Wearable/build.gradle
@@ -14,6 +14,7 @@
apply plugin: 'com.android.application'
+
dependencies {
compile 'com.google.android.gms:play-services:5.0.+@aar'
compile 'com.android.support:support-v13:20.0.+'