diff options
Diffstat (limited to 'tests')
18 files changed, 451 insertions, 428 deletions
diff --git a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java index dd823ae..b54f9be 100644 --- a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java +++ b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java @@ -30,6 +30,7 @@ import android.util.Log; import junit.framework.Assert; +import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -102,7 +103,11 @@ public class AppCompatibility extends InstrumentationTestCase { // otherwise raise an // exception with the first error encountered. assertNull(getStackTrace(err), err); - assertTrue("App crashed after launch.", processStillUp(packageName)); + try { + assertTrue("App crashed after launch.", processStillUp(packageName)); + } finally { + returnHome(); + } } else { Log.d(TAG, "Missing argument, use " + PACKAGE_TO_LAUNCH + " to specify the package to launch"); @@ -138,6 +143,19 @@ public class AppCompatibility extends InstrumentationTestCase { } } + private void returnHome() { + Intent homeIntent = new Intent(Intent.ACTION_MAIN); + homeIntent.addCategory(Intent.CATEGORY_HOME); + homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + // Send the "home" intent and wait 2 seconds for us to get there + mContext.startActivity(homeIntent); + try { + Thread.sleep(mWorkspaceLaunchTimeout); + } catch (InterruptedException e) { + // ignore + } + } + /** * Launches and activity and queries for errors. * @@ -150,9 +168,6 @@ public class AppCompatibility extends InstrumentationTestCase { // the recommended way to see if this is a tv or not. boolean isleanback = !mPackageManager.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN) && !mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY); - Intent homeIntent = new Intent(Intent.ACTION_MAIN); - homeIntent.addCategory(Intent.CATEGORY_HOME); - homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Intent intent; if (isleanback) { Log.d(TAG, "Leanback and relax! " + packageName); @@ -173,14 +188,6 @@ public class AppCompatibility extends InstrumentationTestCase { // ignore } - // Send the "home" intent and wait 2 seconds for us to get there - mContext.startActivity(homeIntent); - try { - Thread.sleep(mWorkspaceLaunchTimeout); - } catch (InterruptedException e) { - // ignore - } - // See if there are any errors. We wait until down here to give ANRs as // much time as // possible to occur. @@ -198,6 +205,12 @@ public class AppCompatibility extends InstrumentationTestCase { return null; } + private boolean ensureForegroundActivity(RunningAppProcessInfo info) { + Log.d(TAG, String.format("ensureForegroundActivity: proc=%s, pid=%d, state=%d", + info.processName, info.pid, info.processState)); + return info.processState == ActivityManager.PROCESS_STATE_TOP; + } + /** * Determine if a given package is still running. * @@ -207,19 +220,32 @@ public class AppCompatibility extends InstrumentationTestCase { private boolean processStillUp(String packageName) { String processName = getProcessName(packageName); List<RunningAppProcessInfo> runningApps = mActivityManager.getRunningAppProcesses(); + List<RunningAppProcessInfo> relatedProcs = new ArrayList<>(); for (RunningAppProcessInfo app : runningApps) { if (app.processName.equalsIgnoreCase(processName)) { - Log.d(TAG, "Found process " + app.processName); + if (!ensureForegroundActivity(app)) { + Log.w(TAG, "Found process but it's not top activity."); + return false; + } return true; } for (String relatedPackage : app.pkgList) { - if (relatedPackage.equalsIgnoreCase(processName)) { - Log.d(TAG, "Found process " + app.processName); + if (relatedPackage.equalsIgnoreCase(packageName)) { + relatedProcs.add(app); + } + } + } + // now that we are here, we've found no RAPI's directly matching processName, but + // potentially a List of them with one of related packages being processName + if (!relatedProcs.isEmpty()) { + for (RunningAppProcessInfo app : relatedProcs) { + if (ensureForegroundActivity(app)) { return true; } } + Log.w(TAG, "Found related processes, but none has top activity."); } - Log.d(TAG, "Failed to find process " + processName + " with package name " + Log.w(TAG, "Failed to find process " + processName + " with package name " + packageName); return false; } diff --git a/tests/HierarchyViewerTest/.gitignore b/tests/HierarchyViewerTest/.gitignore new file mode 100644 index 0000000..75eec98 --- /dev/null +++ b/tests/HierarchyViewerTest/.gitignore @@ -0,0 +1,6 @@ +.gradle +.idea +*.iml +gradle* +build +local.properties diff --git a/tests/HierarchyViewerTest/Android.mk b/tests/HierarchyViewerTest/Android.mk new file mode 100644 index 0000000..07b90f0 --- /dev/null +++ b/tests/HierarchyViewerTest/Android.mk @@ -0,0 +1,12 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := HierarchyViewerTest + +LOCAL_JAVA_LIBRARIES := android.test.runner + +include $(BUILD_PACKAGE) diff --git a/tests/HierarchyViewerTest/AndroidManifest.xml b/tests/HierarchyViewerTest/AndroidManifest.xml new file mode 100644 index 0000000..65f2fd3 --- /dev/null +++ b/tests/HierarchyViewerTest/AndroidManifest.xml @@ -0,0 +1,36 @@ +<!-- + ~ Copyright (C) 2015 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.test.hierarchyviewer"> + + <application> + <uses-library android:name="android.test.runner" /> + + <activity + android:name=".MainActivity" + android:label="HvTest" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + + <instrumentation + android:name="android.test.InstrumentationTestRunner" + android:targetPackage="com.android.test.hierarchyviewer" /> +</manifest> diff --git a/tests/HierarchyViewerTest/build.gradle b/tests/HierarchyViewerTest/build.gradle new file mode 100644 index 0000000..e8cdfa2 --- /dev/null +++ b/tests/HierarchyViewerTest/build.gradle @@ -0,0 +1,31 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.1.0+' + + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 21 + buildToolsVersion "22.0.0" + + defaultConfig { + minSdkVersion 21 + targetSdkVersion 21 + versionCode 1 + versionName "1.0" + } + + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + java.srcDirs = ['src'] + res.srcDirs = ['res'] + } + } +} diff --git a/tests/HierarchyViewerTest/res/layout/activity_main.xml b/tests/HierarchyViewerTest/res/layout/activity_main.xml new file mode 100644 index 0000000..410a776 --- /dev/null +++ b/tests/HierarchyViewerTest/res/layout/activity_main.xml @@ -0,0 +1,12 @@ +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" + android:layout_height="match_parent"> + + <TextView + android:id="@+id/textView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:scaleX="10" + android:text="@string/test" /> + +</RelativeLayout> diff --git a/tests/HierarchyViewerTest/res/menu/menu_main.xml b/tests/HierarchyViewerTest/res/menu/menu_main.xml new file mode 100644 index 0000000..9b78a1e --- /dev/null +++ b/tests/HierarchyViewerTest/res/menu/menu_main.xml @@ -0,0 +1,5 @@ +<menu xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity"> + <item android:id="@+id/action_settings" android:title="Settings" + android:orderInCategory="100" android:showAsAction="never" /> +</menu> diff --git a/tests/HierarchyViewerTest/res/values/strings.xml b/tests/HierarchyViewerTest/res/values/strings.xml new file mode 100644 index 0000000..800ee1c --- /dev/null +++ b/tests/HierarchyViewerTest/res/values/strings.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="test">Hello World</string> +</resources>
\ No newline at end of file diff --git a/tests/HierarchyViewerTest/run_tests.sh b/tests/HierarchyViewerTest/run_tests.sh new file mode 100644 index 0000000..094bb4c --- /dev/null +++ b/tests/HierarchyViewerTest/run_tests.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +# Runs the tests in this apk +adb install $OUT/data/app/HierarchyViewerTest/HierarchyViewerTest.apk +adb shell am instrument -w com.android.test.hierarchyviewer/android.test.InstrumentationTestRunner diff --git a/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/Decoder.java b/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/Decoder.java new file mode 100644 index 0000000..c6f1470 --- /dev/null +++ b/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/Decoder.java @@ -0,0 +1,101 @@ +package com.android.test.hierarchyviewer; + +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.util.HashMap; +import java.util.Map; + +public class Decoder { + // Prefixes for simple primitives. These match the JNI definitions. + public static final byte SIG_BOOLEAN = 'Z'; + public static final byte SIG_BYTE = 'B'; + public static final byte SIG_SHORT = 'S'; + public static final byte SIG_INT = 'I'; + public static final byte SIG_LONG = 'J'; + public static final byte SIG_FLOAT = 'F'; + public static final byte SIG_DOUBLE = 'D'; + + // Prefixes for some commonly used objects + public static final byte SIG_STRING = 'R'; + + public static final byte SIG_MAP = 'M'; // a map with an short key + public static final short SIG_END_MAP = 0; + + private final ByteBuffer mBuf; + + public Decoder(byte[] buf) { + this(ByteBuffer.wrap(buf)); + } + + public Decoder(ByteBuffer buf) { + mBuf = buf; + } + + public boolean hasRemaining() { + return mBuf.hasRemaining(); + } + + public Object readObject() { + byte sig = mBuf.get(); + + switch (sig) { + case SIG_BOOLEAN: + return mBuf.get() == 0 ? Boolean.FALSE : Boolean.TRUE; + case SIG_BYTE: + return mBuf.get(); + case SIG_SHORT: + return mBuf.getShort(); + case SIG_INT: + return mBuf.getInt(); + case SIG_LONG: + return mBuf.getLong(); + case SIG_FLOAT: + return mBuf.getFloat(); + case SIG_DOUBLE: + return mBuf.getDouble(); + case SIG_STRING: + return readString(); + case SIG_MAP: + return readMap(); + default: + throw new DecoderException(sig, mBuf.position() - 1); + } + } + + private String readString() { + short len = mBuf.getShort(); + byte[] b = new byte[len]; + mBuf.get(b, 0, len); + return new String(b, Charset.forName("utf-8")); + } + + private Map<Short, Object> readMap() { + Map<Short, Object> m = new HashMap<Short, Object>(); + + while (true) { + Object o = readObject(); + if (!(o instanceof Short)) { + throw new DecoderException("Expected short key, got " + o.getClass()); + } + + Short key = (Short)o; + if (key == SIG_END_MAP) { + break; + } + + m.put(key, readObject()); + } + + return m; + } + + public static class DecoderException extends RuntimeException { + public DecoderException(byte seen, int pos) { + super(String.format("Unexpected byte %c seen at position %d", (char)seen, pos)); + } + + public DecoderException(String msg) { + super(msg); + } + } +} diff --git a/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/MainActivity.java b/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/MainActivity.java new file mode 100644 index 0000000..3a67273 --- /dev/null +++ b/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/MainActivity.java @@ -0,0 +1,44 @@ +package com.android.test.hierarchyviewer; + +import android.app.Activity; +import android.os.Bundle; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; + + +public class MainActivity extends Activity { + private static final String TAG = "Main"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + View textView = findViewById(R.id.textView); + Log.d(TAG, "x, y = " + textView.getX() + ", " + textView.getY()); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.menu_main, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + + //noinspection SimplifiableIfStatement + if (id == R.id.action_settings) { + return true; + } + + return super.onOptionsItemSelected(item); + } +} diff --git a/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/MainActivityTest.java b/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/MainActivityTest.java new file mode 100644 index 0000000..ea3710d --- /dev/null +++ b/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/MainActivityTest.java @@ -0,0 +1,81 @@ +package com.android.test.hierarchyviewer; + +import android.test.ActivityInstrumentationTestCase2; +import android.view.View; + +import java.io.ByteArrayOutputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map; + +public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> { + private MainActivity mActivity; + private View mTextView; + + + public MainActivityTest() { + super(MainActivity.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mActivity = getActivity(); + mTextView = mActivity.findViewById(R.id.textView); + } + + private byte[] encode(View view) throws ClassNotFoundException, NoSuchMethodException, + IllegalAccessException, InstantiationException, InvocationTargetException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(1024 * 1024); + + Object encoder = createEncoder(baos); + invokeMethod(View.class, view, "encode", encoder); + invokeMethod(encoder.getClass(), encoder, "endStream"); + + return baos.toByteArray(); + } + + private Object invokeMethod(Class targetClass, Object target, String methodName, Object... params) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class[] paramClasses = new Class[params.length]; + for (int i = 0; i < params.length; i++) { + paramClasses[i] = params[i].getClass(); + } + Method method = targetClass.getDeclaredMethod(methodName, paramClasses); + method.setAccessible(true); + return method.invoke(target, params); + } + + private Object createEncoder(ByteArrayOutputStream baos) throws ClassNotFoundException, + NoSuchMethodException, IllegalAccessException, InvocationTargetException, + InstantiationException { + Class clazz = Class.forName("android.view.ViewHierarchyEncoder"); + Constructor constructor = clazz.getConstructor(ByteArrayOutputStream.class); + return constructor.newInstance(baos); + } + + public void testTextView() throws Exception { + byte[] data = encode(mTextView); + assertNotNull(data); + assertTrue(data.length > 0); + + ViewDumpParser parser = new ViewDumpParser(); + parser.parse(data); + + List<Map<Short, Object>> views = parser.getViews(); + Map<String, Short> propertyNameTable = parser.getIds(); + + assertEquals(1, views.size()); + assertNotNull(propertyNameTable); + + Map<Short, Object> textViewProperties = views.get(0); + assertEquals("android.widget.TextView", + textViewProperties.get(propertyNameTable.get("meta:__name__"))); + + assertEquals(mActivity.getString(R.string.test), + textViewProperties.get(propertyNameTable.get("text:text"))); + } +} diff --git a/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/ViewDumpParser.java b/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/ViewDumpParser.java new file mode 100644 index 0000000..0111bc6 --- /dev/null +++ b/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/ViewDumpParser.java @@ -0,0 +1,73 @@ +package com.android.test.hierarchyviewer; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +public class ViewDumpParser { + private Map<String, Short> mIds; + private List<Map<Short,Object>> mViews; + + public void parse(byte[] data) { + Decoder d = new Decoder(ByteBuffer.wrap(data)); + + mViews = new ArrayList<>(100); + while (d.hasRemaining()) { + Object o = d.readObject(); + if (o instanceof Map) { + //noinspection unchecked + mViews.add((Map<Short, Object>) o); + } + } + + if (mViews.isEmpty()) { + return; + } + + // the last one is the property map + Map<Short,Object> idMap = mViews.remove(mViews.size() - 1); + mIds = reverse(idMap); + } + + public String getFirstView() { + if (mViews.isEmpty()) { + return null; + } + + Map<Short, Object> props = mViews.get(0); + Object name = getProperty(props, "__name__"); + Object hash = getProperty(props, "__hash__"); + + if (name instanceof String && hash instanceof Integer) { + return String.format(Locale.US, "%s@%x", name, hash); + } else { + return null; + } + } + + private Object getProperty(Map<Short, Object> props, String key) { + return props.get(mIds.get(key)); + } + + private static Map<String, Short> reverse(Map<Short, Object> m) { + Map<String, Short> r = new HashMap<String, Short>(m.size()); + + for (Map.Entry<Short, Object> e : m.entrySet()) { + r.put((String)e.getValue(), e.getKey()); + } + + return r; + } + + public List<Map<Short, Object>> getViews() { + return mViews; + } + + public Map<String, Short> getIds() { + return mIds; + } + +} diff --git a/tests/OneMedia/Android.mk b/tests/OneMedia/Android.mk index b7d7f98..9fc6403 100644 --- a/tests/OneMedia/Android.mk +++ b/tests/OneMedia/Android.mk @@ -9,9 +9,6 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) \ LOCAL_PACKAGE_NAME := OneMedia LOCAL_CERTIFICATE := platform -LOCAL_STATIC_JAVA_LIBRARIES := \ - android-support-media-protocols - LOCAL_JAVA_LIBRARIES += org.apache.http.legacy LOCAL_PROGUARD_ENABLED := disabled diff --git a/tests/OneMedia/AndroidManifest.xml b/tests/OneMedia/AndroidManifest.xml index ef3fad5..c6824ec 100644 --- a/tests/OneMedia/AndroidManifest.xml +++ b/tests/OneMedia/AndroidManifest.xml @@ -27,15 +27,6 @@ android:name="com.android.onemedia.OnePlayerService" android:exported="true" android:process="com.android.onemedia.service" /> - <service - android:name=".provider.OneMediaRouteProvider" - android:permission="android.permission.BIND_MEDIA_ROUTE_SERVICE" - android:exported="true" - android:process="com.android.onemedia.provider"> - <intent-filter> - <action android:name="android.media.routing.MediaRouteService" /> - </intent-filter> - </service> </application> </manifest> diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java index 141a209..2455c9c 100644 --- a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java +++ b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java @@ -19,25 +19,17 @@ import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.media.MediaMetadata; -import android.media.routing.MediaRouteSelector; -import android.media.routing.MediaRouter; -import android.media.routing.MediaRouter.ConnectionRequest; -import android.media.routing.MediaRouter.DestinationInfo; -import android.media.routing.MediaRouter.RouteInfo; import android.media.session.MediaSession; import android.media.session.MediaSession.QueueItem; import android.media.session.MediaSessionManager; import android.media.session.PlaybackState; import android.os.Bundle; -import android.support.media.protocols.MediaPlayerProtocol; -import android.support.media.protocols.MediaPlayerProtocol.MediaStatus; import android.os.RemoteException; import android.os.SystemClock; import android.util.Log; import android.view.KeyEvent; import com.android.onemedia.playback.LocalRenderer; -import com.android.onemedia.playback.OneMRPRenderer; import com.android.onemedia.playback.Renderer; import com.android.onemedia.playback.RequestUtils; @@ -48,7 +40,6 @@ public class PlayerSession { private static final String TAG = "PlayerSession"; protected MediaSession mSession; - protected MediaRouter mRouter; protected Context mContext; protected Renderer mRenderer; protected MediaSession.Callback mCallback; @@ -84,22 +75,11 @@ public class PlayerSession { .getSystemService(Context.MEDIA_SESSION_SERVICE); Log.d(TAG, "Creating session for package " + mContext.getBasePackageName()); - mRouter = new MediaRouter(mContext); - mRouter.addSelector(new MediaRouteSelector.Builder() - .addRequiredProtocol(MediaPlayerProtocol.class) - .build()); - mRouter.addSelector(new MediaRouteSelector.Builder() - .setRequiredFeatures(MediaRouter.ROUTE_FEATURE_LIVE_AUDIO) - .setOptionalFeatures(MediaRouter.ROUTE_FEATURE_LIVE_VIDEO) - .build()); - mRouter.setRoutingCallback(new RoutingCallback(), null); - mSession = new MediaSession(mContext, "OneMedia"); mSession.setCallback(mCallback); mSession.setPlaybackState(mPlaybackState); mSession.setFlags(MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS | MediaSession.FLAG_HANDLES_MEDIA_BUTTONS); - mSession.setMediaRouter(mRouter); mSession.setActive(true); updateMetadata(); } @@ -117,10 +97,6 @@ public class PlayerSession { mSession.release(); mSession = null; } - if (mRouter != null) { - mRouter.release(); - mRouter = null; - } } public void setListener(Listener listener) { @@ -278,63 +254,4 @@ public class PlayerSession { mRenderer.onPause(); } } - - private class RoutingCallback extends MediaRouter.RoutingCallback { - @Override - public void onConnectionStateChanged(int state) { - if (state == MediaRouter.CONNECTION_STATE_CONNECTING) { - if (mRenderer != null) { - mRenderer.onStop(); - } - mRenderer = null; - updateState(PlaybackState.STATE_CONNECTING); - return; - } - - MediaRouter.ConnectionInfo connection = mRouter.getConnection(); - if (connection != null) { - MediaPlayerProtocol protocol = - connection.getProtocolObject(MediaPlayerProtocol.class); - if (protocol != null) { - Log.d(TAG, "Connected to route using media player protocol"); - - protocol.setCallback(new PlayerCallback(), null); - mRenderer = new OneMRPRenderer(protocol); - updateState(PlaybackState.STATE_NONE); - return; - } - } - - // Use local route - mRenderer = new LocalRenderer(mContext, null); - mRenderer.registerListener(mRenderListener); - updateState(PlaybackState.STATE_NONE); - } - } - - private class PlayerCallback extends MediaPlayerProtocol.Callback { - @Override - public void onStatusUpdated(MediaStatus status, Bundle extras) { - if (status != null) { - Log.d(TAG, "Received status update: " + status.toBundle()); - switch (status.getPlayerState()) { - case MediaStatus.PLAYER_STATE_BUFFERING: - updateState(PlaybackState.STATE_BUFFERING); - break; - case MediaStatus.PLAYER_STATE_IDLE: - updateState(PlaybackState.STATE_STOPPED); - break; - case MediaStatus.PLAYER_STATE_PAUSED: - updateState(PlaybackState.STATE_PAUSED); - break; - case MediaStatus.PLAYER_STATE_PLAYING: - updateState(PlaybackState.STATE_PLAYING); - break; - case MediaStatus.PLAYER_STATE_UNKNOWN: - updateState(PlaybackState.STATE_NONE); - break; - } - } - } - } } diff --git a/tests/OneMedia/src/com/android/onemedia/playback/OneMRPRenderer.java b/tests/OneMedia/src/com/android/onemedia/playback/OneMRPRenderer.java deleted file mode 100644 index 55eb92c..0000000 --- a/tests/OneMedia/src/com/android/onemedia/playback/OneMRPRenderer.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.android.onemedia.playback; - -import android.os.Bundle; -import android.support.media.protocols.MediaPlayerProtocol; -import android.support.media.protocols.MediaPlayerProtocol.MediaInfo; - -/** - * Renderer for communicating with the OneMRP route - */ -public class OneMRPRenderer extends Renderer { - private final MediaPlayerProtocol mProtocol; - - public OneMRPRenderer(MediaPlayerProtocol protocol) { - super(null, null); - mProtocol = protocol; - } - - @Override - public void setContent(Bundle request) { - MediaInfo mediaInfo = new MediaInfo(request.getString(RequestUtils.EXTRA_KEY_SOURCE), - MediaInfo.STREAM_TYPE_BUFFERED, "audio/mp3"); - mProtocol.load(mediaInfo, true, 0, null); - } - - @Override - public boolean onStop() { - mProtocol.stop(null); - return true; - } - - @Override - public boolean onPlay() { - mProtocol.play(null); - return true; - } - - @Override - public boolean onPause() { - mProtocol.pause(null); - return true; - } - - @Override - public long getSeekPosition() { - return -1; - } -} diff --git a/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java b/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java deleted file mode 100644 index 5845e48..0000000 --- a/tests/OneMedia/src/com/android/onemedia/provider/OneMediaRouteProvider.java +++ /dev/null @@ -1,270 +0,0 @@ -/* - * 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.android.onemedia.provider; - -import android.media.routing.MediaRouteSelector; -import android.media.routing.MediaRouteService; -import android.media.routing.MediaRouter.ConnectionInfo; -import android.media.routing.MediaRouter.ConnectionRequest; -import android.media.routing.MediaRouter.DestinationInfo; -import android.media.routing.MediaRouter.DiscoveryRequest; -import android.media.routing.MediaRouter.RouteInfo; -import android.media.session.PlaybackState; -import android.os.Bundle; -import android.os.Handler; -import android.os.Process; -import android.support.media.protocols.MediaPlayerProtocol; -import android.support.media.protocols.MediaPlayerProtocol.MediaInfo; -import android.support.media.protocols.MediaPlayerProtocol.MediaStatus; -import android.os.Looper; -import android.os.ResultReceiver; -import android.os.SystemClock; -import android.util.Log; - -import com.android.onemedia.playback.LocalRenderer; -import com.android.onemedia.playback.Renderer; -import com.android.onemedia.playback.RequestUtils; - -import java.util.ArrayList; - -/** - * Test of MediaRouteProvider. Show a dummy provider with a simple interface for - * playing music. - */ -public class OneMediaRouteProvider extends MediaRouteService { - private static final String TAG = "OneMRP"; - private static final boolean DEBUG = true; - - private static final String TEST_DESTINATION_ID = "testDestination"; - private static final String TEST_ROUTE_ID = "testRoute"; - - private Renderer mRenderer; - private RenderListener mRenderListener; - private PlaybackState mPlaybackState; - private Handler mHandler; - - private OneStub mStub; - - @Override - public void onCreate() { - mHandler = new Handler(); - mRenderer = new LocalRenderer(this, null); - mRenderListener = new RenderListener(); - PlaybackState.Builder bob = new PlaybackState.Builder(); - bob.setActions(PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_PLAY); - mPlaybackState = bob.build(); - - mRenderer.registerListener(mRenderListener); - } - - @Override - public ClientSession onCreateClientSession(ClientInfo client) { - if (client.getUid() != Process.myUid()) { - // for testing purposes, only allow connections from this application - // since this provider is not fully featured - return null; - } - return new OneSession(client); - } - - private final class OneSession extends ClientSession { - private final ClientInfo mClient; - - public OneSession(ClientInfo client) { - mClient = client; - } - - @Override - public boolean onStartDiscovery(DiscoveryRequest req, DiscoveryCallback callback) { - for (MediaRouteSelector selector : req.getSelectors()) { - if (isMatch(selector)) { - DestinationInfo destination = new DestinationInfo.Builder( - TEST_DESTINATION_ID, getServiceMetadata(), "OneMedia") - .setDescription("Test route from OneMedia app.") - .build(); - ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>(); - routes.add(new RouteInfo.Builder( - TEST_ROUTE_ID, destination, selector).build()); - callback.onDestinationFound(destination, routes); - return true; - } - } - return false; - } - - @Override - public void onStopDiscovery() { - } - - @Override - public boolean onConnect(ConnectionRequest req, ConnectionCallback callback) { - if (req.getRoute().getId().equals(TEST_ROUTE_ID)) { - mStub = new OneStub(); - ConnectionInfo connection = new ConnectionInfo.Builder(req.getRoute()) - .setProtocolStub(MediaPlayerProtocol.class, mStub) - .build(); - callback.onConnected(connection); - return true; - } - return false; - } - - @Override - public void onDisconnect() { - mStub = null; - } - - private boolean isMatch(MediaRouteSelector selector) { - if (!selector.containsProtocol(MediaPlayerProtocol.class)) { - return false; - } - for (String protocol : selector.getRequiredProtocols()) { - if (!protocol.equals(MediaPlayerProtocol.class.getName())) { - return false; - } - } - return true; - } - } - - private final class OneStub extends MediaPlayerProtocol.Stub { - MediaInfo mMediaInfo; - - public OneStub() { - super(mHandler); - } - - @Override - public void onLoad(MediaInfo mediaInfo, boolean autoplay, long playPosition, - Bundle extras) { - if (DEBUG) { - Log.d(TAG, "Attempting to play " + mediaInfo.getContentId()); - } - // look up the route and send a play command to it - mMediaInfo = mediaInfo; - Bundle bundle = new Bundle(); - bundle.putString(RequestUtils.EXTRA_KEY_SOURCE, mediaInfo.getContentId()); - mRenderer.setContent(bundle); - } - - @Override - public void onPlay(Bundle extras) { - mRenderer.onPlay(); - } - - @Override - public void onPause(Bundle extras) { - mRenderer.onPause(); - } - } - - private class RenderListener implements Renderer.Listener { - - @Override - public void onError(int type, int extra, Bundle extras, Throwable error) { - Log.d(TAG, "Sending onError with type " + type + " and extra " + extra); - sendStatusUpdate(PlaybackState.STATE_ERROR); - } - - @Override - public void onStateChanged(int newState) { - long position = -1; - if (mRenderer != null) { - position = mRenderer.getSeekPosition(); - } - int pbState; - float rate = 0; - String errorMsg = null; - switch (newState) { - case Renderer.STATE_ENDED: - case Renderer.STATE_STOPPED: - pbState = PlaybackState.STATE_STOPPED; - break; - case Renderer.STATE_INIT: - case Renderer.STATE_PREPARING: - pbState = PlaybackState.STATE_BUFFERING; - break; - case Renderer.STATE_ERROR: - pbState = PlaybackState.STATE_ERROR; - break; - case Renderer.STATE_PAUSED: - pbState = PlaybackState.STATE_PAUSED; - break; - case Renderer.STATE_PLAYING: - pbState = PlaybackState.STATE_PLAYING; - rate = 1; - break; - default: - pbState = PlaybackState.STATE_ERROR; - errorMsg = "unknown state"; - break; - } - PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState); - bob.setState(pbState, position, rate, SystemClock.elapsedRealtime()); - bob.setErrorMessage(errorMsg); - mPlaybackState = bob.build(); - - sendStatusUpdate(mPlaybackState.getState()); - } - - @Override - public void onBufferingUpdate(int percent) { - } - - @Override - public void onFocusLost() { - Log.d(TAG, "Focus lost, pausing"); - // Don't update state here, we'll get a separate call to - // onStateChanged when it pauses - mRenderer.onPause(); - } - - @Override - public void onNextStarted() { - } - - private void sendStatusUpdate(int state) { - if (mStub != null) { - MediaStatus status = new MediaStatus(1, mStub.mMediaInfo); - switch (state) { - case PlaybackState.STATE_BUFFERING: - case PlaybackState.STATE_FAST_FORWARDING: - case PlaybackState.STATE_REWINDING: - case PlaybackState.STATE_SKIPPING_TO_NEXT: - case PlaybackState.STATE_SKIPPING_TO_PREVIOUS: - status.setPlayerState(MediaStatus.PLAYER_STATE_BUFFERING); - break; - case PlaybackState.STATE_CONNECTING: - case PlaybackState.STATE_STOPPED: - status.setPlayerState(MediaStatus.PLAYER_STATE_IDLE); - break; - case PlaybackState.STATE_PAUSED: - status.setPlayerState(MediaStatus.PLAYER_STATE_PAUSED); - break; - case PlaybackState.STATE_PLAYING: - status.setPlayerState(MediaStatus.PLAYER_STATE_PLAYING); - break; - case PlaybackState.STATE_NONE: - case PlaybackState.STATE_ERROR: - default: - status.setPlayerState(MediaStatus.PLAYER_STATE_UNKNOWN); - break; - } - mStub.sendStatusUpdatedEvent(status, null); - } - } - } -} |