resolved conflicts for merge of 748fb34d to lmp-mr1-dev
Change-Id: I729cc4282ff2b65907fd8013de270bca514c6e83
diff --git a/apps/Development/res/layout/connectivity.xml b/apps/Development/res/layout/connectivity.xml
index 2aaf6c6..d23a6b1 100644
--- a/apps/Development/res/layout/connectivity.xml
+++ b/apps/Development/res/layout/connectivity.xml
@@ -274,6 +274,16 @@
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
+ <Button android:id="@+id/report_all_bad"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/report_all_bad" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
<Button android:id="@+id/crash"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/apps/Development/res/values/strings.xml b/apps/Development/res/values/strings.xml
index 0c13987..d670cf4 100644
--- a/apps/Development/res/values/strings.xml
+++ b/apps/Development/res/values/strings.xml
@@ -43,6 +43,8 @@
<string name="start_hipri">Start HiPri</string>
<string name="stop_hipri">Stop HiPri</string>
<string name="crash">CRASH</string>
+ <string name="report_all_bad">Report all bad</string>
+
<string name="netid">NetId</string>
<string name="add_default_route">Add Default Route</string>
<string name="remove_default_route">Remove Default Route</string>
diff --git a/apps/Development/src/com/android/development/Connectivity.java b/apps/Development/src/com/android/development/Connectivity.java
index 93d199b..a576eb3 100644
--- a/apps/Development/src/com/android/development/Connectivity.java
+++ b/apps/Development/src/com/android/development/Connectivity.java
@@ -29,6 +29,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.ConnectivityManager;
import android.net.LinkAddress;
+import android.net.Network;
import android.net.NetworkUtils;
import android.net.RouteInfo;
import android.net.wifi.ScanResult;
@@ -304,6 +305,7 @@
findViewById(R.id.stop_mms).setOnClickListener(mClickListener);
findViewById(R.id.start_hipri).setOnClickListener(mClickListener);
findViewById(R.id.stop_hipri).setOnClickListener(mClickListener);
+ findViewById(R.id.report_all_bad).setOnClickListener(mClickListener);
findViewById(R.id.crash).setOnClickListener(mClickListener);
findViewById(R.id.add_default_route).setOnClickListener(mClickListener);
@@ -318,6 +320,11 @@
registerReceiver(mReceiver, new IntentFilter(CONNECTIVITY_TEST_ALARM));
}
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ unregisterReceiver(mReceiver);
+ }
@Override
public void onResume() {
@@ -387,6 +394,9 @@
case R.id.add_default_route:
onAddDefaultRoute();
break;
+ case R.id.report_all_bad:
+ onReportAllBad();
+ break;
case R.id.crash:
onCrash();
break;
@@ -460,6 +470,13 @@
private void onStopScreenCycle() {
}
+ private void onReportAllBad() {
+ Network[] networks = mCm.getAllNetworks();
+ for (Network network : networks) {
+ mCm.reportBadNetwork(network);
+ }
+ }
+
private void onCrash() {
ConnectivityManager foo = null;
foo.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
diff --git a/build/product_sdk.mk b/build/product_sdk.mk
index 7aba4ee..68a4ecc 100644
--- a/build/product_sdk.mk
+++ b/build/product_sdk.mk
@@ -44,4 +44,5 @@
layoutlib-tests \
llvm-rs-cc \
sqlite3 \
- vgabios-cirrus.bin
+ vgabios-cirrus.bin \
+ split-select
diff --git a/build/sdk-windows-x86.atree b/build/sdk-windows-x86.atree
index a0e19ba..7ff3add 100644
--- a/build/sdk-windows-x86.atree
+++ b/build/sdk-windows-x86.atree
@@ -61,6 +61,9 @@
rm build-tools/${PLATFORM_NAME}/aapt
bin/aapt.exe strip build-tools/${PLATFORM_NAME}/aapt.exe
+rm build-tools/${PLATFORM_NAME}/split-select
+bin/split-select.exe strip build-tools/${PLATFORM_NAME}/split-select.exe
+
rm build-tools/${PLATFORM_NAME}/aidl
bin/aidl.exe strip build-tools/${PLATFORM_NAME}/aidl.exe
diff --git a/build/sdk.atree b/build/sdk.atree
index 229e782..9c7ba8a 100644
--- a/build/sdk.atree
+++ b/build/sdk.atree
@@ -79,6 +79,7 @@
# build tools from out/host/$(HOST_OS)-$(HOST_ARCH)/
bin/aapt strip build-tools/${PLATFORM_NAME}/aapt
bin/aidl strip build-tools/${PLATFORM_NAME}/aidl
+bin/split-select strip build-tools/${PLATFORM_NAME}/split-select
bin/zipalign strip build-tools/${PLATFORM_NAME}/zipalign
# renderscript (cc + headers)
diff --git a/build/tools/windows_sdk.mk b/build/tools/windows_sdk.mk
index d107d37..dadb773 100644
--- a/build/tools/windows_sdk.mk
+++ b/build/tools/windows_sdk.mk
@@ -41,6 +41,7 @@
prebuilt \
sqlite3 \
zipalign \
+ split-select \
$(WIN_SDK_TARGETS)
# This is the list of *Linux* build tools that we need
diff --git a/build/windows_sdk_whitelist.mk b/build/windows_sdk_whitelist.mk
index dfeaf3a..d91dde5 100644
--- a/build/windows_sdk_whitelist.mk
+++ b/build/windows_sdk_whitelist.mk
@@ -40,6 +40,7 @@
external/clang \
external/easymock \
external/expat \
+ external/gtest \
external/libcxx \
external/libcxxabi \
external/compiler-rt \
diff --git a/samples/ApiDemos/res/layout/media_projection.xml b/samples/ApiDemos/res/layout/media_projection.xml
index 412db4c..d9082a3 100644
--- a/samples/ApiDemos/res/layout/media_projection.xml
+++ b/samples/ApiDemos/res/layout/media_projection.xml
@@ -30,6 +30,7 @@
android:orientation="horizontal"
android:layout_alignParentBottom="true">
<ToggleButton
+ android:id="@+id/screen_sharing_toggle"
android:text="@string/screen_sharing_toggle"
android:layout_width="0dp"
android:layout_height="match_parent"
diff --git a/samples/ApiDemos/res/values/strings.xml b/samples/ApiDemos/res/values/strings.xml
index 58daf39..65bfba3 100644
--- a/samples/ApiDemos/res/values/strings.xml
+++ b/samples/ApiDemos/res/values/strings.xml
@@ -790,6 +790,10 @@
<string name="require_encryption">Require encryption</string>
<string name="activate_encryption">Activate encryption</string>
+ <string name="trust_agent_category">Trust Agent Features</string>
+ <string name="set_trust_agent_component_name">Enabled Component Name</string>
+ <string name="set_trust_agent_feature_list">Enabled Features (comma-separated)</string>
+
<!-- Strings used by DeviceAdminSample controller code -->
<string name="password_sufficient">Current password meets policy requirements</string>
<string name="password_insufficient">Current password does not meet policy requirements</string>
diff --git a/samples/ApiDemos/res/xml/device_admin_general.xml b/samples/ApiDemos/res/xml/device_admin_general.xml
index cfd0048..1d0084e 100644
--- a/samples/ApiDemos/res/xml/device_admin_general.xml
+++ b/samples/ApiDemos/res/xml/device_admin_general.xml
@@ -57,4 +57,19 @@
</PreferenceCategory>
+ <PreferenceCategory
+ android:title="@string/trust_agent_category" >
+
+ <EditTextPreference
+ android:key="key_trust_agent_component"
+ android:title="@string/set_trust_agent_component_name"
+ android:dialogTitle="@string/set_trust_agent_component_name" />
+
+ <EditTextPreference
+ android:key="key_trust_agent_features"
+ android:title="@string/set_trust_agent_feature_list"
+ android:dialogTitle="@string/set_trust_agent_feature_list" />
+
+ </PreferenceCategory>
+
</PreferenceScreen>
diff --git a/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.java b/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.java
index 82df903..71badcd 100644
--- a/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.java
+++ b/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.java
@@ -26,7 +26,9 @@
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.os.Bundle;
+import android.os.PersistableBundle;
import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
@@ -41,6 +43,8 @@
import android.util.Log;
import android.widget.Toast;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -71,6 +75,8 @@
private static final String KEY_DISABLE_NOTIFICATIONS = "key_disable_notifications";
private static final String KEY_DISABLE_UNREDACTED = "key_disable_unredacted";
private static final String KEY_DISABLE_TRUST_AGENTS = "key_disable_trust_agents";
+ private static final String KEY_TRUST_AGENT_COMPONENT = "key_trust_agent_component";
+ private static final String KEY_TRUST_AGENT_FEATURES = "key_trust_agent_features";
private static final String KEY_DISABLE_KEYGUARD_WIDGETS = "key_disable_keyguard_widgets";
private static final String KEY_DISABLE_KEYGUARD_SECURE_CAMERA
= "key_disable_keyguard_secure_camera";
@@ -274,6 +280,8 @@
private CheckBoxPreference mDisableKeyguardNotificationCheckbox;
private CheckBoxPreference mDisableKeyguardTrustAgentCheckbox;
private CheckBoxPreference mDisableKeyguardUnredactedCheckbox;
+ private EditTextPreference mTrustAgentComponent;
+ private EditTextPreference mTrustAgentFeatures;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -304,6 +312,14 @@
mDisableKeyguardTrustAgentCheckbox =
(CheckBoxPreference) findPreference(KEY_DISABLE_TRUST_AGENTS);
mDisableKeyguardTrustAgentCheckbox.setOnPreferenceChangeListener(this);
+
+ mTrustAgentComponent =
+ (EditTextPreference) findPreference(KEY_TRUST_AGENT_COMPONENT);
+ mTrustAgentComponent.setOnPreferenceChangeListener(this);
+
+ mTrustAgentFeatures =
+ (EditTextPreference) findPreference(KEY_TRUST_AGENT_FEATURES);
+ mTrustAgentFeatures.setOnPreferenceChangeListener(this);
}
// At onResume time, reload UI with current values as required
@@ -340,8 +356,8 @@
if (super.onPreferenceChange(preference, newValue)) {
return true;
}
- boolean value = (Boolean) newValue;
if (preference == mEnableCheckbox) {
+ boolean value = (Boolean) newValue;
if (value != mAdminActive) {
if (value) {
// Launch the activity to have the user enable our admin.
@@ -359,6 +375,7 @@
}
}
} else if (preference == mDisableCameraCheckbox) {
+ boolean value = (Boolean) newValue;
mDPM.setCameraDisabled(mDeviceAdminSample, value);
// Delay update because the change is only applied after exiting this method.
postReloadSummaries();
@@ -366,20 +383,39 @@
|| preference == mDisableKeyguardSecureCameraCheckbox
|| preference == mDisableKeyguardNotificationCheckbox
|| preference == mDisableKeyguardUnredactedCheckbox
- || preference == mDisableKeyguardTrustAgentCheckbox) {
- // Delay update because the change is only applied after exiting this method.
- getView().post(new Runnable() {
- @Override
- public void run() {
- mDPM.setKeyguardDisabledFeatures(mDeviceAdminSample,
- createKeyguardDisabledFlag());
- }
- });
+ || preference == mDisableKeyguardTrustAgentCheckbox
+ || preference == mTrustAgentComponent
+ || preference == mTrustAgentFeatures) {
+ postUpdateDpmDisableFeatures();
postReloadSummaries();
}
return true;
}
+ private void postUpdateDpmDisableFeatures() {
+ getView().post(new Runnable() {
+ @Override
+ public void run() {
+ mDPM.setKeyguardDisabledFeatures(mDeviceAdminSample,
+ createKeyguardDisabledFlag());
+ String component = mTrustAgentComponent.getText();
+ if (component != null) {
+ ComponentName agent = ComponentName.unflattenFromString(component);
+ if (agent != null) {
+ String featureString = mTrustAgentFeatures.getText();
+ if (featureString != null) {
+ PersistableBundle bundle = new PersistableBundle();
+ bundle.putStringArray("features", featureString.split(","));
+ mDPM.setTrustAgentConfiguration(mDeviceAdminSample, agent, bundle);
+ }
+ } else {
+ Log.w(TAG, "Invalid component: " + component);
+ }
+ }
+ }
+ });
+ }
+
@Override
protected void reloadSummaries() {
super.reloadSummaries();
@@ -416,6 +452,17 @@
R.string.keyguard_trust_agents_disabled
: R.string.keyguard_trust_agents_enabled);
mDisableKeyguardTrustAgentCheckbox.setSummary(keyguardEnableTrustAgentSummary);
+
+ final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
+ final boolean trustDisabled =
+ (disabled & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0;
+ String component = prefs.getString(mTrustAgentComponent.getKey(), null);
+ mTrustAgentComponent.setSummary(component);
+ mTrustAgentComponent.setEnabled(trustDisabled);
+
+ String features = prefs.getString(mTrustAgentFeatures.getKey(), null);
+ mTrustAgentFeatures.setSummary(features);
+ mTrustAgentFeatures.setEnabled(trustDisabled);
}
/** Updates the device capabilities area (dis/enabling) as the admin is (de)activated */
@@ -426,6 +473,8 @@
mDisableKeyguardNotificationCheckbox.setEnabled(enabled);
mDisableKeyguardUnredactedCheckbox.setEnabled(enabled);
mDisableKeyguardTrustAgentCheckbox.setEnabled(enabled);
+ mTrustAgentComponent.setEnabled(enabled);
+ mTrustAgentFeatures.setEnabled(enabled);
}
}
diff --git a/samples/ApiDemos/src/com/example/android/apis/media/projection/MediaProjectionDemo.java b/samples/ApiDemos/src/com/example/android/apis/media/projection/MediaProjectionDemo.java
index c593daf..f8a5d05 100644
--- a/samples/ApiDemos/src/com/example/android/apis/media/projection/MediaProjectionDemo.java
+++ b/samples/ApiDemos/src/com/example/android/apis/media/projection/MediaProjectionDemo.java
@@ -64,6 +64,7 @@
private VirtualDisplay mVirtualDisplay;
private Surface mSurface;
private SurfaceView mSurfaceView;
+ private ToggleButton mToggle;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -85,6 +86,8 @@
s.setAdapter(arrayAdapter);
s.setOnItemSelectedListener(new ResolutionSelector());
s.setSelection(0);
+
+ mToggle = (ToggleButton) findViewById(R.id.screen_sharing_toggle);
}
@Override
@@ -108,6 +111,7 @@
return;
}
mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
+ mMediaProjection.registerCallback(new MediaProjectionCallback(), null);
mVirtualDisplay = createVirtualDisplay();
}
@@ -133,11 +137,14 @@
}
private void stopScreenSharing() {
- mScreenSharing = false;
- if (mVirtualDisplay == null) {
- return;
+ if (mToggle.isChecked()) {
+ mToggle.setChecked(false);
}
- mVirtualDisplay.release();
+ mScreenSharing = false;
+ if (mVirtualDisplay != null) {
+ mVirtualDisplay.release();
+ mVirtualDisplay = null;
+ }
}
private VirtualDisplay createVirtualDisplay() {
diff --git a/samples/ApiDemos/src/com/example/android/apis/os/MmsMessagingDemo.java b/samples/ApiDemos/src/com/example/android/apis/os/MmsMessagingDemo.java
index 6a5d94c..0b66d6f 100644
--- a/samples/ApiDemos/src/com/example/android/apis/os/MmsMessagingDemo.java
+++ b/samples/ApiDemos/src/com/example/android/apis/os/MmsMessagingDemo.java
@@ -238,7 +238,8 @@
if (code == Activity.RESULT_OK) {
final byte[] response = intent.getByteArrayExtra(SmsManager.EXTRA_MMS_DATA);
if (response != null) {
- final GenericPdu pdu = new PduParser(response).parse();
+ final GenericPdu pdu = new PduParser(
+ response, PduParserUtil.shouldParseContentDisposition()).parse();
if (pdu instanceof SendConf) {
final SendConf sendConf = (SendConf) pdu;
if (sendConf.getResponseStatus() == PduHeaders.RESPONSE_STATUS_OK) {
@@ -281,7 +282,8 @@
final byte[] response = new byte[nBytes];
final int read = reader.read(response, 0, nBytes);
if (read == nBytes) {
- final GenericPdu pdu = new PduParser(response).parse();
+ final GenericPdu pdu = new PduParser(
+ response, PduParserUtil.shouldParseContentDisposition()).parse();
if (pdu instanceof RetrieveConf) {
final RetrieveConf retrieveConf = (RetrieveConf) pdu;
mRecipientsInput.setText(getRecipients(context, retrieveConf));
diff --git a/samples/ApiDemos/src/com/example/android/apis/os/MmsWapPushReceiver.java b/samples/ApiDemos/src/com/example/android/apis/os/MmsWapPushReceiver.java
index a291e4a..f2ca090 100644
--- a/samples/ApiDemos/src/com/example/android/apis/os/MmsWapPushReceiver.java
+++ b/samples/ApiDemos/src/com/example/android/apis/os/MmsWapPushReceiver.java
@@ -16,18 +16,18 @@
package com.example.android.apis.os;
-import com.google.android.mms.ContentType;
-import com.google.android.mms.pdu.GenericPdu;
-import com.google.android.mms.pdu.NotificationInd;
-import com.google.android.mms.pdu.PduHeaders;
-import com.google.android.mms.pdu.PduParser;
-
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.provider.Telephony;
import android.util.Log;
+import com.google.android.mms.ContentType;
+import com.google.android.mms.pdu.GenericPdu;
+import com.google.android.mms.pdu.NotificationInd;
+import com.google.android.mms.pdu.PduHeaders;
+import com.google.android.mms.pdu.PduParser;
+
/**
* Receiver for MMS WAP push
*/
@@ -39,7 +39,8 @@
if (Telephony.Sms.Intents.WAP_PUSH_RECEIVED_ACTION.equals(intent.getAction())
&& ContentType.MMS_MESSAGE.equals(intent.getType())) {
final byte[] data = intent.getByteArrayExtra("data");
- final PduParser parser = new PduParser(data);
+ final PduParser parser = new PduParser(
+ data, PduParserUtil.shouldParseContentDisposition());
GenericPdu pdu = null;
try {
pdu = parser.parse();
diff --git a/samples/ApiDemos/src/com/example/android/apis/os/PduParserUtil.java b/samples/ApiDemos/src/com/example/android/apis/os/PduParserUtil.java
new file mode 100644
index 0000000..541854e
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/os/PduParserUtil.java
@@ -0,0 +1,37 @@
+/*
+ * 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.apis.os;
+
+import android.telephony.SmsManager;
+
+/**
+ * Util methods for PduParser
+ */
+public class PduParserUtil {
+ /**
+ * Get the config of whether Content-Disposition header is supported
+ * for default carrier using new SmsManager API
+ *
+ * @return true if supported, false otherwise
+ */
+ public static boolean shouldParseContentDisposition() {
+ return SmsManager
+ .getDefault()
+ .getCarrierConfigValues()
+ .getBoolean(SmsManager.MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION, true);
+ }
+}
diff --git a/samples/SoftKeyboard/src/com/example/android/softkeyboard/ImePreferences.java b/samples/SoftKeyboard/src/com/example/android/softkeyboard/ImePreferences.java
index db6c1d9..14c67b7 100644
--- a/samples/SoftKeyboard/src/com/example/android/softkeyboard/ImePreferences.java
+++ b/samples/SoftKeyboard/src/com/example/android/softkeyboard/ImePreferences.java
@@ -41,6 +41,11 @@
setTitle(R.string.settings_name);
}
+ @Override
+ protected boolean isValidFragment(final String fragmentName) {
+ return Settings.class.getName().equals(fragmentName);
+ }
+
public static class Settings extends InputMethodSettingsFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
diff --git a/samples/Support7Demos/AndroidManifest.xml b/samples/Support7Demos/AndroidManifest.xml
index 4077bb1..1d087a4 100644
--- a/samples/Support7Demos/AndroidManifest.xml
+++ b/samples/Support7Demos/AndroidManifest.xml
@@ -31,7 +31,7 @@
reading images from the media store from API v19+. -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="17" />
+ <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="21" />
<!-- 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
@@ -86,6 +86,14 @@
</intent-filter>
</activity>
+ <activity android:name=".media.SampleMediaRouteSettingsActivity"
+ android:label="@string/sample_media_route_settings_activity"
+ android:theme="@style/Theme.AppCompat.Light">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
+ </activity>
+
<service android:name=".media.SampleMediaRouteProviderService"
android:label="@string/sample_media_route_provider_service"
android:process=":mrp">
@@ -130,6 +138,16 @@
</intent-filter>
</activity>
+ <activity android:name=".app.SearchActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.SEARCH" />
+ </intent-filter>
+
+ <meta-data android:name="android.app.searchable"
+ android:resource="@xml/searchable" />
+
+ </activity>
+
<activity android:name=".app.ActionBarUsage"
android:label="@string/action_bar_usage"
android:theme="@style/Theme.AppCompat">
@@ -151,7 +169,7 @@
<activity android:name=".app.ActionBarTabs"
android:label="@string/action_bar_tabs"
- android:theme="@style/Theme.AppCompat">
+ android:theme="@style/Theme.Custom">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
@@ -160,7 +178,7 @@
<activity android:name=".app.ActionBarSettingsActionProviderActivity"
android:label="@string/action_bar_settings_action_provider"
- android:theme="@style/Theme.AppCompat">
+ android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
@@ -177,15 +195,49 @@
</activity>
<activity android:name=".app.ActionBarWithDrawerLayout"
- android:label="@string/action_bar_with_navigation_drawer"
- android:theme="@style/Theme.AppCompat"
- >
+ android:label="@string/action_bar_with_navigation_drawer"
+ android:theme="@style/Theme.AppCompat"
+ >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="com.example.android.supportv7.SAMPLE_CODE"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".app.ToolbarUsage"
+ android:label="@string/toolbar_usage"
+ android:theme="@style/Theme.Custom.NoActionBar">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
+ </intent-filter>
+
+ <meta-data
+ android:name="android.app.default_searchable"
+ android:value=".app.SearchActivity" />
+ </activity>
+
+ <activity android:name=".app.ToolbarDisplayOptions"
+ android:label="@string/toolbar_display_options"
+ android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv7.SAMPLE_CODE" />
</intent-filter>
</activity>
+ <activity android:name=".app.ToolbarFragmentPagerMenu"
+ android:label="@string/toolbar_fragment_pager"
+ android:theme="@style/Theme.AppCompat.Light.NoActionBar">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
+ </intent-filter>
+ </activity>
+
+ <provider android:name=".app.RecentSuggestionsProvider"
+ android:authorities="com.example.android.supportv7.RecentSuggestionsProvider" />
+
<!-- RecyclerView samples -->
<activity android:name=".widget.RecyclerViewActivity"
android:label="@string/recycler_view"
diff --git a/samples/Support7Demos/res/layout/activity_card_view.xml b/samples/Support7Demos/res/layout/activity_card_view.xml
index cfd3071..9b985f7 100644
--- a/samples/Support7Demos/res/layout/activity_card_view.xml
+++ b/samples/Support7Demos/res/layout/activity_card_view.xml
@@ -123,13 +123,61 @@
android:layout_height="wrap_content"
android:layout_toRightOf="@id/alpha_label"
android:layout_alignTop="@id/alpha_label"/>
-
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="5dp"
+ android:id="@+id/color_label"
+ android:textColor="@android:color/black"
+ android:text="@string/card_view_bg_color"
+ android:layout_below="@id/alpha_label"
+ android:layout_alignRight="@id/alpha_label"/>
+ <RadioGroup
+ android:id="@+id/select_bg_color_radio"
+ android:layout_toRightOf="@id/color_label"
+ android:layout_alignTop="@id/color_label"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_below="@id/alpha_seek_bar">
+ <RadioButton
+ android:id="@+id/def"
+ android:layout_width="40dp"
+ android:layout_height="wrap_content"
+ android:background="@color/cardview_light_background"
+ android:checked="true"/>
+ <RadioButton
+ android:id="@+id/yellow"
+ android:layout_width="40dp"
+ android:layout_height="wrap_content"
+ android:background="@color/card_yellow"/>
+ <RadioButton
+ android:id="@+id/aquatic"
+ android:layout_width="40dp"
+ android:layout_height="wrap_content"
+ android:background="@color/card_aquatic"/>
+ <RadioButton
+ android:id="@+id/classic"
+ android:layout_width="40dp"
+ android:layout_height="wrap_content"
+ android:background="@color/card_classic"/>
+ <RadioButton
+ android:id="@+id/sunbrite"
+ android:layout_width="40dp"
+ android:layout_height="wrap_content"
+ android:background="@color/card_sunbrite"/>
+ <RadioButton
+ android:id="@+id/tropical"
+ android:layout_width="40dp"
+ android:layout_height="wrap_content"
+ android:background="@color/card_tropical"/>
+ </RadioGroup>
<RadioGroup
android:id="@+id/select_target_radio"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:layout_below="@id/alpha_seek_bar">
+ android:layout_below="@id/color_label">
<RadioButton
android:id="@+id/resize_card_view"
android:layout_width="wrap_content"
@@ -144,7 +192,6 @@
android:textColor="@android:color/black"
android:text="@string/card_view_resize_content"/>
</RadioGroup>
-
</RelativeLayout>
<RelativeLayout android:layout_width="fill_parent"
android:layout_height="match_parent">
@@ -155,9 +202,10 @@
card_view:cardElevation="10dp">
<TextView
android:id="@+id/info_text"
+ android:text="@string/card_view"
android:textColor="@android:color/black"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
</android.support.v7.widget.CardView>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@string/card_view_sample_text"
diff --git a/samples/Support7Demos/res/layout/toolbar_display_options.xml b/samples/Support7Demos/res/layout/toolbar_display_options.xml
new file mode 100644
index 0000000..cc3e66c
--- /dev/null
+++ b/samples/Support7Demos/res/layout/toolbar_display_options.xml
@@ -0,0 +1,85 @@
+<?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:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <android.support.v7.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:minHeight="?attr/actionBarSize"
+ android:background="?attr/colorPrimary" />
+
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <Button
+ android:id="@+id/toggle_home_as_up"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/toggle_home_as_up"/>
+
+ <Button
+ android:id="@+id/toggle_show_home"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/toggle_show_home"/>
+
+ <Button
+ android:id="@+id/toggle_use_logo"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/toggle_use_logo"/>
+
+ <Button
+ android:id="@+id/toggle_show_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/toggle_show_title"/>
+
+ <Button
+ android:id="@+id/toggle_show_custom"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/toggle_show_custom"/>
+
+ <Button
+ android:id="@+id/cycle_custom_gravity"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/cycle_custom_gravity"/>
+
+ <Button
+ android:id="@+id/toggle_visibility"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/toggle_visibility"/>
+
+ </LinearLayout>
+
+ </ScrollView>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/Support7Demos/res/layout/toolbar_fragment_pager.xml b/samples/Support7Demos/res/layout/toolbar_fragment_pager.xml
new file mode 100644
index 0000000..9f56f19
--- /dev/null
+++ b/samples/Support7Demos/res/layout/toolbar_fragment_pager.xml
@@ -0,0 +1,34 @@
+<?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="match_parent"
+ android:orientation="vertical">
+
+ <android.support.v7.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?actionBarSize"
+ android:background="?attr/colorPrimaryDark" />
+
+ <android.support.v4.view.ViewPager
+ android:id="@+id/viewpager"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/Support7Demos/res/layout/toolbar_usage.xml b/samples/Support7Demos/res/layout/toolbar_usage.xml
new file mode 100644
index 0000000..b202e1f
--- /dev/null
+++ b/samples/Support7Demos/res/layout/toolbar_usage.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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <android.support.v7.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:minHeight="?attr/actionBarSize"
+ android:background="?attr/colorPrimaryDark"
+ app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
+ app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:text="Your content"
+ android:gravity="center"
+ android:textAppearance="?android:attr/textAppearanceLarge"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/Support7Demos/res/menu/actions.xml b/samples/Support7Demos/res/menu/actions.xml
index 38d291e..43605fd 100644
--- a/samples/Support7Demos/res/menu/actions.xml
+++ b/samples/Support7Demos/res/menu/actions.xml
@@ -16,9 +16,9 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/action_search"
- android:icon="@android:drawable/ic_menu_search"
android:title="@string/action_bar_search"
- app:showAsAction="ifRoom"
+ android:icon="@drawable/abc_ic_search_api_mtrl_alpha"
+ app:showAsAction="ifRoom|collapseActionView"
app:actionViewClass="android.support.v7.widget.SearchView" />
<item android:id="@+id/action_add"
android:icon="@android:drawable/ic_menu_add"
@@ -30,6 +30,7 @@
<item android:id="@+id/action_share"
android:icon="@android:drawable/ic_menu_share"
android:title="@string/action_bar_share"
+ android:enabled="false"
app:showAsAction="ifRoom" />
<item android:id="@+id/action_sort"
android:icon="@android:drawable/ic_menu_sort_by_size"
@@ -38,12 +39,10 @@
<menu>
<item android:id="@+id/action_sort_size"
android:icon="@android:drawable/ic_menu_sort_by_size"
- android:title="@string/action_bar_sort_size"
- android:onClick="onSort" />
+ android:title="@string/action_bar_sort_size" />
<item android:id="@+id/action_sort_alpha"
android:icon="@android:drawable/ic_menu_sort_alphabetically"
- android:title="@string/action_bar_sort_alpha"
- android:onClick="onSort" />
+ android:title="@string/action_bar_sort_alpha" />
</menu>
</item>
</menu>
diff --git a/samples/Support7Demos/res/values/colors.xml b/samples/Support7Demos/res/values/colors.xml
index b129b8d..c8c67a0 100644
--- a/samples/Support7Demos/res/values/colors.xml
+++ b/samples/Support7Demos/res/values/colors.xml
@@ -16,4 +16,9 @@
<resources>
<drawable name="blue">#770000ff</drawable>
+ <color name="card_yellow">#FCF0AD</color>
+ <color name="card_aquatic">#FCF0AD</color>
+ <color name="card_classic">#BAB7A9</color>
+ <color name="card_sunbrite">#F9D6AC</color>
+ <color name="card_tropical">#56C4E8</color>
</resources>
diff --git a/samples/Support7Demos/res/values/strings.xml b/samples/Support7Demos/res/values/strings.xml
index 14569a5..4b3a28f 100644
--- a/samples/Support7Demos/res/values/strings.xml
+++ b/samples/Support7Demos/res/values/strings.xml
@@ -25,6 +25,7 @@
<string name="sample_media_router_text">This activity demonstrates how to
use MediaRouter from the support library. Select a route from the action bar.</string>
<string name="media_route_menu_title">Play on...</string>
+ <string name="sample_media_route_settings_activity">Sample route settings</string>
<string name="library_tab_text">Library</string>
<string name="playlist_tab_text">Playlist</string>
@@ -121,6 +122,9 @@
necessary.
</string>
+ <string name="toolbar_usage">AppCompat/Toolbar/Toolbar as Action Bar</string>
+ <string name="toolbar_display_options">AppCompat/Toolbar/Toolbar Display Options</string>
+ <string name="toolbar_fragment_pager">AppCompat/Toolbar/Toolbar Fragment ViewPager</string>
<string name="sample_media_route_provider_remote">Remote Playback (Simulated)</string>
<string name="sample_media_route_activity_local">Local Playback</string>
@@ -147,6 +151,7 @@
<string name="card_view_radius">Radius</string>
<string name="card_view_width">Width</string>
<string name="card_view_height">Height</string>
+ <string name="card_view_bg_color">Background</string>
<string name="card_view_elevation">Elevation</string>
<string name="card_view_max_elevation">Max Elevation</string>
<string name="card_view_alpha">Alpha</string>
@@ -156,5 +161,6 @@
<string name="palette">Palette</string>
<string name="palette_all_colors">Full color palette</string>
+ <string name="search_hint">Search...</string>
</resources>
diff --git a/samples/Support7Demos/res/values/styles.xml b/samples/Support7Demos/res/values/styles.xml
new file mode 100644
index 0000000..f085fa5
--- /dev/null
+++ b/samples/Support7Demos/res/values/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.Custom" parent="Theme.AppCompat.Light.DarkActionBar">
+ <item name="colorPrimary">#ff00bcd4</item>
+ <item name="colorPrimaryDark">#00838f</item>
+ <item name="colorAccent">#ffff00</item>
+ </style>
+
+ <style name="Theme.Custom.NoActionBar" parent="Theme.AppCompat.Light.NoActionBar">
+ <item name="colorPrimary">#ff00bcd4</item>
+ <item name="colorPrimaryDark">#00838f</item>
+ <item name="colorAccent">#ffff00</item>
+ </style>
+
+</resources>
\ No newline at end of file
diff --git a/samples/Support7Demos/res/xml/searchable.xml b/samples/Support7Demos/res/xml/searchable.xml
new file mode 100644
index 0000000..7f0fa74
--- /dev/null
+++ b/samples/Support7Demos/res/xml/searchable.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.
+-->
+
+<searchable xmlns:android="http://schemas.android.com/apk/res/android"
+ android:label="@string/activity_sample_code"
+ android:hint="@string/search_hint"
+ android:searchSuggestAuthority="com.example.android.supportv7.RecentSuggestionsProvider"
+ android:searchSuggestSelection=" ?" />
\ No newline at end of file
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarDisplayOptions.java b/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarDisplayOptions.java
index b7b25e8..ebda999 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarDisplayOptions.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarDisplayOptions.java
@@ -15,6 +15,8 @@
*/
package com.example.android.supportv7.app;
+import com.example.android.supportv7.R;
+
import android.os.Bundle;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.ActionBar;
@@ -24,8 +26,8 @@
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
-
-import com.example.android.supportv7.R;
+import android.widget.ArrayAdapter;
+import android.widget.Toast;
/**
* This demo shows how various action bar display option flags can be combined and their effects.
@@ -59,6 +61,21 @@
bar.addTab(bar.newTab().setText("Tab 1").setTabListener(this));
bar.addTab(bar.newTab().setText("Tab 2").setTabListener(this));
bar.addTab(bar.newTab().setText("Tab 3").setTabListener(this));
+
+ final ArrayAdapter<String> listAdapter = new ArrayAdapter<String>(bar.getThemedContext(),
+ R.layout.support_simple_spinner_dropdown_item,
+ new String[] { "Item 1", "Item 2", "Item 3" });
+ bar.setListNavigationCallbacks(listAdapter, new ActionBar.OnNavigationListener() {
+ @Override
+ public boolean onNavigationItemSelected(int itemPosition, long itemId) {
+ Toast.makeText(ActionBarDisplayOptions.this,
+ listAdapter.getItem(itemPosition),
+ Toast.LENGTH_SHORT).show();
+ return true;
+ }
+ });
+
+ bar.setLogo(R.drawable.ic_media_play);
}
@Override
@@ -94,10 +111,17 @@
flags = ActionBar.DISPLAY_SHOW_CUSTOM;
break;
case R.id.toggle_navigation:
- bar.setNavigationMode(
- bar.getNavigationMode() == ActionBar.NAVIGATION_MODE_STANDARD
- ? ActionBar.NAVIGATION_MODE_TABS
- : ActionBar.NAVIGATION_MODE_STANDARD);
+ switch (bar.getNavigationMode()) {
+ case ActionBar.NAVIGATION_MODE_STANDARD:
+ bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+ break;
+ case ActionBar.NAVIGATION_MODE_TABS:
+ bar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
+ break;
+ case ActionBar.NAVIGATION_MODE_LIST:
+ bar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
+ break;
+ }
return;
case R.id.cycle_custom_gravity: {
ActionBar.LayoutParams lp = mCustomViewLayoutParams;
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarTabs.java b/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarTabs.java
index aaa916c..4bfea50 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarTabs.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarTabs.java
@@ -36,7 +36,6 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
setContentView(R.layout.action_bar_tabs);
}
@@ -61,10 +60,8 @@
if (bar.getNavigationMode() == ActionBar.NAVIGATION_MODE_TABS) {
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
- bar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE, ActionBar.DISPLAY_SHOW_TITLE);
} else {
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
- bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
}
}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarUsage.java b/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarUsage.java
index 6ed59fb..f8c29ca 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarUsage.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarUsage.java
@@ -67,14 +67,19 @@
@Override
public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.action_sort_alpha:
+ case R.id.action_sort_size:
+ onSort(item);
+ break;
+ }
+
Toast.makeText(this, "Selected Item: " + item.getTitle(), Toast.LENGTH_SHORT).show();
+
return true;
}
- // This method is specified as an onClick handler in the menu xml and will
- // take precedence over the Activity's onOptionsItemSelected method.
- // See res/menu/actions.xml for more info.
- public void onSort(MenuItem item) {
+ private void onSort(MenuItem item) {
mSortMode = item.getItemId();
// Request a call to onPrepareOptionsMenu so we can change the sort icon
supportInvalidateOptionsMenu();
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/RecentSuggestionsProvider.java b/samples/Support7Demos/src/com/example/android/supportv7/app/RecentSuggestionsProvider.java
new file mode 100644
index 0000000..8d6666d
--- /dev/null
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/RecentSuggestionsProvider.java
@@ -0,0 +1,28 @@
+/*
+ * 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.supportv7.app;
+
+import android.content.SearchRecentSuggestionsProvider;
+
+public class RecentSuggestionsProvider extends SearchRecentSuggestionsProvider {
+ public final static String AUTHORITY = "com.example.android.supportv7.RecentSuggestionsProvider";
+ public final static int MODE = DATABASE_MODE_QUERIES;
+
+ public RecentSuggestionsProvider() {
+ setupSuggestions(AUTHORITY, MODE);
+ }
+}
\ No newline at end of file
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/SearchActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/app/SearchActivity.java
new file mode 100644
index 0000000..622516f
--- /dev/null
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/SearchActivity.java
@@ -0,0 +1,45 @@
+/*
+ * 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.supportv7.app;
+
+import android.app.Activity;
+import android.app.SearchManager;
+import android.content.Intent;
+import android.os.Bundle;
+import android.provider.SearchRecentSuggestions;
+
+/**
+ * An Activity which is only used for recieving ACTION_SEARCH intents, saving any queries
+ * to our SearchRecentSuggestions so that SearchView's can display suggestions.
+ */
+public class SearchActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Get the intent, verify the action and get the query
+ Intent intent = getIntent();
+ if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
+ String query = intent.getStringExtra(SearchManager.QUERY);
+ SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
+ RecentSuggestionsProvider.AUTHORITY, RecentSuggestionsProvider.MODE);
+ suggestions.saveRecentQuery(query, null);
+ finish();
+ }
+ }
+}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarDisplayOptions.java b/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarDisplayOptions.java
new file mode 100644
index 0000000..f5c3d75
--- /dev/null
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarDisplayOptions.java
@@ -0,0 +1,129 @@
+/*
+ * 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.supportv7.app;
+
+import com.example.android.supportv7.R;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.ActionBar.Tab;
+import android.support.v7.app.ActionBarActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.Gravity;
+import android.view.Menu;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.ArrayAdapter;
+import android.widget.Toast;
+
+/**
+ * This demo shows how various action bar display option flags can be combined and their effects
+ * when used on a Toolbar-provided Action Bar
+ */
+public class ToolbarDisplayOptions extends ActionBarActivity
+ implements View.OnClickListener {
+
+ private View mCustomView;
+ private ActionBar.LayoutParams mCustomViewLayoutParams;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.toolbar_display_options);
+
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+
+ findViewById(R.id.toggle_home_as_up).setOnClickListener(this);
+ findViewById(R.id.toggle_show_home).setOnClickListener(this);
+ findViewById(R.id.toggle_use_logo).setOnClickListener(this);
+ findViewById(R.id.toggle_show_title).setOnClickListener(this);
+ findViewById(R.id.toggle_show_custom).setOnClickListener(this);
+ findViewById(R.id.cycle_custom_gravity).setOnClickListener(this);
+ findViewById(R.id.toggle_visibility).setOnClickListener(this);
+
+ // Configure several action bar elements that will be toggled by display options.
+ mCustomView = getLayoutInflater().inflate(R.layout.action_bar_display_options_custom, null);
+ mCustomViewLayoutParams = new ActionBar.LayoutParams(
+ LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.display_options_actions, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onSupportNavigateUp() {
+ finish();
+ return true;
+ }
+
+ @Override
+ public void onClick(View v) {
+ final ActionBar bar = getSupportActionBar();
+ int flags = 0;
+ switch (v.getId()) {
+ case R.id.toggle_home_as_up:
+ flags = ActionBar.DISPLAY_HOME_AS_UP;
+ break;
+ case R.id.toggle_show_home:
+ flags = ActionBar.DISPLAY_SHOW_HOME;
+ break;
+ case R.id.toggle_use_logo:
+ flags = ActionBar.DISPLAY_USE_LOGO;
+ getSupportActionBar().setLogo(R.drawable.ic_media_play);
+ break;
+ case R.id.toggle_show_title:
+ flags = ActionBar.DISPLAY_SHOW_TITLE;
+ break;
+ case R.id.toggle_show_custom:
+ flags = ActionBar.DISPLAY_SHOW_CUSTOM;
+ break;
+ case R.id.cycle_custom_gravity: {
+ ActionBar.LayoutParams lp = mCustomViewLayoutParams;
+ int newGravity = 0;
+ switch (lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
+ case Gravity.LEFT:
+ newGravity = Gravity.CENTER_HORIZONTAL;
+ break;
+ case Gravity.CENTER_HORIZONTAL:
+ newGravity = Gravity.RIGHT;
+ break;
+ case Gravity.RIGHT:
+ newGravity = Gravity.LEFT;
+ break;
+ }
+ lp.gravity = lp.gravity & ~Gravity.HORIZONTAL_GRAVITY_MASK | newGravity;
+ bar.setCustomView(mCustomView, lp);
+ return;
+ }
+ case R.id.toggle_visibility:
+ if (bar.isShowing()) {
+ bar.hide();
+ } else {
+ bar.show();
+ }
+ return;
+ }
+
+ int change = bar.getDisplayOptions() ^ flags;
+ bar.setDisplayOptions(change, flags);
+ }
+}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarFragmentPagerMenu.java b/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarFragmentPagerMenu.java
new file mode 100644
index 0000000..9b57933
--- /dev/null
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarFragmentPagerMenu.java
@@ -0,0 +1,171 @@
+/*
+ * 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.supportv7.app;
+
+import com.example.android.supportv7.R;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v4.view.MenuItemCompat;
+import android.support.v4.view.ViewPager;
+import android.support.v7.app.ActionBarActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.CheckBox;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Demonstrates how fragments can participate in the options menu from within a {@link ViewPager}.
+ */
+public class ToolbarFragmentPagerMenu extends ActionBarActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.toolbar_fragment_pager);
+
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+
+ ViewPager vp = (ViewPager) findViewById(R.id.viewpager);
+ PagerAdapter adapter = new PagerAdapter(getSupportFragmentManager(),
+ new MenuFragment(), new Menu2Fragment());
+ vp.setAdapter(adapter);
+ }
+
+ private static class PagerAdapter extends FragmentPagerAdapter {
+ private final List<Fragment> mFragments;
+
+ public PagerAdapter(FragmentManager fm, Fragment... fragments) {
+ super(fm);
+
+ mFragments = new ArrayList<Fragment>();
+ for (Fragment fragment : fragments) {
+ mFragments.add(fragment);
+ }
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ return mFragments.get(position);
+ }
+
+ @Override
+ public int getCount() {
+ return mFragments.size();
+ }
+ }
+
+ /**
+ * A fragment that displays a menu. This fragment happens to not
+ * have a UI (it does not implement onCreateView), but it could also
+ * have one if it wanted.
+ */
+ public static class MenuFragment extends Fragment {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ MenuItemCompat.setShowAsAction(menu.add("Menu 1a"), MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+ MenuItemCompat.setShowAsAction(menu.add("Menu 1b"), MenuItemCompat.SHOW_AS_ACTION_NEVER);
+ super.onCreateOptionsMenu(menu, inflater);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ TextView textView = new TextView(container.getContext());
+
+ textView.setText(getClass().getSimpleName());
+ textView.setGravity(Gravity.CENTER);
+ textView.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+
+ return textView;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getTitle().equals("Menu 1a")) {
+ Toast.makeText(getActivity(), "Selected Menu 1a.", Toast.LENGTH_SHORT).show();
+ return true;
+ }
+ if (item.getTitle().equals("Menu 1b")) {
+ Toast.makeText(getActivity(), "Selected Menu 1b.", Toast.LENGTH_SHORT).show();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ /**
+ * Second fragment with a menu.
+ */
+ public static class Menu2Fragment extends Fragment {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ MenuItemCompat.setShowAsAction(menu.add("Menu 2"), MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ TextView textView = new TextView(container.getContext());
+
+ textView.setText(getClass().getSimpleName());
+ textView.setGravity(Gravity.CENTER);
+ textView.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+
+ return textView;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getTitle().equals("Menu 2")) {
+ Toast.makeText(getActivity(), "Selected Menu 2.", Toast.LENGTH_SHORT).show();
+ return true;
+ }
+ return false;
+ }
+ }
+}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarUsage.java b/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarUsage.java
new file mode 100644
index 0000000..f5ac03b
--- /dev/null
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarUsage.java
@@ -0,0 +1,80 @@
+/*
+ * 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.supportv7.app;
+
+import com.example.android.supportv7.R;
+
+import android.app.SearchManager;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v4.view.MenuItemCompat;
+import android.support.v7.app.ActionBarActivity;
+import android.support.v7.view.ActionMode;
+import android.support.v7.widget.PopupMenu;
+import android.support.v7.widget.SearchView;
+import android.support.v7.widget.Toolbar;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.Toast;
+
+/**
+ * This demonstrates idiomatic usage of the Toolbar as the action bar.
+ */
+public class ToolbarUsage extends ActionBarActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.toolbar_usage);
+
+ // Retrieve the Toolbar from our content view, and set it as the action bar
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.actions, menu);
+
+ // Retrieve the SearchView and plug it into SearchManager
+ final SearchView searchView = (SearchView) MenuItemCompat
+ .getActionView(menu.findItem(R.id.action_search));
+
+ SearchManager searchManager = (SearchManager) getSystemService(SEARCH_SERVICE);
+ searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ Toast.makeText(this, "Selected Item: " + item.getTitle(), Toast.LENGTH_SHORT).show();
+ return true;
+ }
+
+}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java b/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java
index 806df25..b3c14c2 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java
@@ -28,6 +28,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
+import android.support.v4.media.session.MediaSessionCompat;
import android.support.v7.media.MediaRouter.RouteInfo;
import android.support.v7.media.MediaItemStatus;
import android.util.Log;
@@ -56,12 +57,6 @@
private static final String TAG = "LocalPlayer";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private static final int STATE_IDLE = 0;
- private static final int STATE_PLAY_PENDING = 1;
- private static final int STATE_READY = 2;
- private static final int STATE_PLAYING = 3;
- private static final int STATE_PAUSED = 4;
-
private final Context mContext;
private final Handler mHandler = new Handler();
private MediaPlayer mMediaPlayer;
@@ -109,6 +104,11 @@
}
}
+ @Override
+ public MediaSessionCompat getMediaSession() {
+ return mMediaSession;
+ }
+
// Player
@Override
public void play(final PlaylistItem item) {
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java b/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java
index 32b1285..fcab57d 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java
@@ -16,11 +16,17 @@
package com.example.android.supportv7.media;
-import android.net.Uri;
+import android.app.PendingIntent;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.graphics.Bitmap;
+import android.support.v4.media.MediaMetadataCompat;
+import android.support.v4.media.session.MediaSessionCompat;
+import android.support.v4.media.session.PlaybackStateCompat;
import android.support.v7.media.MediaControlIntent;
import android.support.v7.media.MediaRouter.RouteInfo;
+import android.util.Log;
/**
* Abstraction of common playback operations of media items, such as play,
@@ -28,7 +34,18 @@
* of media items.
*/
public abstract class Player {
+ private static final String TAG = "SampleMediaRoutePlayer";
+ protected static final int STATE_IDLE = 0;
+ protected static final int STATE_PLAY_PENDING = 1;
+ protected static final int STATE_READY = 2;
+ protected static final int STATE_PLAYING = 3;
+ protected static final int STATE_PAUSED = 4;
+
+ private static final long PLAYBACK_ACTIONS = PlaybackStateCompat.ACTION_PAUSE
+ | PlaybackStateCompat.ACTION_PLAY;
+
protected Callback mCallback;
+ protected MediaSessionCompat mMediaSession;
public abstract boolean isRemotePlayback();
public abstract boolean isQueuingSupported();
@@ -61,7 +78,7 @@
mCallback = callback;
}
- public static Player create(Context context, RouteInfo route) {
+ public static Player create(Context context, RouteInfo route, MediaSessionCompat session) {
Player player;
if (route != null && route.supportsControlCategory(
MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) {
@@ -71,10 +88,62 @@
} else {
player = new LocalPlayer.OverlayPlayer(context);
}
+ player.initMediaSession(session);
player.connect(route);
return player;
}
+ public MediaSessionCompat getMediaSession() {
+ return mMediaSession;
+ }
+
+ protected void updateMetadata() {
+ if (mMediaSession == null) {
+ return;
+ }
+ MediaMetadataCompat.Builder bob = new MediaMetadataCompat.Builder();
+ bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, getDescription());
+ bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, "Subtitle of the thing");
+ bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_DESCRIPTION,
+ "Description of the thing");
+ bob.putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, getSnapshot());
+ mMediaSession.setMetadata(bob.build());
+ }
+
+ protected void publishState(int state) {
+ if (mMediaSession == null) {
+ return;
+ }
+ PlaybackStateCompat.Builder bob = new PlaybackStateCompat.Builder();
+ bob.setActions(PLAYBACK_ACTIONS);
+ switch (state) {
+ case STATE_PLAYING:
+ bob.setState(PlaybackStateCompat.STATE_PLAYING, -1, 1);
+ break;
+ case STATE_READY:
+ case STATE_PAUSED:
+ bob.setState(PlaybackStateCompat.STATE_PAUSED, -1, 0);
+ break;
+ case STATE_IDLE:
+ bob.setState(PlaybackStateCompat.STATE_STOPPED, -1, 0);
+ break;
+ }
+ PlaybackStateCompat pbState = bob.build();
+ Log.d(TAG, "Setting state to " + pbState);
+ mMediaSession.setPlaybackState(pbState);
+ if (state != STATE_IDLE) {
+ mMediaSession.setActive(true);
+ } else {
+ mMediaSession.setActive(false);
+ }
+ }
+
+ private void initMediaSession(MediaSessionCompat session) {
+ mMediaSession = session;
+ updateMetadata();
+ }
+
+
public interface Callback {
void onError();
void onCompletion();
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/RemotePlayer.java b/samples/Support7Demos/src/com/example/android/supportv7/media/RemotePlayer.java
index 5020c37..d47c260 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/RemotePlayer.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/RemotePlayer.java
@@ -140,6 +140,9 @@
}
if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
pause();
+ publishState(STATE_PAUSED);
+ } else {
+ publishState(STATE_PLAYING);
}
if (mCallback != null) {
mCallback.onPlaylistChanged();
@@ -214,6 +217,7 @@
if (mCallback != null) {
mCallback.onPlaylistChanged();
}
+ publishState(STATE_PAUSED);
}
@Override
@@ -239,6 +243,7 @@
if (mCallback != null) {
mCallback.onPlaylistChanged();
}
+ publishState(STATE_PLAYING);
}
@Override
@@ -254,6 +259,7 @@
// ignore if no session
return;
}
+ publishState(STATE_IDLE);
if (DEBUG) {
Log.d(TAG, "stop");
}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteControllerDialog.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteControllerDialog.java
deleted file mode 100644
index a2cacc3..0000000
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteControllerDialog.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * 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.supportv7.media;
-
-import com.example.android.supportv7.R;
-
-import android.app.Dialog;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.os.Bundle;
-import android.support.v7.app.MediaRouteControllerDialog;
-import android.support.v7.media.MediaRouteSelector;
-import android.support.v7.media.MediaRouter;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-/**
- * This class serves as an example on how to customize the media router control
- * dialog. It is derived from the standard MediaRouteControllerDialog with the
- * following overrides:
- *
- * 1. Shows thumbnail/snapshot of the current item
- *
- * 2. For variable volume routes, only allow volume control via Volume Up/Down
- * keys (to prevent accidental tapping on the volume adjust seekbar that sets
- * volume to maximum)
- *
- * 3. Provides transport control buttons (play/pause, stop)
- */
-public class SampleMediaRouteControllerDialog extends MediaRouteControllerDialog {
- private static final String TAG = "SampleMediaRouteControllerDialog";
- private final SampleMediaRouterActivity mActivity;
- private final SessionManager mSessionManager;
- private final Player mPlayer;
- private ImageButton mPauseResumeButton;
- private ImageButton mStopButton;
- private ImageView mThumbnail;
- private TextView mTextView;
- private LinearLayout mInfoLayout;
- private LinearLayout mVolumeLayout;
-
- public SampleMediaRouteControllerDialog(Context context,
- SessionManager manager, Player player) {
- super(context);
- mActivity = (SampleMediaRouterActivity) context;
- mSessionManager = manager;
- mPlayer = player;
- }
-
- @Override
- public View onCreateMediaControlView(Bundle savedInstanceState) {
- // Thumbnail and Track info
- View v = getLayoutInflater().inflate(R.layout.sample_media_controller, null);
- mInfoLayout = (LinearLayout)v.findViewById(R.id.media_route_info);
- mTextView = (TextView)v.findViewById(R.id.track_info);
- mThumbnail = (ImageView)v.findViewById(R.id.snapshot);
-
- // Transport controls
- mPauseResumeButton = (ImageButton)v.findViewById(R.id.pause_resume_button);
- mPauseResumeButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mActivity != null) {
- mActivity.handleMediaKey(new KeyEvent(KeyEvent.ACTION_DOWN,
- KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
- }
- }
- });
-
- mStopButton = (ImageButton)v.findViewById(R.id.stop_button);
- mStopButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mActivity != null) {
- mActivity.handleMediaKey(new KeyEvent(KeyEvent.ACTION_DOWN,
- KeyEvent.KEYCODE_MEDIA_STOP));
- }
- }
- });
-
- // update session status (will callback to updateUi at the end)
- mSessionManager.updateStatus();
- return v;
- }
-
- public void updateUi() {
- String trackInfo = mPlayer.getDescription();
- Bitmap snapshot = mPlayer.getSnapshot();
- if (mPlayer.isRemotePlayback() && !trackInfo.isEmpty() && snapshot != null) {
- mInfoLayout.setVisibility(View.VISIBLE);
- mThumbnail.setImageBitmap(snapshot);
- mTextView.setText(trackInfo);
- } else {
- mInfoLayout.setVisibility(View.GONE);
- }
- // show pause or resume icon depending on current state
- mPauseResumeButton.setImageResource(mSessionManager.isPaused() ?
- R.drawable.ic_media_play : R.drawable.ic_media_pause);
- }
-}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java
index 8a20564..15cf19b 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java
@@ -22,6 +22,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter.MalformedMimeTypeException;
+import android.content.IntentSender;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.media.AudioManager;
@@ -173,6 +174,10 @@
private void publishRoutes() {
Resources r = getContext().getResources();
+ Intent settingsIntent = new Intent(Intent.ACTION_MAIN);
+ settingsIntent.setClass(getContext(), SampleMediaRouteSettingsActivity.class);
+ IntentSender is = PendingIntent.getActivity(getContext(), 99, settingsIntent,
+ Intent.FLAG_ACTIVITY_NEW_TASK).getIntentSender();
MediaRouteDescriptor routeDescriptor1 = new MediaRouteDescriptor.Builder(
FIXED_VOLUME_ROUTE_ID,
@@ -183,6 +188,8 @@
.setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
.setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED)
.setVolume(VOLUME_MAX)
+ .setCanDisconnect(true)
+ .setSettingsActivity(is)
.build();
MediaRouteDescriptor routeDescriptor2 = new MediaRouteDescriptor.Builder(
@@ -195,6 +202,7 @@
.setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
.setVolumeMax(VOLUME_MAX)
.setVolume(mVolume)
+ .setSettingsActivity(is)
.build();
MediaRouteDescriptor routeDescriptor3 = new MediaRouteDescriptor.Builder(
@@ -207,6 +215,7 @@
.setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
.setVolumeMax(VOLUME_MAX)
.setVolume(mVolume)
+ .setCanDisconnect(true)
.build();
MediaRouteDescriptor routeDescriptor4 = new MediaRouteDescriptor.Builder(
@@ -239,7 +248,7 @@
public SampleRouteController(String routeId) {
mRouteId = routeId;
- mPlayer = Player.create(getContext(), null);
+ mPlayer = Player.create(getContext(), null, null);
mSessionManager.setPlayer(mPlayer);
mSessionManager.setCallback(new SessionManager.Callback() {
@Override
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteSettingsActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteSettingsActivity.java
new file mode 100644
index 0000000..a1d07fb
--- /dev/null
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteSettingsActivity.java
@@ -0,0 +1,27 @@
+/*
+ * 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.supportv7.media;
+
+import android.support.v7.app.ActionBarActivity;
+
+/**
+ * This activity is a dummy settings activity for the
+ * {@link SampleMediaRouteProvider}.
+ */
+public class SampleMediaRouteSettingsActivity extends ActionBarActivity {
+
+}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
index dfa1416..ba19499 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
@@ -20,6 +20,7 @@
import android.content.ComponentName;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.app.PendingIntent;
@@ -34,9 +35,11 @@
import android.os.Bundle;
import android.os.SystemClock;
import android.support.v4.app.FragmentManager;
+import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.MediaRouteActionProvider;
+import android.support.v7.app.MediaRouteButton;
import android.support.v7.app.MediaRouteControllerDialog;
import android.support.v7.app.MediaRouteControllerDialogFragment;
import android.support.v7.app.MediaRouteDiscoveryFragment;
@@ -66,6 +69,7 @@
import android.widget.TabHost.OnTabChangeListener;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
+
import java.io.File;
/**
@@ -93,7 +97,6 @@
private SeekBar mSeekBar;
private boolean mNeedResume;
private boolean mSeeking;
- private SampleMediaRouteControllerDialog mControllerDialog;
private final Handler mHandler = new Handler();
private final Runnable mUpdateSeekRunnable = new Runnable() {
@@ -130,19 +133,18 @@
public void onRouteSelected(MediaRouter router, RouteInfo route) {
Log.d(TAG, "onRouteSelected: route=" + route);
- mPlayer = Player.create(SampleMediaRouterActivity.this, route);
+ mPlayer = Player.create(SampleMediaRouterActivity.this, route, mMediaSession);
mPlayer.updatePresentation();
mSessionManager.setPlayer(mPlayer);
mSessionManager.unsuspend();
- registerRCC();
updateUi();
}
@Override
public void onRouteUnselected(MediaRouter router, RouteInfo route) {
Log.d(TAG, "onRouteUnselected: route=" + route);
- unregisterRCC();
+ mMediaSession.setActive(false);
PlaylistItem item = getCheckedPlaylistItem();
if (item != null) {
@@ -152,7 +154,6 @@
}
mPlayer.updatePresentation();
mPlayer.release();
- mControllerDialog = null;
}
@Override
@@ -183,7 +184,7 @@
}
};
- private RemoteControlClient mRemoteControlClient;
+ private MediaSessionCompat mMediaSession;
private ComponentName mEventReceiver;
private AudioManager mAudioManager;
private PendingIntent mMediaPendingIntent;
@@ -367,11 +368,13 @@
mMediaPendingIntent = PendingIntent.getBroadcast(this, 0, mediaButtonIntent, 0);
// Create and register the remote control client
- registerRCC();
+ createMediaSession();
+ mMediaRouter.setMediaSessionCompat(mMediaSession);
// Set up playback manager and player
mPlayer = Player.create(SampleMediaRouterActivity.this,
- mMediaRouter.getSelectedRoute());
+ mMediaRouter.getSelectedRoute(), mMediaSession);
+
mSessionManager.setPlayer(mPlayer);
mSessionManager.setCallback(new SessionManager.Callback() {
@Override
@@ -387,40 +390,42 @@
updateUi();
}
- private void registerRCC() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
- // Create the RCC and register with AudioManager and MediaRouter
- mAudioManager.requestAudioFocus(mAfChangeListener,
- AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
- mAudioManager.registerMediaButtonEventReceiver(mEventReceiver);
- mRemoteControlClient = new RemoteControlClient(mMediaPendingIntent);
- mAudioManager.registerRemoteControlClient(mRemoteControlClient);
- mMediaRouter.addRemoteControlClient(mRemoteControlClient);
- SampleMediaButtonReceiver.setActivity(SampleMediaRouterActivity.this);
- mRemoteControlClient.setTransportControlFlags(
- RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE);
- mRemoteControlClient.setPlaybackState(
- RemoteControlClient.PLAYSTATE_PLAYING);
- }
- }
+ private void createMediaSession() {
+ // Create the MediaSession
+ mMediaSession = new MediaSessionCompat(this, "SampleMediaRouter", mEventReceiver,
+ mMediaPendingIntent);
+ mMediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS
+ | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
+ mMediaSession.setCallback(new MediaSessionCompat.Callback() {
+ @Override
+ public boolean onMediaButtonEvent(Intent mediaButtonEvent) {
+ if (mediaButtonEvent != null) {
+ return handleMediaKey(
+ (KeyEvent) mediaButtonEvent.getParcelableExtra(Intent.EXTRA_KEY_EVENT));
+ }
+ return super.onMediaButtonEvent(mediaButtonEvent);
+ }
- private void unregisterRCC() {
- // Unregister the RCC with AudioManager and MediaRouter
- if (mRemoteControlClient != null) {
- mRemoteControlClient.setTransportControlFlags(0);
- mAudioManager.abandonAudioFocus(mAfChangeListener);
- mAudioManager.unregisterMediaButtonEventReceiver(mEventReceiver);
- mAudioManager.unregisterRemoteControlClient(mRemoteControlClient);
- mMediaRouter.removeRemoteControlClient(mRemoteControlClient);
- SampleMediaButtonReceiver.setActivity(null);
- mRemoteControlClient = null;
- }
+ @Override
+ public void onPlay() {
+ mSessionManager.resume();
+ }
+
+ @Override
+ public void onPause() {
+ mSessionManager.pause();
+ }
+ });
+
+ SampleMediaButtonReceiver.setActivity(SampleMediaRouterActivity.this);
}
public boolean handleMediaKey(KeyEvent event) {
- if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
+ if (event != null && event.getAction() == KeyEvent.ACTION_DOWN
+ && event.getRepeatCount() == 0) {
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+ case KeyEvent.KEYCODE_HEADSETHOOK:
{
Log.d(TAG, "Received Play/Pause event from RemoteControlClient");
if (mSessionManager.isPaused()) {
@@ -497,11 +502,9 @@
@Override
public void onDestroy() {
- // Unregister the remote control client
- unregisterRCC();
-
mSessionManager.stop();
mPlayer.release();
+ mMediaSession.release();
super.onDestroy();
}
@@ -520,15 +523,7 @@
mediaRouteActionProvider.setDialogFactory(new MediaRouteDialogFactory() {
@Override
public MediaRouteControllerDialogFragment onCreateControllerDialogFragment() {
- return new MediaRouteControllerDialogFragment() {
- @Override
- public MediaRouteControllerDialog onCreateControllerDialog(
- Context context, Bundle savedInstanceState) {
- mControllerDialog = new SampleMediaRouteControllerDialog(
- context, mSessionManager, mPlayer);
- return mControllerDialog;
- }
- };
+ return new ControllerDialogFragment(mPlayer);
}
});
@@ -564,8 +559,8 @@
updatePlaylist();
updateRouteDescription();
updateButtons();
- if (mControllerDialog != null) {
- mControllerDialog.updateUi();
+ if (mPlayer != null) {
+ mPlayer.updateMetadata();
}
}
@@ -593,11 +588,6 @@
// only enable seek bar when duration is known
PlaylistItem item = getCheckedPlaylistItem();
mSeekBar.setEnabled(item != null && item.getDuration() > 0);
- if (mRemoteControlClient != null) {
- mRemoteControlClient.setPlaybackState(mSessionManager.isPaused() ?
- RemoteControlClient.PLAYSTATE_PAUSED :
- RemoteControlClient.PLAYSTATE_PLAYING);
- }
}
private PlaylistItem getCheckedPlaylistItem() {
@@ -745,4 +735,35 @@
*/
public static class LightWithDarkActionBar extends SampleMediaRouterActivity {
}
+
+ public static class ControllerDialogFragment extends MediaRouteControllerDialogFragment {
+ private MediaRouteControllerDialog mControllerDialog;
+ private Player mPlayer;
+
+ public ControllerDialogFragment() {
+ super();
+ }
+
+ public ControllerDialogFragment(Player player) {
+ mPlayer = player;
+ }
+
+ @Override
+ public MediaRouteControllerDialog onCreateControllerDialog(
+ Context context, Bundle savedInstanceState) {
+ mControllerDialog = super.onCreateControllerDialog(context,
+ savedInstanceState);
+ mControllerDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ mControllerDialog = null;
+ }
+ });
+ return mControllerDialog;
+ }
+
+ public void setPlayer(Player player) {
+ mPlayer = player;
+ }
+ }
}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/view/CardViewActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/view/CardViewActivity.java
index ba4f0cb..ca0c08a 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/view/CardViewActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/view/CardViewActivity.java
@@ -16,6 +16,8 @@
package com.example.android.supportv7.view;
import android.app.Activity;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.view.ViewCompat;
@@ -25,8 +27,11 @@
import android.widget.RadioGroup;
import android.widget.SeekBar;
import android.widget.TextView;
+
import com.example.android.supportv7.R;
+import java.lang.reflect.Field;
+
public class CardViewActivity extends Activity {
CardView mCardView;
@@ -84,7 +89,7 @@
lp = setViewBounds(mInfoText);
}
mInfoText.setText("radius: " + mCornerRadiusSeekBar.getProgress()
- +", alpha: " + mAlphaSeekBar.getProgress()
+ + ", alpha: " + mAlphaSeekBar.getProgress()
+ "\n w: " + lp.width + "\nh: " + lp.height
+ "\nelevation: " + mCardView.getCardElevation() + " of "
+ mCardView.getMaxCardElevation());
@@ -143,15 +148,42 @@
}
});
- update();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
View content = findViewById(android.R.id.content);
+ mWidthSeekBar.setProgress(mCardView.getWidth());
+ mHeightSeekBar.setProgress(mCardView.getHeight());
mWidthSeekBar.setMax(content.getWidth());
mHeightSeekBar.setMax(content.getHeight());
+ update();
}
}, 100);
+
+ ((RadioGroup) findViewById(R.id.select_bg_color_radio))
+ .setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(RadioGroup group, int checkedId) {
+ mCardView.setCardBackgroundColor(
+ getResources().getColor(getColorId(checkedId)));
+ }
+ });
}
+ private int getColorId(int id) {
+ switch (id) {
+ case R.id.yellow:
+ return R.color.card_yellow;
+ case R.id.aquatic:
+ return R.color.card_aquatic;
+ case R.id.classic:
+ return R.color.card_classic;
+ case R.id.sunbrite:
+ return R.color.card_sunbrite;
+ case R.id.tropical:
+ return R.color.card_tropical;
+ default:
+ return R.color.cardview_light_background;
+ }
+ }
}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/AnimatedRecyclerView.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/AnimatedRecyclerView.java
index 50fe1e1..4c56933 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/AnimatedRecyclerView.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/AnimatedRecyclerView.java
@@ -124,8 +124,12 @@
public void itemClicked(View view) {
ViewGroup parent = (ViewGroup) view;
MyViewHolder holder = (MyViewHolder) mRecyclerView.getChildViewHolder(parent);
+ final int position = holder.getAdapterPosition();
+ if (position == RecyclerView.NO_POSITION) {
+ return;
+ }
mAdapter.toggleExpanded(holder);
- mAdapter.notifyItemChanged(holder.getPosition());
+ mAdapter.notifyItemChanged(position);
}
public void deleteItem(View view) {
@@ -240,7 +244,7 @@
if (lastVisibleView != null) {
RecyclerView.LayoutParams lastParams =
(RecyclerView.LayoutParams) lastVisibleView.getLayoutParams();
- int lastPosition = lastParams.getViewPosition();
+ int lastPosition = lastParams.getViewLayoutPosition();
final List<RecyclerView.ViewHolder> previousViews = recycler.getScrapList();
count = previousViews.size();
for (int i = 0; i < count; ++i) {
@@ -250,7 +254,7 @@
if (params.isItemRemoved()) {
continue;
}
- int position = params.getViewPosition();
+ int position = params.getViewLayoutPosition();
int newTop;
if (position < mFirstPosition) {
newTop = view.getHeight() * (position - mFirstPosition);
@@ -480,7 +484,7 @@
}
public void selectItem(MyViewHolder holder, boolean selected) {
- mSelected.put((String) holder.textView.getText(), selected);
+ mSelected.put((String) holder.textView.getText().toString(), selected);
}
public void toggleExpanded(MyViewHolder holder) {
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/BaseLayoutManagerActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/BaseLayoutManagerActivity.java
index 0a6ac6d..4bb64f4 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/BaseLayoutManagerActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/BaseLayoutManagerActivity.java
@@ -84,11 +84,10 @@
vh.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- final int pos = vh.getPosition();
- if (pos + 1 < getItemCount()) {
+ final int pos = vh.getAdapterPosition();
+ if (pos != RecyclerView.NO_POSITION && pos + 1 < getItemCount()) {
swap(pos, pos + 1);
}
- notifyItemChanged(pos);
}
});
return vh;
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/GridLayoutManagerActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/GridLayoutManagerActivity.java
index 00cfbf8..ef25c0b 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/GridLayoutManagerActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/GridLayoutManagerActivity.java
@@ -119,11 +119,13 @@
vh.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- final int pos = vh.getPosition();
+ final int pos = vh.getAdapterPosition();
+ if (pos == RecyclerView.NO_POSITION) {
+ return;
+ }
if (pos + 1 < getItemCount()) {
swap(pos, pos + 1);
}
- notifyItemChanged(pos);
}
});
return vh;
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/RecyclerViewActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/RecyclerViewActivity.java
index 747992b..38b50bd 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/RecyclerViewActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/RecyclerViewActivity.java
@@ -56,7 +56,10 @@
vh.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- final int pos = vh.getPosition();
+ final int pos = vh.getAdapterPosition();
+ if (pos == RecyclerView.NO_POSITION) {
+ return;
+ }
if (pos + 1 < getItemCount()) {
swap(pos, pos + 1);
}
diff --git a/samples/SupportLeanbackDemos/AndroidManifest.xml b/samples/SupportLeanbackDemos/AndroidManifest.xml
index 95f7a2c..391bcb7 100644
--- a/samples/SupportLeanbackDemos/AndroidManifest.xml
+++ b/samples/SupportLeanbackDemos/AndroidManifest.xml
@@ -10,10 +10,12 @@
android:label="@string/app_name"
android:icon="@drawable/ic_launcher"
android:banner="@drawable/ic_launcher"
+ android:supportsRtl="true"
android:theme="@style/Theme.Example.Leanback">
<activity android:name="MainActivity"
- android:label="@string/app_name">
+ android:label="@string/app_name"
+ android:theme="@style/Theme.Example.Leanback.Browse">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
@@ -25,6 +27,11 @@
</activity>
<activity android:name="DetailsActivity"
+ android:theme="@style/Theme.Example.Leanback.Details"
+ android:exported="true" />
+
+ <activity android:name="RowsActivity"
+ android:theme="@style/Theme.Example.Leanback.Rows"
android:exported="true" />
<activity android:name="PlaybackOverlayActivity"
@@ -39,5 +46,7 @@
<activity android:name="BrowseErrorActivity"
android:exported="true" />
+ <activity android:name="HorizontalGridTestActivity"
+ android:exported="true" />
</application>
</manifest>
diff --git a/samples/SupportLeanbackDemos/res/layout/horizontal_grid.xml b/samples/SupportLeanbackDemos/res/layout/horizontal_grid.xml
new file mode 100644
index 0000000..7faea03
--- /dev/null
+++ b/samples/SupportLeanbackDemos/res/layout/horizontal_grid.xml
@@ -0,0 +1,23 @@
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:lb="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+ <android.support.v17.leanback.widget.HorizontalGridView
+ android:id="@+id/gridview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipToPadding="false"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:background="#00ffff"
+ lb:horizontalMargin="12dip"
+ lb:verticalMargin="24dip"
+ lb:numberOfRows="3"
+ lb:rowHeight="150dip"
+ android:paddingBottom="12dip"
+ android:paddingLeft="12dip"
+ android:paddingRight="12dip"
+ android:paddingTop="12dip" />
+</RelativeLayout>
diff --git a/samples/SupportLeanbackDemos/res/layout/rows.xml b/samples/SupportLeanbackDemos/res/layout/rows.xml
new file mode 100644
index 0000000..d77f7ca
--- /dev/null
+++ b/samples/SupportLeanbackDemos/res/layout/rows.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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/rows_frame"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:id="@+id/rows_title"
+ android:text="RowsFragment"
+ style="?attr/browseTitleTextStyle"
+ android:paddingStart="?attr/browsePaddingStart"
+ android:paddingEnd="?attr/browsePaddingEnd"
+ android:paddingTop="?attr/browsePaddingTop"
+ android:paddingBottom="10dp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ <fragment
+ android:name="com.example.android.leanback.RowsFragment"
+ android:id="@+id/main_rows_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ />
+
+</FrameLayout>
diff --git a/samples/SupportLeanbackDemos/res/values/styles.xml b/samples/SupportLeanbackDemos/res/values/styles.xml
new file mode 100644
index 0000000..17ea0ef
--- /dev/null
+++ b/samples/SupportLeanbackDemos/res/values/styles.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.
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <style name="Widget.Example.Leanback.Title.Text" parent="Widget.Leanback.Title.Text" >
+ </style>
+ <style name="Widget.Example.Leanback.Rows.VerticalGridView" parent="Widget.Leanback.Rows.VerticalGridView">
+ <item name="android:paddingTop">96dp</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/samples/SupportLeanbackDemos/res/values/themes.xml b/samples/SupportLeanbackDemos/res/values/themes.xml
index 121e25c..22a41f0 100644
--- a/samples/SupportLeanbackDemos/res/values/themes.xml
+++ b/samples/SupportLeanbackDemos/res/values/themes.xml
@@ -1,13 +1,28 @@
+<?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.Example.Leanback" parent="Theme.Leanback">
-<!-- uncomment to override default transition settings:
- <item name="android:windowEnterTransition">@android:transition/fade</item>
- <item name="android:windowExitTransition">@android:transition/fade</item>
- <item name="android:windowSharedElementExitTransition">@android:transition/move</item>
- <item name="android:windowSharedElementEnterTransition">@android:transition/move</item>
- <item name="android:windowAllowExitTransitionOverlap">true</item>
- <item name="android:windowAllowEnterTransitionOverlap">false</item>
- <item name="android:windowContentTransitions">true</item>
- -->
+ </style>
+ <style name="Theme.Example.Leanback.Browse" parent="Theme.Leanback.Browse">
+ </style>
+ <style name="Theme.Example.Leanback.Details" parent="Theme.Leanback.Details">
+ </style>
+ <style name="Theme.Example.Leanback.Rows" parent="Theme.Leanback">
+ <item name="browseTitleTextStyle">@style/Widget.Example.Leanback.Title.Text</item>
+ <item name="rowsVerticalGridStyle">@style/Widget.Example.Leanback.Rows.VerticalGridView</item>
</style>
</resources>
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseAnimationFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseAnimationFragment.java
index e6b92c4..3883081 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseAnimationFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseAnimationFragment.java
@@ -23,6 +23,7 @@
import android.support.v17.leanback.widget.Row;
import android.util.Log;
import android.view.View;
+import android.os.Handler;
import java.util.Random;
@@ -76,13 +77,13 @@
mRowsAdapter = new ArrayObjectAdapter(lrp);
for (int i = 0; i < NUM_ROWS; ++i) {
mRowsAdapter.add(
- createRandomRow(new HeaderItem(i, "Row " + i, null)));
+ createRandomRow(new HeaderItem(i, "Row " + i)));
}
setAdapter(mRowsAdapter);
}
Item createRandomItem() {
- switch (sRand.nextInt(13)) {
+ switch (sRand.nextInt(15)) {
default:
case 0:
return new Item("Remove Item before", new OnItemClickedListener() {
@@ -198,7 +199,7 @@
if (index >= 0) {
int headerId = sRand.nextInt();
mRowsAdapter.add(index, createRandomRow(new HeaderItem(
- headerId, "Row " + headerId, null)));
+ headerId, "Row " + headerId)));
}
}
});
@@ -211,7 +212,7 @@
int headerId = sRand.nextInt();
mRowsAdapter.add(
index + 1, createRandomRow(new HeaderItem(
- headerId, "Row " + headerId, null)));
+ headerId, "Row " + headerId)));
}
}
});
@@ -242,6 +243,35 @@
}
}
});
+ case 13:
+ return new Item("Replace Item before", new OnItemClickedListener() {
+ @Override
+ public void onItemClicked(Object item, Row row) {
+ ArrayObjectAdapter adapter = ((ArrayObjectAdapter) ((ListRow) row)
+ .getAdapter());
+ int index = adapter.indexOf(item);
+ if (index >= 0) {
+ if (index > 0)
+ index--;
+ adapter.replace(index, createRandomItem());
+ }
+ }
+ });
+ case 14:
+ return new Item("Remove all then re-add", new OnItemClickedListener() {
+ @Override
+ public void onItemClicked(Object item, Row row) {
+ final ArrayObjectAdapter adapter = ((ArrayObjectAdapter) ((ListRow) row)
+ .getAdapter());
+ adapter.clear();
+ new Handler().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ adapter.add(0, createRandomItem());
+ }
+ }, 1000);
+ }
+ });
}
}
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseErrorActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseErrorActivity.java
index a35ab5e..f2f6192 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseErrorActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseErrorActivity.java
@@ -50,6 +50,9 @@
handler.postDelayed(new Runnable() {
@Override
public void run() {
+ if (getFragmentManager().isDestroyed()) {
+ return;
+ }
getFragmentManager().beginTransaction().remove(mSpinnerFragment).commit();
mErrorFragment.setErrorContent(getResources());
}
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java
index abf82e3..91fec5f 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java
@@ -15,6 +15,7 @@
import android.content.Intent;
import android.os.Bundle;
+import android.os.Handler;
import android.support.v4.app.ActivityOptionsCompat;
import android.support.v17.leanback.widget.ArrayObjectAdapter;
import android.support.v17.leanback.widget.HeaderItem;
@@ -33,6 +34,7 @@
public class BrowseFragment extends android.support.v17.leanback.app.BrowseFragment {
private static final String TAG = "leanback.BrowseFragment";
+ private static final boolean TEST_ENTRANCE_TRANSITION = true;
private static final int NUM_ROWS = 10;
private ArrayObjectAdapter mRowsAdapter;
@@ -62,6 +64,18 @@
Log.i(TAG, "onItemSelected: " + item + " row " + row);
}
});
+ if (TEST_ENTRANCE_TRANSITION) {
+ // don't run entrance transition if Activity is restored.
+ if (savedInstanceState == null) {
+ prepareEntranceTransition();
+ }
+ // simulate delay loading data
+ new Handler().postDelayed(new Runnable() {
+ public void run() {
+ startEntranceTransition();
+ }
+ }, 2000);
+ }
}
private void setupRows() {
@@ -78,14 +92,14 @@
for (int i = 0; i < NUM_ROWS; ++i) {
ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_1));
- listRowAdapter.add(new PhotoItem("This is a test", R.drawable.gallery_photo_2));
- listRowAdapter.add(new PhotoItem("Android TV", R.drawable.gallery_photo_3));
+ listRowAdapter.add(new PhotoItem("This is a test", "Only a test", R.drawable.gallery_photo_2));
+ listRowAdapter.add(new PhotoItem("Android TV", "by Google", R.drawable.gallery_photo_3));
listRowAdapter.add(new PhotoItem("Leanback", R.drawable.gallery_photo_4));
listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_5));
- listRowAdapter.add(new PhotoItem("This is a test", R.drawable.gallery_photo_6));
- listRowAdapter.add(new PhotoItem("Android TV", R.drawable.gallery_photo_7));
- listRowAdapter.add(new PhotoItem("Leanback", R.drawable.gallery_photo_8));
- HeaderItem header = new HeaderItem(i, "Row " + i, null);
+ listRowAdapter.add(new PhotoItem("This is a test", "Only a test", R.drawable.gallery_photo_6));
+ listRowAdapter.add(new PhotoItem("Android TV", "open RowsActivity", R.drawable.gallery_photo_7));
+ listRowAdapter.add(new PhotoItem("Leanback", "open MainActivity", R.drawable.gallery_photo_8));
+ HeaderItem header = new HeaderItem(i, "Row " + i);
mRowsAdapter.add(new ListRow(header, listRowAdapter));
}
@@ -96,13 +110,25 @@
@Override
public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
RowPresenter.ViewHolder rowViewHolder, Row row) {
- Intent intent = new Intent(getActivity(), DetailsActivity.class);
- intent.putExtra(DetailsActivity.EXTRA_ITEM, (PhotoItem) item);
- Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(
- getActivity(),
- ((ImageCardView)itemViewHolder.view).getMainImageView(),
- DetailsActivity.SHARED_ELEMENT_NAME).toBundle();
+ Intent intent;
+ Bundle bundle;
+ if ( ((PhotoItem) item).getImageResourceId() == R.drawable.gallery_photo_8) {
+ intent = new Intent(getActivity(), MainActivity.class);
+ bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity())
+ .toBundle();
+ } else if ( ((PhotoItem) item).getImageResourceId() == R.drawable.gallery_photo_7) {
+ intent = new Intent(getActivity(), RowsActivity.class);
+ bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity())
+ .toBundle();
+ } else {
+ intent = new Intent(getActivity(), DetailsActivity.class);
+ intent.putExtra(DetailsActivity.EXTRA_ITEM, (PhotoItem) item);
+ bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(
+ getActivity(),
+ ((ImageCardView)itemViewHolder.view).getMainImageView(),
+ DetailsActivity.SHARED_ELEMENT_NAME).toBundle();
+ }
getActivity().startActivity(intent, bundle);
}
}
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/CardPresenter.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/CardPresenter.java
index 4c53342..f5e486b 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/CardPresenter.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/CardPresenter.java
@@ -17,17 +17,21 @@
import android.graphics.drawable.Drawable;
import android.support.v17.leanback.widget.ImageCardView;
import android.support.v17.leanback.widget.Presenter;
+import android.text.TextUtils;
import android.util.Log;
import android.view.ViewGroup;
import android.view.View.MeasureSpec;
import android.view.ViewGroup.LayoutParams;
import android.widget.TextView;
+import java.util.Random;
+
public class CardPresenter extends Presenter {
private static final String TAG = "CardPresenter";
private static final int IMAGE_HEIGHT_DP = 120;
+ private static Random sRand = new Random();
private static int sRowHeight = 0;
private static int sExpandedRowHeight = 0;
@@ -62,8 +66,17 @@
ImageCardView v = new ImageCardView(parent.getContext());
v.setFocusable(true);
v.setFocusableInTouchMode(true);
- v.setMainImageAdjustViewBounds(true);
- v.setMainImageDimensions(LayoutParams.WRAP_CONTENT, getRowHeight(parent.getContext()));
+ // Randomly makes image view crop as a square or just stretch to original
+ // aspect ratio.
+ if (sRand.nextBoolean()) {
+ v.setMainImageAdjustViewBounds(false);
+ v.setMainImageDimensions(getRowHeight(parent.getContext()),
+ getRowHeight(parent.getContext()));
+ } else {
+ v.setMainImageAdjustViewBounds(true);
+ v.setMainImageDimensions(LayoutParams.WRAP_CONTENT,
+ getRowHeight(parent.getContext()));
+ }
return new ViewHolder(v);
}
@@ -75,6 +88,9 @@
.getDrawable(photoItem.getImageResourceId());
((ImageCardView) viewHolder.view).setMainImage(drawable);
((ImageCardView) viewHolder.view).setTitleText(photoItem.getTitle());
+ if (!TextUtils.isEmpty(photoItem.getContent())) {
+ ((ImageCardView) viewHolder.view).setContentText(photoItem.getContent());
+ }
}
@Override
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsFragment.java
index 5cf0867..bc88e21 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsFragment.java
@@ -16,9 +16,8 @@
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
-import android.support.v4.app.ActivityCompat;
+import android.os.Handler;
import android.support.v4.app.ActivityOptionsCompat;
-import android.support.v4.view.ViewCompat;
import android.support.v17.leanback.widget.Action;
import android.support.v17.leanback.widget.ArrayObjectAdapter;
import android.support.v17.leanback.widget.ClassPresenterSelector;
@@ -35,13 +34,8 @@
import android.support.v17.leanback.widget.Row;
import android.support.v17.leanback.widget.RowPresenter;
import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
import android.widget.Toast;
-import java.util.ArrayList;
-
public class DetailsFragment extends android.support.v17.leanback.app.DetailsFragment {
private static final String TAG = "leanback.DetailsFragment";
private static final String ITEM = "item";
@@ -49,6 +43,17 @@
private static final int NUM_ROWS = 3;
private ArrayObjectAdapter mRowsAdapter;
private PhotoItem mPhotoItem;
+ final CardPresenter cardPresenter = new CardPresenter();
+
+ private static final int ACTION_BUY = 1;
+ private static final int ACTION_RENT = 2;
+ private static final int ACTION_PLAY = 3;
+
+ private static final boolean TEST_SHARED_ELEMENT_TRANSITION = true;
+ private static final boolean TEST_ENTRANCE_TRANSITION = true;
+
+ private static final long TIME_TO_LOAD_OVERVIEW_ROW_MS = 1000;
+ private static final long TIME_TO_LOAD_RELATED_ROWS_MS = 2000;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -59,8 +64,24 @@
DetailsOverviewRowPresenter dorPresenter =
new DetailsOverviewRowPresenter(new DetailsDescriptionPresenter());
dorPresenter.setOnActionClickedListener(new OnActionClickedListener() {
+ @Override
public void onActionClicked(Action action) {
Toast.makeText(getActivity(), action.toString(), Toast.LENGTH_SHORT).show();
+ if (action.getId() == ACTION_BUY) {
+ DetailsOverviewRow dor = new DetailsOverviewRow(mPhotoItem.getTitle() + "(Owned)");
+ dor.setImageDrawable(getResources().getDrawable(mPhotoItem.getImageResourceId()));
+ dor.addAction(new Action(ACTION_PLAY, "Play"));
+ mRowsAdapter.replace(0, dor);
+ } else if (action.getId() == ACTION_RENT) {
+ DetailsOverviewRow dor = new DetailsOverviewRow(mPhotoItem.getTitle() + "(Rented)");
+ dor.setImageDrawable(getResources().getDrawable(mPhotoItem.getImageResourceId()));
+ dor.addAction(new Action(ACTION_PLAY, "Play"));
+ dor.addAction(new Action(ACTION_BUY, "Buy $9.99"));
+ mRowsAdapter.replace(0, dor);
+ } else if (action.getId() == ACTION_PLAY) {
+ Intent intent = new Intent(getActivity(), PlaybackOverlayActivity.class);
+ getActivity().startActivity(intent);
+ }
}
});
@@ -74,8 +95,6 @@
if (item != null) {
setItem(item);
}
- dorPresenter.setSharedElementEnterTransition(getActivity(),
- DetailsActivity.SHARED_ELEMENT_NAME);
setOnItemViewClickedListener(new OnItemViewClickedListener() {
@Override
@@ -101,6 +120,17 @@
Log.i(TAG, "onItemSelected: " + item + " row " + row);
}
});
+
+ if (TEST_SHARED_ELEMENT_TRANSITION) {
+ dorPresenter.setSharedElementEnterTransition(getActivity(),
+ DetailsActivity.SHARED_ELEMENT_NAME);
+ }
+ if (TEST_ENTRANCE_TRANSITION) {
+ // don't run entrance transition if Activity is restored.
+ if (savedInstanceState == null) {
+ prepareEntranceTransition();
+ }
+ }
}
@Override
@@ -113,24 +143,34 @@
mPhotoItem = photoItem;
mRowsAdapter.clear();
- Resources res = getActivity().getResources();
- DetailsOverviewRow dor = new DetailsOverviewRow("Details Overview");
- dor.setImageDrawable(res.getDrawable(photoItem.getImageResourceId()));
- dor.addAction(new Action(1, "Buy $9.99"));
- dor.addAction(new Action(2, "Rent", "$3.99", res.getDrawable(R.drawable.ic_action_a)));
- mRowsAdapter.add(dor);
+ new Handler().postDelayed(new Runnable() {
+ public void run() {
+ Resources res = getActivity().getResources();
+ DetailsOverviewRow dor = new DetailsOverviewRow(mPhotoItem.getTitle());
+ dor.setImageDrawable(res.getDrawable(mPhotoItem.getImageResourceId()));
+ dor.addAction(new Action(ACTION_BUY, "Buy $9.99"));
+ dor.addAction(new Action(ACTION_RENT, "Rent", "$3.99", res.getDrawable(R.drawable.ic_action_a)));
+ mRowsAdapter.add(0, dor);
+ setSelectedPosition(0, false);
+ }
+ }, TIME_TO_LOAD_OVERVIEW_ROW_MS);
- final CardPresenter cardPresenter = new CardPresenter();
- for (int i = 0; i < NUM_ROWS; ++i) {
- ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
- listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_1));
- listRowAdapter.add(new PhotoItem("This is a test", R.drawable.gallery_photo_2));
- listRowAdapter.add(new PhotoItem("Android TV", R.drawable.gallery_photo_3));
- listRowAdapter.add(new PhotoItem("Leanback", R.drawable.gallery_photo_4));
- HeaderItem header = new HeaderItem(i, "Row " + i, null);
- mRowsAdapter.add(new ListRow(header, listRowAdapter));
- }
-
+ new Handler().postDelayed(new Runnable() {
+ public void run() {
+ for (int i = 0; i < NUM_ROWS; ++i) {
+ ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
+ listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_1));
+ listRowAdapter.add(new PhotoItem("This is a test", R.drawable.gallery_photo_2));
+ listRowAdapter.add(new PhotoItem("Android TV", R.drawable.gallery_photo_3));
+ listRowAdapter.add(new PhotoItem("Leanback", R.drawable.gallery_photo_4));
+ HeaderItem header = new HeaderItem(i, "Row " + i);
+ mRowsAdapter.add(new ListRow(header, listRowAdapter));
+ }
+ if (TEST_ENTRANCE_TRANSITION) {
+ startEntranceTransition();
+ }
+ }
+ }, TIME_TO_LOAD_RELATED_ROWS_MS);
setAdapter(mRowsAdapter);
}
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/HorizontalGridTestActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/HorizontalGridTestActivity.java
new file mode 100644
index 0000000..59155af
--- /dev/null
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/HorizontalGridTestActivity.java
@@ -0,0 +1,172 @@
+/*
+ * 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.leanback;
+
+import android.support.v7.widget.RecyclerView;
+import android.support.v17.leanback.widget.HorizontalGridView;
+import android.support.v17.leanback.widget.OnChildSelectedListener;
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnFocusChangeListener;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.io.File;
+
+public class HorizontalGridTestActivity extends Activity {
+ private static final String TAG = "HorizontalGridTestActivity";
+ private static final boolean DEBUG = true;
+ private static final String SELECT_ACTION = "android.test.leanback.widget.SELECT";
+ private static final int NUM_ITEMS = 100;
+ private static final boolean STAGGERED = true;
+
+ private HorizontalGridView mHorizontalGridView;
+ private int mScrollState = RecyclerView.SCROLL_STATE_IDLE;
+
+ private RecyclerView.OnScrollListener mScrollListener = new RecyclerView.OnScrollListener() {
+ @Override
+ public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+ if (DEBUG) {
+ final String[] stateNames = { "IDLE", "DRAGGING", "SETTLING" };
+ Log.v(TAG, "onScrollStateChanged "
+ + (newState < stateNames.length ? stateNames[newState] : newState));
+ }
+ mScrollState = newState;
+ }
+ };
+
+ private View createView() {
+ View view = getLayoutInflater().inflate(R.layout.horizontal_grid, null, false);
+ mHorizontalGridView = (HorizontalGridView) view.findViewById(R.id.gridview);
+
+ mHorizontalGridView.setWindowAlignment(HorizontalGridView.WINDOW_ALIGN_BOTH_EDGE);
+ mHorizontalGridView.setWindowAlignmentOffsetPercent(35);
+ mHorizontalGridView.setOnChildSelectedListener(new OnChildSelectedListener() {
+ @Override
+ public void onChildSelected(ViewGroup parent, View view, int position, long id) {
+ if (DEBUG) Log.d(TAG, "onChildSelected position=" + position + " id="+id);
+ }
+ });
+ return view;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (DEBUG) Log.v(TAG, "onCreate");
+
+ RecyclerView.Adapter adapter = new MyAdapter();
+
+ View view = createView();
+
+ mHorizontalGridView.setAdapter(new MyAdapter());
+ setContentView(view);
+
+ mHorizontalGridView.setOnScrollListener(mScrollListener);
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ if (DEBUG) Log.v(TAG, "onNewIntent " + intent);
+ if (intent.getAction().equals(SELECT_ACTION)) {
+ int position = intent.getIntExtra("SELECT_POSITION", -1);
+ if (position >= 0) {
+ mHorizontalGridView.setSelectedPosition(position);
+ }
+ }
+ super.onNewIntent(intent);
+ }
+
+ private OnFocusChangeListener mItemFocusChangeListener = new OnFocusChangeListener() {
+
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (hasFocus) {
+ v.setBackgroundColor(Color.YELLOW);
+ } else {
+ v.setBackgroundColor(Color.LTGRAY);
+ }
+ }
+ };
+
+ private OnClickListener mItemClickListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mHorizontalGridView.getAdapter().notifyDataSetChanged();
+ }
+ };
+
+ class MyAdapter extends RecyclerView.Adapter {
+
+ private int[] mItemLengths;
+
+ MyAdapter() {
+ mItemLengths = new int[NUM_ITEMS];
+ for (int i = 0; i < mItemLengths.length; i++) {
+ mItemLengths[i] = STAGGERED ? (int)(Math.random() * 180) + 180 : 240;
+ }
+ }
+
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ if (DEBUG) Log.v(TAG, "createViewHolder " + viewType);
+ TextView textView = new TextView(parent.getContext());
+ textView.setTextColor(Color.BLACK);
+ textView.setFocusable(true);
+ textView.setFocusableInTouchMode(true);
+ textView.setOnFocusChangeListener(mItemFocusChangeListener);
+ textView.setOnClickListener(mItemClickListener);
+ return new ViewHolder(textView);
+ }
+
+ @Override
+ public void onBindViewHolder(RecyclerView.ViewHolder baseHolder, int position) {
+ if (DEBUG) Log.v(TAG, "bindViewHolder " + position + " " + baseHolder);
+ ViewHolder holder = (ViewHolder) baseHolder;
+ ((TextView) holder.itemView).setText("Item "+position);
+ holder.itemView.setBackgroundColor(Color.LTGRAY);
+ holder.itemView.setLayoutParams(new ViewGroup.MarginLayoutParams(mItemLengths[position],
+ 80));
+ }
+
+ @Override
+ public int getItemCount() {
+ return mItemLengths.length;
+ }
+ }
+
+ static class ViewHolder extends RecyclerView.ViewHolder {
+
+ public ViewHolder(View v) {
+ super(v);
+ }
+ }
+}
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PhotoItem.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PhotoItem.java
index be3c8a6..adde7d3 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PhotoItem.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PhotoItem.java
@@ -19,10 +19,16 @@
public class PhotoItem implements Parcelable {
private String mTitle;
+ private String mContent;
private int mImageResourceId;
public PhotoItem(String title, int imageResourceId) {
+ this(title, null, imageResourceId);
+ }
+
+ public PhotoItem(String title, String content, int imageResourceId) {
mTitle = title;
+ mContent = content;
mImageResourceId = imageResourceId;
}
@@ -34,6 +40,10 @@
return mTitle;
}
+ public String getContent() {
+ return mContent;
+ }
+
@Override
public String toString() {
return mTitle;
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
index ed3d64f..c37ca20 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
@@ -13,299 +13,395 @@
*/
package com.example.android.leanback;
-import java.util.ArrayList;
-
import android.content.Context;
-import android.content.res.Resources;
import android.graphics.drawable.Drawable;
+import android.media.session.MediaController;
+import android.media.session.MediaSessionManager;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
+import android.os.RemoteException;
+import android.support.v17.leanback.app.MediaControllerGlue;
+import android.support.v17.leanback.app.PlaybackControlGlue;
import android.support.v17.leanback.widget.Action;
import android.support.v17.leanback.widget.ArrayObjectAdapter;
-import android.support.v17.leanback.widget.ClassPresenterSelector;
-import android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter;
import android.support.v17.leanback.widget.PlaybackControlsRow;
-import android.support.v17.leanback.widget.PlaybackControlsRow.PlayPauseAction;
import android.support.v17.leanback.widget.PlaybackControlsRow.RepeatAction;
import android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsUpAction;
import android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsDownAction;
-import android.support.v17.leanback.widget.PlaybackControlsRow.ShuffleAction;
-import android.support.v17.leanback.widget.PlaybackControlsRow.SkipNextAction;
-import android.support.v17.leanback.widget.PlaybackControlsRow.SkipPreviousAction;
import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
import android.support.v17.leanback.widget.HeaderItem;
-import android.support.v17.leanback.widget.VerticalGridView;
+import android.support.v17.leanback.widget.PresenterSelector;
import android.support.v17.leanback.widget.Row;
import android.support.v17.leanback.widget.ListRow;
import android.support.v17.leanback.widget.Presenter;
import android.support.v17.leanback.widget.RowPresenter;
import android.support.v17.leanback.widget.ListRowPresenter;
-import android.support.v17.leanback.widget.OnActionClickedListener;
import android.support.v17.leanback.widget.OnItemViewSelectedListener;
import android.support.v17.leanback.widget.OnItemViewClickedListener;
import android.support.v17.leanback.widget.ControlButtonPresenterSelector;
+import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
+import android.support.v4.media.session.MediaControllerCompat;
+import android.support.v4.media.session.MediaSessionCompat;
import android.util.Log;
import android.widget.Toast;
+import java.util.List;
+
public class PlaybackOverlayFragment extends android.support.v17.leanback.app.PlaybackOverlayFragment {
private static final String TAG = "leanback.PlaybackControlsFragment";
- private static final boolean SHOW_DETAIL = true;
- private static final boolean HIDE_MORE_ACTIONS = false;
- private static final int PRIMARY_CONTROLS = 5;
- private static final boolean SHOW_IMAGE = PRIMARY_CONTROLS <= 5;
+ /**
+ * Change this to choose a different overlay background.
+ */
private static final int BACKGROUND_TYPE = PlaybackOverlayFragment.BG_LIGHT;
- private static final int MORE_ROWS = 3;
- private ArrayObjectAdapter mRowsAdapter;
- private ArrayObjectAdapter mPrimaryActionsAdapter;
- private ArrayObjectAdapter mSecondaryActionsAdapter;
- private PlayPauseAction mPlayPauseAction;
+ /**
+ * Change the number of related content rows.
+ */
+ private static final int RELATED_CONTENT_ROWS = 3;
+
+ /**
+ * Change the location of the thumbs up/down controls
+ */
+ private static final boolean THUMBS_PRIMARY = true;
+
+ /**
+ * Change this to select hidden
+ */
+ private static final boolean SECONDARY_HIDDEN = false;
+
+ private static final String FAUX_TITLE = "A short song of silence";
+ private static final String FAUX_SUBTITLE = "2014";
+ private static final int FAUX_DURATION = 33 * 1000;
+
+ private static final int ROW_CONTROLS = 0;
+
+ private PlaybackControlGlue mGlue;
+ private PlaybackControlsRowPresenter mPlaybackControlsRowPresenter;
+ private ListRowPresenter mListRowPresenter;
+
private RepeatAction mRepeatAction;
private ThumbsUpAction mThumbsUpAction;
private ThumbsDownAction mThumbsDownAction;
- private ShuffleAction mShuffleAction;
- private SkipNextAction mSkipNextAction;
- private SkipPreviousAction mSkipPreviousAction;
- private PlaybackControlsRow mPlaybackControlsRow;
- private ArrayList<MediaItem> mItems = new ArrayList<MediaItem>();
- private int mCurrentItem;
private Handler mHandler;
- private Runnable mRunnable;
+
+ // These should match the playback service FF behavior
+ private int[] mFastForwardSpeeds = { 2, 3, 4, 5 };
+
+ private OnItemViewClickedListener mOnItemViewClickedListener = new OnItemViewClickedListener() {
+ @Override
+ public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
+ RowPresenter.ViewHolder rowViewHolder, Row row) {
+ if (item instanceof Action) {
+ onActionClicked((Action) item);
+ }
+ }
+ };
+
+ private OnItemViewSelectedListener mOnItemViewSelectedListener = new OnItemViewSelectedListener() {
+ @Override
+ public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
+ RowPresenter.ViewHolder rowViewHolder, Row row) {
+ Log.i(TAG, "onItemSelected: " + item + " row " + row);
+ }
+ };
+
+ final Runnable mUpdateProgressRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mGlue.updateProgress();
+ mHandler.postDelayed(this, mGlue.getUpdatePeriod());
+ }
+ };
+
+ public SparseArrayObjectAdapter getAdapter() {
+ return (SparseArrayObjectAdapter) super.getAdapter();
+ }
@Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "onCreate");
super.onCreate(savedInstanceState);
- mHandler = new Handler();
-
setBackgroundType(BACKGROUND_TYPE);
- setFadingEnabled(false);
+ setOnItemViewSelectedListener(mOnItemViewSelectedListener);
- setupRows();
-
- setOnItemViewSelectedListener(new OnItemViewSelectedListener() {
- @Override
- public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
- RowPresenter.ViewHolder rowViewHolder, Row row) {
- Log.i(TAG, "onItemSelected: " + item + " row " + row);
- }
- });
- setOnItemViewClickedListener(new OnItemViewClickedListener() {
- @Override
- public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
- RowPresenter.ViewHolder rowViewHolder, Row row) {
- Log.i(TAG, "onItemClicked: " + item + " row " + row);
- }
- });
+ createComponents(getActivity());
}
+ private void createComponents(Context context) {
+ mHandler = new Handler();
+ mThumbsUpAction = new PlaybackControlsRow.ThumbsUpAction(context);
+ mThumbsUpAction.setIndex(ThumbsUpAction.OUTLINE);
+ mThumbsDownAction = new PlaybackControlsRow.ThumbsDownAction(context);
+ mThumbsDownAction.setIndex(ThumbsDownAction.OUTLINE);
+ mRepeatAction = new PlaybackControlsRow.RepeatAction(context);
- private void setupRows() {
- ClassPresenterSelector ps = new ClassPresenterSelector();
+ mGlue = new PlaybackControlGlue(context, this, mFastForwardSpeeds) {
+ private boolean mIsPlaying;
+ private int mSpeed = PlaybackControlGlue.PLAYBACK_SPEED_PAUSED;
+ private long mStartTime;
+ private long mStartPosition = 0;
- PlaybackControlsRowPresenter playbackControlsRowPresenter;
- if (SHOW_DETAIL) {
- playbackControlsRowPresenter = new PlaybackControlsRowPresenter(
- new DescriptionPresenter());
- } else {
- playbackControlsRowPresenter = new PlaybackControlsRowPresenter();
- }
- playbackControlsRowPresenter.setOnActionClickedListener(new OnActionClickedListener() {
- public void onActionClicked(Action action) {
- if (action.getId() == mPlayPauseAction.getId()) {
- if (mPlayPauseAction.getIndex() == PlayPauseAction.PLAY) {
- startProgressAutomation();
- setFadingEnabled(true);
- } else {
- stopProgressAutomation();
- setFadingEnabled(false);
+ @Override
+ protected SparseArrayObjectAdapter createPrimaryActionsAdapter(
+ PresenterSelector presenterSelector) {
+ return PlaybackOverlayFragment.this.createPrimaryActionsAdapter(
+ presenterSelector);
+ }
+
+ @Override
+ public boolean hasValidMedia() {
+ return true;
+ }
+
+ @Override
+ public boolean isMediaPlaying() {
+ return mIsPlaying;
+ }
+
+ @Override
+ public CharSequence getMediaTitle() {
+ return FAUX_TITLE;
+ }
+
+ @Override
+ public CharSequence getMediaSubtitle() {
+ return FAUX_SUBTITLE;
+ }
+
+ @Override
+ public int getMediaDuration() {
+ return FAUX_DURATION;
+ }
+
+ @Override
+ public Drawable getMediaArt() {
+ return null;
+ }
+
+ @Override
+ public long getSupportedActions() {
+ return PlaybackControlGlue.ACTION_PLAY_PAUSE |
+ PlaybackControlGlue.ACTION_FAST_FORWARD |
+ PlaybackControlGlue.ACTION_REWIND;
+ }
+
+ @Override
+ public int getCurrentSpeedId() {
+ return mSpeed;
+ }
+
+ @Override
+ public int getCurrentPosition() {
+ int speed;
+ if (mSpeed == PlaybackControlGlue.PLAYBACK_SPEED_PAUSED) {
+ speed = 0;
+ } else if (mSpeed == PlaybackControlGlue.PLAYBACK_SPEED_NORMAL) {
+ speed = 1;
+ } else if (mSpeed >= PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0) {
+ int index = mSpeed - PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0;
+ speed = getFastForwardSpeeds()[index];
+ } else if (mSpeed <= -PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0) {
+ int index = -mSpeed - PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0;
+ speed = -getRewindSpeeds()[index];
+ } else {
+ return -1;
+ }
+ long position = mStartPosition +
+ (System.currentTimeMillis() - mStartTime) * speed;
+ if (position > getMediaDuration()) {
+ position = getMediaDuration();
+ onPlaybackComplete(true);
+ } else if (position < 0) {
+ position = 0;
+ onPlaybackComplete(false);
+ }
+ return (int) position;
+ }
+
+ void onPlaybackComplete(final boolean ended) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mRepeatAction.getIndex() == RepeatAction.NONE) {
+ pausePlayback();
+ } else {
+ startPlayback(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL);
+ }
+ mStartPosition = 0;
+ onStateChanged();
}
- } else if (action.getId() == mSkipNextAction.getId()) {
- next();
- } else if (action.getId() == mSkipPreviousAction.getId()) {
- Toast.makeText(getActivity(), "TODO", Toast.LENGTH_SHORT).show();
- }
- if (action instanceof PlaybackControlsRow.MultiAction) {
- ((PlaybackControlsRow.MultiAction) action).nextIndex();
- notifyChanged(action);
- }
+ });
}
- });
- playbackControlsRowPresenter.setSecondaryActionsHidden(HIDE_MORE_ACTIONS);
- ps.addClassPresenter(PlaybackControlsRow.class, playbackControlsRowPresenter);
- ps.addClassPresenter(ListRow.class, new ListRowPresenter());
- mRowsAdapter = new ArrayObjectAdapter(ps);
+ @Override
+ protected void startPlayback(int speed) {
+ if (speed == mSpeed) {
+ return;
+ }
+ mStartPosition = getCurrentPosition();
+ mSpeed = speed;
+ mIsPlaying = true;
+ mStartTime = System.currentTimeMillis();
+ }
- addPlaybackControlsRow();
- addOtherRows();
+ @Override
+ protected void pausePlayback() {
+ if (mSpeed == PlaybackControlGlue.PLAYBACK_SPEED_PAUSED) {
+ return;
+ }
+ mStartPosition = getCurrentPosition();
+ mSpeed = PlaybackControlGlue.PLAYBACK_SPEED_PAUSED;
+ mIsPlaying = false;
+ }
- setAdapter(mRowsAdapter);
- }
+ @Override
+ protected void skipToNext() {
+ // Not supported
+ }
- private void addPlaybackControlsRow() {
- Context context = getActivity();
+ @Override
+ protected void skipToPrevious() {
+ // Not supported
+ }
- if (SHOW_DETAIL) {
- mPlaybackControlsRow = new PlaybackControlsRow(new MediaItem());
- } else {
- mPlaybackControlsRow = new PlaybackControlsRow();
+ @Override
+ protected void onRowChanged(PlaybackControlsRow row) {
+ PlaybackOverlayFragment.this.onRowChanged(row);
+ }
+
+ @Override
+ public void enableProgressUpdating(boolean enable) {
+ PlaybackOverlayFragment.this.enableProgressUpdating(enable);
+ }
+
+ @Override
+ public int getUpdatePeriod() {
+ return PlaybackOverlayFragment.this.getUpdatePeriod();
+ }
+ };
+
+ mGlue.setOnItemViewClickedListener(mOnItemViewClickedListener);
+
+ mPlaybackControlsRowPresenter = mGlue.createControlsRowAndPresenter();
+ mPlaybackControlsRowPresenter.setSecondaryActionsHidden(SECONDARY_HIDDEN);
+ mListRowPresenter = new ListRowPresenter();
+
+ setAdapter(new SparseArrayObjectAdapter(new PresenterSelector() {
+ @Override
+ public Presenter getPresenter(Object object) {
+ if (object instanceof PlaybackControlsRow) {
+ return mPlaybackControlsRowPresenter;
+ } else if (object instanceof ListRow) {
+ return mListRowPresenter;
+ }
+ throw new IllegalArgumentException("Unhandled object: " + object);
+ }
+ }));
+
+ // Set secondary control actions
+ PlaybackControlsRow controlsRow = mGlue.getControlsRow();
+ ArrayObjectAdapter adapter = new ArrayObjectAdapter(new ControlButtonPresenterSelector());
+ controlsRow.setSecondaryActionsAdapter(adapter);
+ if (!THUMBS_PRIMARY) {
+ adapter.add(mThumbsDownAction);
}
- mRowsAdapter.add(mPlaybackControlsRow);
-
- mItems = new ArrayList<MediaItem>();
- mItems.add(new MediaItem("Awesome Tune", "The More Awesome Band", R.drawable.details_img, 15*1000));
- mItems.add(new MediaItem("Pretty nice Tune", "The Nice Guys", R.drawable.details_img, 10*1000));
- mCurrentItem = 1;
- updatePlaybackRow(mCurrentItem);
-
- ControlButtonPresenterSelector presenterSelector = new ControlButtonPresenterSelector();
- mPrimaryActionsAdapter = new ArrayObjectAdapter(presenterSelector);
- mSecondaryActionsAdapter = new ArrayObjectAdapter(presenterSelector);
- mPlaybackControlsRow.setPrimaryActionsAdapter(mPrimaryActionsAdapter);
- mPlaybackControlsRow.setSecondaryActionsAdapter(mSecondaryActionsAdapter);
-
- mPlayPauseAction = new PlayPauseAction(context);
- mRepeatAction = new RepeatAction(context);
- mThumbsUpAction = new ThumbsUpAction(context);
- mThumbsDownAction = new ThumbsDownAction(context);
- mShuffleAction = new ShuffleAction(context);
- mSkipNextAction = new PlaybackControlsRow.SkipNextAction(context);
- mSkipPreviousAction = new PlaybackControlsRow.SkipPreviousAction(context);
-
- if (PRIMARY_CONTROLS > 5) {
- mPrimaryActionsAdapter.add(mThumbsUpAction);
- } else {
- mSecondaryActionsAdapter.add(mThumbsUpAction);
+ adapter.add(mRepeatAction);
+ if (!THUMBS_PRIMARY) {
+ adapter.add(mThumbsUpAction);
}
- mPrimaryActionsAdapter.add(mSkipPreviousAction);
- if (PRIMARY_CONTROLS > 3) {
- mPrimaryActionsAdapter.add(new PlaybackControlsRow.RewindAction(context));
- }
- mPrimaryActionsAdapter.add(mPlayPauseAction);
- if (PRIMARY_CONTROLS > 3) {
- mPrimaryActionsAdapter.add(new PlaybackControlsRow.FastForwardAction(context));
- }
- mPrimaryActionsAdapter.add(mSkipNextAction);
- mSecondaryActionsAdapter.add(mRepeatAction);
- mSecondaryActionsAdapter.add(mShuffleAction);
- if (PRIMARY_CONTROLS > 5) {
- mPrimaryActionsAdapter.add(mThumbsDownAction);
- } else {
- mSecondaryActionsAdapter.add(mThumbsDownAction);
- }
- mSecondaryActionsAdapter.add(new PlaybackControlsRow.HighQualityAction(context));
- mSecondaryActionsAdapter.add(new PlaybackControlsRow.ClosedCaptioningAction(context));
- }
+ // Add the controls row
+ getAdapter().set(ROW_CONTROLS, controlsRow);
- private void notifyChanged(Action action) {
- ArrayObjectAdapter adapter = mPrimaryActionsAdapter;
- if (adapter.indexOf(action) >= 0) {
- adapter.notifyArrayItemRangeChanged(adapter.indexOf(action), 1);
- return;
- }
- adapter = mSecondaryActionsAdapter;
- if (adapter.indexOf(action) >= 0) {
- adapter.notifyArrayItemRangeChanged(adapter.indexOf(action), 1);
- return;
- }
- }
-
- private void updatePlaybackRow(int index) {
- if (mPlaybackControlsRow.getItem() != null) {
- MediaItem item = (MediaItem) mPlaybackControlsRow.getItem();
- item.title = mItems.get(index).title;
- item.subtitle = mItems.get(index).subtitle;
- }
- if (SHOW_IMAGE) {
- mPlaybackControlsRow.setImageDrawable(getResources().getDrawable(
- mItems.get(mCurrentItem).imageResId));
- }
- mRowsAdapter.notifyArrayItemRangeChanged(0, 1);
-
- mPlaybackControlsRow.setTotalTime(mItems.get(mCurrentItem).durationMs);
- mPlaybackControlsRow.setCurrentTime(0);
- mPlaybackControlsRow.setBufferedProgress(75 * 1000);
- }
-
- private void addOtherRows() {
- for (int i = 0; i < MORE_ROWS; ++i) {
+ // Add related content rows
+ for (int i = 0; i < RELATED_CONTENT_ROWS; ++i) {
ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new StringPresenter());
listRowAdapter.add("Some related content");
listRowAdapter.add("Other related content");
- HeaderItem header = new HeaderItem(i, "Row " + i, null);
- mRowsAdapter.add(new ListRow(header, listRowAdapter));
+ HeaderItem header = new HeaderItem(i, "Row " + i);
+ getAdapter().set(ROW_CONTROLS + 1 + i, new ListRow(header, listRowAdapter));
+ }
+ }
+
+ private SparseArrayObjectAdapter createPrimaryActionsAdapter(
+ PresenterSelector presenterSelector) {
+ SparseArrayObjectAdapter adapter = new SparseArrayObjectAdapter(presenterSelector);
+ if (THUMBS_PRIMARY) {
+ adapter.set(PlaybackControlGlue.ACTION_CUSTOM_LEFT_FIRST, mThumbsUpAction);
+ adapter.set(PlaybackControlGlue.ACTION_CUSTOM_RIGHT_FIRST, mThumbsDownAction);
+ }
+ return adapter;
+ }
+
+ private void onRowChanged(PlaybackControlsRow row) {
+ if (getAdapter() == null) {
+ return;
+ }
+ int index = getAdapter().indexOf(row);
+ if (index >= 0) {
+ getAdapter().notifyArrayItemRangeChanged(index, 1);
+ }
+ }
+
+ private void enableProgressUpdating(boolean enable) {
+ Log.v(TAG, "enableProgressUpdating " + enable + " this " + this);
+ mHandler.removeCallbacks(mUpdateProgressRunnable);
+ if (enable) {
+ mUpdateProgressRunnable.run();
}
}
private int getUpdatePeriod() {
- if (getView() == null || mPlaybackControlsRow.getTotalTime() <= 0) {
+ int totalTime = mGlue.getControlsRow().getTotalTime();
+ if (getView() == null || totalTime <= 0) {
return 1000;
}
- return Math.max(16, mPlaybackControlsRow.getTotalTime() / getView().getWidth());
+ return Math.max(16, totalTime / getView().getWidth());
}
- private void startProgressAutomation() {
- mRunnable = new Runnable() {
- @Override
- public void run() {
- int updatePeriod = getUpdatePeriod();
- int currentTime = mPlaybackControlsRow.getCurrentTime() + updatePeriod;
- int totalTime = mPlaybackControlsRow.getTotalTime();
- mPlaybackControlsRow.setCurrentTime(currentTime);
- if (totalTime > 0 && totalTime <= currentTime) {
- next();
- }
- mHandler.postDelayed(this, updatePeriod);
- }
- };
- mHandler.postDelayed(mRunnable, getUpdatePeriod());
- }
-
- private void next() {
- if (++mCurrentItem >= mItems.size()) {
- mCurrentItem = 0;
+ private void onActionClicked(Action action) {
+ Log.v(TAG, "onActionClicked " + action);
+ Toast.makeText(getActivity(), action.toString(), Toast.LENGTH_SHORT).show();
+ if (action instanceof PlaybackControlsRow.MultiAction) {
+ PlaybackControlsRow.MultiAction multiAction = (PlaybackControlsRow.MultiAction) action;
+ multiAction.nextIndex();
+ notifyActionChanged(multiAction);
}
- updatePlaybackRow(mCurrentItem);
}
- private void stopProgressAutomation() {
- if (mHandler != null && mRunnable != null) {
- mHandler.removeCallbacks(mRunnable);
+ private SparseArrayObjectAdapter getPrimaryActionsAdapter() {
+ return (SparseArrayObjectAdapter) mGlue.getControlsRow().getPrimaryActionsAdapter();
+ }
+
+ private ArrayObjectAdapter getSecondaryActionsAdapter() {
+ return (ArrayObjectAdapter) mGlue.getControlsRow().getSecondaryActionsAdapter();
+ }
+
+ private void notifyActionChanged(PlaybackControlsRow.MultiAction action) {
+ int index;
+ index = getPrimaryActionsAdapter().indexOf(action);
+ if (index >= 0) {
+ getPrimaryActionsAdapter().notifyArrayItemRangeChanged(index, 1);
+ } else {
+ index = getSecondaryActionsAdapter().indexOf(action);
+ if (index >= 0) {
+ getSecondaryActionsAdapter().notifyArrayItemRangeChanged(index, 1);
+ }
}
}
@Override
+ public void onStart() {
+ super.onStart();
+ mGlue.enableProgressUpdating(mGlue.hasValidMedia() && mGlue.isMediaPlaying());
+ }
+
+ @Override
public void onStop() {
- stopProgressAutomation();
+ mGlue.enableProgressUpdating(false);
super.onStop();
}
-
- static class MediaItem {
- String title;
- String subtitle;
- int imageResId;
- int durationMs;
-
- MediaItem() {
- }
-
- MediaItem(String title, String subtitle, int imageResId, int durationMs) {
- this.title = title;
- this.subtitle = subtitle;
- this.imageResId = imageResId;
- this.durationMs = durationMs;
- }
- }
-
- static class DescriptionPresenter extends AbstractDetailsDescriptionPresenter {
- @Override
- protected void onBindDescription(ViewHolder vh, Object item) {
- vh.getTitle().setText(((MediaItem) item).title);
- vh.getSubtitle().setText(((MediaItem) item).subtitle);
- }
- }
}
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsActivity.java
new file mode 100644
index 0000000..133e995
--- /dev/null
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsActivity.java
@@ -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 com.example.android.leanback;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.v17.leanback.R;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class RowsActivity extends Activity implements RowsFragment.OnRowsFirstLineSelectedListener
+{
+ TextView mTitleView;
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.rows);
+ mTitleView = (TextView) findViewById(R.id.rows_title);
+ }
+
+ @Override
+ public void onSelectedFirstRow(boolean firstRow) {
+ mTitleView.setVisibility(firstRow ? View.VISIBLE : View.INVISIBLE);
+ }
+}
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsFragment.java
new file mode 100644
index 0000000..2509bfc
--- /dev/null
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsFragment.java
@@ -0,0 +1,124 @@
+/*
+ * 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.leanback;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.ActivityOptionsCompat;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.HeaderItem;
+import android.support.v17.leanback.widget.ImageCardView;
+import android.support.v17.leanback.widget.ListRow;
+import android.support.v17.leanback.widget.ListRowPresenter;
+import android.support.v17.leanback.widget.OnItemViewClickedListener;
+import android.support.v17.leanback.widget.OnItemViewSelectedListener;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class RowsFragment extends android.support.v17.leanback.app.RowsFragment {
+
+ public static interface OnRowsFirstLineSelectedListener {
+ void onSelectedFirstRow(boolean firstRow);
+ }
+
+ private static final String TAG = "leanback.RowsFragment";
+
+ private static final int NUM_ROWS = 10;
+ private ArrayObjectAdapter mRowsAdapter;
+ private OnRowsFirstLineSelectedListener mCallback;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ Log.i(TAG, "onCreate");
+ super.onCreate(savedInstanceState);
+
+ setupRows();
+ setOnItemViewClickedListener(new ItemViewClickedListener());
+ setOnItemViewSelectedListener(new OnItemViewSelectedListener() {
+ @Override
+ public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
+ RowPresenter.ViewHolder rowViewHolder, Row row) {
+ Log.i(TAG, "onItemSelected: " + item + " row " + row);
+ if (mCallback == null) {
+ return;
+ }
+ if (mRowsAdapter != null && mRowsAdapter.size() > 0 && row != null &&
+ row != mRowsAdapter.get(0)) {
+ mCallback.onSelectedFirstRow(false);
+ } else {
+ mCallback.onSelectedFirstRow(true);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ // This makes sure that the container activity has implemented
+ if (activity instanceof OnRowsFirstLineSelectedListener) {
+ mCallback = (OnRowsFirstLineSelectedListener) activity;
+ }
+ }
+
+ private void setupRows() {
+ ListRowPresenter lrp = new ListRowPresenter();
+ lrp.setRowHeight(CardPresenter.getRowHeight(getActivity()));
+ lrp.setExpandedRowHeight(CardPresenter.getExpandedRowHeight(getActivity()));
+
+ mRowsAdapter = new ArrayObjectAdapter(lrp);
+
+ // For good performance, it's important to use a single instance of
+ // a card presenter for all rows using that presenter.
+ final CardPresenter cardPresenter = new CardPresenter();
+
+ for (int i = 0; i < NUM_ROWS; ++i) {
+ ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
+ listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_1));
+ listRowAdapter.add(new PhotoItem("This is a test", R.drawable.gallery_photo_2));
+ listRowAdapter.add(new PhotoItem("Android TV", R.drawable.gallery_photo_3));
+ listRowAdapter.add(new PhotoItem("Leanback", R.drawable.gallery_photo_4));
+ listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_5));
+ listRowAdapter.add(new PhotoItem("This is a test", R.drawable.gallery_photo_6));
+ listRowAdapter.add(new PhotoItem("Android TV", R.drawable.gallery_photo_7));
+ listRowAdapter.add(new PhotoItem("Leanback", R.drawable.gallery_photo_8));
+ HeaderItem header = new HeaderItem(i, "Row " + i);
+ mRowsAdapter.add(new ListRow(header, listRowAdapter));
+ }
+
+ setAdapter(mRowsAdapter);
+ }
+
+ private final class ItemViewClickedListener implements OnItemViewClickedListener {
+ @Override
+ public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
+ RowPresenter.ViewHolder rowViewHolder, Row row) {
+ Intent intent = new Intent(getActivity(), DetailsActivity.class);
+ intent.putExtra(DetailsActivity.EXTRA_ITEM, (PhotoItem) item);
+
+ Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(
+ getActivity(),
+ ((ImageCardView)itemViewHolder.view).getMainImageView(),
+ DetailsActivity.SHARED_ELEMENT_NAME).toBundle();
+ getActivity().startActivity(intent, bundle);
+ }
+ }
+}
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchFragment.java
index c271bc1..b55b82f 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchFragment.java
@@ -73,7 +73,7 @@
ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_1));
listRowAdapter.add(new PhotoItem("This is a test", R.drawable.gallery_photo_2));
- HeaderItem header = new HeaderItem(i, mQuery + " results row " + i, null);
+ HeaderItem header = new HeaderItem(i, mQuery + " results row " + i);
mRowsAdapter.add(new ListRow(header, listRowAdapter));
}
}
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/VerticalGridFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/VerticalGridFragment.java
index ae41b11..9ffaf66 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/VerticalGridFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/VerticalGridFragment.java
@@ -35,7 +35,15 @@
private static final int NUM_ITEMS = 50;
private static final int HEIGHT = 200;
- private ArrayObjectAdapter mAdapter;
+ private static class Adapter extends ArrayObjectAdapter {
+ public Adapter(StringPresenter presenter) {
+ super(presenter);
+ }
+ public void callNotifyChanged() {
+ super.notifyChanged();
+ }
+ }
+ private Adapter mAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -53,7 +61,7 @@
gridPresenter.setNumberOfColumns(NUM_COLUMNS);
setGridPresenter(gridPresenter);
- mAdapter = new ArrayObjectAdapter(new StringPresenter());
+ mAdapter = new Adapter(new StringPresenter());
for (int i = 0; i < NUM_ITEMS; i++) {
mAdapter.add(Integer.toString(i));
}
@@ -72,6 +80,7 @@
public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
RowPresenter.ViewHolder rowViewHolder, Row row) {
Log.i(TAG, "onItemClicked: " + item + " row " + row);
+ mAdapter.callNotifyChanged();
}
});
setOnSearchClickedListener(new View.OnClickListener() {
diff --git a/sdk/platform_source.prop_template b/sdk/platform_source.prop_template
index c46f13d..ccaa597 100644
--- a/sdk/platform_source.prop_template
+++ b/sdk/platform_source.prop_template
@@ -2,9 +2,9 @@
Pkg.UserSrc=false
Platform.Version=${PLATFORM_VERSION}
Platform.CodeName=LOLLIPOP
-Pkg.Revision=3
+Pkg.Revision=1
AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
Layoutlib.Api=13
-Layoutlib.Revision=3
+Layoutlib.Revision=1
Platform.MinToolsRev=22
diff --git a/sdk/sdk_files_NOTICE.txt b/sdk/sdk_files_NOTICE.txt
index bb72a34..2b3d8b5 100644
--- a/sdk/sdk_files_NOTICE.txt
+++ b/sdk/sdk_files_NOTICE.txt
@@ -9740,6 +9740,7 @@
/bin/dexdump
/bin/dx
/bin/jasmin
+/bin/split-select
/framework/android-mock-generatorlib.jar
/framework/jasmin.jar
/lib/lib64cutils.a
diff --git a/tools/idegen/src/Configuration.java b/tools/idegen/src/Configuration.java
index 2f800b1..c09be1a 100644
--- a/tools/idegen/src/Configuration.java
+++ b/tools/idegen/src/Configuration.java
@@ -132,7 +132,7 @@
String path = file.getPath().substring(2);
// Keep track of source roots for .java files.
- if (path.endsWith(".java")) {
+ if (path.endsWith(".java") && !file.isDirectory()) {
if (firstJavaFile) {
// Only parse one .java file per directory.
firstJavaFile = false;