diff options
Diffstat (limited to 'tests')
333 files changed, 14362 insertions, 240 deletions
diff --git a/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/DisplaySinkService.java b/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/DisplaySinkService.java index daec845..8189fa9 100644 --- a/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/DisplaySinkService.java +++ b/tests/AccessoryDisplay/sink/src/com/android/accessorydisplay/sink/DisplaySinkService.java @@ -30,6 +30,7 @@ import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; +import java.io.IOException; import java.nio.ByteBuffer; public class DisplaySinkService extends Service implements SurfaceHolder.Callback { @@ -150,7 +151,12 @@ public class DisplaySinkService extends Service implements SurfaceHolder.Callbac if (mSurface != null) { MediaFormat format = MediaFormat.createVideoFormat( "video/avc", mSurfaceWidth, mSurfaceHeight); - mCodec = MediaCodec.createDecoderByType("video/avc"); + try { + mCodec = MediaCodec.createDecoderByType("video/avc"); + } catch (IOException e) { + throw new RuntimeException( + "failed to create video/avc decoder", e); + } mCodec.configure(format, mSurface, null, 0); mCodec.start(); mCodecBufferInfo = new BufferInfo(); diff --git a/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/DisplaySourceService.java b/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/DisplaySourceService.java index 256f900..a4faca5 100644 --- a/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/DisplaySourceService.java +++ b/tests/AccessoryDisplay/source/src/com/android/accessorydisplay/source/DisplaySourceService.java @@ -32,6 +32,7 @@ import android.os.Message; import android.view.Display; import android.view.Surface; +import java.io.IOException; import java.nio.ByteBuffer; public class DisplaySourceService extends Service { @@ -191,8 +192,13 @@ public class DisplaySourceService extends Service { format.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE); format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE); format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, I_FRAME_INTERVAL); - - MediaCodec codec = MediaCodec.createEncoderByType("video/avc"); + MediaCodec codec; + try { + codec = MediaCodec.createEncoderByType("video/avc"); + } catch (IOException e) { + throw new RuntimeException( + "failed to create video/avc encoder", e); + } codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); Surface surface = codec.createInputSurface(); codec.start(); diff --git a/tests/ActivityTests/AndroidManifest.xml b/tests/ActivityTests/AndroidManifest.xml index 15d075c..3fb547d 100644 --- a/tests/ActivityTests/AndroidManifest.xml +++ b/tests/ActivityTests/AndroidManifest.xml @@ -23,6 +23,7 @@ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" /> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> <uses-permission android:name="android.permission.MANAGE_USERS" /> + <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <application android:label="ActivityTest"> <activity android:name="ActivityTestMain"> <intent-filter> @@ -30,6 +31,11 @@ <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> + <activity android:name="SpamActivity" android:label="Spam!" + android:documentLaunchMode="always"> + </activity> + <activity android:name="DocActivity" android:label="Some doc"> + </activity> <service android:name="SingleUserService" android:singleUser="true" android:exported="true"> </service> diff --git a/tests/ActivityTests/res/drawable-hdpi/icon.png b/tests/ActivityTests/res/drawable-hdpi/icon.png Binary files differnew file mode 100644 index 0000000..2eab6f2 --- /dev/null +++ b/tests/ActivityTests/res/drawable-hdpi/icon.png diff --git a/tests/ActivityTests/res/drawable-mdpi/icon.png b/tests/ActivityTests/res/drawable-mdpi/icon.png Binary files differnew file mode 100644 index 0000000..63aec6f --- /dev/null +++ b/tests/ActivityTests/res/drawable-mdpi/icon.png diff --git a/tests/ActivityTests/res/drawable-xhdpi/icon.png b/tests/ActivityTests/res/drawable-xhdpi/icon.png Binary files differnew file mode 100644 index 0000000..8ea9c48 --- /dev/null +++ b/tests/ActivityTests/res/drawable-xhdpi/icon.png diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java index d7a6c1d..ea0db56 100644 --- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java +++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java @@ -21,6 +21,7 @@ import java.util.List; import android.app.Activity; import android.app.ActivityManager; +import android.app.ActivityOptions; import android.app.AlertDialog; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; @@ -28,8 +29,12 @@ import android.content.ComponentName; import android.content.ContentProviderClient; import android.content.Intent; import android.content.ServiceConnection; +import android.graphics.BitmapFactory; +import android.net.Uri; import android.os.Bundle; +import android.os.Handler; import android.os.IBinder; +import android.os.Message; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; @@ -58,6 +63,28 @@ public class ActivityTestMain extends Activity { ArrayList<ServiceConnection> mConnections = new ArrayList<ServiceConnection>(); + static final int MSG_SPAM = 1; + + final Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_SPAM: { + boolean fg = msg.arg1 != 0; + Intent intent = new Intent(ActivityTestMain.this, SpamActivity.class); + Bundle options = null; + if (fg) { + ActivityOptions opts = ActivityOptions.makeLaunchTaskBehindAnimation(); + options = opts.toBundle(); + } + startActivity(intent, options); + scheduleSpam(!fg); + } break; + } + super.handleMessage(msg); + } + }; + class BroadcastResultReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { @@ -72,7 +99,7 @@ public class ActivityTestMain extends Activity { private void addThumbnail(LinearLayout container, Bitmap bm, final ActivityManager.RecentTaskInfo task, - final ActivityManager.TaskThumbnails thumbs, final int subIndex) { + final ActivityManager.TaskThumbnail thumbs) { ImageView iv = new ImageView(this); if (bm != null) { iv.setImageBitmap(bm); @@ -86,9 +113,6 @@ public class ActivityTestMain extends Activity { @Override public void onClick(View v) { if (task.id >= 0 && thumbs != null) { - if (subIndex < (thumbs.numSubThumbbails-1)) { - mAm.removeSubTask(task.id, subIndex+1); - } mAm.moveTaskToFront(task.id, ActivityManager.MOVE_TASK_WITH_HOME); } else { try { @@ -104,11 +128,7 @@ public class ActivityTestMain extends Activity { @Override public boolean onLongClick(View v) { if (task.id >= 0 && thumbs != null) { - if (subIndex < 0) { - mAm.removeTask(task.id, ActivityManager.REMOVE_TASK_KILL_PROCESS); - } else { - mAm.removeSubTask(task.id, subIndex); - } + mAm.removeTask(task.id, ActivityManager.REMOVE_TASK_KILL_PROCESS); buildUi(); return true; } @@ -137,12 +157,19 @@ public class ActivityTestMain extends Activity { mSecondUser = ui.id; } } + + /* + AlertDialog ad = new AlertDialog.Builder(this).setTitle("title").setMessage("message").create(); + ad.getWindow().getAttributes().type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; + ad.show(); + */ } @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add("Animate!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { - @Override public boolean onMenuItemClick(MenuItem item) { + @Override + public boolean onMenuItemClick(MenuItem item) { AlertDialog.Builder builder = new AlertDialog.Builder(ActivityTestMain.this, R.style.SlowDialog); builder.setTitle("This is a title"); @@ -219,7 +246,7 @@ public class ActivityTestMain extends Activity { @Override public boolean onMenuItemClick(MenuItem item) { Intent intent = new Intent(ActivityTestMain.this, UserTarget.class); sendOrderedBroadcastAsUser(intent, new UserHandle(mSecondUser), null, - new BroadcastResultReceiver(), + new BroadcastResultReceiver(), null, Activity.RESULT_OK, null, null); return true; } @@ -291,6 +318,73 @@ public class ActivityTestMain extends Activity { return true; } }); + menu.add("Add App Recent").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { + @Override public boolean onMenuItemClick(MenuItem item) { + addAppRecents(1); + return true; + } + }); + menu.add("Add App 10x Recent").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { + @Override public boolean onMenuItemClick(MenuItem item) { + addAppRecents(10); + return true; + } + }); + menu.add("Exclude!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { + @Override public boolean onMenuItemClick(MenuItem item) { + setExclude(true); + return true; + } + }); + menu.add("Include!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { + @Override public boolean onMenuItemClick(MenuItem item) { + setExclude(false); + return true; + } + }); + menu.add("Open Doc").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { + @Override public boolean onMenuItemClick(MenuItem item) { + ActivityManager.AppTask task = findDocTask(); + if (task == null) { + Intent intent = new Intent(ActivityTestMain.this, DocActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT + | Intent.FLAG_ACTIVITY_MULTIPLE_TASK + | Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS); + startActivity(intent); + } else { + task.moveToFront(); + } + return true; + } + }); + menu.add("Stack Doc").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { + @Override public boolean onMenuItemClick(MenuItem item) { + ActivityManager.AppTask task = findDocTask(); + if (task != null) { + ActivityManager.RecentTaskInfo recent = task.getTaskInfo(); + Intent intent = new Intent(ActivityTestMain.this, DocActivity.class); + if (recent.id >= 0) { + // Stack on top. + intent.putExtra(DocActivity.LABEL, "Stacked"); + task.startActivity(ActivityTestMain.this, intent, null); + } else { + // Start root activity. + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT + | Intent.FLAG_ACTIVITY_MULTIPLE_TASK + | Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS); + intent.putExtra(DocActivity.LABEL, "New Root"); + task.startActivity(ActivityTestMain.this, intent, null); + } + } + return true; + } + }); + menu.add("Spam!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { + @Override public boolean onMenuItemClick(MenuItem item) { + scheduleSpam(false); + return true; + } + }); return true; } @@ -317,6 +411,65 @@ public class ActivityTestMain extends Activity { mConnections.clear(); } + @Override + protected void onDestroy() { + super.onDestroy(); + mHandler.removeMessages(MSG_SPAM); + } + + void addAppRecents(int count) { + ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE); + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_LAUNCHER); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); + intent.setComponent(new ComponentName(this, ActivityTestMain.class)); + for (int i=0; i<count; i++) { + ActivityManager.TaskDescription desc = new ActivityManager.TaskDescription(); + desc.setLabel("Added #" + i); + Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon); + if ((i&1) == 0) { + desc.setIcon(bitmap); + } + int taskId = am.addAppTask(this, intent, desc, bitmap); + Log.i(TAG, "Added new task id #" + taskId); + } + } + + void setExclude(boolean exclude) { + ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE); + List<ActivityManager.AppTask> tasks = am.getAppTasks(); + int taskId = getTaskId(); + for (int i=0; i<tasks.size(); i++) { + ActivityManager.AppTask task = tasks.get(i); + if (task.getTaskInfo().id == taskId) { + task.setExcludeFromRecents(exclude); + } + } + } + + ActivityManager.AppTask findDocTask() { + ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE); + List<ActivityManager.AppTask> tasks = am.getAppTasks(); + if (tasks != null) { + for (int i=0; i<tasks.size(); i++) { + ActivityManager.AppTask task = tasks.get(i); + ActivityManager.RecentTaskInfo recent = task.getTaskInfo(); + if (recent.baseIntent != null + && recent.baseIntent.getComponent().getClassName().equals( + DocActivity.class.getCanonicalName())) { + return task; + } + } + } + return null; + } + + void scheduleSpam(boolean fg) { + mHandler.removeMessages(MSG_SPAM); + Message msg = mHandler.obtainMessage(MSG_SPAM, fg ? 1 : 0, 0); + mHandler.sendMessageDelayed(msg, 500); + } + private View scrollWrap(View view) { ScrollView scroller = new ScrollView(this); scroller.addView(view, new ScrollView.LayoutParams(ScrollView.LayoutParams.MATCH_PARENT, @@ -333,7 +486,7 @@ public class ActivityTestMain extends Activity { if (recents != null) { for (int i=0; i<recents.size(); i++) { ActivityManager.RecentTaskInfo r = recents.get(i); - ActivityManager.TaskThumbnails tt = mAm.getTaskThumbnails(r.persistentId); + ActivityManager.TaskThumbnail tt = mAm.getTaskThumbnail(r.persistentId); TextView tv = new TextView(this); tv.setText(r.baseIntent.getComponent().flattenToShortString()); top.addView(tv, new LinearLayout.LayoutParams( @@ -341,10 +494,7 @@ public class ActivityTestMain extends Activity { LinearLayout.LayoutParams.WRAP_CONTENT)); LinearLayout item = new LinearLayout(this); item.setOrientation(LinearLayout.HORIZONTAL); - addThumbnail(item, tt != null ? tt.mainThumbnail : null, r, tt, -1); - for (int j=0; j<tt.numSubThumbbails; j++) { - addThumbnail(item, tt.getSubThumbnail(j), r, tt, j); - } + addThumbnail(item, tt != null ? tt.mainThumbnail : null, r, tt); top.addView(item, new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)); diff --git a/tests/ActivityTests/src/com/google/android/test/activity/DocActivity.java b/tests/ActivityTests/src/com/google/android/test/activity/DocActivity.java new file mode 100644 index 0000000..6330c79 --- /dev/null +++ b/tests/ActivityTests/src/com/google/android/test/activity/DocActivity.java @@ -0,0 +1,35 @@ +/* + * 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.google.android.test.activity; + +import android.app.Activity; +import android.app.ActivityManager; +import android.os.Bundle; + +public class DocActivity extends Activity { + static final String LABEL = "label"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + String label = getIntent().getStringExtra(LABEL); + if (label != null) { + setTaskDescription(new ActivityManager.TaskDescription(label)); + setTitle(label); + } + } +} diff --git a/tests/ActivityTests/src/com/google/android/test/activity/SpamActivity.java b/tests/ActivityTests/src/com/google/android/test/activity/SpamActivity.java new file mode 100644 index 0000000..e5de559 --- /dev/null +++ b/tests/ActivityTests/src/com/google/android/test/activity/SpamActivity.java @@ -0,0 +1,31 @@ +/* + * 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.google.android.test.activity; + +import android.app.Activity; +import android.os.Bundle; + +public class SpamActivity extends Activity { + byte[] mBytes; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // Chew up some RAM -- 8 megs worth. + mBytes = new byte[8*1024*1024]; + } +} diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java index dfb8070..8b8d604 100644 --- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java +++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java @@ -22,6 +22,7 @@ import android.app.ActivityManager.ProcessErrorStateInfo; import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.app.IActivityManager.WaitResult; +import android.app.UiAutomation; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; @@ -72,6 +73,18 @@ public class AppLaunch extends InstrumentationTestCase { private Bundle mResult = new Bundle(); private Set<String> mRequiredAccounts; + @Override + protected void setUp() throws Exception { + super.setUp(); + getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_0); + } + + @Override + protected void tearDown() throws Exception { + getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_UNFREEZE); + super.tearDown(); + } + public void testMeasureStartUpTime() throws RemoteException, NameNotFoundException { InstrumentationTestRunner instrumentation = (InstrumentationTestRunner)getInstrumentation(); @@ -331,7 +344,7 @@ public class AppLaunch extends InstrumentationTestCase { } mResult = mAm.startActivityAndWait(null, null, mLaunchIntent, mimeType, - null, null, 0, mLaunchIntent.getFlags(), null, null, null, + null, null, 0, mLaunchIntent.getFlags(), null, null, UserHandle.USER_CURRENT); } catch (RemoteException e) { Log.w(TAG, "Error launching app", e); diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeLtr.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeLtr.java index 2b5e674..ea08a6a 100644 --- a/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeLtr.java +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeLtr.java @@ -22,11 +22,25 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; +import android.widget.FrameLayout; import android.widget.GridLayout; -import android.widget.*; +import android.widget.Space; +import android.widget.TextView; -import static android.text.InputType.*; -import static android.widget.GridLayout.*; +import static android.text.InputType.TYPE_CLASS_TEXT; +import static android.text.InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS; +import static android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD; +import static android.widget.GridLayout.ALIGN_BOUNDS; +import static android.widget.GridLayout.BASELINE; +import static android.widget.GridLayout.CENTER; +import static android.widget.GridLayout.FILL; +import static android.widget.GridLayout.LEFT; +import static android.widget.GridLayout.RIGHT; +import static android.widget.GridLayout.START; +import static android.widget.GridLayout.Spec; +import static android.widget.GridLayout.spec; public class BiDiTestGridLayoutCodeLtr extends Fragment { diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeRtl.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeRtl.java index 3a03c6c..fc3a92c 100644 --- a/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeRtl.java +++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeRtl.java @@ -22,11 +22,25 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; +import android.widget.FrameLayout; import android.widget.GridLayout; -import android.widget.*; +import android.widget.Space; +import android.widget.TextView; -import static android.text.InputType.*; -import static android.widget.GridLayout.*; +import static android.text.InputType.TYPE_CLASS_TEXT; +import static android.text.InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS; +import static android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD; +import static android.widget.GridLayout.ALIGN_BOUNDS; +import static android.widget.GridLayout.BASELINE; +import static android.widget.GridLayout.CENTER; +import static android.widget.GridLayout.FILL; +import static android.widget.GridLayout.LEFT; +import static android.widget.GridLayout.RIGHT; +import static android.widget.GridLayout.START; +import static android.widget.GridLayout.Spec; +import static android.widget.GridLayout.spec; public class BiDiTestGridLayoutCodeRtl extends Fragment { diff --git a/tests/Camera2Tests/CameraToo/Android.mk b/tests/Camera2Tests/CameraToo/Android.mk new file mode 100644 index 0000000..7e5911d --- /dev/null +++ b/tests/Camera2Tests/CameraToo/Android.mk @@ -0,0 +1,23 @@ +# 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. + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests +LOCAL_PACKAGE_NAME := CameraToo +LOCAL_SDK_VERSION := current +LOCAL_SRC_FILES := $(call all-java-files-under,src) + +include $(BUILD_PACKAGE) diff --git a/tests/Camera2Tests/CameraToo/AndroidManifest.xml b/tests/Camera2Tests/CameraToo/AndroidManifest.xml new file mode 100644 index 0000000..a92b5d8 --- /dev/null +++ b/tests/Camera2Tests/CameraToo/AndroidManifest.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.android.camera2.cameratoo"> + <uses-permission android:name="android.permission.CAMERA" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <application android:label="CameraToo"> + <activity + android:name=".CameraTooActivity" + android:screenOrientation="portrait"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/tests/Camera2Tests/CameraToo/res/layout/mainactivity.xml b/tests/Camera2Tests/CameraToo/res/layout/mainactivity.xml new file mode 100644 index 0000000..f93f177 --- /dev/null +++ b/tests/Camera2Tests/CameraToo/res/layout/mainactivity.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. +--> + +<SurfaceView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/mainSurfaceView" + android:layout_height="fill_parent" + android:layout_width="fill_parent" + android:onClick="onClickOnSurfaceView" /> diff --git a/tests/Camera2Tests/CameraToo/src/com/example/android/camera2/cameratoo/CameraTooActivity.java b/tests/Camera2Tests/CameraToo/src/com/example/android/camera2/cameratoo/CameraTooActivity.java new file mode 100644 index 0000000..c630bad --- /dev/null +++ b/tests/Camera2Tests/CameraToo/src/com/example/android/camera2/cameratoo/CameraTooActivity.java @@ -0,0 +1,437 @@ +/* + * 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.camera2.cameratoo; + +import android.app.Activity; +import android.graphics.ImageFormat; +import android.hardware.camera2.CameraAccessException; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraCaptureSession; +import android.hardware.camera2.CameraDevice; +import android.hardware.camera2.CameraManager; +import android.hardware.camera2.CaptureFailure; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.TotalCaptureResult; +import android.hardware.camera2.params.StreamConfigurationMap; +import android.media.Image; +import android.media.ImageReader; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.util.Size; +import android.util.Log; +import android.view.Surface; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * A basic demonstration of how to write a point-and-shoot camera app against the new + * android.hardware.camera2 API. + */ +public class CameraTooActivity extends Activity { + /** Output files will be saved as /sdcard/Pictures/cameratoo*.jpg */ + static final String CAPTURE_FILENAME_PREFIX = "cameratoo"; + /** Tag to distinguish log prints. */ + static final String TAG = "CameraToo"; + + /** An additional thread for running tasks that shouldn't block the UI. */ + HandlerThread mBackgroundThread; + /** Handler for running tasks in the background. */ + Handler mBackgroundHandler; + /** Handler for running tasks on the UI thread. */ + Handler mForegroundHandler; + /** View for displaying the camera preview. */ + SurfaceView mSurfaceView; + /** Used to retrieve the captured image when the user takes a snapshot. */ + ImageReader mCaptureBuffer; + /** Handle to the Android camera services. */ + CameraManager mCameraManager; + /** The specific camera device that we're using. */ + CameraDevice mCamera; + /** Our image capture session. */ + CameraCaptureSession mCaptureSession; + + /** + * Given {@code choices} of {@code Size}s supported by a camera, chooses the smallest one whose + * width and height are at least as large as the respective requested values. + * @param choices The list of sizes that the camera supports for the intended output class + * @param width The minimum desired width + * @param height The minimum desired height + * @return The optimal {@code Size}, or an arbitrary one if none were big enough + */ + static Size chooseBigEnoughSize(Size[] choices, int width, int height) { + // Collect the supported resolutions that are at least as big as the preview Surface + List<Size> bigEnough = new ArrayList<Size>(); + for (Size option : choices) { + if (option.getWidth() >= width && option.getHeight() >= height) { + bigEnough.add(option); + } + } + + // Pick the smallest of those, assuming we found any + if (bigEnough.size() > 0) { + return Collections.min(bigEnough, new CompareSizesByArea()); + } else { + Log.e(TAG, "Couldn't find any suitable preview size"); + return choices[0]; + } + } + + /** + * Compares two {@code Size}s based on their areas. + */ + static class CompareSizesByArea implements Comparator<Size> { + @Override + public int compare(Size lhs, Size rhs) { + // We cast here to ensure the multiplications won't overflow + return Long.signum((long) lhs.getWidth() * lhs.getHeight() - + (long) rhs.getWidth() * rhs.getHeight()); + } + } + + /** + * Called when our {@code Activity} gains focus. <p>Starts initializing the camera.</p> + */ + @Override + protected void onResume() { + super.onResume(); + + // Start a background thread to manage camera requests + mBackgroundThread = new HandlerThread("background"); + mBackgroundThread.start(); + mBackgroundHandler = new Handler(mBackgroundThread.getLooper()); + mForegroundHandler = new Handler(getMainLooper()); + + mCameraManager = (CameraManager) getSystemService(CAMERA_SERVICE); + + // Inflate the SurfaceView, set it as the main layout, and attach a listener + View layout = getLayoutInflater().inflate(R.layout.mainactivity, null); + mSurfaceView = (SurfaceView) layout.findViewById(R.id.mainSurfaceView); + mSurfaceView.getHolder().addCallback(mSurfaceHolderCallback); + setContentView(mSurfaceView); + + // Control flow continues in mSurfaceHolderCallback.surfaceChanged() + } + + /** + * Called when our {@code Activity} loses focus. <p>Tears everything back down.</p> + */ + @Override + protected void onPause() { + super.onPause(); + + try { + // Ensure SurfaceHolderCallback#surfaceChanged() will run again if the user returns + mSurfaceView.getHolder().setFixedSize(/*width*/0, /*height*/0); + + // Cancel any stale preview jobs + if (mCaptureSession != null) { + mCaptureSession.close(); + mCaptureSession = null; + } + } finally { + if (mCamera != null) { + mCamera.close(); + mCamera = null; + } + } + + // Finish processing posted messages, then join on the handling thread + mBackgroundThread.quitSafely(); + try { + mBackgroundThread.join(); + } catch (InterruptedException ex) { + Log.e(TAG, "Background worker thread was interrupted while joined", ex); + } + + // Close the ImageReader now that the background thread has stopped + if (mCaptureBuffer != null) mCaptureBuffer.close(); + } + + /** + * Called when the user clicks on our {@code SurfaceView}, which has ID {@code mainSurfaceView} + * as defined in the {@code mainactivity.xml} layout file. <p>Captures a full-resolution image + * and saves it to permanent storage.</p> + */ + public void onClickOnSurfaceView(View v) { + if (mCaptureSession != null) { + try { + CaptureRequest.Builder requester = + mCamera.createCaptureRequest(mCamera.TEMPLATE_STILL_CAPTURE); + requester.addTarget(mCaptureBuffer.getSurface()); + try { + // This handler can be null because we aren't actually attaching any callback + mCaptureSession.capture(requester.build(), /*listener*/null, /*handler*/null); + } catch (CameraAccessException ex) { + Log.e(TAG, "Failed to file actual capture request", ex); + } + } catch (CameraAccessException ex) { + Log.e(TAG, "Failed to build actual capture request", ex); + } + } else { + Log.e(TAG, "User attempted to perform a capture outside our session"); + } + + // Control flow continues in mImageCaptureListener.onImageAvailable() + } + + /** + * Callbacks invoked upon state changes in our {@code SurfaceView}. + */ + final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() { + /** The camera device to use, or null if we haven't yet set a fixed surface size. */ + private String mCameraId; + + /** Whether we received a change callback after setting our fixed surface size. */ + private boolean mGotSecondCallback; + + @Override + public void surfaceCreated(SurfaceHolder holder) { + // This is called every time the surface returns to the foreground + Log.i(TAG, "Surface created"); + mCameraId = null; + mGotSecondCallback = false; + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + Log.i(TAG, "Surface destroyed"); + holder.removeCallback(this); + // We don't stop receiving callbacks forever because onResume() will reattach us + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + // On the first invocation, width and height were automatically set to the view's size + if (mCameraId == null) { + // Find the device's back-facing camera and set the destination buffer sizes + try { + for (String cameraId : mCameraManager.getCameraIdList()) { + CameraCharacteristics cameraCharacteristics = + mCameraManager.getCameraCharacteristics(cameraId); + if (cameraCharacteristics.get(cameraCharacteristics.LENS_FACING) == + CameraCharacteristics.LENS_FACING_BACK) { + Log.i(TAG, "Found a back-facing camera"); + StreamConfigurationMap info = cameraCharacteristics + .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); + + // Bigger is better when it comes to saving our image + Size largestSize = Collections.max( + Arrays.asList(info.getOutputSizes(ImageFormat.JPEG)), + new CompareSizesByArea()); + + // Prepare an ImageReader in case the user wants to capture images + Log.i(TAG, "Capture size: " + largestSize); + mCaptureBuffer = ImageReader.newInstance(largestSize.getWidth(), + largestSize.getHeight(), ImageFormat.JPEG, /*maxImages*/2); + mCaptureBuffer.setOnImageAvailableListener( + mImageCaptureListener, mBackgroundHandler); + + // Danger, W.R.! Attempting to use too large a preview size could + // exceed the camera bus' bandwidth limitation, resulting in + // gorgeous previews but the storage of garbage capture data. + Log.i(TAG, "SurfaceView size: " + + mSurfaceView.getWidth() + 'x' + mSurfaceView.getHeight()); + Size optimalSize = chooseBigEnoughSize( + info.getOutputSizes(SurfaceHolder.class), width, height); + + // Set the SurfaceHolder to use the camera's largest supported size + Log.i(TAG, "Preview size: " + optimalSize); + SurfaceHolder surfaceHolder = mSurfaceView.getHolder(); + surfaceHolder.setFixedSize(optimalSize.getWidth(), + optimalSize.getHeight()); + + mCameraId = cameraId; + return; + + // Control flow continues with this method one more time + // (since we just changed our own size) + } + } + } catch (CameraAccessException ex) { + Log.e(TAG, "Unable to list cameras", ex); + } + + Log.e(TAG, "Didn't find any back-facing cameras"); + // This is the second time the method is being invoked: our size change is complete + } else if (!mGotSecondCallback) { + if (mCamera != null) { + Log.e(TAG, "Aborting camera open because it hadn't been closed"); + return; + } + + // Open the camera device + try { + mCameraManager.openCamera(mCameraId, mCameraStateListener, + mBackgroundHandler); + } catch (CameraAccessException ex) { + Log.e(TAG, "Failed to configure output surface", ex); + } + mGotSecondCallback = true; + + // Control flow continues in mCameraStateListener.onOpened() + } + }}; + + /** + * Calledbacks invoked upon state changes in our {@code CameraDevice}. <p>These are run on + * {@code mBackgroundThread}.</p> + */ + final CameraDevice.StateListener mCameraStateListener = + new CameraDevice.StateListener() { + @Override + public void onOpened(CameraDevice camera) { + Log.i(TAG, "Successfully opened camera"); + mCamera = camera; + try { + List<Surface> outputs = Arrays.asList( + mSurfaceView.getHolder().getSurface(), mCaptureBuffer.getSurface()); + camera.createCaptureSession(outputs, mCaptureSessionListener, + mBackgroundHandler); + } catch (CameraAccessException ex) { + Log.e(TAG, "Failed to create a capture session", ex); + } + + // Control flow continues in mCaptureSessionListener.onConfigured() + } + + @Override + public void onDisconnected(CameraDevice camera) { + Log.e(TAG, "Camera was disconnected"); + } + + @Override + public void onError(CameraDevice camera, int error) { + Log.e(TAG, "State error on device '" + camera.getId() + "': code " + error); + }}; + + /** + * Callbacks invoked upon state changes in our {@code CameraCaptureSession}. <p>These are run on + * {@code mBackgroundThread}.</p> + */ + final CameraCaptureSession.StateListener mCaptureSessionListener = + new CameraCaptureSession.StateListener() { + @Override + public void onConfigured(CameraCaptureSession session) { + Log.i(TAG, "Finished configuring camera outputs"); + mCaptureSession = session; + + SurfaceHolder holder = mSurfaceView.getHolder(); + if (holder != null) { + try { + // Build a request for preview footage + CaptureRequest.Builder requestBuilder = + mCamera.createCaptureRequest(mCamera.TEMPLATE_PREVIEW); + requestBuilder.addTarget(holder.getSurface()); + CaptureRequest previewRequest = requestBuilder.build(); + + // Start displaying preview images + try { + session.setRepeatingRequest(previewRequest, /*listener*/null, + /*handler*/null); + } catch (CameraAccessException ex) { + Log.e(TAG, "Failed to make repeating preview request", ex); + } + } catch (CameraAccessException ex) { + Log.e(TAG, "Failed to build preview request", ex); + } + } + else { + Log.e(TAG, "Holder didn't exist when trying to formulate preview request"); + } + } + + @Override + public void onClosed(CameraCaptureSession session) { + mCaptureSession = null; + } + + @Override + public void onConfigureFailed(CameraCaptureSession session) { + Log.e(TAG, "Configuration error on device '" + mCamera.getId()); + }}; + + /** + * Callback invoked when we've received a JPEG image from the camera. + */ + final ImageReader.OnImageAvailableListener mImageCaptureListener = + new ImageReader.OnImageAvailableListener() { + @Override + public void onImageAvailable(ImageReader reader) { + // Save the image once we get a chance + mBackgroundHandler.post(new CapturedImageSaver(reader.acquireNextImage())); + + // Control flow continues in CapturedImageSaver#run() + }}; + + /** + * Deferred processor responsible for saving snapshots to disk. <p>This is run on + * {@code mBackgroundThread}.</p> + */ + static class CapturedImageSaver implements Runnable { + /** The image to save. */ + private Image mCapture; + + public CapturedImageSaver(Image capture) { + mCapture = capture; + } + + @Override + public void run() { + try { + // Choose an unused filename under the Pictures/ directory + File file = File.createTempFile(CAPTURE_FILENAME_PREFIX, ".jpg", + Environment.getExternalStoragePublicDirectory( + Environment.DIRECTORY_PICTURES)); + try (FileOutputStream ostream = new FileOutputStream(file)) { + Log.i(TAG, "Retrieved image is" + + (mCapture.getFormat() == ImageFormat.JPEG ? "" : "n't") + " a JPEG"); + ByteBuffer buffer = mCapture.getPlanes()[0].getBuffer(); + Log.i(TAG, "Captured image size: " + + mCapture.getWidth() + 'x' + mCapture.getHeight()); + + // Write the image out to the chosen file + byte[] jpeg = new byte[buffer.remaining()]; + buffer.get(jpeg); + ostream.write(jpeg); + } catch (FileNotFoundException ex) { + Log.e(TAG, "Unable to open output file for writing", ex); + } catch (IOException ex) { + Log.e(TAG, "Failed to write the image to the output file", ex); + } + } catch (IOException ex) { + Log.e(TAG, "Unable to create a new output file", ex); + } finally { + mCapture.close(); + } + } + } +} diff --git a/tests/Camera2Tests/CameraToo/tests/Android.mk b/tests/Camera2Tests/CameraToo/tests/Android.mk new file mode 100644 index 0000000..0b58243 --- /dev/null +++ b/tests/Camera2Tests/CameraToo/tests/Android.mk @@ -0,0 +1,25 @@ +# 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. + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests +LOCAL_PACKAGE_NAME := CameraTooTests +LOCAL_INSTRUMENTATION_FOR := CameraToo +LOCAL_SDK_VERSION := current +LOCAL_SRC_FILES := $(call all-java-files-under,src) +LOCAL_STATIC_JAVA_LIBRARIES := android-support-test mockito-target + +include $(BUILD_PACKAGE) diff --git a/tests/Camera2Tests/CameraToo/tests/AndroidManifest.xml b/tests/Camera2Tests/CameraToo/tests/AndroidManifest.xml new file mode 100644 index 0000000..30210ba --- /dev/null +++ b/tests/Camera2Tests/CameraToo/tests/AndroidManifest.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.android.camera2.cameratoo.tests"> + <uses-permission android:name="android.permission.CAMERA" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <application android:label="CameraToo"> + <uses-library android:name="android.test.runner" /> + </application> + <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + android:targetPackage="com.example.android.camera2.cameratoo" + android:label="CameraToo tests" /> +</manifest> diff --git a/tests/Camera2Tests/CameraToo/tests/src/com/example/android/camera2/cameratoo/CameraTooTest.java b/tests/Camera2Tests/CameraToo/tests/src/com/example/android/camera2/cameratoo/CameraTooTest.java new file mode 100644 index 0000000..3acca5a --- /dev/null +++ b/tests/Camera2Tests/CameraToo/tests/src/com/example/android/camera2/cameratoo/CameraTooTest.java @@ -0,0 +1,189 @@ +/* + * 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.camera2.cameratoo; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.media.Image; +import android.os.Environment; +import android.util.Size; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FilenameFilter; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashSet; +import java.util.Set; + +import com.example.android.camera2.cameratoo.CameraTooActivity; +import org.junit.Test; + +public class CameraTooTest { + private <T> void assertComparatorEq(T lhs, T rhs, Comparator<T> rel) { + assertEquals(String.format("%s should be equal to %s", lhs, rhs), rel.compare(lhs, rhs), 0); + assertEquals(String.format("%s should be equal to %s (reverse check)", lhs, rhs), + rel.compare(rhs, lhs), 0); + } + + private <T> void assertComparatorLt(T lhs, T rhs, Comparator<T> rel) { + assertTrue(String.format("%s should be less than %s", lhs, rhs), rel.compare(lhs, rhs) < 0); + assertTrue(String.format("%s should be less than %s (reverse check)", lhs, rhs), + rel.compare(rhs, lhs) > 0); + } + + @Test + public void compareSizesByArea() { + Size empty = new Size(0, 0), fatAndFlat = new Size(100, 0), tallAndThin = new Size(0, 100); + Size smallSquare = new Size(4, 4), horizRect = new Size(8, 2), vertRect = new Size(2, 8); + Size largeSquare = new Size(5, 5); + Comparator<Size> rel = new CameraTooActivity.CompareSizesByArea(); + + assertComparatorEq(empty, fatAndFlat, rel); + assertComparatorEq(empty, tallAndThin, rel); + assertComparatorEq(fatAndFlat, empty, rel); + assertComparatorEq(fatAndFlat, tallAndThin, rel); + assertComparatorEq(tallAndThin, empty, rel); + assertComparatorEq(tallAndThin, fatAndFlat, rel); + + assertComparatorEq(smallSquare, horizRect, rel); + assertComparatorEq(smallSquare, vertRect, rel); + assertComparatorEq(horizRect, smallSquare, rel); + assertComparatorEq(horizRect, vertRect, rel); + assertComparatorEq(vertRect, smallSquare, rel); + assertComparatorEq(vertRect, horizRect, rel); + + assertComparatorLt(empty, smallSquare, rel); + assertComparatorLt(empty, horizRect, rel); + assertComparatorLt(empty, vertRect, rel); + + assertComparatorLt(fatAndFlat, smallSquare, rel); + assertComparatorLt(fatAndFlat, horizRect, rel); + assertComparatorLt(fatAndFlat, vertRect, rel); + + assertComparatorLt(tallAndThin, smallSquare, rel); + assertComparatorLt(tallAndThin, horizRect, rel); + assertComparatorLt(tallAndThin, vertRect, rel); + + assertComparatorLt(empty, largeSquare, rel); + assertComparatorLt(fatAndFlat, largeSquare, rel); + assertComparatorLt(tallAndThin, largeSquare, rel); + assertComparatorLt(smallSquare, largeSquare, rel); + assertComparatorLt(horizRect, largeSquare, rel); + assertComparatorLt(vertRect, largeSquare, rel); + } + + private void assertOptimalSize(Size[] options, int minWidth, int minHeight, Size expected) { + Size verdict = CameraTooActivity.chooseBigEnoughSize(options, minWidth, minHeight); + assertEquals(String.format("Expected optimal size %s but got %s", expected, verdict), + verdict, expected); + } + + @Test + public void chooseBigEnoughSize() { + Size empty = new Size(0, 0), fatAndFlat = new Size(100, 0), tallAndThin = new Size(0, 100); + Size smallSquare = new Size(4, 4), horizRect = new Size(8, 2), vertRect = new Size(2, 8); + Size largeSquare = new Size(5, 5); + Size[] siz = + { empty, fatAndFlat, tallAndThin, smallSquare, horizRect, vertRect, largeSquare }; + + assertOptimalSize(siz, 0, 0, empty); + + assertOptimalSize(siz, 1, 0, fatAndFlat); + assertOptimalSize(siz, 0, 1, tallAndThin); + + assertOptimalSize(siz, 4, 4, smallSquare); + assertOptimalSize(siz, 1, 1, smallSquare); + assertOptimalSize(siz, 2, 1, smallSquare); + assertOptimalSize(siz, 1, 2, smallSquare); + assertOptimalSize(siz, 3, 4, smallSquare); + assertOptimalSize(siz, 4, 3, smallSquare); + + assertOptimalSize(siz, 8, 2, horizRect); + assertOptimalSize(siz, 5, 1, horizRect); + assertOptimalSize(siz, 5, 2, horizRect); + + assertOptimalSize(siz, 2, 8, vertRect); + assertOptimalSize(siz, 1, 5, vertRect); + assertOptimalSize(siz, 2, 5, vertRect); + + assertOptimalSize(siz, 5, 5, largeSquare); + assertOptimalSize(siz, 3, 5, largeSquare); + assertOptimalSize(siz, 5, 3, largeSquare); + } + + private static final FilenameFilter OUTPUT_FILE_DECIDER = new FilenameFilter() { + @Override + public boolean accept(File dir, String filename) { + return filename.indexOf("cameratoo") == 0 && + filename.indexOf(".jpg") == filename.length() - ".jpg".length(); + }}; + + private static <T> Set<T> newlyAddedElements(Set<T> before, Set<T> after) { + Set<T> result = new HashSet<T>(after); + result.removeAll(before); + return result; + } + + @Test + public void capturedImageSaver() throws FileNotFoundException, IOException { + ByteBuffer buf = ByteBuffer.allocate(25); + for(int index = 0; index < buf.capacity(); ++index) + buf.put(index, (byte) index); + + Image.Plane plane = mock(Image.Plane.class); + when(plane.getBuffer()).thenReturn(buf); + when(plane.getPixelStride()).thenReturn(1); + when(plane.getRowStride()).thenReturn(5); + + Image.Plane[] onlyPlaneThatMatters = { plane }; + Image image = mock(Image.class); + when(image.getPlanes()).thenReturn(onlyPlaneThatMatters); + when(image.getWidth()).thenReturn(5); + when(image.getHeight()).thenReturn(5); + + File picturesFolder = + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); + Set<File> preListing = + new HashSet<File>(Arrays.asList(picturesFolder.listFiles(OUTPUT_FILE_DECIDER))); + + CameraTooActivity.CapturedImageSaver saver = + new CameraTooActivity.CapturedImageSaver(image); + saver.run(); + + Set<File> postListing = + new HashSet<File>(Arrays.asList(picturesFolder.listFiles(OUTPUT_FILE_DECIDER))); + Set<File> newFiles = newlyAddedElements(preListing, postListing); + + assertEquals(newFiles.size(), 1); + + File picture = newFiles.iterator().next(); + FileInputStream istream = new FileInputStream(picture); + + for(int count = 0; count < buf.capacity(); ++count) { + assertEquals(istream.read(), buf.get(count)); + } + assertEquals(istream.read(), -1); + assertTrue(picture.delete()); + } +} diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/Android.mk b/tests/Camera2Tests/SmartCamera/SimpleCamera/Android.mk index 801c81c..4e3675f 100644 --- a/tests/Camera2Tests/SmartCamera/SimpleCamera/Android.mk +++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/Android.mk @@ -23,7 +23,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_PROGUARD_ENABLED := disabled # comment it out for now since we need use some hidden APIs -# LOCAL_SDK_VERSION := current +LOCAL_SDK_VERSION := current LOCAL_STATIC_JAVA_LIBRARIES := android-ex-camera2 diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/GraphReader.java b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/GraphReader.java index ef885e3..ec02d34 100644 --- a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/GraphReader.java +++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/GraphReader.java @@ -117,7 +117,7 @@ public class GraphReader { } @Override - public void execute(CommandStack stack) { + public void execute(CommandStack stack) { Filter filter = null; try { filter = stack.getFactory().createFilterByClassName(mClassName, diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/decoder/AudioTrackDecoder.java b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/decoder/AudioTrackDecoder.java index 0219fd7..3b3de9f 100644 --- a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/decoder/AudioTrackDecoder.java +++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/decoder/AudioTrackDecoder.java @@ -59,8 +59,15 @@ public class AudioTrackDecoder extends TrackDecoder { @Override protected MediaCodec initMediaCodec(MediaFormat format) { - MediaCodec mediaCodec = MediaCodec.createDecoderByType( - format.getString(MediaFormat.KEY_MIME)); + MediaCodec mediaCodec; + try { + mediaCodec = MediaCodec.createDecoderByType( + format.getString(MediaFormat.KEY_MIME)); + } catch (IOException e) { + throw new RuntimeException( + "failed to create decoder for " + + format.getString(MediaFormat.KEY_MIME), e); + } mediaCodec.configure(format, null, null, 0); return mediaCodec; } diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/decoder/CpuVideoTrackDecoder.java b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/decoder/CpuVideoTrackDecoder.java index 96f3059..a624010 100644 --- a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/decoder/CpuVideoTrackDecoder.java +++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/decoder/CpuVideoTrackDecoder.java @@ -29,6 +29,7 @@ import androidx.media.filterfw.Frame; import androidx.media.filterfw.FrameImage2D; import androidx.media.filterfw.PixelUtils; +import java.io.IOException; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.HashSet; @@ -214,7 +215,13 @@ public class CpuVideoTrackDecoder extends VideoTrackDecoder { return null; } else { String bestCodec = candidateCodecs.firstEntry().getValue(); - return MediaCodec.createByCodecName(bestCodec); + try { + return MediaCodec.createByCodecName(bestCodec); + } catch (IOException e) { + throw new RuntimeException( + "failed to create codec for " + + bestCodec, e); + } } } diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/decoder/GpuVideoTrackDecoder.java b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/decoder/GpuVideoTrackDecoder.java index bbba9d8..f5eb513 100644 --- a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/decoder/GpuVideoTrackDecoder.java +++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/decoder/GpuVideoTrackDecoder.java @@ -28,6 +28,7 @@ import androidx.media.filterfw.FrameImage2D; import androidx.media.filterfw.ImageShader; import androidx.media.filterfw.TextureSource; +import java.io.IOException; import java.nio.ByteBuffer; /** @@ -86,9 +87,16 @@ public class GpuVideoTrackDecoder extends VideoTrackDecoder { @Override protected MediaCodec initMediaCodec(MediaFormat format) { + MediaCodec mediaCodec; + try { + mediaCodec = MediaCodec.createDecoderByType( + format.getString(MediaFormat.KEY_MIME)); + } catch (IOException e) { + throw new RuntimeException( + "failed to create decoder for " + + format.getString(MediaFormat.KEY_MIME), e); + } Surface surface = new Surface(mSurfaceTexture); - MediaCodec mediaCodec = MediaCodec.createDecoderByType( - format.getString(MediaFormat.KEY_MIME)); mediaCodec.configure(format, surface, null, 0); surface.release(); return mediaCodec; diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/samples/simplecamera/Camera2Source.java b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/samples/simplecamera/Camera2Source.java index fa0f995..05057f2 100644 --- a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/samples/simplecamera/Camera2Source.java +++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/samples/simplecamera/Camera2Source.java @@ -22,10 +22,12 @@ import android.graphics.ImageFormat; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; +import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraManager; import android.hardware.camera2.CaptureFailure; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; +import android.hardware.camera2.TotalCaptureResult; import android.os.Handler; import android.renderscript.Allocation; import android.renderscript.Element; @@ -36,6 +38,7 @@ import android.util.Log; import android.view.Surface; import com.android.ex.camera2.blocking.BlockingCameraManager; import com.android.ex.camera2.blocking.BlockingCameraManager.BlockingOpenException; +import com.android.ex.camera2.blocking.BlockingSessionListener; import androidx.media.filterfw.Filter; import androidx.media.filterfw.Frame; import androidx.media.filterfw.FrameImage2D; @@ -55,6 +58,7 @@ public class Camera2Source extends Filter implements Allocation.OnBufferAvailabl private static final String TAG = "Camera2Source"; private CameraManager mCameraManager; private CameraDevice mCamera; + private CameraCaptureSession mCameraSession; private RenderScript mRS; private Surface mSurface; private CameraCharacteristics mProperties; @@ -66,6 +70,8 @@ public class Camera2Source extends Filter implements Allocation.OnBufferAvailabl private Allocation mAllocationOut; private Bitmap mBitmap; + private static final long SESSION_TIMEOUT_MS = 2000; + class MyCameraListener extends CameraManager.AvailabilityListener { @Override @@ -82,18 +88,18 @@ public class Camera2Source extends Filter implements Allocation.OnBufferAvailabl } - class MyCaptureListener extends CameraDevice.CaptureListener { + class MyCaptureListener extends CameraCaptureSession.CaptureListener { @Override - public void onCaptureCompleted(CameraDevice camera, CaptureRequest request, - CaptureResult result) { + public void onCaptureCompleted(CameraCaptureSession camera, CaptureRequest request, + TotalCaptureResult result) { // TODO Auto-generated method stub Log.v(TAG, "in onCaptureComplete"); } @Override - public void onCaptureFailed(CameraDevice camera, CaptureRequest request, + public void onCaptureFailed(CameraCaptureSession camera, CaptureRequest request, CaptureFailure failure) { // TODO Auto-generated method stub Log.v(TAG, "onCaptureFailed is being called"); @@ -183,16 +189,21 @@ public class Camera2Source extends Filter implements Allocation.OnBufferAvailabl surfaces.add(mSurface); CaptureRequest.Builder mCaptureRequest = null; try { - mCamera.configureOutputs(surfaces); + BlockingSessionListener blkSession = new BlockingSessionListener(); + + mCamera.createCaptureSession(surfaces, blkSession, mHandler); mCaptureRequest = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); mCaptureRequest.addTarget(mSurface); + + mCameraSession = blkSession.waitAndGetSession(SESSION_TIMEOUT_MS); + } catch (CameraAccessException e) { e.printStackTrace(); throw new RuntimeException(e); } try { - mCamera.setRepeatingRequest(mCaptureRequest.build(), new MyCaptureListener(), + mCameraSession.setRepeatingRequest(mCaptureRequest.build(), new MyCaptureListener(), mHandler); } catch (CameraAccessException e) { e.printStackTrace(); diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/CompareActivity.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/CompareActivity.java index 0b85189..8d8d9de 100644 --- a/tests/CanvasCompare/src/com/android/test/hwuicompare/CompareActivity.java +++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/CompareActivity.java @@ -97,7 +97,7 @@ abstract public class CompareActivity extends Activity { Log.d(LOG_TAG, "failure to access hardware layer"); return; } - Method copyInto = hardwareLayer.getClass().getSuperclass() + Method copyInto = hardwareLayer.getClass() .getDeclaredMethod("copyInto", Bitmap.class); if (!copyInto.isAccessible()) copyInto.setAccessible(true); diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java index 6ad01a0..0f4e122 100644 --- a/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java +++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/DisplayModifier.java @@ -302,6 +302,36 @@ public abstract class DisplayModifier { paint.setShader(ResourceModifiers.instance().mVertGradient); } }); + put("radGradient", new DisplayModifier() { + @Override + public void modifyDrawing(Paint paint, Canvas canvas) { + paint.setShader(ResourceModifiers.instance().mRadGradient); + } + }); + put("sweepGradient", new DisplayModifier() { + @Override + public void modifyDrawing(Paint paint, Canvas canvas) { + paint.setShader(ResourceModifiers.instance().mSweepGradient); + } + }); + put("composeShader", new DisplayModifier() { + @Override + public void modifyDrawing(Paint paint, Canvas canvas) { + paint.setShader(ResourceModifiers.instance().mComposeShader); + } + }); + put("bad composeShader", new DisplayModifier() { + @Override + public void modifyDrawing(Paint paint, Canvas canvas) { + paint.setShader(ResourceModifiers.instance().mBadComposeShader); + } + }); + put("bad composeShader 2", new DisplayModifier() { + @Override + public void modifyDrawing(Paint paint, Canvas canvas) { + paint.setShader(ResourceModifiers.instance().mAnotherBadComposeShader); + } + }); } }); diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java index a08b558..d402699 100644 --- a/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java +++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java @@ -16,9 +16,6 @@ package com.android.test.hwuicompare; -import com.android.test.hwuicompare.R; -import com.android.test.hwuicompare.ScriptC_errorCalculator; - import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; @@ -35,17 +32,17 @@ public class ErrorCalculator { private static final boolean LOG_TIMING = false; private static final boolean LOG_CALC = false; - private final RenderScript mRS; + private RenderScript mRS; private Allocation mIdealPixelsAllocation; private Allocation mGivenPixelsAllocation; private Allocation mOutputPixelsAllocation; - private final Allocation mInputRowsAllocation; - private final Allocation mOutputRegionsAllocation; + private Allocation mInputRowsAllocation; + private Allocation mOutputRegionsAllocation; - private final ScriptC_errorCalculator mScript; + private ScriptC_errorCalculator mScript; - private final int[] mOutputRowRegions; + private int[] mOutputRowRegions; public ErrorCalculator(Context c, Resources resources) { int width = resources.getDimensionPixelSize(R.dimen.layer_width); @@ -57,7 +54,7 @@ public class ErrorCalculator { for (int i = 0; i < rowIndices.length; i++) rowIndices[i] = i * REGION_SIZE; - mScript = new ScriptC_errorCalculator(mRS, resources, R.raw.errorcalculator); + mScript = new ScriptC_errorCalculator(mRS); mScript.set_HEIGHT(height); mScript.set_WIDTH(width); mScript.set_REGION_SIZE(REGION_SIZE); @@ -82,8 +79,8 @@ public class ErrorCalculator { mGivenPixelsAllocation = Allocation.createFromBitmap(mRS, given, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT); - mScript.bind_ideal(mIdealPixelsAllocation); - mScript.bind_given(mGivenPixelsAllocation); + mScript.set_ideal(mIdealPixelsAllocation); + mScript.set_given(mGivenPixelsAllocation); mScript.forEach_countInterestingRegions(mInputRowsAllocation, mOutputRegionsAllocation); mOutputRegionsAllocation.copyTo(mOutputRowRegions); @@ -123,8 +120,8 @@ public class ErrorCalculator { mGivenPixelsAllocation = Allocation.createFromBitmap(mRS, given, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT); - mScript.bind_ideal(mIdealPixelsAllocation); - mScript.bind_given(mGivenPixelsAllocation); + mScript.set_ideal(mIdealPixelsAllocation); + mScript.set_given(mGivenPixelsAllocation); mOutputPixelsAllocation = Allocation.createFromBitmap(mRS, output, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT); diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java index c705443..d522481 100644 --- a/tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java +++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/ResourceModifiers.java @@ -23,7 +23,11 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapShader; import android.graphics.Color; +import android.graphics.ComposeShader; import android.graphics.LinearGradient; +import android.graphics.PorterDuff; +import android.graphics.RadialGradient; +import android.graphics.SweepGradient; import android.graphics.Matrix; import android.graphics.Shader; @@ -38,6 +42,11 @@ public class ResourceModifiers { public final LinearGradient mHorGradient; public final LinearGradient mDiagGradient; public final LinearGradient mVertGradient; + public final RadialGradient mRadGradient; + public final SweepGradient mSweepGradient; + public final ComposeShader mComposeShader; + public final ComposeShader mBadComposeShader; + public final ComposeShader mAnotherBadComposeShader; public final Bitmap mBitmap; private final Matrix mMtx1; private final Matrix mMtx2; @@ -90,6 +99,12 @@ public class ResourceModifiers { mVertGradient = new LinearGradient(0.0f, 0.0f, 0.0f, mDrawHeight / 2.0f, Color.YELLOW, Color.MAGENTA, Shader.TileMode.MIRROR); + mSweepGradient = new SweepGradient(mDrawWidth / 2.0f, mDrawHeight / 2.0f, + Color.YELLOW, Color.MAGENTA); + + mComposeShader = new ComposeShader(mRepeatShader, mHorGradient, + PorterDuff.Mode.MULTIPLY); + final float width = mBitmap.getWidth() / 8.0f; final float height = mBitmap.getHeight() / 8.0f; @@ -106,6 +121,16 @@ public class ResourceModifiers { 0xff00ff00, 0xff0000ff, 0xffff0000, 0xff00ff00, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00ff0000, }; + + // Use a repeating gradient with many colors to test the non simple case. + mRadGradient = new RadialGradient(mDrawWidth / 4.0f, mDrawHeight / 4.0f, 4.0f, + mBitmapColors, null, Shader.TileMode.REPEAT); + + mBadComposeShader = new ComposeShader(mRadGradient, mComposeShader, + PorterDuff.Mode.MULTIPLY); + + mAnotherBadComposeShader = new ComposeShader(mRadGradient, mVertGradient, + PorterDuff.Mode.MULTIPLY); } } diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/errorCalculator.rs b/tests/CanvasCompare/src/com/android/test/hwuicompare/errorCalculator.rs index 3681784..caa947d 100644 --- a/tests/CanvasCompare/src/com/android/test/hwuicompare/errorCalculator.rs +++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/errorCalculator.rs @@ -5,8 +5,8 @@ int REGION_SIZE; int WIDTH; int HEIGHT; -const uchar4 *ideal; -const uchar4 *given; +rs_allocation ideal; +rs_allocation given; void countInterestingRegions(const int32_t *v_in, int32_t *v_out) { int y = v_in[0]; @@ -14,10 +14,10 @@ void countInterestingRegions(const int32_t *v_in, int32_t *v_out) { for (int x = 0; x < HEIGHT; x += REGION_SIZE) { bool interestingRegion = false; - int regionColor = (int)ideal[y * WIDTH + x]; + int regionColor = (int) rsGetElementAt_uchar4(ideal, x, y); for (int i = 0; i < REGION_SIZE && !interestingRegion; i++) { for (int j = 0; j < REGION_SIZE && !interestingRegion; j++) { - interestingRegion |= (int)(ideal[(y + i) * WIDTH + (x + j)]) != regionColor; + interestingRegion |= ((int) rsGetElementAt_uchar4(ideal, x + j, y + i)) != regionColor; } } if (interestingRegion) { @@ -31,8 +31,9 @@ void accumulateError(const int32_t *v_in, int32_t *v_out) { int error = 0; for (int y = startY; y < startY + REGION_SIZE; y++) { for (int x = 0; x < HEIGHT; x++) { - uchar4 idealPixel = ideal[y * WIDTH + x]; - uchar4 givenPixel = given[y * WIDTH + x]; + uchar4 idealPixel = rsGetElementAt_uchar4(ideal, x, y); + uchar4 givenPixel = rsGetElementAt_uchar4(given, x, y); + error += abs(idealPixel.x - givenPixel.x); error += abs(idealPixel.y - givenPixel.y); error += abs(idealPixel.z - givenPixel.z); @@ -43,8 +44,8 @@ void accumulateError(const int32_t *v_in, int32_t *v_out) { } void displayDifference(const uchar4 *v_in, uchar4 *v_out, uint32_t x, uint32_t y) { - float4 idealPixel = rsUnpackColor8888(ideal[y * WIDTH + x]); - float4 givenPixel = rsUnpackColor8888(given[y * WIDTH + x]); + float4 idealPixel = rsGetElementAt_float4(ideal, x, y); + float4 givenPixel = rsGetElementAt_float4(given, x, y); float4 diff = idealPixel - givenPixel; float totalDiff = diff.x + diff.y + diff.z + diff.w; diff --git a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java index f5c4c34..5bf59c7 100644 --- a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java +++ b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java @@ -97,11 +97,11 @@ public class AppCompatibility extends InstrumentationTestCase { String packageName = mArgs.getString(PACKAGE_TO_LAUNCH); if (packageName != null) { Log.d(TAG, "Launching app " + packageName); - Collection<ProcessErrorStateInfo> err = launchActivity(packageName); + ProcessErrorStateInfo err = launchActivity(packageName); // Make sure there are no errors when launching the application, // otherwise raise an // exception with the first error encountered. - assertNull(getFirstError(err), err); + assertNull(getStackTrace(err), err); assertTrue("App crashed after launch.", processStillUp(packageName)); } else { Log.d(TAG, "Missing argument, use " + PACKAGE_TO_LAUNCH + @@ -110,20 +110,32 @@ public class AppCompatibility extends InstrumentationTestCase { } /** - * Gets the first error in collection and return the long message for it. + * Gets the stack trace for the error. * - * @param in {@link Collection} of {@link ProcessErrorStateInfo} to parse. + * @param in {@link ProcessErrorStateInfo} to parse. * @return {@link String} the long message of the error. */ - private String getFirstError(Collection<ProcessErrorStateInfo> in) { + private String getStackTrace(ProcessErrorStateInfo in) { if (in == null) { return null; + } else { + return in.stackTrace; } - ProcessErrorStateInfo err = in.iterator().next(); - if (err != null) { - return err.stackTrace; + } + + /** + * Returns the process name that the package is going to use. + * + * @param packageName name of the package + * @return process name of the package + */ + private String getProcessName(String packageName) { + try { + PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0); + return pi.applicationInfo.processName; + } catch (NameNotFoundException e) { + return packageName; } - return null; } /** @@ -134,7 +146,7 @@ public class AppCompatibility extends InstrumentationTestCase { * @return {@link Collection} of {@link ProcessErrorStateInfo} detected * during the app launch. */ - private Collection<ProcessErrorStateInfo> launchActivity(String packageName) { + private ProcessErrorStateInfo launchActivity(String packageName) { Intent homeIntent = new Intent(Intent.ACTION_MAIN); homeIntent.addCategory(Intent.CATEGORY_HOME); homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); @@ -146,16 +158,7 @@ public class AppCompatibility extends InstrumentationTestCase { return null; } - // We check for any Crash or ANR dialogs that are already up, and we - // ignore them. This is - // so that we don't report crashes that were caused by prior apps (which - // those particular - // tests should have caught and reported already). Otherwise, test - // failures would cascade - // from the initial broken app to many/all of the tests following that - // app's launch. - final Collection<ProcessErrorStateInfo> preErr = - mActivityManager.getProcessesInErrorState(); + String processName = getProcessName(packageName); // Launch Activity mContext.startActivity(intent); @@ -179,13 +182,16 @@ public class AppCompatibility extends InstrumentationTestCase { // possible to occur. final Collection<ProcessErrorStateInfo> postErr = mActivityManager.getProcessesInErrorState(); - // Take the difference between the error processes we see now, and the - // ones that were - // present when we started - if (preErr != null && postErr != null) { - postErr.removeAll(preErr); + + if (postErr == null) { + return null; + } + for (ProcessErrorStateInfo error : postErr) { + if (error.processName.equals(processName)) { + return error; + } } - return postErr; + return null; } /** @@ -195,22 +201,16 @@ public class AppCompatibility extends InstrumentationTestCase { * @return True if package is running, false otherwise. */ private boolean processStillUp(String packageName) { - try { - PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, 0); - String processName = packageInfo.applicationInfo.processName; - List<RunningAppProcessInfo> runningApps = mActivityManager.getRunningAppProcesses(); - for (RunningAppProcessInfo app : runningApps) { - if (app.processName.equalsIgnoreCase(processName)) { - Log.d(TAG, "Found process " + app.processName); - return true; - } + String processName = getProcessName(packageName); + List<RunningAppProcessInfo> runningApps = mActivityManager.getRunningAppProcesses(); + for (RunningAppProcessInfo app : runningApps) { + if (app.processName.equalsIgnoreCase(processName)) { + Log.d(TAG, "Found process " + app.processName); + return true; } - Log.d(TAG, "Failed to find process " + processName + " with package name " - + packageName); - } catch (NameNotFoundException e) { - Log.w(TAG, "Failed to find package " + packageName); - return false; } + Log.d(TAG, "Failed to find process " + processName + " with package name " + + packageName); return false; } } diff --git a/tests/DozeTest/AndroidManifest.xml b/tests/DozeTest/AndroidManifest.xml index c199f69..03778d6 100644 --- a/tests/DozeTest/AndroidManifest.xml +++ b/tests/DozeTest/AndroidManifest.xml @@ -22,7 +22,8 @@ android:name="DozeTestDream" android:exported="true" android:icon="@drawable/ic_app" - android:label="@string/doze_dream_name"> + android:label="@string/doze_dream_name" + android:permission="android.permission.BIND_DREAM_SERVICE"> <!-- Commented out to prevent this dream from appearing in the list of dreams that the user can select via the Settings application. <intent-filter> diff --git a/tests/DozeTest/res/layout/dream.xml b/tests/DozeTest/res/layout/dream.xml index 1c8fd3f..bced230 100644 --- a/tests/DozeTest/res/layout/dream.xml +++ b/tests/DozeTest/res/layout/dream.xml @@ -18,7 +18,8 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical" - android:orientation="vertical"> + android:orientation="vertical" + android:background="#bb2288"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java index a0b2d1a..f4f610b 100644 --- a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java +++ b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java @@ -22,11 +22,12 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.os.Handler; import android.os.PowerManager; -import android.service.dreams.DozeHardware; import android.service.dreams.DreamService; import android.text.format.DateFormat; import android.util.Log; +import android.view.Display; import android.widget.TextView; import java.util.Date; @@ -47,14 +48,16 @@ public class DozeTestDream extends DreamService { // refreshed once the dream has finished rendering a new frame. private static final int UPDATE_TIME_TIMEOUT = 100; - // A doze hardware message string we use for end-to-end testing. - // Doesn't mean anything. Real hardware won't handle it. - private static final String TEST_PING_MESSAGE = "test.ping"; + // Not all hardware supports dozing. We should use Display.STATE_DOZE but + // for testing purposes it is convenient to use Display.STATE_ON so the + // test still works on hardware that does not support dozing. + private static final int DISPLAY_STATE_WHEN_DOZING = Display.STATE_ON; private PowerManager mPowerManager; private PowerManager.WakeLock mWakeLock; private AlarmManager mAlarmManager; private PendingIntent mAlarmIntent; + private Handler mHandler = new Handler(); private TextView mAlarmClock; @@ -62,7 +65,8 @@ public class DozeTestDream extends DreamService { private java.text.DateFormat mTimeFormat; private boolean mDreaming; - private DozeHardware mDozeHardware; + + private long mLastTime = Long.MIN_VALUE; @Override public void onCreate() { @@ -80,6 +84,8 @@ public class DozeTestDream extends DreamService { registerReceiver(mAlarmReceiver, filter); mAlarmIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); + + setDozeScreenState(DISPLAY_STATE_WHEN_DOZING); } @Override @@ -109,17 +115,11 @@ public class DozeTestDream extends DreamService { super.onDreamingStarted(); mDreaming = true; - mDozeHardware = getDozeHardware(); - Log.d(TAG, "Dream started: canDoze=" + canDoze() - + ", dozeHardware=" + mDozeHardware); + Log.d(TAG, "Dream started: canDoze=" + canDoze()); performTimeUpdate(); - if (mDozeHardware != null) { - mDozeHardware.sendMessage(TEST_PING_MESSAGE, null); - mDozeHardware.setEnableMcu(true); - } startDozing(); } @@ -128,10 +128,6 @@ public class DozeTestDream extends DreamService { super.onDreamingStopped(); mDreaming = false; - if (mDozeHardware != null) { - mDozeHardware.setEnableMcu(false); - mDozeHardware = null; - } Log.d(TAG, "Dream ended: isDozing=" + isDozing()); @@ -143,13 +139,33 @@ public class DozeTestDream extends DreamService { if (mDreaming) { long now = System.currentTimeMillis(); now -= now % 60000; // back up to last minute boundary + if (mLastTime == now) { + return; + } + mLastTime = now; mTime.setTime(now); mAlarmClock.setText(mTimeFormat.format(mTime)); mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, now + 60000, mAlarmIntent); - mWakeLock.acquire(UPDATE_TIME_TIMEOUT); + mWakeLock.acquire(UPDATE_TIME_TIMEOUT + 5000 /*for testing brightness*/); + + // flash the screen a bit to test these functions + setDozeScreenState(DISPLAY_STATE_WHEN_DOZING); + setDozeScreenBrightness(200); + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + setDozeScreenBrightness(50); + } + }, 2000); + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + setDozeScreenState(Display.STATE_OFF); + } + }, 5000); } } diff --git a/tests/FeatureSplit/base/Android.mk b/tests/FeatureSplit/base/Android.mk new file mode 100644 index 0000000..7c0fc04 --- /dev/null +++ b/tests/FeatureSplit/base/Android.mk @@ -0,0 +1,25 @@ +# +# 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. +# + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) +LOCAL_PACKAGE_NAME := FeatureSplitBase + +LOCAL_MODULE_TAGS := tests + +include $(BUILD_PACKAGE) diff --git a/tests/FeatureSplit/base/AndroidManifest.xml b/tests/FeatureSplit/base/AndroidManifest.xml new file mode 100644 index 0000000..989e802 --- /dev/null +++ b/tests/FeatureSplit/base/AndroidManifest.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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.test.split.feature"> + <application android:label="@string/app_title" + android:hasCode="false"> + </application> +</manifest> diff --git a/tests/FeatureSplit/base/res/values/values.xml b/tests/FeatureSplit/base/res/values/values.xml new file mode 100644 index 0000000..564d301 --- /dev/null +++ b/tests/FeatureSplit/base/res/values/values.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <string name="app_title">FeatureSplit APK</string> + + <item type="id" name="test_id"/> + <integer name="test_integer">100</integer> + <color name="test_color">#ff0000</color> +</resources> + diff --git a/tests/FeatureSplit/feature1/Android.mk b/tests/FeatureSplit/feature1/Android.mk new file mode 100644 index 0000000..adfb575 --- /dev/null +++ b/tests/FeatureSplit/feature1/Android.mk @@ -0,0 +1,31 @@ +# +# 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. +# + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) +LOCAL_PACKAGE_NAME := FeatureSplit1 +LOCAL_MODULE_TAGS := tests + +featureOf := FeatureSplitBase +featureOfApk := $(call intermediates-dir-for,APPS,$(featureOf))/package.apk +localRStamp := $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),,COMMON)/src/R.stamp +$(localRStamp): $(featureOfApk) + +LOCAL_AAPT_FLAGS := --feature-of $(featureOfApk) + +include $(BUILD_PACKAGE) diff --git a/tests/FeatureSplit/feature1/AndroidManifest.xml b/tests/FeatureSplit/feature1/AndroidManifest.xml new file mode 100644 index 0000000..2aadc6d --- /dev/null +++ b/tests/FeatureSplit/feature1/AndroidManifest.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.test.split.feature" + featureName="feature1"> + <application android:hasCode="false" /> +</manifest> diff --git a/tests/FeatureSplit/feature1/res/values/values.xml b/tests/FeatureSplit/feature1/res/values/values.xml new file mode 100644 index 0000000..70eb56a --- /dev/null +++ b/tests/FeatureSplit/feature1/res/values/values.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <item type="id" name="test_id2"/> + <integer name="test_integer2">200</integer> + <color name="test_color2">#00ff00</color> + <string-array name="string_array2"> + <item>@*string/app_title</item> + </string-array> +</resources> + diff --git a/tests/FeatureSplit/feature2/Android.mk b/tests/FeatureSplit/feature2/Android.mk new file mode 100644 index 0000000..e69cbe8 --- /dev/null +++ b/tests/FeatureSplit/feature2/Android.mk @@ -0,0 +1,35 @@ +# +# 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. +# + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) +LOCAL_PACKAGE_NAME := FeatureSplit2 +LOCAL_MODULE_TAGS := tests + +featureOf := FeatureSplitBase +featureAfter := FeatureSplit1 + +featureOfApk := $(call intermediates-dir-for,APPS,$(featureOf))/package.apk +featureAfterApk := $(call intermediates-dir-for,APPS,$(featureAfter))/package.apk +localRStamp := $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),,COMMON)/src/R.stamp +$(localRStamp): $(featureOfApk) $(featureAfterApk) + +LOCAL_AAPT_FLAGS := --feature-of $(featureOfApk) +LOCAL_AAPT_FLAGS += --feature-after $(featureAfterApk) + +include $(BUILD_PACKAGE) diff --git a/tests/FeatureSplit/feature2/AndroidManifest.xml b/tests/FeatureSplit/feature2/AndroidManifest.xml new file mode 100644 index 0000000..d139900 --- /dev/null +++ b/tests/FeatureSplit/feature2/AndroidManifest.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.test.split.feature" + featureName="feature2"> + <application android:hasCode="false"/> +</manifest> diff --git a/tests/FeatureSplit/feature2/res/values/values.xml b/tests/FeatureSplit/feature2/res/values/values.xml new file mode 100644 index 0000000..af5ed1b --- /dev/null +++ b/tests/FeatureSplit/feature2/res/values/values.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <integer name="test_integer3">300</integer> + <color name="test_color3">#0000ff</color> + <string-array name="string_array3"> + <item>@string/app_title</item> + </string-array> +</resources> + diff --git a/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfActivity.java b/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfActivity.java index 6633787..78e360b 100644 --- a/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfActivity.java +++ b/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfActivity.java @@ -20,6 +20,7 @@ import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; +import android.graphics.Color; import android.os.Binder; import android.os.Bundle; import android.os.Handler; @@ -199,6 +200,7 @@ public class FrameworkPerfActivity extends Activity mLocalCheckBox = (CheckBox)findViewById(R.id.local); mLog = (TextView)findViewById(R.id.log); + mLog.setTextColor(Color.RED); PowerManager pm = (PowerManager)getSystemService(POWER_SERVICE); mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Scheduler"); diff --git a/tests/GridLayoutTest/src/com/android/test/layout/AbstractLayoutTest.java b/tests/GridLayoutTest/src/com/android/test/layout/AbstractLayoutTest.java index 4d3a843..196a5c1 100644 --- a/tests/GridLayoutTest/src/com/android/test/layout/AbstractLayoutTest.java +++ b/tests/GridLayoutTest/src/com/android/test/layout/AbstractLayoutTest.java @@ -24,7 +24,13 @@ import android.view.View; import android.view.ViewGroup; import android.widget.Button; -import static android.view.Gravity.*; +import static android.view.Gravity.BOTTOM; +import static android.view.Gravity.CENTER; +import static android.view.Gravity.FILL; +import static android.view.Gravity.LEFT; +import static android.view.Gravity.NO_GRAVITY; +import static android.view.Gravity.RIGHT; +import static android.view.Gravity.TOP; public abstract class AbstractLayoutTest extends Activity { diff --git a/tests/GridLayoutTest/src/com/android/test/layout/AlignmentTest.java b/tests/GridLayoutTest/src/com/android/test/layout/AlignmentTest.java index b1c4486..5559707 100644 --- a/tests/GridLayoutTest/src/com/android/test/layout/AlignmentTest.java +++ b/tests/GridLayoutTest/src/com/android/test/layout/AlignmentTest.java @@ -20,15 +20,25 @@ import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.view.View; +import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.Button; import android.widget.EditText; import android.widget.GridLayout; +import android.widget.GridLayout.Alignment; +import android.widget.GridLayout.LayoutParams; import android.widget.TextView; -import static android.widget.GridLayout.*; +import static android.widget.GridLayout.BASELINE; +import static android.widget.GridLayout.BOTTOM; +import static android.widget.GridLayout.CENTER; +import static android.widget.GridLayout.FILL; +import static android.widget.GridLayout.LEFT; +import static android.widget.GridLayout.RIGHT; +import static android.widget.GridLayout.TOP; +import static android.widget.GridLayout.spec; -public class AlignmentTest extends Activity { +public class AlignmentTest extends Activity { public static final String[] HORIZONTAL_NAMES = {"LEFT", "center", "east", "fill"}; public static final Alignment[] HORIZONTAL_ALIGNMENTS = {LEFT, CENTER, RIGHT, FILL}; diff --git a/tests/GridLayoutTest/src/com/android/test/layout/GridLayoutTest.java b/tests/GridLayoutTest/src/com/android/test/layout/GridLayoutTest.java index 4ce449a..8047c5f 100644 --- a/tests/GridLayoutTest/src/com/android/test/layout/GridLayoutTest.java +++ b/tests/GridLayoutTest/src/com/android/test/layout/GridLayoutTest.java @@ -21,7 +21,10 @@ import android.view.View; import android.view.ViewGroup; import android.widget.GridLayout; -import static android.widget.GridLayout.*; +import static android.widget.GridLayout.Spec; +import static android.widget.GridLayout.UNDEFINED; +import static android.widget.GridLayout.VERTICAL; +import static android.widget.GridLayout.spec; public class GridLayoutTest extends AbstractLayoutTest { public ViewGroup create(Context context) { diff --git a/tests/GridLayoutTest/src/com/android/test/layout/LinearLayoutTest.java b/tests/GridLayoutTest/src/com/android/test/layout/LinearLayoutTest.java index c7f4665..dc5b12c 100644 --- a/tests/GridLayoutTest/src/com/android/test/layout/LinearLayoutTest.java +++ b/tests/GridLayoutTest/src/com/android/test/layout/LinearLayoutTest.java @@ -20,9 +20,9 @@ import android.content.Context; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; +import android.widget.LinearLayout.LayoutParams; -import static android.widget.LinearLayout.*; -import static android.widget.LinearLayout.LayoutParams.*; +import static android.widget.LinearLayout.LayoutParams.WRAP_CONTENT; public class LinearLayoutTest extends AbstractLayoutTest { public ViewGroup create(Context context) { diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index 1bb0db0..bc2f1fd 100644 --- a/tests/HwAccelerationTest/AndroidManifest.xml +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -216,6 +216,15 @@ </activity> <activity + android:name="ClipOutlineActivity" + android:label="Clip/Outline"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="com.android.test.hwui.TEST" /> + </intent-filter> + </activity> + + <activity android:name="DisplayListLayersActivity" android:label="Layers/Display Lists"> <intent-filter> @@ -232,6 +241,15 @@ <category android:name="com.android.test.hwui.TEST" /> </intent-filter> </activity> + + <activity + android:name="LooperAcceleration" + android:label="Misc/LooperAcceleration"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="com.android.test.hwui.TEST" /> + </intent-filter> + </activity> <activity android:name="TextFadeActivity" @@ -322,7 +340,7 @@ <category android:name="com.android.test.hwui.TEST" /> </intent-filter> </activity> - + <activity android:name="GLTextureViewActivity" android:label="TextureView/OpenGL"> @@ -331,7 +349,7 @@ <category android:name="com.android.test.hwui.TEST" /> </intent-filter> </activity> - + <activity android:name="BitmapMeshActivity" android:label="Bitmaps/Mesh"> @@ -706,6 +724,15 @@ </activity> <activity + android:name="ColorFiltersMutateActivity" + android:label="ColorFilters/Mutate Filters"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="com.android.test.hwui.TEST" /> + </intent-filter> + </activity> + + <activity android:name="LinesActivity" android:label="Draw/Lines"> <intent-filter> @@ -849,5 +876,59 @@ </intent-filter> </activity> + <activity + android:name="ProjectionActivity" + android:label="Reordering/Projection"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="com.android.test.hwui.TEST" /> + </intent-filter> + </activity> + + <activity + android:name=".ProjectionClippingActivity" + android:label="Reordering/Projection Clipping"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="com.android.test.hwui.TEST" /> + </intent-filter> + </activity> + + <activity + android:name=".ZOrderingActivity" + android:label="Reordering/Z Ordering"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="com.android.test.hwui.TEST" /> + </intent-filter> + </activity> + + <activity + android:name="GLDepthTestActivity" + android:label="Reordering/OpenGL Depth Test"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="com.android.test.hwui.TEST" /> + </intent-filter> + </activity> + + <activity + android:name="CirclePropActivity" + android:label="Animation/Circle Props"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="com.android.test.hwui.TEST" /> + </intent-filter> + </activity> + + <activity + android:name="RevealActivity" + android:label="Animation/Reveal Animation"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="com.android.test.hwui.TEST" /> + </intent-filter> + </activity> + </application> </manifest> diff --git a/tests/HwAccelerationTest/res/drawable/robot.png b/tests/HwAccelerationTest/res/drawable/robot.png Binary files differnew file mode 100644 index 0000000..8a9e698 --- /dev/null +++ b/tests/HwAccelerationTest/res/drawable/robot.png diff --git a/tests/HwAccelerationTest/res/drawable/round_rect_background.xml b/tests/HwAccelerationTest/res/drawable/round_rect_background.xml new file mode 100644 index 0000000..14d4073 --- /dev/null +++ b/tests/HwAccelerationTest/res/drawable/round_rect_background.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape + xmlns:android="http://schemas.android.com/apk/res/android" > + <solid android:color="#eee" /> + <corners android:radius="30dp" /> +</shape>
\ No newline at end of file diff --git a/tests/HwAccelerationTest/res/layout/projection.xml b/tests/HwAccelerationTest/res/layout/projection.xml new file mode 100644 index 0000000..b6e4c5e --- /dev/null +++ b/tests/HwAccelerationTest/res/layout/projection.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:background="#66ff0000" + tools:context="com.example.projection.ProjectionActivity" + tools:ignore="MergeRootFrame"> + <TextView + android:layout_width="match_parent" + android:layout_height="100dp" + android:textSize="50sp" + android:text="TextView"/> + <FrameLayout + android:layout_width="match_parent" + android:layout_height="100dp" + android:clipChildren="false"> + <view class="com.android.test.hwui.ProjectionActivity$ProjectedView" + android:id="@+id/projection" + android:layout_width="match_parent" + android:layout_height="match_parent"/> + <TextView + android:layout_width="match_parent" + android:layout_height="match_parent" + android:textSize="50sp" + android:text="TextView"/> + </FrameLayout> + + <TextView + android:layout_width="match_parent" + android:layout_height="100dp" + android:textSize="50sp" + android:text="TextView"/> +</LinearLayout>
\ No newline at end of file diff --git a/tests/HwAccelerationTest/res/layout/projection_clipping.xml b/tests/HwAccelerationTest/res/layout/projection_clipping.xml new file mode 100644 index 0000000..7177fc8f --- /dev/null +++ b/tests/HwAccelerationTest/res/layout/projection_clipping.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <FrameLayout + android:translationX="50dp" + android:translationY="50dp" + android:elevation="30dp" + android:layout_width="200dp" + android:layout_height="200dp" + android:background="@drawable/round_rect_background"> + <View + android:id="@+id/clickable1" + android:layout_width="100dp" + android:layout_height="100dp" + android:background="?android:attr/selectableItemBackground"/> + <View + android:id="@+id/clickable2" + android:translationX="50dp" + android:translationY="10dp" + android:layout_width="150dp" + android:layout_height="100dp" + android:background="?android:attr/selectableItemBackground"/> + </FrameLayout> +</LinearLayout>
\ No newline at end of file diff --git a/tests/HwAccelerationTest/res/layout/z_ordering.xml b/tests/HwAccelerationTest/res/layout/z_ordering.xml new file mode 100644 index 0000000..970c5fd --- /dev/null +++ b/tests/HwAccelerationTest/res/layout/z_ordering.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:id="@+id/parent"> + <RelativeLayout + android:layout_width="400dp" + android:layout_height="200dp" + android:layout_weight="1" + android:orientation="vertical"> + <TextView style="@style/TopLeftReorderTextView"/> + <TextView style="@style/BottomLeftReorderTextView"/> + <TextView style="@style/TopRightReorderTextView"/> + <TextView style="@style/BottomRightReorderTextView"/> + </RelativeLayout> +</LinearLayout>
\ No newline at end of file diff --git a/tests/HwAccelerationTest/res/values/styles.xml b/tests/HwAccelerationTest/res/values/styles.xml new file mode 100644 index 0000000..108709b --- /dev/null +++ b/tests/HwAccelerationTest/res/values/styles.xml @@ -0,0 +1,37 @@ +<resources> + <style name="ReorderTextView" parent="@android:style/TextAppearance.Medium"> + <item name="android:background">@drawable/appwidget_background</item> + <item name="android:layout_width">300dp</item> + <item name="android:layout_height">100dp</item> + <item name="android:gravity">center</item> + </style> + <style name="LeftReorderTextView" parent="@style/ReorderTextView"> + <item name="android:translationX">50dp</item> + <item name="android:layout_alignParentLeft">true</item> + </style> + <style name="RightReorderTextView" parent="@style/ReorderTextView"> + <item name="android:translationX">-50dp</item> + <item name="android:layout_alignParentRight">true</item> + </style> + + <style name="TopLeftReorderTextView" parent="@style/LeftReorderTextView"> + <item name="android:text">200</item> + <item name="android:translationZ">200dp</item> + <item name="android:layout_alignParentTop">true</item> + </style> + <style name="BottomLeftReorderTextView" parent="@style/LeftReorderTextView"> + <item name="android:text">300</item> + <item name="android:translationZ">300dp</item> + <item name="android:layout_alignParentBottom">true</item> + </style> + <style name="TopRightReorderTextView" parent="@style/RightReorderTextView"> + <item name="android:text">100</item> + <item name="android:translationZ">100dp</item> + <item name="android:layout_alignParentTop">true</item> + </style> + <style name="BottomRightReorderTextView" parent="@style/RightReorderTextView"> + <item name="android:text">400</item> + <item name="android:translationZ">400dp</item> + <item name="android:layout_alignParentBottom">true</item> + </style> +</resources> diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java new file mode 100644 index 0000000..a81e063 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java @@ -0,0 +1,159 @@ +/* + * 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.test.hwui; + +import android.animation.TimeInterpolator; +import android.app.Activity; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.CanvasProperty; +import android.graphics.Paint; +import android.graphics.Paint.Style; +import android.os.Bundle; +import android.os.Trace; +import android.view.HardwareCanvas; +import android.view.RenderNodeAnimator; +import android.view.View; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.OvershootInterpolator; +import android.webkit.WebChromeClient; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import android.widget.LinearLayout; +import android.widget.LinearLayout.LayoutParams; +import android.widget.ProgressBar; + +import java.util.ArrayList; + +public class CirclePropActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final LinearLayout layout = new LinearLayout(this); + layout.setOrientation(LinearLayout.VERTICAL); + + ProgressBar spinner = new ProgressBar(this, null, android.R.attr.progressBarStyleLarge); + layout.addView(spinner, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); + // For testing with a functor in the tree +// WebView wv = new WebView(this); +// wv.setWebViewClient(new WebViewClient()); +// wv.setWebChromeClient(new WebChromeClient()); +// wv.loadUrl("http://theverge.com"); +// layout.addView(wv, new LayoutParams(LayoutParams.MATCH_PARENT, 100)); + + layout.addView(new CircleView(this), + new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + + setContentView(layout); + } + + static class CircleView extends View { + static final int DURATION = 500; + + private boolean mToggle = false; + ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<RenderNodeAnimator>(); + + CanvasProperty<Float> mX; + CanvasProperty<Float> mY; + CanvasProperty<Float> mRadius; + CanvasProperty<Paint> mPaint; + + CircleView(Context c) { + super(c); + setClickable(true); + + mX = CanvasProperty.createFloat(200.0f); + mY = CanvasProperty.createFloat(200.0f); + mRadius = CanvasProperty.createFloat(150.0f); + + Paint p = new Paint(); + p.setAntiAlias(true); + p.setColor(0xFFFF0000); + p.setStyle(Style.STROKE); + p.setStrokeWidth(60.0f); + mPaint = CanvasProperty.createPaint(p); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (canvas.isHardwareAccelerated()) { + HardwareCanvas hwcanvas = (HardwareCanvas) canvas; + hwcanvas.drawCircle(mX, mY, mRadius, mPaint); + } + } + + @Override + public boolean performClick() { + for (int i = 0; i < mRunningAnimations.size(); i++) { + mRunningAnimations.get(i).cancel(); + } + mRunningAnimations.clear(); + + mToggle = !mToggle; + + mRunningAnimations.add(new RenderNodeAnimator( + mX, mToggle ? 400.0f : 200.0f)); + + mRunningAnimations.add(new RenderNodeAnimator( + mY, mToggle ? 600.0f : 200.0f)); + + mRunningAnimations.add(new RenderNodeAnimator( + mRadius, mToggle ? 250.0f : 150.0f)); + + mRunningAnimations.add(new RenderNodeAnimator( + mPaint, RenderNodeAnimator.PAINT_STROKE_WIDTH, + mToggle ? 5.0f : 60.0f)); + + mRunningAnimations.add(new RenderNodeAnimator( + mPaint, RenderNodeAnimator.PAINT_ALPHA, 64.0f)); + + // Will be "chained" to run after the above + mRunningAnimations.add(new RenderNodeAnimator( + mPaint, RenderNodeAnimator.PAINT_ALPHA, 255.0f)); + + for (int i = 0; i < mRunningAnimations.size(); i++) { + RenderNodeAnimator anim = mRunningAnimations.get(i); + anim.setDuration(1000); + anim.setTarget(this); + if (i == (mRunningAnimations.size() - 1)) { + // "chain" test + anim.setStartValue(64.0f); + anim.setStartDelay(anim.getDuration()); + } + anim.start(); + } + + if (mToggle) { + post(new Runnable() { + @Override + public void run() { + Trace.traceBegin(Trace.TRACE_TAG_VIEW, "pretendBusy"); + try { + Thread.sleep(DURATION); + } catch (InterruptedException e) { + } + Trace.traceEnd(Trace.TRACE_TAG_VIEW); + } + }); + } + return true; + } + } +} diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ClipOutlineActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ClipOutlineActivity.java new file mode 100644 index 0000000..23bb6b4 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ClipOutlineActivity.java @@ -0,0 +1,94 @@ +/* + * 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.test.hwui; + +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.app.Activity; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Outline; +import android.graphics.Path; +import android.graphics.Rect; +import android.os.Bundle; +import android.view.View; +import android.view.ViewOutlineProvider; +import android.widget.FrameLayout; +import android.widget.TextView; + +public class ClipOutlineActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final RegionView group = new RegionView(this); + + final TextView text = new TextView(this); + text.setText(buildText()); + group.addView(text); + + setContentView(group); + + ObjectAnimator animator = ObjectAnimator.ofFloat(group, "clipPosition", 0.0f, 1.0f); + animator.setDuration(3000); + animator.setRepeatCount(ValueAnimator.INFINITE); + animator.setRepeatMode(ValueAnimator.REVERSE); + animator.start(); + } + + private static CharSequence buildText() { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < 10; i++) { + buffer.append(LOREM_IPSUM); + } + return buffer; + } + + public static class RegionView extends FrameLayout { + private float mClipPosition = 0.0f; + private Rect mRect = new Rect(); + + public RegionView(Context c) { + super(c); + setOutlineProvider(new ViewOutlineProvider() { + + @Override + public void getOutline(View view, Outline outline) { + int w = getWidth() / 2; + int h = getHeight() / 2; + + mRect.set(0, 0, w, h); + mRect.offset((int) (mClipPosition * w), getHeight() / 4); + + outline.setRoundRect(mRect, w / 2); + } + }); + setClipToOutline(true); + } + + public float getClipPosition() { + return mClipPosition; + } + + public void setClipPosition(float clipPosition) { + mClipPosition = clipPosition; + invalidateOutline(); + } + } + + private static final String LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed sagittis molestie aliquam. Donec metus metus, laoreet nec sagittis vitae, ultricies sit amet eros. Suspendisse sed massa sit amet felis consectetur gravida. In vitae erat mi, in egestas nisl. Phasellus quis ipsum massa, at scelerisque arcu. Nam lectus est, pellentesque eget lacinia non, congue vitae augue. Aliquam erat volutpat. Pellentesque bibendum tincidunt viverra. Aliquam erat volutpat. Maecenas pretium vulputate placerat. Nulla varius elementum rutrum. Aenean mollis blandit imperdiet. Pellentesque interdum fringilla ligula."; +} diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java new file mode 100644 index 0000000..808b5d3 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.test.hwui; + +import android.animation.ArgbEvaluator; +import android.animation.ObjectAnimator; +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; +import android.graphics.LightingColorFilter; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.os.Bundle; +import android.view.View; + +@SuppressWarnings({"UnusedDeclaration"}) +public class ColorFiltersMutateActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + final BitmapsView view = new BitmapsView(this); + setContentView(view); + } + + static class BitmapsView extends View { + private final Bitmap mBitmap1; + private final Bitmap mBitmap2; + private final Paint mColorMatrixPaint; + private final Paint mLightingPaint; + private final Paint mBlendPaint; + + private float mSaturation = 0.0f; + private int mLightAdd = 0; + private int mLightMul = 0; + private int mPorterDuffColor = 0; + + BitmapsView(Context c) { + super(c); + + mBitmap1 = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1); + mBitmap2 = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset2); + + mColorMatrixPaint = new Paint(); + final ColorMatrix colorMatrix = new ColorMatrix(); + colorMatrix.setSaturation(0); + mColorMatrixPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); + + mLightingPaint = new Paint(); + mLightingPaint.setColorFilter(new LightingColorFilter(0, 0)); + + mBlendPaint = new Paint(); + mBlendPaint.setColorFilter(new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_OVER)); + + ObjectAnimator sat = ObjectAnimator.ofFloat(this, "saturation", 1.0f); + sat.setDuration(1000); + sat.setRepeatCount(ObjectAnimator.INFINITE); + sat.setRepeatMode(ObjectAnimator.REVERSE); + sat.start(); + + ObjectAnimator light = ObjectAnimator.ofInt(this, "lightAdd", 0x00101030); + light.setEvaluator(new ArgbEvaluator()); + light.setDuration(1000); + light.setRepeatCount(ObjectAnimator.INFINITE); + light.setRepeatMode(ObjectAnimator.REVERSE); + light.start(); + + ObjectAnimator mult = ObjectAnimator.ofInt(this, "lightMul", 0x0060ffff); + mult.setEvaluator(new ArgbEvaluator()); + mult.setDuration(1000); + mult.setRepeatCount(ObjectAnimator.INFINITE); + mult.setRepeatMode(ObjectAnimator.REVERSE); + mult.start(); + + ObjectAnimator color = ObjectAnimator.ofInt(this, "porterDuffColor", 0x7f990040); + color.setEvaluator(new ArgbEvaluator()); + color.setDuration(1000); + color.setRepeatCount(ObjectAnimator.INFINITE); + color.setRepeatMode(ObjectAnimator.REVERSE); + color.start(); + } + + public int getPorterDuffColor() { + return mPorterDuffColor; + } + + public void setPorterDuffColor(int porterDuffColor) { + mPorterDuffColor = porterDuffColor; + final PorterDuffColorFilter filter = + (PorterDuffColorFilter) mBlendPaint.getColorFilter(); + filter.setColor(mPorterDuffColor); + invalidate(); + } + + public int getLightAdd() { + return mLightAdd; + } + + public void setLightAdd(int lightAdd) { + mLightAdd = lightAdd; + final LightingColorFilter filter = + (LightingColorFilter) mLightingPaint.getColorFilter(); + filter.setColorAdd(lightAdd); + invalidate(); + } + + public int getLightMul() { + return mLightAdd; + } + + public void setLightMul(int lightMul) { + mLightMul = lightMul; + final LightingColorFilter filter = + (LightingColorFilter) mLightingPaint.getColorFilter(); + filter.setColorMultiply(lightMul); + invalidate(); + } + + public void setSaturation(float saturation) { + mSaturation = saturation; + final ColorMatrixColorFilter filter = + (ColorMatrixColorFilter) mColorMatrixPaint.getColorFilter(); + final ColorMatrix m = filter.getColorMatrix(); + m.setSaturation(saturation); + filter.setColorMatrix(m); + invalidate(); + } + + public float getSaturation() { + return mSaturation; + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + canvas.drawARGB(255, 255, 255, 255); + + canvas.save(); + canvas.translate(120.0f, 50.0f); + canvas.drawBitmap(mBitmap1, 0.0f, 0.0f, mColorMatrixPaint); + + canvas.translate(0.0f, 50.0f + mBitmap1.getHeight()); + canvas.drawBitmap(mBitmap1, 0.0f, 0.0f, mLightingPaint); + + canvas.translate(0.0f, 50.0f + mBitmap1.getHeight()); + canvas.drawBitmap(mBitmap1, 0.0f, 0.0f, mBlendPaint); + canvas.restore(); + + canvas.save(); + canvas.translate(120.0f + mBitmap1.getWidth() + 120.0f, 50.0f); + canvas.drawBitmap(mBitmap2, 0.0f, 0.0f, mColorMatrixPaint); + + canvas.translate(0.0f, 50.0f + mBitmap2.getHeight()); + canvas.drawBitmap(mBitmap2, 0.0f, 0.0f, mLightingPaint); + + canvas.translate(0.0f, 50.0f + mBitmap2.getHeight()); + canvas.drawBitmap(mBitmap2, 0.0f, 0.0f, mBlendPaint); + canvas.restore(); + } + } +} diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GLDepthTestActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GLDepthTestActivity.java new file mode 100644 index 0000000..1bb6d0c --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GLDepthTestActivity.java @@ -0,0 +1,367 @@ +/* + * 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.test.hwui; + +import android.app.Activity; +import android.app.ActivityManager; +import android.content.Context; +import android.content.pm.ConfigurationInfo; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.opengl.EGL14; +import android.opengl.EGLDisplay; +import android.opengl.GLES20; +import android.opengl.GLSurfaceView; +import android.opengl.GLUtils; +import android.opengl.Matrix; +import android.os.Bundle; +import android.os.SystemClock; +import android.util.Log; +import android.view.MotionEvent; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; + +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; + +/** + * This sample shows how to check for OpenGL ES 2.0 support at runtime, and then + * use either OpenGL ES 1.0 or OpenGL ES 2.0, as appropriate. + */ +public class GLDepthTestActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mGLSurfaceView = new GLSurfaceView(this); + if (detectOpenGLES20()) { + // Tell the surface view we want to create an OpenGL ES + // 2.0-compatible + // context, and set an OpenGL ES 2.0-compatible renderer. + mGLSurfaceView.setEGLContextClientVersion(2); + mRenderer = new GLES20TriangleRenderer(this); + mGLSurfaceView.setRenderer(mRenderer); + } else { + throw new IllegalStateException("Can't find OGL ES2.0 context"); + } + setContentView(mGLSurfaceView); + } + + private boolean detectOpenGLES20() { + ActivityManager am = + (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); + ConfigurationInfo info = am.getDeviceConfigurationInfo(); + return (info.reqGlEsVersion >= 0x20000); + } + + @Override + protected void onResume() { + // Ideally a game should implement onResume() and onPause() + // to take appropriate action when the activity looses focus + super.onResume(); + mGLSurfaceView.onResume(); + } + + @Override + protected void onPause() { + // Ideally a game should implement onResume() and onPause() + // to take appropriate action when the activity looses focus + super.onPause(); + mGLSurfaceView.onPause(); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + Log.i("motion", event.toString()); + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + mRenderer.toggleDepthTest(); + } + return true; + } + + private GLSurfaceView mGLSurfaceView; + private GLES20TriangleRenderer mRenderer; + + /* + * Copyright (C) 2009 The Android Open Source Project Licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by + * applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for + * the specific language governing permissions and limitations under the + * License. + */ + + class GLES20TriangleRenderer implements GLSurfaceView.Renderer { + private final static int REPEAT_RECTANGLES = 10; + private boolean mDepthTestEnabled = true; + private final static int FRAME_REPEAT_TIMES = 1; + public GLES20TriangleRenderer(Context context) { + mContext = context; + mTriangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length + * FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer(); + mTriangleVertices.put(mTriangleVerticesData).position(0); + } + + + public void toggleDepthTest() { + mDepthTestEnabled = !mDepthTestEnabled; + Log.v(TAG, "mDepthTestEnabled is " + mDepthTestEnabled); + } + + public void onDrawFrame(GL10 glUnused) { + for (int j = 0 ; j < FRAME_REPEAT_TIMES; j ++) { + // Ignore the passed-in GL10 interface, and use the GLES20 + // class's static methods instead. + GLES20.glClearColor(0.0f, 0.0f, 1.0f, 1.0f); + if (mDepthTestEnabled) { + GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT); + } else { + GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); + } + GLES20.glUseProgram(mProgram); + if (mDepthTestEnabled) { + GLES20.glEnable(GLES20.GL_DEPTH_TEST); + } else { + GLES20.glDisable(GLES20.GL_DEPTH_TEST); + } + checkGlError("glUseProgram"); + + GLES20.glActiveTexture(GLES20.GL_TEXTURE0); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID); + + mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET); + GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, + TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices); + checkGlError("glVertexAttribPointer maPosition"); + mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET); + GLES20.glEnableVertexAttribArray(maPositionHandle); + checkGlError("glEnableVertexAttribArray maPositionHandle"); + GLES20.glVertexAttribPointer(maTextureHandle, 2, GLES20.GL_FLOAT, false, + TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices); + checkGlError("glVertexAttribPointer maTextureHandle"); + GLES20.glEnableVertexAttribArray(maTextureHandle); + checkGlError("glEnableVertexAttribArray maTextureHandle"); + + for (int i = 0 ; i < REPEAT_RECTANGLES; i ++) { + float step = ((float)i) / REPEAT_RECTANGLES; + Matrix.setIdentityM(mMMatrix, 0); + Matrix.translateM(mMMatrix, 0, 0, step, step / 2); + Matrix.scaleM(mMMatrix, 0, 2.0f, 1.0f, 1.0f); + Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0); + Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0); + + GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0); + GLES20.glUniform4f(muOverlayHandle, step , step, step , step); + GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); + checkGlError("glDrawArrays"); + } + } + } + + public void onSurfaceChanged(GL10 glUnused, int width, int height) { + // Ignore the passed-in GL10 interface, and use the GLES20 + // class's static methods instead. + GLES20.glViewport(0, 0, width, height); + float ratio = (float) width / height; + Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7); + } + + public void onSurfaceCreated(GL10 glUnused, EGLConfig config) { + // Ignore the passed-in GL10 interface, and use the GLES20 + // class's static methods instead. + mProgram = createProgram(mVertexShader, mFragmentShader); + if (mProgram == 0) { + return; + } + maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition"); + checkGlError("glGetAttribLocation aPosition"); + if (maPositionHandle == -1) { + throw new RuntimeException("Could not get attrib location for aPosition"); + } + maTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTextureCoord"); + checkGlError("glGetAttribLocation aTextureCoord"); + if (maTextureHandle == -1) { + throw new RuntimeException("Could not get attrib location for aTextureCoord"); + } + + muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); + checkGlError("glGetUniformLocation uMVPMatrix"); + if (muMVPMatrixHandle == -1) { + throw new RuntimeException("Could not get attrib location for uMVPMatrix"); + } + + muOverlayHandle = GLES20.glGetUniformLocation(mProgram, "uOverlay"); + checkGlError("glGetUniformLocation uOverlay"); + if (muOverlayHandle == -1) { + throw new RuntimeException("Could not get attrib location for muOverlayHandle"); + } + + /* + * Create our texture. This has to be done each time the surface is + * created. + */ + + int[] textures = new int[1]; + GLES20.glGenTextures(1, textures, 0); + + mTextureID = textures[0]; + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID); + + GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, + GLES20.GL_NEAREST); + GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, + GLES20.GL_TEXTURE_MAG_FILTER, + GLES20.GL_LINEAR); + + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, + GLES20.GL_REPEAT); + GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, + GLES20.GL_REPEAT); + + InputStream is = mContext.getResources() + .openRawResource(R.drawable.robot); + Bitmap bitmap; + try { + bitmap = BitmapFactory.decodeStream(is); + } finally { + try { + is.close(); + } catch (IOException e) { + // Ignore. + } + } + + GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); + bitmap.recycle(); + + Matrix.setLookAtM(mVMatrix, 0, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f); + + EGLDisplay display = EGL14.eglGetCurrentDisplay(); + EGL14.eglSwapInterval(display, 0); + + } + + private int loadShader(int shaderType, String source) { + int shader = GLES20.glCreateShader(shaderType); + if (shader != 0) { + GLES20.glShaderSource(shader, source); + GLES20.glCompileShader(shader); + int[] compiled = new int[1]; + GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0); + if (compiled[0] == 0) { + Log.e(TAG, "Could not compile shader " + shaderType + ":"); + Log.e(TAG, GLES20.glGetShaderInfoLog(shader)); + GLES20.glDeleteShader(shader); + shader = 0; + } + } + return shader; + } + + private int createProgram(String vertexSource, String fragmentSource) { + int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource); + if (vertexShader == 0) { + return 0; + } + + int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource); + if (pixelShader == 0) { + return 0; + } + + int program = GLES20.glCreateProgram(); + if (program != 0) { + GLES20.glAttachShader(program, vertexShader); + checkGlError("glAttachShader"); + GLES20.glAttachShader(program, pixelShader); + checkGlError("glAttachShader"); + GLES20.glLinkProgram(program); + int[] linkStatus = new int[1]; + GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0); + if (linkStatus[0] != GLES20.GL_TRUE) { + Log.e(TAG, "Could not link program: "); + Log.e(TAG, GLES20.glGetProgramInfoLog(program)); + GLES20.glDeleteProgram(program); + program = 0; + } + } + return program; + } + + private void checkGlError(String op) { + int error; + while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { + Log.e(TAG, op + ": glError " + error); + throw new RuntimeException(op + ": glError " + error); + } + } + + private static final int FLOAT_SIZE_BYTES = 4; + private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES; + private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0; + private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3; + private final float[] mTriangleVerticesData = { + // X, Y, Z, U, V + -1.0f, -1.0f, 0, 0.0f, 0.0f, + -1.0f, 1.0f, 0, 0.0f, 1.0f, + 1.0f, -1.0f, 0, 1.0f, 0.0f, + 1.0f, 1.0f, 0, 1.0f, 1.0f, }; + + private FloatBuffer mTriangleVertices; + + private final String mVertexShader = + "uniform mat4 uMVPMatrix;\n" + + "attribute vec4 aPosition;\n" + + "attribute vec2 aTextureCoord;\n" + + "varying vec2 vTextureCoord;\n" + + "void main() {\n" + + " gl_Position = uMVPMatrix * aPosition;\n" + + " vTextureCoord = aTextureCoord;\n" + + "}\n"; + + private final String mFragmentShader = + "precision mediump float;\n" + + "varying vec2 vTextureCoord;\n" + + "uniform sampler2D sTexture;\n" + + "uniform vec4 uOverlay;\n" + + "void main() {\n" + + " gl_FragColor = texture2D(sTexture, vTextureCoord) * uOverlay;\n" + + "}\n"; + + private float[] mMVPMatrix = new float[16]; + private float[] mProjMatrix = new float[16]; + private float[] mMMatrix = new float[16]; + private float[] mVMatrix = new float[16]; + + private int mProgram; + private int mTextureID; + private int muMVPMatrixHandle; + private int maPositionHandle; + private int maTextureHandle; + private int muOverlayHandle; + + private Context mContext; + private static final String TAG = "GLES20TriangleRenderer"; + } + +} diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java index 90db818..fbe7856 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java @@ -223,12 +223,11 @@ public class GradientsActivity extends Activity { float left = 40.0f; float bottom = 40.0f + mDrawHeight; - mPaint.setShader(mGradient); - mMatrix.setScale(1, mDrawWidth); mMatrix.postRotate(90); mMatrix.postTranslate(right, top); mGradient.setLocalMatrix(mMatrix); + mPaint.setShader(mGradient); canvas.drawRect(right - mDrawWidth, top, right, top + mDrawHeight, mPaint); top += 40.0f + mDrawHeight; @@ -237,6 +236,7 @@ public class GradientsActivity extends Activity { mMatrix.setScale(1, mDrawHeight); mMatrix.postTranslate(left, top); mGradient.setLocalMatrix(mMatrix); + mPaint.setShader(mGradient); canvas.drawRect(left, top, right, top + mDrawHeight, mPaint); left += 40.0f + mDrawWidth; @@ -248,6 +248,7 @@ public class GradientsActivity extends Activity { mMatrix.postRotate(180); mMatrix.postTranslate(left, bottom); mGradient.setLocalMatrix(mMatrix); + mPaint.setShader(mGradient); canvas.drawRect(left, bottom - mDrawHeight, right, bottom, mPaint); top += 40.0f + mDrawHeight; @@ -257,6 +258,7 @@ public class GradientsActivity extends Activity { mMatrix.postRotate(-90); mMatrix.postTranslate(left, top); mGradient.setLocalMatrix(mMatrix); + mPaint.setShader(mGradient); canvas.drawRect(left, top, left + mDrawWidth, bottom, mPaint); right = left + mDrawWidth; @@ -264,12 +266,11 @@ public class GradientsActivity extends Activity { top = bottom + 20.0f; bottom = top + 50.0f; - mPaint.setShader(mGradientStops); - mMatrix.setScale(1, mDrawWidth); mMatrix.postRotate(90); mMatrix.postTranslate(right, top); mGradientStops.setLocalMatrix(mMatrix); + mPaint.setShader(mGradientStops); canvas.drawRect(left, top, right, bottom, mPaint); canvas.restore(); diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/LooperAcceleration.java b/tests/HwAccelerationTest/src/com/android/test/hwui/LooperAcceleration.java new file mode 100644 index 0000000..20d8e11 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/LooperAcceleration.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.test.hwui; + +import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.graphics.Canvas; +import android.os.Bundle; +import android.os.Looper; +import android.view.View; +import android.view.ViewGroup.LayoutParams; +import android.webkit.WebChromeClient; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import android.widget.LinearLayout; + +public class LooperAcceleration extends Activity { + + static final boolean INCLUDE_WEBVIEW = false; + + static class IsAcceleratedView extends View { + + public IsAcceleratedView(Context context) { + super(context); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (canvas.isHardwareAccelerated()) { + canvas.drawARGB(0xFF, 0x00, 0xFF, 0x00); + } else { + canvas.drawARGB(0xFF, 0xFF, 0x00, 0x00); + } + } + + } + + private View makeView() { + LinearLayout layout = new LinearLayout(this); + layout.addView(new IsAcceleratedView(this), LayoutParams.MATCH_PARENT, 60); + + if (INCLUDE_WEBVIEW) { + WebView wv = new WebView(this); + wv.setWebViewClient(new WebViewClient()); + wv.setWebChromeClient(new WebChromeClient()); + wv.loadUrl("http://www.webkit.org/blog-files/3d-transforms/poster-circle.html"); + layout.addView(wv, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + } + return layout; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(makeView()); + + new Thread() { + @Override + public void run() { + Looper.prepare(); + final Context context = LooperAcceleration.this; + Dialog dlg = new Dialog(context); + dlg.addContentView(makeView(), new LayoutParams(300, 400)); + dlg.setCancelable(true); + dlg.setCanceledOnTouchOutside(true); + dlg.setOnDismissListener(new DialogInterface.OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialog) { + Looper.myLooper().quit(); + } + }); + dlg.setTitle("Not Looper.getMainLooper() check"); + dlg.show(); + Looper.loop(); + } + }.start(); + } +} diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java new file mode 100644 index 0000000..5ba3ad9 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java @@ -0,0 +1,83 @@ +package com.android.test.hwui; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; +import android.os.Bundle; + +import android.app.Activity; +import android.util.AttributeSet; +import android.view.RenderNode; +import android.view.View; +import android.widget.LinearLayout; + +public class ProjectionActivity extends Activity { + /** + * The content from this view should be projected in between the background of the + * ProjecteeLayout and its children, unclipped. + * + * This view doesn't clip to its bounds (because its parent has clipChildren=false) so that + * when it is projected onto the ProjecteeLayout, it draws outside its view bounds. + */ + public static class ProjectedView extends View { + private final Paint mPaint = new Paint(); + private final RectF mRectF = new RectF(); + + public ProjectedView(Context context) { + this(context, null); + } + + public ProjectedView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ProjectedView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + + setOnClickListener(new OnClickListener() { + boolean toggle = false; + @Override + public void onClick(View v) { + toggle = !toggle; + setProject(toggle); + } + }); + } + + private void setProject(boolean value) { + RenderNode displayList = getDisplayList(); + if (displayList != null) { + displayList.setProjectBackwards(value); + } + // NOTE: we can't invalidate ProjectedView for the redraw because: + // 1) the view won't preserve displayList properties that it doesn't know about + // 2) the damage rect won't be big enough + + // instead, twiddle properties on the container, so that enough area of the screen is + // redrawn without rerecording any DisplayLists. + container.setTranslationX(100f); + container.setTranslationX(0.0f); + } + + @Override + protected void onDraw(Canvas canvas) { + // TODO: set projection flag + final int w = getWidth(); + final int h = getHeight(); + mRectF.set(0, -h, w, 2 * h); + mPaint.setAntiAlias(true); + mPaint.setColor(0x5f00ff00); + canvas.drawOval(mRectF, mPaint); + } + } + + static View container; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.projection); + container = findViewById(R.id.container); + } +} diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionClippingActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionClippingActivity.java new file mode 100644 index 0000000..2ae960b --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionClippingActivity.java @@ -0,0 +1,27 @@ +package com.android.test.hwui; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; +import android.os.Bundle; +import android.util.AttributeSet; +import android.view.RenderNode; +import android.view.View; + +public class ProjectionClippingActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.projection_clipping); + View.OnClickListener listener = new View.OnClickListener() { + @Override + public void onClick(View v) { + // woo! nothing! + } + }; + findViewById(R.id.clickable1).setOnClickListener(listener); + findViewById(R.id.clickable2).setOnClickListener(listener); + } +} diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/RevealActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/RevealActivity.java new file mode 100644 index 0000000..3360e30 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/RevealActivity.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.test.hwui; + +import android.animation.Animator; +import android.app.Activity; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.os.Bundle; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewAnimationUtils; +import android.widget.LinearLayout; +import android.widget.LinearLayout.LayoutParams; +import android.widget.ProgressBar; + +public class RevealActivity extends Activity implements OnClickListener { + + private static final int DURATION = 800; + + private boolean mShouldBlock; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final LinearLayout layout = new LinearLayout(this); + layout.setOrientation(LinearLayout.VERTICAL); + + ProgressBar spinner = new ProgressBar(this, null, android.R.attr.progressBarStyleLarge); + layout.addView(spinner, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); + View revealView = new MyView(this); + layout.addView(revealView, + new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + setContentView(layout); + + revealView.setOnClickListener(this); + } + + @Override + public void onClick(View view) { + Animator animator = ViewAnimationUtils.createCircularReveal(view, + view.getWidth() / 2, view.getHeight() / 2, + 0, Math.max(view.getWidth(), view.getHeight())); + animator.setDuration(DURATION); + animator.setAllowRunningAsynchronously(true); + animator.start(); + + mShouldBlock = !mShouldBlock; + if (mShouldBlock) { + view.post(sBlockThread); + } + } + + private final static Runnable sBlockThread = new Runnable() { + @Override + public void run() { + try { + Thread.sleep(DURATION); + } catch (InterruptedException e) { + } + } + }; + + static class MyView extends View { + + public MyView(Context context) { + super(context); + } + + @Override + protected void onDraw(Canvas canvas) { + canvas.drawColor(Color.RED); + } + } +} diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/SmallCircleActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/SmallCircleActivity.java index 8c02539..a3f4ddc 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/SmallCircleActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/SmallCircleActivity.java @@ -57,7 +57,7 @@ public class SmallCircleActivity extends Activity { mPaint = new Paint(); mPaint.setAntiAlias(true); - mPaint.setColor(0xffffffff); + mPaint.setColor(0xff00ffff); } @Override diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ZOrderingActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ZOrderingActivity.java new file mode 100644 index 0000000..45e77ed --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ZOrderingActivity.java @@ -0,0 +1,28 @@ +package com.android.test.hwui; + +import android.app.Activity; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; + +public class ZOrderingActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.z_ordering); + + ViewGroup grandParent = (ViewGroup) findViewById(R.id.parent); + if (grandParent == null) throw new IllegalStateException(); + View.OnClickListener l = new View.OnClickListener() { + @Override + public void onClick(View v) {} + }; + for (int i = 0; i < grandParent.getChildCount(); i++) { + ViewGroup parent = (ViewGroup) grandParent.getChildAt(i); + for (int j = 0; j < parent.getChildCount(); j++) { + parent.getChildAt(j).setOnClickListener(l); + } + } + } +} diff --git a/tests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java b/tests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java index 25ac2f0..299e6bb 100644 --- a/tests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java +++ b/tests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java @@ -81,11 +81,11 @@ public class InputTypeActivity extends Activity { /* Uri Edit Text */ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_URI, - R.string.uri_edit_text_label)); + R.string.uri_edit_text_label)); /* Email Address Edit Text */ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS, - R.string.email_address_edit_text_label)); + R.string.email_address_edit_text_label)); /* Email Subject Text */ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_EMAIL_SUBJECT, @@ -142,7 +142,7 @@ public class InputTypeActivity extends Activity { private View buildEntryView(int inputType, int label) { - View view = mInflater.inflate(R.layout.sample_edit_text, mParent, false); + View view = mInflater.inflate(R.layout.sample_edit_text, mParent, false); EditText editText = (EditText) view.findViewById(R.id.data); editText.setInputType(inputType); diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java index a1c5fd2..2db11c5 100644 --- a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java +++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java @@ -24,26 +24,26 @@ import com.android.imftest.R; public class BigEditTextActivityNonScrollablePanScanTests extends ImfBaseTestCase<BigEditTextActivityNonScrollablePanScan> { - public final String TAG = "BigEditTextActivityNonScrollablePanScanTests"; - + public final String TAG = "BigEditTextActivityNonScrollablePanScanTests"; + public BigEditTextActivityNonScrollablePanScanTests() { super(BigEditTextActivityNonScrollablePanScan.class); } - - @LargeTest - public void testAppAdjustmentPanScan() { - // Give the IME 2 seconds to appear. - pause(2000); + + @LargeTest + public void testAppAdjustmentPanScan() { + // Give the IME 2 seconds to appear. + pause(2000); + + View rootView = ((BigEditTextActivityNonScrollablePanScan) mTargetActivity).getRootView(); + View servedView = ((BigEditTextActivityNonScrollablePanScan) mTargetActivity).getDefaultFocusedView(); + + assertNotNull(rootView); + assertNotNull(servedView); + + destructiveCheckImeInitialState(rootView, servedView); - View rootView = ((BigEditTextActivityNonScrollablePanScan) mTargetActivity).getRootView(); - View servedView = ((BigEditTextActivityNonScrollablePanScan) mTargetActivity).getDefaultFocusedView(); - - assertNotNull(rootView); - assertNotNull(servedView); - - destructiveCheckImeInitialState(rootView, servedView); - verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight()); - } - + } + } diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java index 2e0b0eb..1050794 100644 --- a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java +++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java @@ -24,14 +24,14 @@ import com.android.imftest.R; public class BigEditTextActivityNonScrollableResizeTests extends ImfBaseTestCase<BigEditTextActivityNonScrollableResize> { - public final String TAG = "BigEditTextActivityNonScrollableResizeTests"; - + public final String TAG = "BigEditTextActivityNonScrollableResizeTests"; + public BigEditTextActivityNonScrollableResizeTests() { super(BigEditTextActivityNonScrollableResize.class); } - - @LargeTest - public void testAppAdjustmentPanScan() { // Give the IME 2 seconds to appear. + + @LargeTest + public void testAppAdjustmentPanScan() { // Give the IME 2 seconds to appear. pause(2000); View rootView = ((BigEditTextActivityNonScrollableResize) mTargetActivity).getRootView(); @@ -43,6 +43,6 @@ public class BigEditTextActivityNonScrollableResizeTests extends ImfBaseTestCase destructiveCheckImeInitialState(rootView, servedView); verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight()); - } - + } + } diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java index d3eefb5..1e848b0 100644 --- a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java +++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java @@ -24,14 +24,14 @@ import com.android.imftest.R; public class BigEditTextActivityScrollablePanScanTests extends ImfBaseTestCase<BigEditTextActivityScrollablePanScan> { - public final String TAG = "BigEditTextActivityScrollablePanScanTests"; - + public final String TAG = "BigEditTextActivityScrollablePanScanTests"; + public BigEditTextActivityScrollablePanScanTests() { super(BigEditTextActivityScrollablePanScan.class); } - - @LargeTest - public void testAppAdjustmentPanScan() { // Give the IME 2 seconds to appear. + + @LargeTest + public void testAppAdjustmentPanScan() { // Give the IME 2 seconds to appear. pause(2000); View rootView = ((BigEditTextActivityScrollablePanScan) mTargetActivity).getRootView(); @@ -43,6 +43,6 @@ public class BigEditTextActivityScrollablePanScanTests extends ImfBaseTestCase<B destructiveCheckImeInitialState(rootView, servedView); verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight()); - } - + } + } diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java index 5c40e6d..de607d6 100644 --- a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java +++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java @@ -24,15 +24,15 @@ import com.android.imftest.R; public class BigEditTextActivityScrollableResizeTests extends ImfBaseTestCase<BigEditTextActivityScrollableResize> { - public final String TAG = "BigEditTextActivityScrollableResizeTests"; - + public final String TAG = "BigEditTextActivityScrollableResizeTests"; + public BigEditTextActivityScrollableResizeTests() { super(BigEditTextActivityScrollableResize.class); } - - @LargeTest - public void testAppAdjustmentPanScan() { - // Give the IME 2 seconds to appear. + + @LargeTest + public void testAppAdjustmentPanScan() { + // Give the IME 2 seconds to appear. pause(2000); View rootView = ((BigEditTextActivityScrollableResize) mTargetActivity).getRootView(); @@ -44,6 +44,6 @@ public class BigEditTextActivityScrollableResizeTests extends ImfBaseTestCase<Bi destructiveCheckImeInitialState(rootView, servedView); verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight()); - } - + } + } diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java index 9a93133..c521905 100644 --- a/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java +++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java @@ -24,14 +24,14 @@ import com.android.imftest.R; public class BottomEditTextActivityPanScanTests extends ImfBaseTestCase<BottomEditTextActivityPanScan> { - public final String TAG = "BottomEditTextActivityPanScanTests"; - + public final String TAG = "BottomEditTextActivityPanScanTests"; + public BottomEditTextActivityPanScanTests() { super(BottomEditTextActivityPanScan.class); } - - @LargeTest - public void testAppAdjustmentPanScan() { + + @LargeTest + public void testAppAdjustmentPanScan() { // Give the IME 2 seconds to appear. pause(2000); @@ -44,6 +44,6 @@ public class BottomEditTextActivityPanScanTests extends ImfBaseTestCase<BottomEd destructiveCheckImeInitialState(rootView, servedView); verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight()); - } - + } + } diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java index ae900c3..f6f97b5 100644 --- a/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java +++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java @@ -23,8 +23,8 @@ import android.widget.Button; public class ButtonActivityTest extends ImfBaseTestCase<ButtonActivity> { - final public String TAG = "ButtonActivityTest"; - + final public String TAG = "ButtonActivityTest"; + public ButtonActivityTest() { super(ButtonActivity.class); } diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java index ed5b0c9..6147d3c 100644 --- a/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java +++ b/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java @@ -22,21 +22,21 @@ import android.view.View; public class OneEditTextActivityNotSelectedTests extends ImfBaseTestCase<OneEditTextActivityNotSelected> { - public final String TAG = "OneEditTextActivityNotSelectedTests"; - + public final String TAG = "OneEditTextActivityNotSelectedTests"; + public OneEditTextActivityNotSelectedTests() { super(OneEditTextActivityNotSelected.class); } - @LargeTest - public void testSoftKeyboardNoAutoPop() { - - // Give the IME 2 seconds to appear. - pause(2000); - - assertFalse(mImm.isAcceptingText()); - - View rootView = ((OneEditTextActivityNotSelected) mTargetActivity).getRootView(); + @LargeTest + public void testSoftKeyboardNoAutoPop() { + + // Give the IME 2 seconds to appear. + pause(2000); + + assertFalse(mImm.isAcceptingText()); + + View rootView = ((OneEditTextActivityNotSelected) mTargetActivity).getRootView(); View servedView = ((OneEditTextActivityNotSelected) mTargetActivity).getDefaultFocusedView(); assertNotNull(rootView); @@ -45,6 +45,6 @@ public class OneEditTextActivityNotSelectedTests extends ImfBaseTestCase<OneEdit destructiveCheckImeInitialState(rootView, servedView); verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight()); - } - + } + } diff --git a/tests/JobSchedulerTestApp/Android.mk b/tests/JobSchedulerTestApp/Android.mk new file mode 100644 index 0000000..7336d8c --- /dev/null +++ b/tests/JobSchedulerTestApp/Android.mk @@ -0,0 +1,15 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res + +LOCAL_PACKAGE_NAME := JobSchedulerTestApp + +LOCAL_PROGUARD_ENABLED := disabled + +include $(BUILD_PACKAGE) + diff --git a/tests/JobSchedulerTestApp/AndroidManifest.xml b/tests/JobSchedulerTestApp/AndroidManifest.xml new file mode 100644 index 0000000..9654197 --- /dev/null +++ b/tests/JobSchedulerTestApp/AndroidManifest.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.demo.jobSchedulerApp" > + + <uses-sdk + android:minSdkVersion="18" + android:targetSdkVersion="18" /> + + <uses-permission android:name="android.permission.INTERNET" /> + <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> + + <application + android:icon="@drawable/ic_launcher" + android:label="@string/app_name" + android:theme="@style/AppTheme" > + <activity + android:name="com.android.demo.jobSchedulerApp.MainActivity" + android:label="@string/app_name" + android:windowSoftInputMode="stateHidden" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <service + android:name=".service.TestJobService" + android:permission="android.permission.BIND_JOB_SERVICE" + android:exported="true"/> + </application> + +</manifest> diff --git a/tests/JobSchedulerTestApp/res/drawable-hdpi/ic_launcher.png b/tests/JobSchedulerTestApp/res/drawable-hdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..a0f7005 --- /dev/null +++ b/tests/JobSchedulerTestApp/res/drawable-hdpi/ic_launcher.png diff --git a/tests/JobSchedulerTestApp/res/drawable-mdpi/ic_launcher.png b/tests/JobSchedulerTestApp/res/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..a085462 --- /dev/null +++ b/tests/JobSchedulerTestApp/res/drawable-mdpi/ic_launcher.png diff --git a/tests/JobSchedulerTestApp/res/drawable-xhdpi/ic_action_refresh.png b/tests/JobSchedulerTestApp/res/drawable-xhdpi/ic_action_refresh.png Binary files differnew file mode 100644 index 0000000..4f5d255 --- /dev/null +++ b/tests/JobSchedulerTestApp/res/drawable-xhdpi/ic_action_refresh.png diff --git a/tests/JobSchedulerTestApp/res/drawable-xhdpi/ic_launcher.png b/tests/JobSchedulerTestApp/res/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..4f78eb8 --- /dev/null +++ b/tests/JobSchedulerTestApp/res/drawable-xhdpi/ic_launcher.png diff --git a/tests/JobSchedulerTestApp/res/drawable-xxhdpi/ic_launcher.png b/tests/JobSchedulerTestApp/res/drawable-xxhdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..b198ee3 --- /dev/null +++ b/tests/JobSchedulerTestApp/res/drawable-xxhdpi/ic_launcher.png diff --git a/tests/JobSchedulerTestApp/res/layout/activity_main.xml b/tests/JobSchedulerTestApp/res/layout/activity_main.xml new file mode 100644 index 0000000..96e1641 --- /dev/null +++ b/tests/JobSchedulerTestApp/res/layout/activity_main.xml @@ -0,0 +1,178 @@ +<?xml version="1.0" encoding="utf-8"?> +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" > + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_weight="1" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="100dp"> + <TextView + android:id="@+id/onstart_textview" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_weight="1" + android:background="@color/none_received" + android:gravity="center" + android:text="@string/onstarttask"/> + <TextView + android:id="@+id/onstop_textview" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_weight="1" + android:background="@color/none_received" + android:gravity="center" + android:text="@string/onstoptask"/> + </LinearLayout> + <Button + android:id="@+id/finished_button" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="20dp" + android:layout_marginBottom="5dp" + android:onClick="finishJob" + android:text="@string/finish_job_button_text"/> + + <TextView + android:id="@+id/task_params" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/defaultparamtext" + android:gravity="center" + android:textSize="20dp" + + android:padding="15dp" + android:layout_marginBottom="10dp" /> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/constraints" + android:layout_margin="15dp" + android:textSize="18dp"/> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:layout_marginLeft="10dp"> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/connectivity" + android:layout_marginRight="10dp"/> + <RadioGroup + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <RadioButton android:id="@+id/checkbox_any" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/any"/> + <RadioButton android:id="@+id/checkbox_unmetered" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/unmetered"/> + </RadioGroup> + + </LinearLayout> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/timing"/> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="15dp" + android:textSize="17dp" + android:text="@string/delay"/> + <EditText + android:id="@+id/delay_time" + android:layout_width="60dp" + android:layout_height="wrap_content" + android:inputType="number"/> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/deadline" + android:textSize="17dp"/> + <EditText + android:id="@+id/deadline_time" + android:layout_width="60dp" + android:layout_height="wrap_content" + android:inputType="number"/> + </LinearLayout> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/charging_caption" + android:layout_marginRight="15dp"/> + <CheckBox + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:id="@+id/checkbox_charging" + android:text="@string/charging_text"/> + </LinearLayout> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/idle_caption" + android:layout_marginRight="15dp"/> + <CheckBox + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:id="@+id/checkbox_idle" + android:text="@string/idle_mode_text"/> + </LinearLayout> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/persisted_caption" + android:layout_marginRight="15dp"/> + <CheckBox + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:id="@+id/checkbox_persisted" + android:text="@string/persisted_mode_text"/> + </LinearLayout> + + </LinearLayout> + <Button + android:id="@+id/schedule_button" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="20dp" + android:layout_marginLeft="40dp" + android:layout_marginRight="40dp" + android:onClick="scheduleJob" + android:text="@string/schedule_job_button_text"/> + <Button + android:id="@+id/cancel_button" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="40dp" + android:layout_marginRight="40dp" + android:onClick="cancelAllJobs" + android:text="@string/cancel_all_jobs_button_text"/> + </LinearLayout> +</ScrollView> diff --git a/tests/JobSchedulerTestApp/res/values-v11/styles.xml b/tests/JobSchedulerTestApp/res/values-v11/styles.xml new file mode 100644 index 0000000..ff65301 --- /dev/null +++ b/tests/JobSchedulerTestApp/res/values-v11/styles.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2013 The Android Open Source Project + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +--> + +<resources> + + <!-- + Base application theme for API 11+. This theme completely replaces + AppBaseTheme from res/values/styles.xml on API 11+ devices. + --> + <style name="AppBaseTheme" parent="android:Theme.Holo.Light"> + <!-- API 11 theme customizations can go here. --> + </style> + +</resources>
\ No newline at end of file diff --git a/tests/JobSchedulerTestApp/res/values-v14/styles.xml b/tests/JobSchedulerTestApp/res/values-v14/styles.xml new file mode 100644 index 0000000..a4a443a --- /dev/null +++ b/tests/JobSchedulerTestApp/res/values-v14/styles.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2013 The Android Open Source Project + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +--> + +<resources> + + <!-- + Base application theme for API 14+. This theme completely replaces + AppBaseTheme from BOTH res/values/styles.xml and + res/values-v11/styles.xml on API 14+ devices. + --> + <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar"> + <!-- API 14 theme customizations can go here. --> + </style> + +</resources>
\ No newline at end of file diff --git a/tests/JobSchedulerTestApp/res/values/color.xml b/tests/JobSchedulerTestApp/res/values/color.xml new file mode 100644 index 0000000..7bd3a91 --- /dev/null +++ b/tests/JobSchedulerTestApp/res/values/color.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2014 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> +<resources> + <color name="none_received">#999999</color> + <color name="start_received">#00FF00</color> + <color name="stop_received">#FF0000</color> +</resources>
\ No newline at end of file diff --git a/tests/JobSchedulerTestApp/res/values/strings.xml b/tests/JobSchedulerTestApp/res/values/strings.xml new file mode 100644 index 0000000..90dd2b6 --- /dev/null +++ b/tests/JobSchedulerTestApp/res/values/strings.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2013 The Android Open Source Project + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +--> + +<resources> + <string name="onstoptask">onStopTask</string> + <string name="onstarttask">onStartTask</string> + <string name="defaultparamtext">task params will show up here.</string> + <string name="schedule_job_button_text">Schedule Job</string> + <string name="cancel_all_jobs_button_text">Cancel all</string> + <string name="app_name">Job Scheduler Test</string> + <string name="finish_job_button_text">taskFinished</string> + <string name="idle_mode_text">Requires device in idle mode.</string> + <string name="charging_caption">Charging:</string> + <string name="charging_text">Requires device plugged in.</string> + <string name="idle_caption">Idle:</string> + <string name="persisted_caption">Persisted:</string> + <string name="constraints">Constraints</string> + <string name="connectivity">Connectivity:</string> + <string name="any">Any</string> + <string name="unmetered">WiFi</string> + <string name="timing">Timing:</string> + <string name="delay">Delay:</string> + <string name="deadline">Deadline:</string> + <string name="persisted_mode_text">Persisted:</string> +</resources> diff --git a/tests/JobSchedulerTestApp/res/values/styles.xml b/tests/JobSchedulerTestApp/res/values/styles.xml new file mode 100644 index 0000000..43a8f2b --- /dev/null +++ b/tests/JobSchedulerTestApp/res/values/styles.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2013 The Android Open Source Project + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +--> + +<resources> + + <!-- + Base application theme, dependent on API level. This theme is replaced + by AppBaseTheme from res/values-vXX/styles.xml on newer devices. + --> + <style name="AppBaseTheme" parent="android:Theme.Light"> + <!-- + Theme customizations available in newer API levels can go in + res/values-vXX/styles.xml, while customizations related to + backward-compatibility can go here. + --> + </style> + + <!-- Application theme. --> + <style name="AppTheme" parent="AppBaseTheme"> + <!-- All customizations that are NOT specific to a particular API-level can go here. --> + </style> + +</resources>
\ No newline at end of file diff --git a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java new file mode 100644 index 0000000..b9a2a7e --- /dev/null +++ b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/MainActivity.java @@ -0,0 +1,187 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.demo.jobSchedulerApp; + +import android.app.Activity; +import android.app.job.JobInfo; +import android.app.job.JobParameters; +import android.app.job.JobScheduler; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.Messenger; +import android.text.TextUtils; +import android.view.View; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.RadioButton; +import android.widget.TextView; +import android.widget.Toast; + +import com.android.demo.jobSchedulerApp.service.TestJobService; + +public class MainActivity extends Activity { + + private static final String TAG = "MainActivity"; + + public static final int MSG_UNCOLOUR_START = 0; + public static final int MSG_UNCOLOUR_STOP = 1; + public static final int MSG_SERVICE_OBJ = 2; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + Resources res = getResources(); + defaultColor = res.getColor(R.color.none_received); + startJobColor = res.getColor(R.color.start_received); + stopJobColor = res.getColor(R.color.stop_received); + + // Set up UI. + mShowStartView = (TextView) findViewById(R.id.onstart_textview); + mShowStopView = (TextView) findViewById(R.id.onstop_textview); + mParamsTextView = (TextView) findViewById(R.id.task_params); + mDelayEditText = (EditText) findViewById(R.id.delay_time); + mDeadlineEditText = (EditText) findViewById(R.id.deadline_time); + mWiFiConnectivityRadioButton = (RadioButton) findViewById(R.id.checkbox_unmetered); + mAnyConnectivityRadioButton = (RadioButton) findViewById(R.id.checkbox_any); + mRequiresChargingCheckBox = (CheckBox) findViewById(R.id.checkbox_charging); + mRequiresIdleCheckbox = (CheckBox) findViewById(R.id.checkbox_idle); + mIsPersistedCheckbox = (CheckBox) findViewById(R.id.checkbox_persisted); + + mServiceComponent = new ComponentName(this, TestJobService.class); + // Start service and provide it a way to communicate with us. + Intent startServiceIntent = new Intent(this, TestJobService.class); + startServiceIntent.putExtra("messenger", new Messenger(mHandler)); + startService(startServiceIntent); + } + // UI fields. + int defaultColor; + int startJobColor; + int stopJobColor; + + TextView mShowStartView; + TextView mShowStopView; + TextView mParamsTextView; + EditText mDelayEditText; + EditText mDeadlineEditText; + RadioButton mWiFiConnectivityRadioButton; + RadioButton mAnyConnectivityRadioButton; + CheckBox mRequiresChargingCheckBox; + CheckBox mRequiresIdleCheckbox; + CheckBox mIsPersistedCheckbox; + + ComponentName mServiceComponent; + /** Service object to interact scheduled jobs. */ + TestJobService mTestService; + + private static int kJobId = 0; + + Handler mHandler = new Handler(/* default looper */) { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_UNCOLOUR_START: + mShowStartView.setBackgroundColor(defaultColor); + break; + case MSG_UNCOLOUR_STOP: + mShowStopView.setBackgroundColor(defaultColor); + break; + case MSG_SERVICE_OBJ: + mTestService = (TestJobService) msg.obj; + mTestService.setUiCallback(MainActivity.this); + } + } + }; + + private boolean ensureTestService() { + if (mTestService == null) { + Toast.makeText(MainActivity.this, "Service null, never got callback?", + Toast.LENGTH_SHORT).show(); + return false; + } + return true; + } + + /** + * UI onclick listener to schedule a job. What this job is is defined in + * TestJobService#scheduleJob() + */ + public void scheduleJob(View v) { + if (!ensureTestService()) { + return; + } + + JobInfo.Builder builder = new JobInfo.Builder(kJobId++, mServiceComponent); + + String delay = mDelayEditText.getText().toString(); + if (delay != null && !TextUtils.isEmpty(delay)) { + builder.setMinimumLatency(Long.valueOf(delay) * 1000); + } + String deadline = mDeadlineEditText.getText().toString(); + if (deadline != null && !TextUtils.isEmpty(deadline)) { + builder.setOverrideDeadline(Long.valueOf(deadline) * 1000); + } + boolean requiresUnmetered = mWiFiConnectivityRadioButton.isChecked(); + boolean requiresAnyConnectivity = mAnyConnectivityRadioButton.isChecked(); + if (requiresUnmetered) { + builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED); + } else if (requiresAnyConnectivity) { + builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); + } + builder.setRequiresDeviceIdle(mRequiresIdleCheckbox.isChecked()); + builder.setRequiresCharging(mRequiresChargingCheckBox.isChecked()); + builder.setPersisted(mIsPersistedCheckbox.isChecked()); + mTestService.scheduleJob(builder.build()); + + } + + public void cancelAllJobs(View v) { + JobScheduler tm = + (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); + tm.cancelAll(); + } + + /** + * UI onclick listener to call jobFinished() in our service. + */ + public void finishJob(View v) { + if (!ensureTestService()) { + return; + } + mTestService.callJobFinished(); + mParamsTextView.setText(""); + } + + public void onReceivedStartJob(JobParameters params) { + mShowStartView.setBackgroundColor(startJobColor); + Message m = Message.obtain(mHandler, MSG_UNCOLOUR_START); + mHandler.sendMessageDelayed(m, 1000L); // uncolour in 1 second. + mParamsTextView.setText("Executing: " + params.getJobId() + " " + params.getExtras()); + } + + public void onReceivedStopJob() { + mShowStopView.setBackgroundColor(stopJobColor); + Message m = Message.obtain(mHandler, MSG_UNCOLOUR_STOP); + mHandler.sendMessageDelayed(m, 2000L); // uncolour in 1 second. + mParamsTextView.setText(""); + } +} diff --git a/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java new file mode 100644 index 0000000..a68e04e --- /dev/null +++ b/tests/JobSchedulerTestApp/src/com/android/demo/jobSchedulerApp/service/TestJobService.java @@ -0,0 +1,136 @@ +/* + * Copyright 2013 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.demo.jobSchedulerApp.service; + +import android.app.job.JobInfo; +import android.app.job.JobScheduler; +import android.app.job.JobParameters; +import android.app.job.JobService; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.os.AsyncTask; +import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; +import android.util.Log; +import android.util.SparseArray; + +import com.android.demo.jobSchedulerApp.MainActivity; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Random; + + +/** + * Service to handle sync requests. + * <p> + * This service is invoked in response to Intents with action android.content.SyncAdapter, and + * returns a Binder connection to SyncAdapter. + * <p> + * For performance, only one sync adapter will be initialized within this application's context. + * <p> + * Note: The SyncService itself is not notified when a new sync occurs. It's role is to manage the + * lifecycle of our and provide a handle to said SyncAdapter to the OS on + * request. + */ +public class TestJobService extends JobService { + private static final String TAG = "SyncService"; + + @Override + public void onCreate() { + super.onCreate(); + Log.i(TAG, "Service created"); + } + + @Override + public void onDestroy() { + super.onDestroy(); + Log.i(TAG, "Service destroyed"); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Messenger callback = intent.getParcelableExtra("messenger"); + Message m = Message.obtain(); + m.what = MainActivity.MSG_SERVICE_OBJ; + m.obj = this; + try { + callback.send(m); + } catch (RemoteException e) { + Log.e(TAG, "Error passing service object back to activity."); + } + return START_NOT_STICKY; + } + + @Override + public boolean onStartJob(JobParameters params) { + Log.i(TAG, "on start job: " + params.getJobId()); + currentId++; + jobParamsMap.put(currentId, params); + final int currId = this.currentId; + Log.d(TAG, "putting :" + currId + " for " + params.toString()); + Log.d(TAG, " pulled: " + jobParamsMap.get(currId)); + if (mActivity != null) { + mActivity.onReceivedStartJob(params); + } + + return true; + } + + + @Override + public boolean onStopJob(JobParameters params) { + Log.i(TAG, "on stop job: " + params.getJobId()); + int ind = jobParamsMap.indexOfValue(params); + jobParamsMap.remove(ind); + mActivity.onReceivedStopJob(); + return true; + } + + static int currentId = 0; + MainActivity mActivity; + private final SparseArray<JobParameters> jobParamsMap = new SparseArray<JobParameters>(); + + + public void setUiCallback(MainActivity activity) { + mActivity = activity; + } + + /** Send job to the JobScheduler. */ + public void scheduleJob(JobInfo job) { + Log.d(TAG, "Scheduling job " + job); + JobScheduler tm = + (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); + tm.schedule(job); + } + + public boolean callJobFinished() { + if (jobParamsMap.size() == 0) { + return false; + } + JobParameters params = jobParamsMap.valueAt(0); + if (params == null) { + return false; + } else { + jobFinished(params, false); + return true; + } + } + +} diff --git a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java index 397ef13..a7e3bec 100644 --- a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java +++ b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java @@ -20,6 +20,7 @@ import android.app.ActivityManager.ProcessErrorStateInfo; import android.app.ActivityManager.RunningAppProcessInfo; import android.app.ActivityManagerNative; import android.app.IActivityManager; +import android.app.UiAutomation; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; @@ -34,8 +35,10 @@ import android.util.Log; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; /** * This test is intended to measure the amount of memory applications use when @@ -57,13 +60,26 @@ public class MemoryUsageTest extends InstrumentationTestCase { private static final String TAG = "MemoryUsageInstrumentation"; private static final String KEY_APPS = "apps"; - + private static final String KEY_PROCS = "persistent"; + private static final String LAUNCHER_KEY = "launcher"; private Map<String, Intent> mNameToIntent; private Map<String, String> mNameToProcess; private Map<String, String> mNameToResultKey; - + private Set<String> mPersistentProcesses; private IActivityManager mAm; + @Override + protected void setUp() throws Exception { + super.setUp(); + getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_0); + } + + @Override + protected void tearDown() throws Exception { + getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_UNFREEZE); + super.tearDown(); + } + public void testMemory() { MemoryUsageInstrumentation instrumentation = (MemoryUsageInstrumentation) getInstrumentation(); @@ -75,35 +91,61 @@ public class MemoryUsageTest extends InstrumentationTestCase { Bundle results = new Bundle(); for (String app : mNameToResultKey.keySet()) { - String processName; - try { - processName = startApp(app); - measureMemory(app, processName, results); - closeApp(); - } catch (NameNotFoundException e) { - Log.i(TAG, "Application " + app + " not found"); + if (!mPersistentProcesses.contains(app)) { + String processName; + try { + processName = startApp(app); + measureMemory(app, processName, results); + closeApp(); + } catch (NameNotFoundException e) { + Log.i(TAG, "Application " + app + " not found"); + } + } else { + measureMemory(app, app, results); } - } instrumentation.sendStatus(0, results); } - private void parseArgs(Bundle args) { - mNameToResultKey = new HashMap<String, String>(); - String appList = args.getString(KEY_APPS); - - if (appList == null) - return; + private String getLauncherPackageName() { + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_HOME); + ResolveInfo resolveInfo = getInstrumentation().getContext(). + getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); + return resolveInfo.activityInfo.packageName; + } - String appNames[] = appList.split("\\|"); - for (String pair : appNames) { + private Map<String, String> parseListToMap(String list) { + Map<String, String> map = new HashMap<String, String>(); + String names[] = list.split("\\|"); + for (String pair : names) { String[] parts = pair.split("\\^"); if (parts.length != 2) { Log.e(TAG, "The apps key is incorectly formatted"); fail(); } + map.put(parts[0], parts[1]); + } + return map; + } - mNameToResultKey.put(parts[0], parts[1]); + private void parseArgs(Bundle args) { + mNameToResultKey = new HashMap<String, String>(); + mPersistentProcesses = new HashSet<String>(); + String appList = args.getString(KEY_APPS); + String procList = args.getString(KEY_PROCS); + String mLauncherPackageName = getLauncherPackageName(); + mPersistentProcesses.add(mLauncherPackageName); + mNameToResultKey.put(mLauncherPackageName, LAUNCHER_KEY); + if (appList == null && procList == null) + return; + if (appList != null) { + mNameToResultKey.putAll(parseListToMap(appList)); + } + if (procList != null) { + Map<String, String> procMap = parseListToMap(procList); + mPersistentProcesses.addAll(procMap.keySet()); + mNameToResultKey.putAll(procMap); } } @@ -276,7 +318,7 @@ public class MemoryUsageTest extends InstrumentationTestCase { } mAm.startActivityAndWait(null, null, mLaunchIntent, mimeType, - null, null, 0, mLaunchIntent.getFlags(), null, null, null, + null, null, 0, mLaunchIntent.getFlags(), null, null, UserHandle.USER_CURRENT_OR_SELF); } catch (RemoteException e) { Log.w(TAG, "Error launching app", e); diff --git a/tests/MusicBrowserDemo/Android.mk b/tests/MusicBrowserDemo/Android.mk new file mode 100644 index 0000000..207774b --- /dev/null +++ b/tests/MusicBrowserDemo/Android.mk @@ -0,0 +1,35 @@ +# 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. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_PACKAGE_NAME := MusicBrowserDemo +#LOCAL_SDK_VERSION := current +LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_STATIC_JAVA_LIBRARIES := \ + android-support-v4 \ + android-support-v7-appcompat + +LOCAL_RESOURCE_DIR := \ + $(LOCAL_PATH)/res \ + frameworks/support/v7/appcompat/res +LOCAL_PROGUARD_ENABLED := disabled +#LOCAL_PROGUARD_FLAG_FILES := proguard.flags + +LOCAL_AAPT_FLAGS := \ + --auto-add-overlay \ + --extra-packages android.support.v7.appcompat +include $(BUILD_PACKAGE) diff --git a/tests/MusicBrowserDemo/AndroidManifest.xml b/tests/MusicBrowserDemo/AndroidManifest.xml new file mode 100644 index 0000000..d2acfe2 --- /dev/null +++ b/tests/MusicBrowserDemo/AndroidManifest.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.android.musicbrowserdemo" + android:versionCode="1" + android:versionName="1.0" > + + <uses-sdk + android:minSdkVersion="9" + android:targetSdkVersion="19" /> + + <application + android:allowBackup="true" + android:icon="@drawable/ic_launcher" + android:label="@string/app_name" + android:theme="@style/AppTheme" + > + + <activity + android:name="com.example.android.musicbrowserdemo.MainActivity" + android:label="@string/app_name" + > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + </application> + +</manifest> diff --git a/tests/MusicBrowserDemo/res/drawable-hdpi/ic_launcher.png b/tests/MusicBrowserDemo/res/drawable-hdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..47d6854 --- /dev/null +++ b/tests/MusicBrowserDemo/res/drawable-hdpi/ic_launcher.png diff --git a/tests/MusicBrowserDemo/res/drawable-mdpi/ic_launcher.png b/tests/MusicBrowserDemo/res/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..01b53fd --- /dev/null +++ b/tests/MusicBrowserDemo/res/drawable-mdpi/ic_launcher.png diff --git a/tests/MusicBrowserDemo/res/drawable-xhdpi/ic_launcher.png b/tests/MusicBrowserDemo/res/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..af762f2 --- /dev/null +++ b/tests/MusicBrowserDemo/res/drawable-xhdpi/ic_launcher.png diff --git a/tests/MusicBrowserDemo/res/drawable-xxhdpi/ic_launcher.png b/tests/MusicBrowserDemo/res/drawable-xxhdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..eef47aa --- /dev/null +++ b/tests/MusicBrowserDemo/res/drawable-xxhdpi/ic_launcher.png diff --git a/tests/MusicBrowserDemo/res/values/strings.xml b/tests/MusicBrowserDemo/res/values/strings.xml new file mode 100644 index 0000000..858f278 --- /dev/null +++ b/tests/MusicBrowserDemo/res/values/strings.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<resources> + + <string name="app_name">Music Browser</string> + +</resources> diff --git a/tests/MusicBrowserDemo/res/values/styles.xml b/tests/MusicBrowserDemo/res/values/styles.xml new file mode 100644 index 0000000..b83662d --- /dev/null +++ b/tests/MusicBrowserDemo/res/values/styles.xml @@ -0,0 +1,36 @@ +<?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> + + <!-- + Base application theme, dependent on API level. This theme is replaced + by AppBaseTheme from res/values-vXX/styles.xml on newer devices. + --> + <style name="AppBaseTheme" parent="Theme.AppCompat.Light"> + <!-- + Theme customizations available in newer API levels can go in + res/values-vXX/styles.xml, while customizations related to + backward-compatibility can go here. + --> + </style> + + <!-- Application theme. --> + <style name="AppTheme" parent="AppBaseTheme"> + <!-- All customizations that are NOT specific to a particular API-level can go here. --> + </style> + +</resources> diff --git a/tests/MusicBrowserDemo/src/com/example/android/musicbrowserdemo/AppListFragment.java b/tests/MusicBrowserDemo/src/com/example/android/musicbrowserdemo/AppListFragment.java new file mode 100644 index 0000000..526ea5d --- /dev/null +++ b/tests/MusicBrowserDemo/src/com/example/android/musicbrowserdemo/AppListFragment.java @@ -0,0 +1,149 @@ +/* + * 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.musicbrowserdemo; + +import android.content.Context; +import android.content.ComponentName; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.media.browse.MediaBrowserService; +import android.os.Bundle; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentTransaction; +import android.support.v4.app.ListFragment; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ListView; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.List; + +// TODO: Include an icon. + +public class AppListFragment extends ListFragment { + + private Adapter mAdapter; + private List<Item> mItems; + + public AppListFragment() { + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + mAdapter = new Adapter(); + setListAdapter(mAdapter); + } + + @Override + public void onListItemClick(ListView l, View v, int position, long id) { + final Item item = mItems.get(position); + + Log.i("AppListFragment", "Item clicked: " + position + " -- " + item.component); + + final BrowserListFragment fragment = new BrowserListFragment(); + + final Bundle args = new Bundle(); + args.putParcelable(BrowserListFragment.ARG_COMPONENT, item.component); + fragment.setArguments(args); + + getFragmentManager().beginTransaction() + .replace(android.R.id.content, fragment) + .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) + .addToBackStack(null) + .commit(); + } + + private static class Item { + final String label; + final ComponentName component; + + Item(String l, ComponentName c) { + this.label = l; + this.component = c; + } + } + + private class Adapter extends BaseAdapter { + private final LayoutInflater mInflater; + + Adapter() { + super(); + + final Context context = getActivity(); + mInflater = LayoutInflater.from(context); + + // Load the data + final PackageManager pm = context.getPackageManager(); + final Intent intent = new Intent(MediaBrowserService.SERVICE_ACTION); + final List<ResolveInfo> list = pm.queryIntentServices(intent, 0); + final int N = list.size(); + mItems = new ArrayList(N); + for (int i=0; i<N; i++) { + final ResolveInfo ri = list.get(i); + mItems.add(new Item(ri.loadLabel(pm).toString(), new ComponentName( + ri.serviceInfo.applicationInfo.packageName, + ri.serviceInfo.name))); + } + } + + @Override + public int getCount() { + return mItems.size(); + } + + @Override + public Item getItem(int position) { + return mItems.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public int getItemViewType(int position) { + return 1; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if (convertView == null) { + convertView = mInflater.inflate(android.R.layout.simple_list_item_1, parent, false); + } + + final TextView tv = (TextView)convertView; + final Item item = mItems.get(position); + tv.setText(item.label); + + return convertView; + } + + @Override + public int getViewTypeCount() { + return 1; + } + } +} + + diff --git a/tests/MusicBrowserDemo/src/com/example/android/musicbrowserdemo/BrowserListFragment.java b/tests/MusicBrowserDemo/src/com/example/android/musicbrowserdemo/BrowserListFragment.java new file mode 100644 index 0000000..2fc77dc --- /dev/null +++ b/tests/MusicBrowserDemo/src/com/example/android/musicbrowserdemo/BrowserListFragment.java @@ -0,0 +1,212 @@ +/* + * 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.musicbrowserdemo; + +import android.content.Context; +import android.content.ComponentName; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.media.browse.MediaBrowser; +import android.media.browse.MediaBrowserItem; +import android.media.browse.MediaBrowserService; +import android.os.Bundle; +import android.net.Uri; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentTransaction; +import android.support.v4.app.ListFragment; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ListView; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.List; + +public class BrowserListFragment extends ListFragment { + private static final String TAG = "BrowserListFragment"; + + // Hints + public static final String HINT_DISPLAY = "com.example.android.musicbrowserdemo.DISPLAY"; + + // For args + public static final String ARG_COMPONENT = "component"; + public static final String ARG_URI = "uri"; + + private Adapter mAdapter; + private List<Item> mItems = new ArrayList(); + private ComponentName mComponent; + private Uri mUri; + private MediaBrowser mBrowser; + + private static class Item { + final MediaBrowserItem media; + + Item(MediaBrowserItem m) { + this.media = m; + } + } + + public BrowserListFragment() { + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + Log.d(TAG, "onActivityCreated -- " + hashCode()); + mAdapter = new Adapter(); + setListAdapter(mAdapter); + + // Get our arguments + final Bundle args = getArguments(); + mComponent = args.getParcelable(ARG_COMPONENT); + mUri = args.getParcelable(ARG_URI); + + // A hint about who we are, so the service can customize the results if it wants to. + final Bundle rootHints = new Bundle(); + rootHints.putBoolean(HINT_DISPLAY, true); + + mBrowser = new MediaBrowser(getActivity(), mComponent, mConnectionCallbacks, rootHints); + } + + @Override + public void onStart() { + super.onStart(); + mBrowser.connect(); + } + + @Override + public void onStop() { + super.onStop(); + mBrowser.disconnect(); + } + + @Override + public void onListItemClick(ListView l, View v, int position, long id) { + final Item item = mItems.get(position); + + Log.i("BrowserListFragment", "Item clicked: " + position + " -- " + + mAdapter.getItem(position).media.getUri()); + + final BrowserListFragment fragment = new BrowserListFragment(); + + final Bundle args = new Bundle(); + args.putParcelable(BrowserListFragment.ARG_COMPONENT, mComponent); + args.putParcelable(BrowserListFragment.ARG_URI, item.media.getUri()); + fragment.setArguments(args); + + getFragmentManager().beginTransaction() + .replace(android.R.id.content, fragment) + .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) + .addToBackStack(null) + .commit(); + + } + + final MediaBrowser.ConnectionCallback mConnectionCallbacks + = new MediaBrowser.ConnectionCallback() { + @Override + public void onConnected() { + Log.d(TAG, "mConnectionCallbacks.onConnected"); + if (mUri == null) { + mUri = mBrowser.getRoot(); + } + mBrowser.subscribe(mUri, new MediaBrowser.SubscriptionCallback() { + @Override + public void onChildrenLoaded(Uri parentUri, List<MediaBrowserItem> children) { + Log.d(TAG, "onChildrenLoaded parentUri=" + parentUri + + " children= " + children); + mItems.clear(); + final int N = children.size(); + for (int i=0; i<N; i++) { + mItems.add(new Item(children.get(i))); + } + mAdapter.notifyDataSetChanged(); + } + + @Override + public void onError(Uri parentUri) { + Log.d(TAG, "onError parentUri=" + parentUri); + } + }); + } + + @Override + public void onConnectionSuspended() { + Log.d(TAG, "mConnectionCallbacks.onConnectionSuspended"); + } + + @Override + public void onConnectionFailed() { + Log.d(TAG, "mConnectionCallbacks.onConnectionFailed"); + } + }; + + private class Adapter extends BaseAdapter { + private final LayoutInflater mInflater; + + Adapter() { + super(); + + final Context context = getActivity(); + mInflater = LayoutInflater.from(context); + } + + @Override + public int getCount() { + return mItems.size(); + } + + @Override + public Item getItem(int position) { + return mItems.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public int getItemViewType(int position) { + return 1; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if (convertView == null) { + convertView = mInflater.inflate(android.R.layout.simple_list_item_1, parent, false); + } + + final TextView tv = (TextView)convertView; + final Item item = mItems.get(position); + tv.setText(item.media.getTitle()); + + return convertView; + } + + @Override + public int getViewTypeCount() { + return 1; + } + } +} + + diff --git a/tests/MusicBrowserDemo/src/com/example/android/musicbrowserdemo/MainActivity.java b/tests/MusicBrowserDemo/src/com/example/android/musicbrowserdemo/MainActivity.java new file mode 100644 index 0000000..4c28234 --- /dev/null +++ b/tests/MusicBrowserDemo/src/com/example/android/musicbrowserdemo/MainActivity.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.musicbrowserdemo; + +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentManager; + +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.ListView; + +/** + * Main activity class. + */ +public class MainActivity extends FragmentActivity { + + private static final String BROWSER_FRAGMENT_TAG = "browser"; + + @Override + protected void onCreate(Bundle icicle) { + super.onCreate(icicle); + + Log.d("MainActivity", "-------------------------------------------------------"); + + // If we are starting afresh, start at the app list. + final FragmentManager fm = getSupportFragmentManager(); + if (fm.findFragmentById(android.R.id.content) == null) { + fm.beginTransaction().add(android.R.id.content, new AppListFragment()).commit(); + } + } +} + diff --git a/tests/MusicServiceDemo/Android.mk b/tests/MusicServiceDemo/Android.mk new file mode 100644 index 0000000..feef67a --- /dev/null +++ b/tests/MusicServiceDemo/Android.mk @@ -0,0 +1,35 @@ +# 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. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_PACKAGE_NAME := MusicServiceDemo +#LOCAL_SDK_VERSION := current +LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_STATIC_JAVA_LIBRARIES := \ + android-support-v4 \ + android-support-v7-appcompat + +LOCAL_RESOURCE_DIR := \ + $(LOCAL_PATH)/res \ + frameworks/support/v7/appcompat/res +LOCAL_PROGUARD_ENABLED := disabled +#LOCAL_PROGUARD_FLAG_FILES := proguard.flags + +LOCAL_AAPT_FLAGS := \ + --auto-add-overlay \ + --extra-packages android.support.v7.appcompat +include $(BUILD_PACKAGE) diff --git a/tests/MusicServiceDemo/AndroidManifest.xml b/tests/MusicServiceDemo/AndroidManifest.xml new file mode 100644 index 0000000..e00e2e2 --- /dev/null +++ b/tests/MusicServiceDemo/AndroidManifest.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.android.musicservicedemo" + android:versionCode="1" + android:versionName="1.0" > + + <uses-permission android:name="android.permission.INTERNET" /> + <uses-permission android:name="android.permission.WAKE_LOCK" /> + + <uses-sdk + android:minSdkVersion="9" + android:targetSdkVersion="19" /> + + <application + android:allowBackup="true" + android:icon="@drawable/ic_launcher" + android:label="@string/app_name" + android:theme="@style/AppTheme" + > + + <activity + android:name="com.example.android.automotive.musicplayer.MainActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <service + android:name=".BrowserService" + android:exported="true" + > + <intent-filter> + <action android:name="android.media.browse.MediaBrowserService" /> + </intent-filter> + </service> + </application> + +</manifest> diff --git a/tests/MusicServiceDemo/proguard-project.txt b/tests/MusicServiceDemo/proguard-project.txt new file mode 100644 index 0000000..f2fe155 --- /dev/null +++ b/tests/MusicServiceDemo/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/tests/MusicServiceDemo/res/drawable-hdpi/ic_launcher.png b/tests/MusicServiceDemo/res/drawable-hdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..47d6854 --- /dev/null +++ b/tests/MusicServiceDemo/res/drawable-hdpi/ic_launcher.png diff --git a/tests/MusicServiceDemo/res/drawable-mdpi/ic_launcher.png b/tests/MusicServiceDemo/res/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..01b53fd --- /dev/null +++ b/tests/MusicServiceDemo/res/drawable-mdpi/ic_launcher.png diff --git a/tests/MusicServiceDemo/res/drawable-xhdpi/ic_launcher.png b/tests/MusicServiceDemo/res/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..af762f2 --- /dev/null +++ b/tests/MusicServiceDemo/res/drawable-xhdpi/ic_launcher.png diff --git a/tests/MusicServiceDemo/res/drawable-xxhdpi/ic_launcher.png b/tests/MusicServiceDemo/res/drawable-xxhdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..eef47aa --- /dev/null +++ b/tests/MusicServiceDemo/res/drawable-xxhdpi/ic_launcher.png diff --git a/tests/MusicServiceDemo/res/drawable-xxhdpi/thumbsup.png b/tests/MusicServiceDemo/res/drawable-xxhdpi/thumbsup.png Binary files differnew file mode 100644 index 0000000..ea98c95 --- /dev/null +++ b/tests/MusicServiceDemo/res/drawable-xxhdpi/thumbsup.png diff --git a/tests/MusicServiceDemo/res/layout/activity_main.xml b/tests/MusicServiceDemo/res/layout/activity_main.xml new file mode 100644 index 0000000..71753e3 --- /dev/null +++ b/tests/MusicServiceDemo/res/layout/activity_main.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/container" + android:layout_width="match_parent" + android:layout_height="match_parent" + tools:context="com.example.android.automotive.musicplayer.MainActivity" + tools:ignore="MergeRootFrame" /> diff --git a/tests/MusicServiceDemo/res/layout/fragment_main.xml b/tests/MusicServiceDemo/res/layout/fragment_main.xml new file mode 100644 index 0000000..8796e86 --- /dev/null +++ b/tests/MusicServiceDemo/res/layout/fragment_main.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. + --> +<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" + android:paddingBottom="@dimen/activity_vertical_margin" + android:paddingLeft="@dimen/activity_horizontal_margin" + android:paddingRight="@dimen/activity_horizontal_margin" + android:paddingTop="@dimen/activity_vertical_margin" + tools:context="com.example.android.automotive.musicplayer.MainActivity$PlaceholderFragment" > + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/app_name" /> + +</RelativeLayout> diff --git a/tests/MusicServiceDemo/res/values/colors.xml b/tests/MusicServiceDemo/res/values/colors.xml new file mode 100644 index 0000000..44dd05d --- /dev/null +++ b/tests/MusicServiceDemo/res/values/colors.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <color name="yellow">#ffffff00</color> + <color name="green">#ff00ff00</color> + <color name="blue">#ff0000ff</color> + <color name="red">#ffff0000</color> +</resources> diff --git a/tests/MusicServiceDemo/res/values/dimens.xml b/tests/MusicServiceDemo/res/values/dimens.xml new file mode 100644 index 0000000..9f63ef2 --- /dev/null +++ b/tests/MusicServiceDemo/res/values/dimens.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> + + <!-- Default screen margins, per the Android Design guidelines. --> + <dimen name="activity_horizontal_margin">16dp</dimen> + <dimen name="activity_vertical_margin">16dp</dimen> + +</resources> diff --git a/tests/MusicServiceDemo/res/values/strings.xml b/tests/MusicServiceDemo/res/values/strings.xml new file mode 100644 index 0000000..14c0171 --- /dev/null +++ b/tests/MusicServiceDemo/res/values/strings.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<resources> + + <string name="app_name">Music Service Demo</string> + <string name="action_settings">Settings</string> + <string name="thumbs_up">Thumbs Up</string> + <string name="music_error">No music found</string> + <string name="now_playing">Now Playing</string> + +</resources> diff --git a/tests/MusicServiceDemo/res/values/styles.xml b/tests/MusicServiceDemo/res/values/styles.xml new file mode 100644 index 0000000..b83662d --- /dev/null +++ b/tests/MusicServiceDemo/res/values/styles.xml @@ -0,0 +1,36 @@ +<?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> + + <!-- + Base application theme, dependent on API level. This theme is replaced + by AppBaseTheme from res/values-vXX/styles.xml on newer devices. + --> + <style name="AppBaseTheme" parent="Theme.AppCompat.Light"> + <!-- + Theme customizations available in newer API levels can go in + res/values-vXX/styles.xml, while customizations related to + backward-compatibility can go here. + --> + </style> + + <!-- Application theme. --> + <style name="AppTheme" parent="AppBaseTheme"> + <!-- All customizations that are NOT specific to a particular API-level can go here. --> + </style> + +</resources> diff --git a/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/BrowserService.java b/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/BrowserService.java new file mode 100644 index 0000000..937f1e6 --- /dev/null +++ b/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/BrowserService.java @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2014 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.musicservicedemo; + +import android.app.SearchManager; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.content.UriMatcher; +import android.content.res.Resources.NotFoundException; +import android.database.MatrixCursor; +import android.graphics.Bitmap; +import android.media.AudioManager; +import android.media.MediaPlayer; +import android.media.MediaPlayer.OnCompletionListener; +import android.media.MediaPlayer.OnErrorListener; +import android.media.MediaPlayer.OnPreparedListener; +import android.media.browse.MediaBrowserItem; +import android.media.browse.MediaBrowserService; +import android.media.browse.MediaBrowserService.BrowserRoot; +import android.media.session.MediaSession; +import android.net.Uri; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.WifiLock; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.PowerManager; +import android.os.RemoteException; +import android.os.SystemClock; +import android.util.Log; + +import com.example.android.musicservicedemo.browser.MusicProvider; +import com.example.android.musicservicedemo.browser.MusicProviderTask; +import com.example.android.musicservicedemo.browser.MusicProviderTaskListener; +import com.example.android.musicservicedemo.browser.MusicTrack; + +import org.json.JSONException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * Service that implements MediaBrowserService and returns our menu hierarchy. + */ +public class BrowserService extends MediaBrowserService { + private static final String TAG = "BrowserService"; + + // URI paths for browsing music + public static final String BROWSE_ROOT_BASE_PATH = "browse"; + public static final String NOW_PLAYING_PATH = "now_playing"; + public static final String PIANO_BASE_PATH = "piano"; + public static final String VOICE_BASE_PATH = "voice"; + + // Content URIs + public static final String AUTHORITY = "com.example.android.automotive.musicplayer"; + public static final Uri BASE_URI = Uri.parse("content://" + AUTHORITY); + public static final Uri BROWSE_URI = Uri.withAppendedPath(BASE_URI, BROWSE_ROOT_BASE_PATH); + + // URI matcher constants for browsing paths + public static final int BROWSE_ROOT = 1; + public static final int NOW_PLAYING = 2; + public static final int PIANO = 3; + public static final int VOICE = 4; + + // Map the the URI paths with the URI matcher constants + private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); + static { + sUriMatcher.addURI(AUTHORITY, BROWSE_ROOT_BASE_PATH, BROWSE_ROOT); + sUriMatcher.addURI(AUTHORITY, NOW_PLAYING_PATH, NOW_PLAYING); + sUriMatcher.addURI(AUTHORITY, PIANO_BASE_PATH, PIANO); + sUriMatcher.addURI(AUTHORITY, VOICE_BASE_PATH, VOICE); + } + + // Media metadata that will be provided for a media container + public static final String[] MEDIA_CONTAINER_PROJECTION = { + "uri", + "title", + "subtitle", + "image_uri", + "supported_actions" + }; + + // MusicProvider will download the music catalog + private MusicProvider mMusicProvider; + + private MediaSession mSession; + + @Override + public void onCreate() { + super.onCreate(); + + mSession = new MediaSession(this, "com.example.android.musicservicedemo.BrowserService"); + setSessionToken(mSession.getSessionToken()); + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + @Override + public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) { + return new BrowserRoot(BROWSE_URI, null); + } + + @Override + public void onLoadChildren(final Uri parentUri, + final Result<List<MediaBrowserItem>> result) { + new Handler().postDelayed(new Runnable() { + public void run() { + final ArrayList<MediaBrowserItem> list = new ArrayList(); + + for (int i=0; i<10; i++) { + list.add(new MediaBrowserItem.Builder( + Uri.withAppendedPath(BASE_URI, Integer.toString(i)), + MediaBrowserItem.FLAG_BROWSABLE, "Title " + i) + .setSummary("Summary " + i) + .build()); + } + + result.sendResult(list); + } + }, 2000); + result.detach(); + } + + @Override + public void onLoadIcon(Uri uri, int width, int height, Result<Bitmap> result) { + result.sendResult(null); + } + + /* + @Override + public void query(final Query query, final IMetadataResultHandler metadataResultHandler, + final IErrorHandler errorHandler) + throws RemoteException { + Log.d(TAG, "query: " + query); + Utils.checkNotNull(query); + Utils.checkNotNull(metadataResultHandler); + Utils.checkNotNull(errorHandler); + + // Handle async response + new Thread(new Runnable() { + public void run() { + try { + // Pre-load the list of music + List<MusicTrack> musicTracks = getMusicList(); + if (musicTracks == null) { + notifyListenersOnPlaybackStateUpdate(getCurrentPlaybackState()); + errorHandler.onError(new Error(Error.UNKNOWN, + getString(R.string.music_error))); + return; + } + + final Uri uri = query.getUri(); + int match = sUriMatcher.match(uri); + Log.d(TAG, "Queried: " + uri + "; match: " + match); + switch (match) { + case BROWSE_ROOT: + { + Log.d(TAG, "Browse_root"); + + try { + MatrixCursor matrixCursor = mMusicProvider + .getRootContainerCurser(); + DataHolder holder = new DataHolder(MEDIA_CONTAINER_PROJECTION, + matrixCursor, null); + + Log.d(TAG, "on metadata response called " + holder.getCount()); + metadataResultHandler.onMetadataResponse(holder); + } catch (RemoteException e) { + Log.w(TAG, "Error delivering metadata in the callback.", e); + } + break; + } + case NOW_PLAYING: + { + try { + Log.d(TAG, "query NOW_PLAYING"); + MatrixCursor matrixCursor = mMusicProvider + .getRootItemCursor( + PIANO); + DataHolder holder = new DataHolder(MEDIA_CONTAINER_PROJECTION, + matrixCursor, null); + Log.d(TAG, "on metadata response called " + holder.getCount()); + metadataResultHandler.onMetadataResponse(holder); + } catch (RemoteException e) { + Log.w(TAG, "Error querying NOW_PLAYING"); + } + break; + } + case PIANO: + { + try { + Log.d(TAG, "query PIANO"); + MatrixCursor matrixCursor = mMusicProvider + .getRootItemCursor( + PIANO); + DataHolder holder = new DataHolder(MEDIA_CONTAINER_PROJECTION, + matrixCursor, null); + Log.d(TAG, "on metadata response called " + holder.getCount()); + metadataResultHandler.onMetadataResponse(holder); + } catch (RemoteException e) { + Log.w(TAG, "Error querying PIANO"); + } + break; + } + case VOICE: + { + try { + Log.d(TAG, "query VOICE"); + MatrixCursor matrixCursor = mMusicProvider + .getRootItemCursor( + VOICE); + DataHolder holder = new DataHolder(MEDIA_CONTAINER_PROJECTION, + matrixCursor, null); + Log.d(TAG, "on metadata response called " + holder.getCount()); + metadataResultHandler.onMetadataResponse(holder); + } catch (RemoteException e) { + Log.w(TAG, "Error querying VOICE"); + } + break; + } + default: + { + Log.w(TAG, "Skipping unmatched URI: " + uri); + } + } + } catch (NotFoundException e) { + Log.e(TAG, "::run:", e); + } catch (RemoteException e) { + Log.e(TAG, "::run:", e); + } + } // end run + }).start(); + } + + */ +} diff --git a/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/MainActivity.java b/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/MainActivity.java new file mode 100644 index 0000000..db45b9d --- /dev/null +++ b/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/MainActivity.java @@ -0,0 +1,101 @@ +/* Copyright 2014 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.musicservicedemo; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v7.app.ActionBarActivity; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; + +import com.example.android.musicservicedemo.R; + +// TODO Local UI + +/** + * Main activity of the app. + */ +public class MainActivity extends ActionBarActivity { + + private static final String LOG = "MainActivity"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + if (savedInstanceState == null) { + getSupportFragmentManager().beginTransaction() + .add(R.id.container, new PlaceholderFragment()) + .commit(); + } + + } + + /* + * (non-Javadoc) + * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu) + */ + @Override + public boolean onCreateOptionsMenu(Menu menu) { + + // Inflate the menu; this adds items to the action bar if it is present. + //getMenuInflater().inflate(R.menu.main, menu); + return true; + } + + /* + * (non-Javadoc) + * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem) + */ + @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(); + // if (id == R.id.action_settings) { + // return true; + // } + return super.onOptionsItemSelected(item); + } + + /** + * A placeholder fragment containing a simple view. + */ + public static class PlaceholderFragment extends Fragment { + + public PlaceholderFragment() { + } + + /* + * (non-Javadoc) + * @see + * android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater + * , android.view.ViewGroup, android.os.Bundle) + */ + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View rootView = inflater.inflate(R.layout.fragment_main, container, false); + return rootView; + } + } + +} diff --git a/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/Utils.java b/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/Utils.java new file mode 100644 index 0000000..3589761 --- /dev/null +++ b/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/Utils.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2014 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.musicservicedemo; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.util.Log; + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; + +public class Utils { + + private static final String TAG = "Utils"; + + /** + * Utility method to check that parameters are not null + * + * @param object + */ + public static final void checkNotNull(Object object) { + if (object == null) { + throw new NullPointerException(); + } + } + + /** + * Utility to download a bitmap + * + * @param source + * @return + */ + public static Bitmap getBitmapFromURL(String source) { + try { + URL url = new URL(source); + HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection(); + httpConnection.setDoInput(true); + httpConnection.connect(); + InputStream inputStream = httpConnection.getInputStream(); + return BitmapFactory.decodeStream(inputStream); + } catch (IOException e) { + Log.e(TAG, "getBitmapFromUrl: " + source, e); + } + return null; + } + + /** + * Utility method to wrap an index + * + * @param i + * @param size + * @return + */ + public static int wrapIndex(int i, int size) { + int m = i % size; + if (m < 0) { // java modulus can be negative + m += size; + } + return m; + } +} diff --git a/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/browser/MusicProvider.java b/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/browser/MusicProvider.java new file mode 100644 index 0000000..15038d7 --- /dev/null +++ b/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/browser/MusicProvider.java @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2014 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.musicservicedemo.browser; + +import android.database.MatrixCursor; +import android.media.session.PlaybackState; +import android.net.Uri; +import android.util.Log; + +import com.example.android.musicservicedemo.BrowserService; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.List; + +/** + * Utility class to get a list of MusicTrack's based on a server-side JSON + * configuration. + */ +public class MusicProvider { + + private static final String TAG = "MusicProvider"; + + private static final String MUSIC_URL = "http://storage.googleapis.com/automotive-media/music.json"; + + private static String MUSIC = "music"; + private static String TITLE = "title"; + private static String ALBUM = "album"; + private static String ARTIST = "artist"; + private static String GENRE = "genre"; + private static String SOURCE = "source"; + private static String IMAGE = "image"; + private static String TRACK_NUMBER = "trackNumber"; + private static String TOTAL_TRACK_COUNT = "totalTrackCount"; + private static String DURATION = "duration"; + + // Cache for music track data + private static List<MusicTrack> mMusicList; + + /** + * Get the cached list of music tracks + * + * @return + * @throws JSONException + */ + public List<MusicTrack> getMedia() throws JSONException { + if (null != mMusicList && mMusicList.size() > 0) { + return mMusicList; + } + return null; + } + + /** + * Get the list of music tracks from a server and return the list of + * MusicTrack objects. + * + * @return + * @throws JSONException + */ + public List<MusicTrack> retreiveMedia() throws JSONException { + if (null != mMusicList) { + return mMusicList; + } + int slashPos = MUSIC_URL.lastIndexOf('/'); + String path = MUSIC_URL.substring(0, slashPos + 1); + JSONObject jsonObj = parseUrl(MUSIC_URL); + + try { + JSONArray videos = jsonObj.getJSONArray(MUSIC); + if (null != videos) { + mMusicList = new ArrayList<MusicTrack>(); + for (int j = 0; j < videos.length(); j++) { + JSONObject music = videos.getJSONObject(j); + String title = music.getString(TITLE); + String album = music.getString(ALBUM); + String artist = music.getString(ARTIST); + String genre = music.getString(GENRE); + String source = music.getString(SOURCE); + // Media is stored relative to JSON file + if (!source.startsWith("http")) { + source = path + source; + } + String image = music.getString(IMAGE); + if (!image.startsWith("http")) { + image = path + image; + } + int trackNumber = music.getInt(TRACK_NUMBER); + int totalTrackCount = music.getInt(TOTAL_TRACK_COUNT); + int duration = music.getInt(DURATION) * 1000; // ms + + mMusicList.add(new MusicTrack(title, album, artist, genre, source, + image, trackNumber, totalTrackCount, duration)); + } + } + } catch (NullPointerException e) { + Log.e(TAG, "retreiveMedia", e); + } + return mMusicList; + } + + /** + * Download a JSON file from a server, parse the content and return the JSON + * object. + * + * @param urlString + * @return + */ + private JSONObject parseUrl(String urlString) { + InputStream is = null; + try { + java.net.URL url = new java.net.URL(urlString); + URLConnection urlConnection = url.openConnection(); + is = new BufferedInputStream(urlConnection.getInputStream()); + BufferedReader reader = new BufferedReader(new InputStreamReader( + urlConnection.getInputStream(), "iso-8859-1"), 8); + StringBuilder sb = new StringBuilder(); + String line = null; + while ((line = reader.readLine()) != null) { + sb.append(line); + } + return new JSONObject(sb.toString()); + } catch (Exception e) { + Log.d(TAG, "Failed to parse the json for media list", e); + return null; + } finally { + if (null != is) { + try { + is.close(); + } catch (IOException e) { + // ignore + } + } + } + } + + public MatrixCursor getRootContainerCurser() { + MatrixCursor matrixCursor = new MatrixCursor(BrowserService.MEDIA_CONTAINER_PROJECTION); + Uri.Builder pianoBuilder = new Uri.Builder(); + pianoBuilder.authority(BrowserService.AUTHORITY); + pianoBuilder.appendPath(BrowserService.PIANO_BASE_PATH); + matrixCursor.addRow(new Object[] { + pianoBuilder.build(), + BrowserService.PIANO_BASE_PATH, + "subtitle", + null, + 0 + }); + + Uri.Builder voiceBuilder = new Uri.Builder(); + voiceBuilder.authority(BrowserService.AUTHORITY); + voiceBuilder.appendPath(BrowserService.VOICE_BASE_PATH); + matrixCursor.addRow(new Object[] { + voiceBuilder.build(), + BrowserService.VOICE_BASE_PATH, + "subtitle", + null, + 0 + }); + return matrixCursor; + } + + public MatrixCursor getRootItemCursor(int type) { + if (type == BrowserService.NOW_PLAYING) { + MatrixCursor matrixCursor = new MatrixCursor(BrowserService.MEDIA_CONTAINER_PROJECTION); + + try { + // Just return all of the tracks for now + List<MusicTrack> musicTracks = retreiveMedia(); + for (MusicTrack musicTrack : musicTracks) { + Uri.Builder builder = new Uri.Builder(); + builder.authority(BrowserService.AUTHORITY); + builder.appendPath(BrowserService.NOW_PLAYING_PATH); + builder.appendPath(musicTrack.getTitle()); + matrixCursor.addRow(new Object[] { + builder.build(), + musicTrack.getTitle(), + musicTrack.getArtist(), + musicTrack.getImage(), + PlaybackState.ACTION_PLAY + }); + Log.d(TAG, "Uri " + builder.build()); + } + } catch (JSONException e) { + Log.e(TAG, "::getRootItemCursor:", e); + } + + Log.d(TAG, "cursor: " + matrixCursor.getCount()); + return matrixCursor; + } else if (type == BrowserService.PIANO) { + MatrixCursor matrixCursor = new MatrixCursor(BrowserService.MEDIA_CONTAINER_PROJECTION); + + try { + List<MusicTrack> musicTracks = retreiveMedia(); + for (MusicTrack musicTrack : musicTracks) { + Uri.Builder builder = new Uri.Builder(); + builder.authority(BrowserService.AUTHORITY); + builder.appendPath(BrowserService.PIANO_BASE_PATH); + builder.appendPath(musicTrack.getTitle()); + matrixCursor.addRow(new Object[] { + builder.build(), + musicTrack.getTitle(), + musicTrack.getArtist(), + musicTrack.getImage(), + PlaybackState.ACTION_PLAY + }); + Log.d(TAG, "Uri " + builder.build()); + } + } catch (JSONException e) { + Log.e(TAG, "::getRootItemCursor:", e); + } + + Log.d(TAG, "cursor: " + matrixCursor.getCount()); + return matrixCursor; + } else if (type == BrowserService.VOICE) { + MatrixCursor matrixCursor = new MatrixCursor(BrowserService.MEDIA_CONTAINER_PROJECTION); + + try { + List<MusicTrack> musicTracks = retreiveMedia(); + for (MusicTrack musicTrack : musicTracks) { + Uri.Builder builder = new Uri.Builder(); + builder.authority(BrowserService.AUTHORITY); + builder.appendPath(BrowserService.VOICE_BASE_PATH); + builder.appendPath(musicTrack.getTitle()); + matrixCursor.addRow(new Object[] { + builder.build(), + musicTrack.getTitle(), + musicTrack.getArtist(), + musicTrack.getImage(), + PlaybackState.ACTION_PLAY + }); + Log.d(TAG, "Uri " + builder.build()); + } + } catch (JSONException e) { + Log.e(TAG, "::getRootItemCursor:", e); + } + + Log.d(TAG, "cursor: " + matrixCursor.getCount()); + return matrixCursor; + + } + return null; + } +} diff --git a/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/browser/MusicProviderTask.java b/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/browser/MusicProviderTask.java new file mode 100644 index 0000000..ffda110 --- /dev/null +++ b/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/browser/MusicProviderTask.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.musicservicedemo.browser; + +import android.os.AsyncTask; +import android.util.Log; + +import org.json.JSONException; + +/** + * Asynchronous task to retrieve the music data using MusicProvider. + */ +public class MusicProviderTask extends AsyncTask<Void, Void, Void> { + + private static final String TAG = "MusicProviderTask"; + + MusicProvider mMusicProvider; + MusicProviderTaskListener mMusicProviderTaskListener; + + /** + * Initialize the task with the provider to download the music data and the + * listener to be informed when the task is done. + * + * @param musicProvider + * @param listener + */ + public MusicProviderTask(MusicProvider musicProvider, + MusicProviderTaskListener listener) { + mMusicProvider = musicProvider; + mMusicProviderTaskListener = listener; + } + + /* + * (non-Javadoc) + * @see android.os.AsyncTask#doInBackground(java.lang.Object[]) + */ + @Override + protected Void doInBackground(Void... arg0) { + try { + mMusicProvider.retreiveMedia(); + } catch (JSONException e) { + Log.e(TAG, "::doInBackground:", e); + } + return null; + } + + /* + * (non-Javadoc) + * @see android.os.AsyncTask#onPostExecute(java.lang.Object) + */ + @Override + protected void onPostExecute(Void result) { + mMusicProviderTaskListener.onMusicProviderTaskCompleted(); + } + +} diff --git a/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/browser/MusicProviderTaskListener.java b/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/browser/MusicProviderTaskListener.java new file mode 100644 index 0000000..b1d168f --- /dev/null +++ b/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/browser/MusicProviderTaskListener.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2014 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.musicservicedemo.browser; + +/** + * Callback listener for completion of MusicProviderTask + */ +public interface MusicProviderTaskListener { + public void onMusicProviderTaskCompleted(); +} diff --git a/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/browser/MusicTrack.java b/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/browser/MusicTrack.java new file mode 100644 index 0000000..02ea899 --- /dev/null +++ b/tests/MusicServiceDemo/src/com/example/android/musicservicedemo/browser/MusicTrack.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2014 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.musicservicedemo.browser; + +/** + * A class to model music track metadata. + */ +public class MusicTrack { + + private static final String TAG = "MusicTrack"; + + private String mTitle; + private String mAlbum; + private String mArtist; + private String mGenre; + private String mSource; + private String mImage; + private int mTrackNumber; + private int mTotalTrackCount; + private int mDuration; + + /** + * Constructor creating a MusicTrack instance. + * + * @param title + * @param album + * @param artist + * @param genre + * @param source + * @param image + * @param trackNumber + * @param totalTrackCount + * @param duration + */ + public MusicTrack(String title, String album, String artist, String genre, String source, + String image, int trackNumber, int totalTrackCount, int duration) { + this.mTitle = title; + this.mAlbum = album; + this.mArtist = artist; + this.mGenre = genre; + this.mSource = source; + this.mImage = image; + this.mTrackNumber = trackNumber; + this.mTotalTrackCount = totalTrackCount; + this.mDuration = duration; + } + + public String getTitle() { + return mTitle; + } + + public void setTitle(String mTitle) { + this.mTitle = mTitle; + } + + public String getAlbum() { + return mAlbum; + } + + public void setAlbum(String mAlbum) { + this.mAlbum = mAlbum; + } + + public String getArtist() { + return mArtist; + } + + public void setArtist(String mArtist) { + this.mArtist = mArtist; + } + + public String getGenre() { + return mGenre; + } + + public void setGenre(String mGenre) { + this.mGenre = mGenre; + } + + public String getSource() { + return mSource; + } + + public void setSource(String mSource) { + this.mSource = mSource; + } + + public String getImage() { + return mImage; + } + + public void setImage(String mImage) { + this.mImage = mImage; + } + + public int getTrackNumber() { + return mTrackNumber; + } + + public void setTrackNumber(int mTrackNumber) { + this.mTrackNumber = mTrackNumber; + } + + public int getTotalTrackCount() { + return mTotalTrackCount; + } + + public void setTotalTrackCount(int mTotalTrackCount) { + this.mTotalTrackCount = mTotalTrackCount; + } + + public int getDuration() { + return mDuration; + } + + public void setDuration(int mDuration) { + this.mDuration = mDuration; + } + + public String toString() { + return mTitle; + } + +} diff --git a/tests/OneMedia/Android.mk b/tests/OneMedia/Android.mk new file mode 100644 index 0000000..4d39728 --- /dev/null +++ b/tests/OneMedia/Android.mk @@ -0,0 +1,14 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-subdir-java-files) \ + $(call all-Iaidl-files-under, src) + +LOCAL_PACKAGE_NAME := OneMedia +LOCAL_CERTIFICATE := platform + +LOCAL_PROGUARD_ENABLED := disabled + +include $(BUILD_PACKAGE) diff --git a/tests/OneMedia/AndroidManifest.xml b/tests/OneMedia/AndroidManifest.xml new file mode 100644 index 0000000..beafeb4 --- /dev/null +++ b/tests/OneMedia/AndroidManifest.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.onemedia" + android:versionCode="1" + android:versionName="1.0" > + + <uses-sdk android:minSdkVersion="19"/> + <uses-permission android:name="android.permission.INTERNET" /> + <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> + + <application + android:allowBackup="true" + android:icon="@drawable/ic_launcher" + android:label="@string/app_name" + android:theme="@style/AppTheme" > + <activity + android:name="com.android.onemedia.OnePlayerActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + <service + android:name="com.android.onemedia.OnePlayerService" + android:exported="true" + android:process="com.android.onemedia.service" /> + </application> + +</manifest> diff --git a/tests/OneMedia/res/drawable-hdpi/ic_launcher.png b/tests/OneMedia/res/drawable-hdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..288b665 --- /dev/null +++ b/tests/OneMedia/res/drawable-hdpi/ic_launcher.png diff --git a/tests/OneMedia/res/drawable-mdpi/ic_launcher.png b/tests/OneMedia/res/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..6ae570b --- /dev/null +++ b/tests/OneMedia/res/drawable-mdpi/ic_launcher.png diff --git a/tests/OneMedia/res/drawable-xhdpi/ic_launcher.png b/tests/OneMedia/res/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..d4fb7cd --- /dev/null +++ b/tests/OneMedia/res/drawable-xhdpi/ic_launcher.png diff --git a/tests/OneMedia/res/drawable-xxhdpi/ic_launcher.png b/tests/OneMedia/res/drawable-xxhdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..85a6081 --- /dev/null +++ b/tests/OneMedia/res/drawable-xxhdpi/ic_launcher.png diff --git a/tests/OneMedia/res/drawable/ic_fast_forward.xml b/tests/OneMedia/res/drawable/ic_fast_forward.xml new file mode 100644 index 0000000..8daf07d --- /dev/null +++ b/tests/OneMedia/res/drawable/ic_fast_forward.xml @@ -0,0 +1,25 @@ +<!-- +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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="36dp" + android:height="36dp" + android:viewportWidth="24" + android:viewportHeight="24" > + + <path + android:fillColor="#FFFFFFFF" + android:pathData="M4.0,18.0l8.5,-6.0L4.0,6.0L4.0,18.0zM13.0,6.0l0.0,12.0l8.5,-6.0L13.0,6.0z"/> +</vector> diff --git a/tests/OneMedia/res/drawable/ic_fast_rewind.xml b/tests/OneMedia/res/drawable/ic_fast_rewind.xml new file mode 100644 index 0000000..4ed1f54 --- /dev/null +++ b/tests/OneMedia/res/drawable/ic_fast_rewind.xml @@ -0,0 +1,24 @@ +<!-- +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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="36dp" + android:height="36dp" + android:viewportWidth="24" + android:viewportHeight="24" > + <path + android:fillColor="#FFFFFFFF" + android:pathData="M11.0,18.0L11.0,6.0l-8.5,6.0L11.0,18.0zM11.5,12.0l8.5,6.0L20.0,6.0L11.5,12.0z"/> +</vector> diff --git a/tests/OneMedia/res/drawable/ic_pause.xml b/tests/OneMedia/res/drawable/ic_pause.xml new file mode 100644 index 0000000..15d0756 --- /dev/null +++ b/tests/OneMedia/res/drawable/ic_pause.xml @@ -0,0 +1,25 @@ +<!-- +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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="36dp" + android:height="36dp" + android:viewportWidth="24" + android:viewportHeight="24" > + + <path + android:fillColor="#FFFFFFFF" + android:pathData="M6.0,19.0l4.0,0.0L10.0,5.0L6.0,5.0L6.0,19.0zM14.0,5.0l0.0,14.0l4.0,0.0L18.0,5.0L14.0,5.0z"/> +</vector> diff --git a/tests/OneMedia/res/drawable/ic_play_arrow.xml b/tests/OneMedia/res/drawable/ic_play_arrow.xml new file mode 100644 index 0000000..49d766d --- /dev/null +++ b/tests/OneMedia/res/drawable/ic_play_arrow.xml @@ -0,0 +1,25 @@ +<!-- +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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="36dp" + android:height="36dp" + android:viewportWidth="24" + android:viewportHeight="24" > + + <path + android:fillColor="#FFFFFFFF" + android:pathData="M8.0,5.0l0.0,14.0 11.0,-7.0z"/> +</vector> diff --git a/tests/OneMedia/res/drawable/ic_skip_next.xml b/tests/OneMedia/res/drawable/ic_skip_next.xml new file mode 100644 index 0000000..8a6ceca --- /dev/null +++ b/tests/OneMedia/res/drawable/ic_skip_next.xml @@ -0,0 +1,25 @@ +<!-- +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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="36dp" + android:height="36dp" + android:viewportWidth="24" + android:viewportHeight="24" > + + <path + android:fillColor="#FFFFFFFF" + android:pathData="M6.0,18.0l8.5,-6.0L6.0,6.0L6.0,18.0zM16.0,6.0l0.0,12.0l2.0,0.0L18.0,6.0L16.0,6.0z"/> +</vector> diff --git a/tests/OneMedia/res/drawable/ic_skip_previous.xml b/tests/OneMedia/res/drawable/ic_skip_previous.xml new file mode 100644 index 0000000..c5d07db --- /dev/null +++ b/tests/OneMedia/res/drawable/ic_skip_previous.xml @@ -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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="36dp" + android:height="36dp" + android:viewportWidth="24" + android:viewportHeight="24" > + + <path + android:fillColor="#FFFFFFFF" + android:pathData="M6.0,6.0l2.0,0.0l0.0,12.0l-2.0,0.0z"/> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M9.5,12.0l8.5,6.0 0.0,-12.0z"/> +</vector> diff --git a/tests/OneMedia/res/drawable/ic_stop.xml b/tests/OneMedia/res/drawable/ic_stop.xml new file mode 100644 index 0000000..6043fdb --- /dev/null +++ b/tests/OneMedia/res/drawable/ic_stop.xml @@ -0,0 +1,25 @@ +<!-- +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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="36dp" + android:height="36dp" + android:viewportWidth="24" + android:viewportHeight="24" > + + <path + android:fillColor="#FFFFFFFF" + android:pathData="M6.0,6.0l12.0,0.0l0.0,12.0l-12.0,0.0z"/> +</vector> diff --git a/tests/OneMedia/res/layout/activity_main.xml b/tests/OneMedia/res/layout/activity_main.xml new file mode 100644 index 0000000..168c9b8 --- /dev/null +++ b/tests/OneMedia/res/layout/activity_main.xml @@ -0,0 +1,16 @@ +<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" + android:paddingBottom="@dimen/activity_vertical_margin" + android:paddingLeft="@dimen/activity_horizontal_margin" + android:paddingRight="@dimen/activity_horizontal_margin" + android:paddingTop="@dimen/activity_vertical_margin" + tools:context=".MainActivity" > + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/hello_world" /> + +</RelativeLayout> diff --git a/tests/OneMedia/res/layout/activity_one_player.xml b/tests/OneMedia/res/layout/activity_one_player.xml new file mode 100644 index 0000000..ce2d641 --- /dev/null +++ b/tests/OneMedia/res/layout/activity_one_player.xml @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2014 Google Inc. All Rights Reserved. --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center_horizontal" + android:orientation="vertical"> + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center" + android:text="@string/app_name" + style="@style/Title" /> + <EditText + android:id="@+id/content" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:inputType="textUri" + android:hint="@string/media_content_hint" + android:gravity="center" + android:textSize="24sp" /> + <EditText + android:id="@+id/next_content" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:inputType="textNoSuggestions" + android:hint="@string/media_next_hint" + android:gravity="center" + android:textSize="24sp" /> + <CheckBox + android:id="@+id/has_video" + android:layout_marginRight="8dip" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/has_video" /> + <ImageView + android:id="@+id/art" + android:layout_width="match_parent" + android:layout_height="96dp" + android:scaleType="centerCrop" + android:visibility="gone" + /> + <Button + android:id="@+id/art_picker" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/art_picker" + /> + <LinearLayout + android:id="@+id/controls" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" > + <Button + android:id="@+id/start_button" + style="@style/BottomBarButton" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_weight="1" + android:text="@string/start_button" /> + <Button + android:id="@+id/play_button" + style="@style/BottomBarButton" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_weight="1" + android:text="@string/play_button" /> + </LinearLayout> + <Button + android:id="@+id/route_button" + style="@style/BottomBarButton" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/route_button" /> + <TextView + android:id="@+id/status" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + +</LinearLayout> diff --git a/tests/OneMedia/res/menu/main.xml b/tests/OneMedia/res/menu/main.xml new file mode 100644 index 0000000..c002028 --- /dev/null +++ b/tests/OneMedia/res/menu/main.xml @@ -0,0 +1,9 @@ +<menu xmlns:android="http://schemas.android.com/apk/res/android" > + + <item + android:id="@+id/action_settings" + android:orderInCategory="100" + android:showAsAction="never" + android:title="@string/action_settings"/> + +</menu> diff --git a/tests/OneMedia/res/values/colors.xml b/tests/OneMedia/res/values/colors.xml new file mode 100644 index 0000000..9b9dc2a --- /dev/null +++ b/tests/OneMedia/res/values/colors.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* + * Copyright (C) 2014 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> + +<resources> + <color name="title_color">#33B5E5</color> +</resources> diff --git a/tests/OneMedia/res/values/dimens.xml b/tests/OneMedia/res/values/dimens.xml new file mode 100644 index 0000000..562edef --- /dev/null +++ b/tests/OneMedia/res/values/dimens.xml @@ -0,0 +1,9 @@ +<resources> + + <!-- Default screen margins, per the Android Design guidelines. --> + <dimen name="activity_horizontal_margin">16dp</dimen> + <dimen name="activity_vertical_margin">16dp</dimen> + <dimen name="title_size">22sp</dimen> + <dimen name="small_size">11sp</dimen> + +</resources> diff --git a/tests/OneMedia/res/values/strings.xml b/tests/OneMedia/res/values/strings.xml new file mode 100644 index 0000000..86657fd --- /dev/null +++ b/tests/OneMedia/res/values/strings.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <string name="app_name">OneMedia</string> + <string name="action_settings">Settings</string> + <string name="hello_world">Test app for trying out new media components</string> + + <string name="start_button">Start</string> + <string name="play_button">Play</string> + <string name="route_button">Change route</string> + <string name="media_content_hint">Content</string> + <string name="media_next_hint">Next content</string> + <string name="has_video">Is video</string> + <string name="has_duration">Has duration</string> + <string name="art_picker">Choose artwork</string> +</resources> diff --git a/tests/OneMedia/res/values/styles.xml b/tests/OneMedia/res/values/styles.xml new file mode 100644 index 0000000..60f3139 --- /dev/null +++ b/tests/OneMedia/res/values/styles.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <!-- + Base application theme, dependent on API level. This theme is replaced + by AppBaseTheme from res/values-vXX/styles.xml on newer devices. + --> + <style name="AppBaseTheme" parent="android:Theme.Light"> + <!-- + Theme customizations available in newer API levels can go in + res/values-vXX/styles.xml, while customizations related to + backward-compatibility can go here. + --> + </style> + + <!-- Application theme. --> + <style name="AppTheme" parent="AppBaseTheme"> + <!-- All customizations that are NOT specific to a particular API-level can go here. --> + </style> + + <style name="Title"> + <item name="android:textSize">@dimen/title_size</item> + <item name="android:textColor">@color/title_color</item> + <item name="android:clickable">false</item> + <item name="android:longClickable">false</item> + </style> + + <style name="Text"> + <item name="android:textSize">@dimen/small_size</item> + <item name="android:textColor">@color/title_color</item> + <item name="android:clickable">false</item> + <item name="android:longClickable">false</item> + </style> + + <style name="BottomBarButton"> + <item name="android:layout_width">match_parent</item> + <item name="android:layout_height">match_parent</item> + <item name="android:paddingTop">0dip</item> + <item name="android:paddingLeft">0dip</item> + <item name="android:paddingRight">0dip</item> + <item name="android:paddingBottom">0dip</item> + <item name="android:textSize">12sp</item> + <item name="android:textStyle">bold</item> + </style> +</resources> diff --git a/tests/OneMedia/src/com/android/onemedia/IPlayerCallback.aidl b/tests/OneMedia/src/com/android/onemedia/IPlayerCallback.aidl new file mode 100644 index 0000000..d04f56f --- /dev/null +++ b/tests/OneMedia/src/com/android/onemedia/IPlayerCallback.aidl @@ -0,0 +1,22 @@ +/* Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.onemedia; + +import android.media.session.MediaSession; + +interface IPlayerCallback { + void onSessionChanged(in MediaSession.Token session); +} diff --git a/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl b/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl new file mode 100644 index 0000000..f53eac0 --- /dev/null +++ b/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl @@ -0,0 +1,31 @@ +/* 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; + +import android.graphics.Bitmap; +import android.media.session.MediaSession; +import android.os.Bundle; + +import com.android.onemedia.IPlayerCallback; +import com.android.onemedia.playback.IRequestCallback; + +interface IPlayerService { + MediaSession.Token getSessionToken(); + void registerCallback(in IPlayerCallback cb); + void unregisterCallback(in IPlayerCallback cb); + void sendRequest(String action, in Bundle params, in IRequestCallback cb); + void setIcon(in Bitmap icon); +} diff --git a/tests/OneMedia/src/com/android/onemedia/NotificationHelper.java b/tests/OneMedia/src/com/android/onemedia/NotificationHelper.java new file mode 100644 index 0000000..a5bcda5 --- /dev/null +++ b/tests/OneMedia/src/com/android/onemedia/NotificationHelper.java @@ -0,0 +1,234 @@ +package com.android.onemedia; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.graphics.Bitmap; +import android.media.MediaMetadata; +import android.media.session.MediaController; +import android.media.session.MediaSession; +import android.media.session.PlaybackState; +import android.text.format.DateUtils; +import android.util.Log; +import android.util.SparseArray; + +import com.android.onemedia.playback.RequestUtils; + +/** + * Keeps track of a notification and updates it automatically for a given + * MediaSession. + */ +public class NotificationHelper extends BroadcastReceiver { + private static final String TAG = "NotificationHelper"; + + private static final int NOTIFICATION_ID = 433; // John Cage, 1952 + + private final Service mService; + private final MediaSession mSession; + private final MediaController mController; + private final MediaController.TransportControls mTransportControls; + private final SparseArray<PendingIntent> mIntents = new SparseArray<PendingIntent>(); + + private PlaybackState mPlaybackState; + private MediaMetadata mMetadata; + + private boolean mStarted = false; + + public NotificationHelper(Service service, MediaSession session) { + mService = service; + mSession = session; + mController = session.getController(); + mTransportControls = mController.getTransportControls(); + String pkg = mService.getPackageName(); + + mIntents.put(R.drawable.ic_pause, PendingIntent.getBroadcast(mService, 100, new Intent( + com.android.onemedia.playback.RequestUtils.ACTION_PAUSE).setPackage(pkg), + PendingIntent.FLAG_CANCEL_CURRENT)); + mIntents.put(R.drawable.ic_play_arrow, PendingIntent.getBroadcast(mService, 100, + new Intent(com.android.onemedia.playback.RequestUtils.ACTION_PLAY).setPackage(pkg), + PendingIntent.FLAG_CANCEL_CURRENT)); + mIntents.put(R.drawable.ic_skip_previous, PendingIntent.getBroadcast(mService, 100, + new Intent(com.android.onemedia.playback.RequestUtils.ACTION_PREV).setPackage(pkg), + PendingIntent.FLAG_CANCEL_CURRENT)); + mIntents.put(R.drawable.ic_skip_next, PendingIntent.getBroadcast(mService, 100, + new Intent(com.android.onemedia.playback.RequestUtils.ACTION_NEXT).setPackage(pkg), + PendingIntent.FLAG_CANCEL_CURRENT)); + mIntents.put(R.drawable.ic_fast_rewind, PendingIntent.getBroadcast(mService, 100, + new Intent(com.android.onemedia.playback.RequestUtils.ACTION_REW).setPackage(pkg), + PendingIntent.FLAG_CANCEL_CURRENT)); + mIntents.put(R.drawable.ic_fast_forward, PendingIntent.getBroadcast(mService, 100, + new Intent(com.android.onemedia.playback.RequestUtils.ACTION_FFWD).setPackage(pkg), + PendingIntent.FLAG_CANCEL_CURRENT)); + } + + /** + * Posts the notification and starts tracking the session to keep it + * updated. The notification will automatically be removed if the session is + * destroyed before {@link #onStop} is called. + */ + public void onStart() { + mController.addCallback(mCb); + IntentFilter filter = new IntentFilter(); + filter.addAction(RequestUtils.ACTION_FFWD); + filter.addAction(RequestUtils.ACTION_NEXT); + filter.addAction(RequestUtils.ACTION_PAUSE); + filter.addAction(RequestUtils.ACTION_PLAY); + filter.addAction(RequestUtils.ACTION_PREV); + filter.addAction(RequestUtils.ACTION_REW); + mService.registerReceiver(this, filter); + + mMetadata = mController.getMetadata(); + mPlaybackState = mController.getPlaybackState(); + + mStarted = true; + // The notification must be updated after setting started to true + updateNotification(); + } + + /** + * Removes the notification and stops tracking the session. If the session + * was destroyed this has no effect. + */ + public void onStop() { + mStarted = false; + mController.removeCallback(mCb); + mService.unregisterReceiver(this); + updateNotification(); + } + + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + Log.d(TAG, "Received intent with action " + action); + if (RequestUtils.ACTION_PAUSE.equals(action)) { + mTransportControls.pause(); + } else if (RequestUtils.ACTION_PLAY.equals(action)) { + mTransportControls.play(); + } else if (RequestUtils.ACTION_NEXT.equals(action)) { + mTransportControls.skipToNext(); + } else if (RequestUtils.ACTION_PREV.equals(action)) { + mTransportControls.skipToPrevious(); + } else if (RequestUtils.ACTION_REW.equals(action)) { + mTransportControls.rewind(); + } else if (RequestUtils.ACTION_FFWD.equals(action)) { + mTransportControls.fastForward(); + } + + } + + private final MediaController.Callback mCb = new MediaController.Callback() { + @Override + public void onPlaybackStateChanged(PlaybackState state) { + mPlaybackState = state; + Log.d(TAG, "Received new playback state" + state); + updateNotification(); + } + + @Override + public void onMetadataChanged(MediaMetadata metadata) { + mMetadata = metadata; + Log.d(TAG, "Received new metadata " + metadata); + updateNotification(); + } + }; + + NotificationManager mNoMan = null; + + private void updateNotification() { + if (mNoMan == null) { + mNoMan = (NotificationManager) mService.getSystemService(Context.NOTIFICATION_SERVICE); + } + if (mPlaybackState == null) { + mNoMan.cancel(NOTIFICATION_ID); + return; + } + if (!mStarted) { + mNoMan.cancel(NOTIFICATION_ID); + return; + } + + String status; + final int state = mPlaybackState.getState(); + switch (state) { + case PlaybackState.STATE_PLAYING: + status = "PLAYING: "; + break; + case PlaybackState.STATE_PAUSED: + status = "PAUSED: "; + break; + case PlaybackState.STATE_STOPPED: + status = "STOPPED: "; + break; + case PlaybackState.STATE_ERROR: + status = "ERROR: "; + break; + case PlaybackState.STATE_BUFFERING: + status = "BUFFERING: "; + break; + case PlaybackState.STATE_NONE: + default: + status = ""; + break; + } + CharSequence title, text; + Bitmap art; + if (mMetadata == null) { + title = status; + text = "Empty metadata!"; + art = null; + } else { + MediaMetadata.Description description = mMetadata.getDescription(); + title = description.getTitle(); + text = description.getSubtitle(); + art = description.getIcon(); + } + + String playPauseLabel = ""; + int playPauseIcon; + if (state == PlaybackState.STATE_PLAYING) { + playPauseLabel = "Pause"; + playPauseIcon = R.drawable.ic_pause; + } else { + playPauseLabel = "Play"; + playPauseIcon = R.drawable.ic_play_arrow; + } + + final long pos = mPlaybackState.getPosition(); + final long end = mMetadata == null ? 0 : mMetadata + .getLong(MediaMetadata.METADATA_KEY_DURATION); + Notification notification = new Notification.Builder(mService) + .setSmallIcon(android.R.drawable.stat_notify_chat) + .setContentTitle(title) + .setContentText(text) + .setShowWhen(false) + .setContentInfo(DateUtils.formatElapsedTime(pos)) + .setProgress((int) end, (int) pos, false) + .setLargeIcon(art) + .addAction(R.drawable.ic_skip_previous, "Previous", + mIntents.get(R.drawable.ic_skip_previous)) + .addAction(R.drawable.ic_fast_rewind, "Rewind", + mIntents.get(R.drawable.ic_fast_rewind)) + .addAction(playPauseIcon, playPauseLabel, + mIntents.get(playPauseIcon)) + .addAction(R.drawable.ic_fast_forward, "Fast Forward", + mIntents.get(R.drawable.ic_fast_forward)) + .addAction(R.drawable.ic_skip_next, "Next", + mIntents.get(R.drawable.ic_skip_next)) + .setStyle(new Notification.MediaStyle() + .setShowActionsInCompactView(2) + .setMediaSession(mSession.getSessionToken())) + .setColor(0xFFDB4437) + .build(); + + mService.startForeground(NOTIFICATION_ID, notification); + } + +} diff --git a/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java b/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java new file mode 100644 index 0000000..2ff3e20 --- /dev/null +++ b/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java @@ -0,0 +1,234 @@ +/* + * 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; + + +import android.app.Activity; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.ComponentName; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.media.MediaMetadata; +import android.media.session.PlaybackState; +import android.net.Uri; +import android.os.Bundle; +import android.provider.MediaStore; +import android.text.format.DateUtils; +import android.util.Log; +import android.view.Menu; +import android.view.View; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.TextView; + +import java.io.IOException; + +public class OnePlayerActivity extends Activity { + private static final String TAG = "OnePlayerActivity"; + + private static final int READ_REQUEST_CODE = 42; + + protected PlayerController mPlayer; + + private Button mStartButton; + private Button mPlayButton; + private Button mRouteButton; + private TextView mStatusView; + + private EditText mContentText; + private EditText mNextContentText; + private CheckBox mHasVideo; + private ImageView mArtView; + + private PlaybackState mPlaybackState; + private Bitmap mAlbumArtBitmap; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_one_player); + mPlayer = new PlayerController(this, OnePlayerService.getServiceIntent(this)); + + + mStartButton = (Button) findViewById(R.id.start_button); + mPlayButton = (Button) findViewById(R.id.play_button); + mRouteButton = (Button) findViewById(R.id.route_button); + mStatusView = (TextView) findViewById(R.id.status); + mContentText = (EditText) findViewById(R.id.content); + mNextContentText = (EditText) findViewById(R.id.next_content); + mHasVideo = (CheckBox) findViewById(R.id.has_video); + mArtView = (ImageView) findViewById(R.id.art); + + final Button artPicker = (Button) findViewById(R.id.art_picker); + artPicker.setOnClickListener(mButtonListener); + + mStartButton.setOnClickListener(mButtonListener); + mPlayButton.setOnClickListener(mButtonListener); + mRouteButton.setOnClickListener(mButtonListener); + + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.main, menu); + return true; + } + + @Override + public void onResume() { + super.onResume(); + mPlayer.onResume(); + mPlayer.setListener(mListener); + } + + @Override + public void onPause() { + mPlayer.setListener(null); + mPlayer.onPause(); + super.onPause(); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, + Intent resultData) { + if (requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK) { + Uri uri = null; + if (resultData != null) { + uri = resultData.getData(); + Log.i(TAG, "Uri: " + uri.toString()); + mAlbumArtBitmap = null; + try { + mAlbumArtBitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri); + } catch (IOException e) { + Log.v(TAG, "Couldn't load album art", e); + } + mArtView.setImageBitmap(mAlbumArtBitmap); + if (mAlbumArtBitmap != null) { + mArtView.setVisibility(View.VISIBLE); + } else { + mArtView.setVisibility(View.GONE); + } + mPlayer.setArt(mAlbumArtBitmap); + } + } + } + + private void setControlsEnabled(boolean enabled) { + mStartButton.setEnabled(enabled); + mPlayButton.setEnabled(enabled); + } + + private View.OnClickListener mButtonListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + final int state = mPlaybackState.getState(); + switch (v.getId()) { + case R.id.play_button: + Log.d(TAG, "Play button pressed, in state " + state); + if (state == PlaybackState.STATE_PAUSED + || state == PlaybackState.STATE_STOPPED) { + mPlayer.play(); + } else if (state == PlaybackState.STATE_PLAYING) { + mPlayer.pause(); + } + break; + case R.id.start_button: + Log.d(TAG, "Start button pressed, in state " + state); + mPlayer.setContent(mContentText.getText().toString()); + break; + case R.id.route_button: + mPlayer.showRoutePicker(); + break; + case R.id.art_picker: + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("image/*"); + + startActivityForResult(intent, READ_REQUEST_CODE); + break; + } + + } + }; + + private PlayerController.Listener mListener = new PlayerController.Listener() { + public MediaMetadata mMetadata; + + @Override + public void onPlaybackStateChange(PlaybackState state) { + mPlaybackState = state; + boolean enablePlay = false; + boolean enableControls = true; + StringBuilder statusBuilder = new StringBuilder(); + switch (mPlaybackState.getState()) { + case PlaybackState.STATE_PLAYING: + statusBuilder.append("playing"); + mPlayButton.setText("Pause"); + enablePlay = true; + break; + case PlaybackState.STATE_PAUSED: + statusBuilder.append("paused"); + mPlayButton.setText("Play"); + enablePlay = true; + break; + case PlaybackState.STATE_STOPPED: + statusBuilder.append("ended"); + mPlayButton.setText("Play"); + enablePlay = true; + break; + case PlaybackState.STATE_ERROR: + statusBuilder.append("error: ").append(state.getErrorMessage()); + break; + case PlaybackState.STATE_BUFFERING: + statusBuilder.append("buffering"); + break; + case PlaybackState.STATE_NONE: + statusBuilder.append("none"); + break; + case PlaybackState.STATE_CONNECTING: + statusBuilder.append("connecting"); + enableControls = false; + break; + default: + statusBuilder.append(mPlaybackState); + } + statusBuilder.append(" -- At position: ").append(state.getPosition()); + mStatusView.setText(statusBuilder.toString()); + mPlayButton.setEnabled(enablePlay); + setControlsEnabled(enableControls); + } + + @Override + public void onConnectionStateChange(int state) { + if (state == PlayerController.STATE_DISCONNECTED) { + setControlsEnabled(false); + } else if (state == PlayerController.STATE_CONNECTED) { + setControlsEnabled(true); + } + } + + @Override + public void onMetadataChange(MediaMetadata metadata) { + mMetadata = metadata; + } + }; +} diff --git a/tests/OneMedia/src/com/android/onemedia/OnePlayerService.java b/tests/OneMedia/src/com/android/onemedia/OnePlayerService.java new file mode 100644 index 0000000..573f7ff --- /dev/null +++ b/tests/OneMedia/src/com/android/onemedia/OnePlayerService.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.onemedia; + +import android.content.Context; +import android.content.Intent; + +import java.util.ArrayList; + +public class OnePlayerService extends PlayerService { + private static final String TAG = "OnePlayerService"; + + public static Intent getServiceIntent(Context context) { + return new Intent(context, OnePlayerService.class).setPackage( + OnePlayerService.class.getPackage().getName()); + } + + @Override + protected Intent onCreateServiceIntent() { + return getServiceIntent(this); + } + + @Override + protected ArrayList<String> getAllowedPackages() { + ArrayList<String> allowedPackages = new ArrayList<String>(); + allowedPackages.add("com.android.onemedia"); + return allowedPackages; + } +} diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerController.java b/tests/OneMedia/src/com/android/onemedia/PlayerController.java new file mode 100644 index 0000000..c8d72ca --- /dev/null +++ b/tests/OneMedia/src/com/android/onemedia/PlayerController.java @@ -0,0 +1,234 @@ + +/* + * 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; + +import android.media.MediaMetadata; +import android.media.session.MediaController; +import android.media.session.MediaSession; +import android.media.session.MediaSessionManager; +import android.media.session.PlaybackState; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.RemoteException; +import android.app.Activity; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.graphics.Bitmap; +import android.util.Log; + +import com.android.onemedia.playback.RequestUtils; + +public class PlayerController { + private static final String TAG = "PlayerController"; + + public static final int STATE_DISCONNECTED = 0; + public static final int STATE_CONNECTED = 1; + + protected MediaController mController; + protected IPlayerService mBinder; + protected MediaController.TransportControls mTransportControls; + + private final Intent mServiceIntent; + private Activity mContext; + private Listener mListener; + private SessionCallback mControllerCb; + private MediaSessionManager mManager; + private Handler mHandler = new Handler(); + + private boolean mResumed; + private Bitmap mArt; + + public PlayerController(Activity context, Intent serviceIntent) { + mContext = context; + if (serviceIntent == null) { + mServiceIntent = new Intent(mContext, PlayerService.class); + } else { + mServiceIntent = serviceIntent; + } + mControllerCb = new SessionCallback(); + mManager = (MediaSessionManager) context + .getSystemService(Context.MEDIA_SESSION_SERVICE); + + mResumed = false; + } + + public void setListener(Listener listener) { + mListener = listener; + Log.d(TAG, "Listener set to " + listener + " session is " + mController); + if (mListener != null) { + mHandler = new Handler(); + mListener.onConnectionStateChange( + mController == null ? STATE_DISCONNECTED : STATE_CONNECTED); + } + } + + public void onResume() { + mResumed = true; + Log.d(TAG, "onResume. Binding to service with intent " + mServiceIntent.toString()); + bindToService(); + } + + public void onPause() { + mResumed = false; + Log.d(TAG, "onPause, unbinding from service"); + unbindFromService(); + } + + public void setArt(Bitmap art) { + mArt = art; + if (mBinder != null) { + try { + mBinder.setIcon(art); + } catch (RemoteException e) { + } + } + } + + public void play() { + if (mTransportControls != null) { + mTransportControls.play(); + } + } + + public void pause() { + if (mTransportControls != null) { + mTransportControls.pause(); + } + } + + public void setContent(String source) { + RequestUtils.ContentBuilder bob = new RequestUtils.ContentBuilder(); + bob.setSource(source); + try { + mBinder.sendRequest(RequestUtils.ACTION_SET_CONTENT, bob.build(), null); + } catch (RemoteException e) { + Log.d(TAG, "setContent failed, service may have died.", e); + } + } + + public void setNextContent(String source) { + RequestUtils.ContentBuilder bob = new RequestUtils.ContentBuilder(); + bob.setSource(source); + try { + mBinder.sendRequest(RequestUtils.ACTION_SET_NEXT_CONTENT, bob.build(), null); + } catch (RemoteException e) { + Log.d(TAG, "setNexctContent failed, service may have died.", e); + } + } + + public void showRoutePicker() { + // TODO + } + + public MediaSession.Token getSessionToken() { + if (mBinder != null) { + try { + return mBinder.getSessionToken(); + } catch (RemoteException e) { + } + } + return null; + } + + private void unbindFromService() { + mContext.unbindService(mServiceConnection); + } + + private void bindToService() { + mContext.bindService(mServiceIntent, mServiceConnection, Context.BIND_AUTO_CREATE); + } + + private ServiceConnection mServiceConnection = new ServiceConnection() { + @Override + public void onServiceDisconnected(ComponentName name) { + if (mController != null) { + mController.removeCallback(mControllerCb); + } + mBinder = null; + mController = null; + mTransportControls = null; + mContext.setMediaController(null); + Log.d(TAG, "Disconnected from PlayerService"); + + if (mListener != null) { + mListener.onConnectionStateChange(STATE_DISCONNECTED); + } + } + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + mBinder = IPlayerService.Stub.asInterface(service); + Log.d(TAG, "service is " + service + " binder is " + mBinder); + MediaSession.Token token; + try { + token = mBinder.getSessionToken(); + } catch (RemoteException e) { + Log.e(TAG, "Error getting session", e); + return; + } + mController = new MediaController(mContext, token); + mContext.setMediaController(mController); + mController.addCallback(mControllerCb, mHandler); + mTransportControls = mController.getTransportControls(); + if (mArt != null) { + setArt(mArt); + } + Log.d(TAG, "Ready to use PlayerService"); + + if (mListener != null) { + mListener.onConnectionStateChange(STATE_CONNECTED); + if (mTransportControls != null) { + mListener.onPlaybackStateChange(mController.getPlaybackState()); + } + } + } + }; + + private class SessionCallback extends MediaController.Callback { + @Override + public void onPlaybackStateChanged(PlaybackState state) { + if (state == null) { + return; + } + Log.d(TAG, "Received playback state change to state " + state.getState()); + if (mListener != null) { + mListener.onPlaybackStateChange(state); + } + } + + @Override + public void onMetadataChanged(MediaMetadata metadata) { + if (metadata == null) { + return; + } + Log.d(TAG, "Received metadata change, " + metadata.getDescription()); + if (mListener != null) { + mListener.onMetadataChange(metadata); + } + } + } + + public interface Listener { + public void onPlaybackStateChange(PlaybackState state); + public void onMetadataChange(MediaMetadata metadata); + public void onConnectionStateChange(int state); + } + +} diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerService.java b/tests/OneMedia/src/com/android/onemedia/PlayerService.java new file mode 100644 index 0000000..9967c99 --- /dev/null +++ b/tests/OneMedia/src/com/android/onemedia/PlayerService.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.android.onemedia; + +import android.app.Service; +import android.content.Intent; +import android.graphics.Bitmap; +import android.media.session.MediaSession; +import android.media.session.PlaybackState; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import com.android.onemedia.playback.IRequestCallback; +import com.android.onemedia.playback.RequestUtils; + +import java.util.ArrayList; + +public class PlayerService extends Service { + private static final String TAG = "PlayerService"; + + private PlayerBinder mBinder; + private PlayerSession mSession; + private NotificationHelper mNotifyHelper; + private Intent mIntent; + private boolean mStarted = false; + + private ArrayList<IPlayerCallback> mCbs = new ArrayList<IPlayerCallback>(); + + @Override + public void onCreate() { + Log.d(TAG, "onCreate"); + mIntent = onCreateServiceIntent(); + if (mSession == null) { + mSession = onCreatePlayerController(); + mSession.createSession(); + mSession.setListener(mPlayerListener); + mNotifyHelper = new NotificationHelper(this, mSession.mSession); + } + } + + @Override + public IBinder onBind(Intent intent) { + if (mBinder == null) { + mBinder = new PlayerBinder(); + } + return mBinder; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Log.d(TAG, "onStartCommand"); + return START_STICKY; + } + + @Override + public void onDestroy() { + Log.d(TAG, "onDestroy"); + mSession.onDestroy(); + mSession = null; + } + + public void onPlaybackStarted() { + if (!mStarted) { + Log.d(TAG, "Starting self"); + startService(onCreateServiceIntent()); + mNotifyHelper.onStart(); + mStarted = true; + } + } + + public void onPlaybackEnded() { + if (mStarted) { + Log.d(TAG, "Stopping self"); + mNotifyHelper.onStop(); + stopSelf(); + mStarted = false; + } + } + + protected Intent onCreateServiceIntent() { + return new Intent(this, PlayerService.class).setPackage(getBasePackageName()); + } + + protected PlayerSession onCreatePlayerController() { + return new PlayerSession(this); + } + + protected ArrayList<String> getAllowedPackages() { + return null; + } + + private final PlayerSession.Listener mPlayerListener = new PlayerSession.Listener() { + @Override + public void onPlayStateChanged(PlaybackState state) { + switch (state.getState()) { + case PlaybackState.STATE_PLAYING: + onPlaybackStarted(); + break; + case PlaybackState.STATE_STOPPED: + case PlaybackState.STATE_ERROR: + onPlaybackEnded(); + break; + } + } + }; + + public class PlayerBinder extends IPlayerService.Stub { + @Override + public void sendRequest(String action, Bundle params, IRequestCallback cb) { + if (RequestUtils.ACTION_SET_CONTENT.equals(action)) { + mSession.setContent(params); + } else if (RequestUtils.ACTION_SET_NEXT_CONTENT.equals(action)) { + mSession.setNextContent(params); + } + } + + @Override + public void registerCallback(final IPlayerCallback cb) throws RemoteException { + if (!mCbs.contains(cb)) { + mCbs.add(cb); + cb.asBinder().linkToDeath(new IBinder.DeathRecipient() { + @Override + public void binderDied() { + mCbs.remove(cb); + } + }, 0); + } + try { + cb.onSessionChanged(getSessionToken()); + } catch (RemoteException e) { + mCbs.remove(cb); + throw e; + } + } + + @Override + public void unregisterCallback(IPlayerCallback cb) throws RemoteException { + mCbs.remove(cb); + } + + @Override + public MediaSession.Token getSessionToken() throws RemoteException { + if (mSession == null) { + Log.e(TAG, "Error in PlayerService: mSession=null in getSessionToken()"); + return null; + } + return mSession.getSessionToken(); + } + + @Override + public void setIcon(Bitmap icon) { + mSession.setIcon(icon); + } + } + +} diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java new file mode 100644 index 0000000..8b7c883 --- /dev/null +++ b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java @@ -0,0 +1,245 @@ +/* + * 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; + +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.media.MediaMetadata; +import android.media.session.MediaSession; +import android.media.session.MediaSessionManager; +import android.media.session.PlaybackState; +import android.os.Bundle; +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.Renderer; +import com.android.onemedia.playback.RequestUtils; + +import java.util.ArrayList; +import java.util.List; + +public class PlayerSession { + private static final String TAG = "PlayerSession"; + + protected MediaSession mSession; + protected Context mContext; + protected Renderer mRenderer; + protected MediaSession.Callback mCallback; + protected Renderer.Listener mRenderListener; + protected MediaMetadata.Builder mMetadataBuilder; + + protected PlaybackState mPlaybackState; + protected Listener mListener; + + private String mContent; + + public PlayerSession(Context context) { + mContext = context; + mRenderer = new LocalRenderer(context, null); + mCallback = new SessionCb(); + mRenderListener = new RenderListener(); + PlaybackState.Builder psBob = new PlaybackState.Builder(); + psBob.setActions(PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_PLAY); + mPlaybackState = psBob.build(); + + mRenderer.registerListener(mRenderListener); + + initMetadata(); + } + + public void createSession() { + releaseSession(); + + MediaSessionManager man = (MediaSessionManager) mContext + .getSystemService(Context.MEDIA_SESSION_SERVICE); + Log.d(TAG, "Creating session for package " + mContext.getBasePackageName()); + + mSession = new MediaSession(mContext, "OneMedia"); + mSession.setCallback(mCallback); + mSession.setPlaybackState(mPlaybackState); + mSession.setFlags(MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS + | MediaSession.FLAG_HANDLES_MEDIA_BUTTONS); + mSession.setActive(true); + updateMetadata(); + } + + public void onDestroy() { + releaseSession(); + if (mRenderer != null) { + mRenderer.unregisterListener(mRenderListener); + mRenderer.onDestroy(); + } + } + + private void releaseSession() { + if (mSession != null) { + mSession.release(); + mSession = null; + } + } + + public void setListener(Listener listener) { + mListener = listener; + } + + public MediaSession.Token getSessionToken() { + return mSession.getSessionToken(); + } + + public void setContent(Bundle request) { + mRenderer.setContent(request); + mContent = request.getString(RequestUtils.EXTRA_KEY_SOURCE); + } + + public void setNextContent(Bundle request) { + mRenderer.setNextContent(request); + } + + public void setIcon(Bitmap icon) { + mMetadataBuilder.putBitmap(MediaMetadata.METADATA_KEY_DISPLAY_ICON, icon); + updateMetadata(); + } + + private void updateMetadata() { + // This is a mild abuse of metadata and shouldn't be duplicated in real + // code + if (mSession != null && mSession.isActive()) { + mSession.setMetadata(mMetadataBuilder.build()); + } + } + + private void updateState(int newState) { + float rate = newState == PlaybackState.STATE_PLAYING ? 1 : 0; + long position = mRenderer == null ? -1 : mRenderer.getSeekPosition(); + PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState); + bob.setState(newState, position, rate, SystemClock.elapsedRealtime()); + bob.setErrorMessage(null); + mPlaybackState = bob.build(); + mSession.setPlaybackState(mPlaybackState); + } + + private void initMetadata() { + mMetadataBuilder = new MediaMetadata.Builder(); + mMetadataBuilder.putString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE, + "OneMedia display title"); + mMetadataBuilder.putString(MediaMetadata.METADATA_KEY_DISPLAY_SUBTITLE, + "OneMedia display subtitle"); + } + + public interface Listener { + public void onPlayStateChanged(PlaybackState state); + } + + 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); + PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState); + bob.setState(PlaybackState.STATE_ERROR, -1, 0, 0); + if (error != null) { + bob.setErrorMessage(error.getLocalizedMessage()); + } + mPlaybackState = bob.build(); + mSession.setPlaybackState(mPlaybackState); + if (mListener != null) { + mListener.onPlayStateChanged(mPlaybackState); + } + } + + @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(); + mSession.setPlaybackState(mPlaybackState); + if (mListener != null) { + mListener.onPlayStateChanged(mPlaybackState); + } + } + + @Override + public void onBufferingUpdate(int percent) { + } + + @Override + public void onFocusLost() { + Log.d(TAG, "Focus lost, changing state to " + Renderer.STATE_PAUSED); + long position = mRenderer == null ? -1 : mRenderer.getSeekPosition(); + PlaybackState.Builder bob = new PlaybackState.Builder(mPlaybackState); + bob.setState(PlaybackState.STATE_PAUSED, position, 0, SystemClock.elapsedRealtime()); + bob.setErrorMessage(null); + mPlaybackState = bob.build(); + mSession.setPlaybackState(mPlaybackState); + if (mListener != null) { + mListener.onPlayStateChanged(mPlaybackState); + } + } + + @Override + public void onNextStarted() { + } + + } + + private class SessionCb extends MediaSession.Callback { + @Override + public void onPlay() { + mRenderer.onPlay(); + } + + @Override + public void onPause() { + mRenderer.onPause(); + } + } +} diff --git a/tests/OneMedia/src/com/android/onemedia/playback/IRequestCallback.aidl b/tests/OneMedia/src/com/android/onemedia/playback/IRequestCallback.aidl new file mode 100644 index 0000000..c5a30a8 --- /dev/null +++ b/tests/OneMedia/src/com/android/onemedia/playback/IRequestCallback.aidl @@ -0,0 +1,22 @@ +/* Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.onemedia.playback; + +import android.os.Bundle; + +oneway interface IRequestCallback { + void onResult(in Bundle result); +}
\ No newline at end of file diff --git a/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java b/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java new file mode 100644 index 0000000..c8a8d6c --- /dev/null +++ b/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java @@ -0,0 +1,721 @@ +/* + * 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.playback; + +import org.apache.http.Header; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; + +import android.content.Context; +import android.media.AudioManager; +import android.media.AudioManager.OnAudioFocusChangeListener; +import android.media.MediaPlayer; +import android.media.MediaPlayer.OnBufferingUpdateListener; +import android.media.MediaPlayer.OnCompletionListener; +import android.media.MediaPlayer.OnErrorListener; +import android.media.MediaPlayer.OnPreparedListener; +import android.net.Uri; +import android.net.http.AndroidHttpClient; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.util.Log; +import android.view.SurfaceHolder; + +import java.io.IOException; +import java.util.Map; + +/** + * Helper class for wrapping a MediaPlayer and doing a lot of the default work + * to play audio. This class is not currently thread safe and all calls to it + * should be made on the same thread. + */ +public class LocalRenderer extends Renderer implements OnPreparedListener, + OnBufferingUpdateListener, OnCompletionListener, OnErrorListener, + OnAudioFocusChangeListener { + private static final String TAG = "MediaPlayerManager"; + private static final boolean DEBUG = true; + private static long sDebugInstanceId = 0; + + private static final String[] SUPPORTED_FEATURES = { + FEATURE_SET_CONTENT, + FEATURE_SET_NEXT_CONTENT, + FEATURE_PLAY, + FEATURE_PAUSE, + FEATURE_NEXT, + FEATURE_PREVIOUS, + FEATURE_SEEK_TO, + FEATURE_STOP + }; + + /** + * These are the states where it is valid to call play directly on the + * MediaPlayer. + */ + private static final int CAN_PLAY = STATE_READY | STATE_PAUSED | STATE_ENDED; + /** + * These are the states where we expect the MediaPlayer to be ready in the + * future, so we can set a flag to start playing when it is. + */ + private static final int CAN_READY_PLAY = STATE_INIT | STATE_PREPARING; + /** + * The states when it is valid to call pause on the MediaPlayer. + */ + private static final int CAN_PAUSE = STATE_PLAYING; + /** + * The states where it is valid to call seek on the MediaPlayer. + */ + private static final int CAN_SEEK = STATE_READY | STATE_PLAYING | STATE_PAUSED | STATE_ENDED; + /** + * The states where we expect the MediaPlayer to be ready in the future and + * can store a seek position to set later. + */ + private static final int CAN_READY_SEEK = STATE_INIT | STATE_PREPARING; + /** + * The states where it is valid to call stop on the MediaPlayer. + */ + private static final int CAN_STOP = STATE_READY | STATE_PLAYING | STATE_PAUSED | STATE_ENDED; + /** + * The states where it is valid to get the current play position and the + * duration from the MediaPlayer. + */ + private static final int CAN_GET_POSITION = STATE_READY | STATE_PLAYING | STATE_PAUSED; + + + + private class PlayerContent { + public final String source; + public final Map<String, String> headers; + + public PlayerContent(String source, Map<String, String> headers) { + this.source = source; + this.headers = headers; + } + } + + private class AsyncErrorRetriever extends AsyncTask<HttpGet, Void, Void> { + private final long errorId; + private boolean closeHttpClient; + + public AsyncErrorRetriever(long errorId) { + this.errorId = errorId; + closeHttpClient = false; + } + + public boolean cancelRequestLocked(boolean closeHttp) { + closeHttpClient = closeHttp; + return this.cancel(false); + } + + @Override + protected Void doInBackground(HttpGet[] params) { + synchronized (mErrorLock) { + if (isCancelled() || mHttpClient == null) { + if (mErrorRetriever == this) { + mErrorRetriever = null; + } + return null; + } + mSafeToCloseClient = false; + } + final PlaybackError error = new PlaybackError(); + try { + HttpResponse response = mHttpClient.execute(params[0]); + synchronized (mErrorLock) { + if (mErrorId != errorId || mError == null) { + // A new error has occurred, abort + return null; + } + error.type = mError.type; + error.extra = mError.extra; + error.errorMessage = mError.errorMessage; + } + final int code = response.getStatusLine().getStatusCode(); + if (code >= 300) { + error.extra = code; + } + final Bundle errorExtras = new Bundle(); + Header[] headers = response.getAllHeaders(); + if (headers != null && headers.length > 0) { + for (Header header : headers) { + errorExtras.putString(header.getName(), header.getValue()); + } + error.errorExtras = errorExtras; + } + } catch (IOException e) { + Log.e(TAG, "IOException requesting from server, unable to get more exact error"); + } finally { + synchronized (mErrorLock) { + mSafeToCloseClient = true; + if (mErrorRetriever == this) { + mErrorRetriever = null; + } + if (isCancelled()) { + if (closeHttpClient) { + mHttpClient.close(); + mHttpClient = null; + } + return null; + } + } + } + mHandler.post(new Runnable() { + @Override + public void run() { + synchronized (mErrorLock) { + if (mErrorId == errorId) { + setError(error.type, error.extra, error.errorExtras, null); + } + } + } + }); + return null; + } + } + + private int mState = STATE_INIT; + + private AudioManager mAudioManager; + private MediaPlayer mPlayer; + private PlayerContent mContent; + private MediaPlayer mNextPlayer; + private PlayerContent mNextContent; + private SurfaceHolder mHolder; + private SurfaceHolder.Callback mHolderCB; + private Context mContext; + + private Handler mHandler = new Handler(); + + private AndroidHttpClient mHttpClient = AndroidHttpClient.newInstance("TUQ"); + // The ongoing error request thread if there is one. This should only be + // modified while mErrorLock is held. + private AsyncErrorRetriever mErrorRetriever; + // This is set to false while a server request is being made to retrieve + // the current error. It should only be set while mErrorLock is held. + private boolean mSafeToCloseClient = true; + private final Object mErrorLock = new Object(); + // A tracking id for the current error. This should only be modified while + // mErrorLock is held. + private long mErrorId = 0; + // The current error state of this player. This is cleared when the state + // leaves an error state and set when it enters one. This should only be + // modified when mErrorLock is held. + private PlaybackError mError; + + private boolean mPlayOnReady; + private int mSeekOnReady; + private boolean mHasAudioFocus; + private long mDebugId = sDebugInstanceId++; + + public LocalRenderer(Context context, Bundle params) { + super(context, params); + mContext = context; + mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + } + + @Override + protected void initFeatures(Bundle params) { + for (String feature : SUPPORTED_FEATURES) { + mFeatures.add(feature); + } + } + + /** + * Call this when completely finished with the MediaPlayerManager to have it + * clean up. The instance may not be used again after this is called. + */ + @Override + public void onDestroy() { + synchronized (mErrorLock) { + if (DEBUG) { + Log.d(TAG, "onDestroy, error retriever? " + mErrorRetriever + " safe to close? " + + mSafeToCloseClient + " client? " + mHttpClient); + } + if (mErrorRetriever != null) { + mErrorRetriever.cancelRequestLocked(true); + mErrorRetriever = null; + } + // Increment the error id to ensure no errors are sent after this + // point. + mErrorId++; + if (mSafeToCloseClient) { + mHttpClient.close(); + mHttpClient = null; + } + } + } + + @Override + public void onPrepared(MediaPlayer player) { + if (!isCurrentPlayer(player)) { + return; + } + setState(STATE_READY); + if (DEBUG) { + Log.d(TAG, mDebugId + ": Finished preparing, seekOnReady is " + mSeekOnReady); + } + if (mSeekOnReady >= 0) { + onSeekTo(mSeekOnReady); + mSeekOnReady = -1; + } + if (mPlayOnReady) { + player.start(); + setState(STATE_PLAYING); + } + } + + @Override + public void onBufferingUpdate(MediaPlayer player, int percent) { + if (!isCurrentPlayer(player)) { + return; + } + pushOnBufferingUpdate(percent); + } + + @Override + public void onCompletion(MediaPlayer player) { + if (!isCurrentPlayer(player)) { + return; + } + if (DEBUG) { + Log.d(TAG, mDebugId + ": Completed item. Have next item? " + (mNextPlayer != null)); + } + if (mNextPlayer != null) { + if (mPlayer != null) { + mPlayer.release(); + } + mPlayer = mNextPlayer; + mContent = mNextContent; + mNextPlayer = null; + mNextContent = null; + pushOnNextStarted(); + return; + } + setState(STATE_ENDED); + } + + @Override + public boolean onError(MediaPlayer player, int what, int extra) { + if (!isCurrentPlayer(player)) { + return false; + } + if (DEBUG) { + Log.d(TAG, mDebugId + ": Entered error state, what: " + what + " extra: " + extra); + } + synchronized (mErrorLock) { + ++mErrorId; + mError = new PlaybackError(); + mError.type = what; + mError.extra = extra; + } + + if (what == MediaPlayer.MEDIA_ERROR_UNKNOWN && extra == MediaPlayer.MEDIA_ERROR_IO + && mContent != null && mContent.source.startsWith("http")) { + HttpGet request = new HttpGet(mContent.source); + if (mContent.headers != null) { + for (String key : mContent.headers.keySet()) { + request.addHeader(key, mContent.headers.get(key)); + } + } + synchronized (mErrorLock) { + if (mErrorRetriever != null) { + mErrorRetriever.cancelRequestLocked(false); + } + mErrorRetriever = new AsyncErrorRetriever(mErrorId); + mErrorRetriever.execute(request); + } + } else { + setError(what, extra, null, null); + } + return true; + } + + @Override + public void onAudioFocusChange(int focusChange) { + // TODO figure out appropriate logic for handling focus loss at the TUQ + // level. + switch (focusChange) { + case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: + case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: + if (mState == STATE_PLAYING) { + onPause(); + mPlayOnReady = true; + } + mHasAudioFocus = false; + break; + case AudioManager.AUDIOFOCUS_LOSS: + if (mState == STATE_PLAYING) { + onPause(); + mPlayOnReady = false; + } + pushOnFocusLost(); + mHasAudioFocus = false; + break; + case AudioManager.AUDIOFOCUS_GAIN: + mHasAudioFocus = true; + if (mPlayOnReady) { + onPlay(); + } + break; + default: + Log.d(TAG, "Unknown focus change event " + focusChange); + break; + } + } + + @Override + public void setContent(Bundle request) { + setContent(request, null); + } + + /** + * Prepares the player for the given playback request. If the holder is null + * it is assumed this is an audio only source. If playOnReady is set to true + * the media will begin playing as soon as it can. + * + * @see RequestUtils for the set of valid keys. + */ + public void setContent(Bundle request, SurfaceHolder holder) { + String source = request.getString(RequestUtils.EXTRA_KEY_SOURCE); + Map<String, String> headers = null; // request.mHeaders; + boolean playOnReady = true; // request.mPlayOnReady; + if (DEBUG) { + Log.d(TAG, mDebugId + ": Settings new content. Have a player? " + (mPlayer != null) + + " have a next player? " + (mNextPlayer != null)); + } + cleanUpPlayer(); + setState(STATE_PREPARING); + mPlayOnReady = playOnReady; + mSeekOnReady = -1; + final MediaPlayer newPlayer = new MediaPlayer(); + + requestAudioFocus(); + + mPlayer = newPlayer; + mContent = new PlayerContent(source, headers); + try { + if (headers != null) { + Uri sourceUri = Uri.parse(source); + newPlayer.setDataSource(mContext, sourceUri, headers); + } else { + newPlayer.setDataSource(source); + } + } catch (Exception e) { + setError(Listener.ERROR_LOAD_FAILED, 0, null, e); + return; + } + if (isHolderReady(holder, newPlayer)) { + preparePlayer(newPlayer, true); + } + } + + @Override + public void setNextContent(Bundle request) { + String source = request.getString(RequestUtils.EXTRA_KEY_SOURCE); + Map<String, String> headers = null; // request.mHeaders; + + // TODO support video + + if (DEBUG) { + Log.d(TAG, mDebugId + ": Setting next content. Have player? " + (mPlayer != null) + + " have next player? " + (mNextPlayer != null)); + } + + if (mPlayer == null) { + // The manager isn't being used to play anything, don't try to + // set a next. + return; + } + if (mNextPlayer != null) { + // Before setting up the new one clear out the old one and release + // it to ensure it doesn't play. + mPlayer.setNextMediaPlayer(null); + mNextPlayer.release(); + mNextPlayer = null; + mNextContent = null; + } + if (source == null) { + // If there's no new content we're done + return; + } + final MediaPlayer newPlayer = new MediaPlayer(); + + try { + if (headers != null) { + Uri sourceUri = Uri.parse(source); + newPlayer.setDataSource(mContext, sourceUri, headers); + } else { + newPlayer.setDataSource(source); + } + } catch (Exception e) { + newPlayer.release(); + // Don't return an error until we get to this item in playback + return; + } + + if (preparePlayer(newPlayer, false)) { + mPlayer.setNextMediaPlayer(newPlayer); + mNextPlayer = newPlayer; + mNextContent = new PlayerContent(source, headers); + } + } + + private void requestAudioFocus() { + int result = mAudioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, + AudioManager.AUDIOFOCUS_GAIN); + mHasAudioFocus = result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED; + } + + /** + * Start the player if possible or queue it to play when ready. If the + * player is in a state where it will never be ready returns false. + * + * @return true if the content was started or will be started later + */ + @Override + public boolean onPlay() { + MediaPlayer player = mPlayer; + if (player != null && mState == STATE_PLAYING) { + // already playing, just return + return true; + } + if (!mHasAudioFocus) { + requestAudioFocus(); + } + if (player != null && canPlay()) { + player.start(); + setState(STATE_PLAYING); + } else if (canReadyPlay()) { + mPlayOnReady = true; + } else if (!isPlaying()) { + return false; + } + return true; + } + + /** + * Pause the player if possible or set it to not play when ready. If the + * player is in a state where it will never be ready returns false. + * + * @return true if the content was paused or will wait to play when ready + * later + */ + @Override + public boolean onPause() { + MediaPlayer player = mPlayer; + // If the user paused us make sure we won't start playing again until + // asked to + mPlayOnReady = false; + if (player != null && (mState & CAN_PAUSE) != 0) { + player.pause(); + setState(STATE_PAUSED); + } else if (!isPaused()) { + return false; + } + return true; + } + + /** + * Seek to a given position in the media. If the seek succeeded or will be + * performed when loading is complete returns true. If the position is not + * in range or the player will never be ready returns false. + * + * @param position The position to seek to in milliseconds + * @return true if playback was moved or will be moved when ready + */ + @Override + public boolean onSeekTo(int position) { + MediaPlayer player = mPlayer; + if (player != null && (mState & CAN_SEEK) != 0) { + if (position < 0 || position >= getDuration()) { + return false; + } else { + if (mState == STATE_ENDED) { + player.start(); + player.pause(); + setState(STATE_PAUSED); + } + player.seekTo(position); + } + } else if ((mState & CAN_READY_SEEK) != 0) { + mSeekOnReady = position; + } else { + return false; + } + return true; + } + + /** + * Stop the player. It cannot be used again until + * {@link #setContent(String, boolean)} is called. + * + * @return true if stopping the player succeeded + */ + @Override + public boolean onStop() { + cleanUpPlayer(); + setState(STATE_STOPPED); + return true; + } + + public boolean isPlaying() { + return mState == STATE_PLAYING; + } + + public boolean isPaused() { + return mState == STATE_PAUSED; + } + + @Override + public long getSeekPosition() { + return ((mState & CAN_GET_POSITION) == 0) ? -1 : mPlayer.getCurrentPosition(); + } + + @Override + public long getDuration() { + return ((mState & CAN_GET_POSITION) == 0) ? -1 : mPlayer.getDuration(); + } + + private boolean canPlay() { + return ((mState & CAN_PLAY) != 0) && mHasAudioFocus; + } + + private boolean canReadyPlay() { + return (mState & CAN_PLAY) != 0 || (mState & CAN_READY_PLAY) != 0; + } + + /** + * Sends a state update if the listener exists + */ + private void setState(int state) { + if (state == mState) { + return; + } + Log.d(TAG, "Entering state " + state + " from state " + mState); + mState = state; + if (state != STATE_ERROR) { + // Don't notify error here, it'll get sent via onError + pushOnStateChanged(state); + } + } + + private boolean preparePlayer(final MediaPlayer player, boolean current) { + player.setOnPreparedListener(this); + player.setOnBufferingUpdateListener(this); + player.setOnCompletionListener(this); + player.setOnErrorListener(this); + try { + player.prepareAsync(); + if (current) { + setState(STATE_PREPARING); + } + } catch (IllegalStateException e) { + if (current) { + setError(Listener.ERROR_PREPARE_ERROR, 0, null, e); + } + return false; + } + return true; + } + + /** + * @param extra + * @param e + */ + private void setError(int type, int extra, Bundle extras, Exception e) { + setState(STATE_ERROR); + pushOnError(type, extra, extras, e); + cleanUpPlayer(); + return; + } + + /** + * Checks if the holder is ready and either sets up a callback to wait for + * it or sets it directly. If + * + * @param holder + * @param player + * @return + */ + private boolean isHolderReady(final SurfaceHolder holder, final MediaPlayer player) { + mHolder = holder; + if (holder != null) { + if (holder.getSurface() != null && holder.getSurface().isValid()) { + player.setDisplay(holder); + return true; + } else { + Log.w(TAG, "Holder not null, waiting for it to be ready"); + // If the holder isn't ready yet add a callback to set the + // holder when it's ready. + SurfaceHolder.Callback cb = new SurfaceHolder.Callback() { + @Override + public void surfaceDestroyed(SurfaceHolder arg0) { + } + + @Override + public void surfaceCreated(SurfaceHolder arg0) { + if (player.equals(mPlayer)) { + player.setDisplay(arg0); + preparePlayer(player, true); + } + } + + @Override + public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { + } + }; + mHolderCB = cb; + holder.addCallback(cb); + return false; + } + } + return true; + } + + private void cleanUpPlayer() { + if (DEBUG) { + Log.d(TAG, mDebugId + ": Cleaning up current player"); + } + synchronized (mErrorLock) { + mError = null; + if (mErrorRetriever != null) { + mErrorRetriever.cancelRequestLocked(false); + // Don't set to null as we may need to cancel again with true if + // the object gets destroyed. + } + } + mAudioManager.abandonAudioFocus(this); + + SurfaceHolder.Callback cb = mHolderCB; + mHolderCB = null; + SurfaceHolder holder = mHolder; + mHolder = null; + if (holder != null && cb != null) { + holder.removeCallback(cb); + } + + MediaPlayer player = mPlayer; + mPlayer = null; + if (player != null) { + player.reset(); + player.release(); + } + } + + private boolean isCurrentPlayer(MediaPlayer player) { + return player.equals(mPlayer); + } +} diff --git a/tests/OneMedia/src/com/android/onemedia/playback/MediaItem.java b/tests/OneMedia/src/com/android/onemedia/playback/MediaItem.java new file mode 100644 index 0000000..c133325 --- /dev/null +++ b/tests/OneMedia/src/com/android/onemedia/playback/MediaItem.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.onemedia.playback; + +import android.media.MediaMetadata; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * TODO: Insert description here. (generated by epastern) + */ +public class MediaItem implements Parcelable { + private Bundle mBundle; + + public MediaItem() { + + } + + private MediaItem(Parcel in) { + mBundle = in.readBundle(); + } + + public String getTitle() { + return mBundle.getString(MediaMetadata.METADATA_KEY_TITLE); + } + + public String getArtist() { + return mBundle.getString(MediaMetadata.METADATA_KEY_ALBUM_ARTIST); + } + + /* (non-Javadoc) + * @see android.os.Parcelable#describeContents() + */ + @Override + public int describeContents() { + // TODO(epastern): Auto-generated method stub + return 0; + } + + /* + * (non-Javadoc) + * @see android.os.Parcelable#writeToParcel(android.os.Parcel, int) + */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeBundle(mBundle); + } + + public static final Parcelable.Creator<MediaItem> CREATOR + = new Parcelable.Creator<MediaItem>() { + public MediaItem createFromParcel(Parcel in) { + return new MediaItem(in); + } + + public MediaItem[] newArray(int size) { + return new MediaItem[size]; + } + }; + +} diff --git a/tests/OneMedia/src/com/android/onemedia/playback/PlaybackError.java b/tests/OneMedia/src/com/android/onemedia/playback/PlaybackError.java new file mode 100644 index 0000000..ac9da23 --- /dev/null +++ b/tests/OneMedia/src/com/android/onemedia/playback/PlaybackError.java @@ -0,0 +1,25 @@ +/* + * 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.playback; + +import android.os.Bundle; + +public class PlaybackError { + public int type; + public int extra; + public String errorMessage; + public Bundle errorExtras; +} diff --git a/tests/OneMedia/src/com/android/onemedia/playback/Renderer.java b/tests/OneMedia/src/com/android/onemedia/playback/Renderer.java new file mode 100644 index 0000000..09debcf --- /dev/null +++ b/tests/OneMedia/src/com/android/onemedia/playback/Renderer.java @@ -0,0 +1,229 @@ +/* + * 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.playback; + +import android.content.Context; +import android.media.MediaPlayer; +import android.os.Bundle; + +import java.util.ArrayList; +import java.util.List; + +/** + * TODO: Insert description here. (generated by epastern) + */ +public abstract class Renderer { + public static final String FEATURE_SET_CONTENT = "com.android.media.SET_CONTENT"; + public static final String FEATURE_SET_NEXT_CONTENT = "com.android.media.SET_NEXT_CONTENT"; + public static final String FEATURE_PLAY = "com.android.media.PLAY"; + public static final String FEATURE_PAUSE = "com.android.media.PAUSE"; + public static final String FEATURE_NEXT = "com.android.media.NEXT"; + public static final String FEATURE_PREVIOUS = "com.android.media.PREVIOUS"; + public static final String FEATURE_SEEK_TO = "com.android.media.SEEK_TO"; + public static final String FEATURE_STOP = "com.android.media.STOP"; + // TODO move states somewhere else + public static final int STATE_ERROR = 0; + /** + * The state MediaPlayerManager starts in before any action has been + * performed. + */ + public static final int STATE_INIT = 1 << 0; + /** + * Indicates the source has been set and it is being prepared/buffered + * before starting playback. + */ + public static final int STATE_PREPARING = 1 << 1; + /** + * The media is ready and playback can be started. + */ + public static final int STATE_READY = 1 << 2; + /** + * The media is currently playing. + */ + public static final int STATE_PLAYING = 1 << 3; + /** + * The media is currently paused. + */ + public static final int STATE_PAUSED = 1 << 4; + /** + * The service has been stopped and cannot be started again until a new + * source has been set. + */ + public static final int STATE_STOPPED = 1 << 5; + /** + * The playback has reached the end. It can be restarted by calling play(). + */ + public static final int STATE_ENDED = 1 << 6; + + // TODO decide on proper way of describing features + protected List<String> mFeatures = new ArrayList<String>(); + protected List<Listener> mListeners = new ArrayList<Listener>(); + + public Renderer(Context context, Bundle params) { + onCreate(params); + initFeatures(params); + } + + abstract public void setContent(Bundle request); + + public void onCreate(Bundle params) { + // Do nothing by default + } + + public void setNextContent(Bundle request) { + throw new UnsupportedOperationException("setNextContent() is not supported."); + } + + public List<String> getFeatures() { + return mFeatures; + } + + public boolean onPlay() { + // TODO consider making these log warnings instead of crashes (or + // Log.wtf) + // throw new UnsupportedOperationException("play is not supported."); + return false; + } + + public boolean onPause() { + // throw new UnsupportedOperationException("pause is not supported."); + return false; + } + + public boolean onNext() { + // throw new UnsupportedOperationException("next is not supported."); + return false; + } + + public boolean onPrevious() { + // throw new + // UnsupportedOperationException("previous is not supported."); + return false; + } + + public boolean onStop() { + // throw new UnsupportedOperationException("stop is not supported."); + return false; + } + + public boolean onSeekTo(int time) { + // throw new UnsupportedOperationException("seekTo is not supported."); + return false; + } + + public long getSeekPosition() { + // throw new + // UnsupportedOperationException("getSeekPosition is not supported."); + return -1; + } + + public long getDuration() { + // throw new + // UnsupportedOperationException("getDuration is not supported."); + return -1; + } + + public int getPlayState() { + // throw new + // UnsupportedOperationException("getPlayState is not supported."); + return 0; + } + + public void onDestroy() { + // Do nothing by default + } + + public void registerListener(Listener listener) { + if (!mListeners.contains(listener)) { + mListeners.add(listener); + } + } + + public void unregisterListener(Listener listener) { + mListeners.remove(listener); + } + + protected void initFeatures(Bundle params) { + mFeatures.add(FEATURE_SET_CONTENT); + } + + protected void pushOnError(int type, int extra, Bundle extras, Throwable error) { + for (Listener listener : mListeners) { + listener.onError(type, extra, extras, error); + } + } + + protected void pushOnStateChanged(int newState) { + for (Listener listener : mListeners) { + listener.onStateChanged(newState); + } + } + + protected void pushOnBufferingUpdate(int percent) { + for (Listener listener : mListeners) { + listener.onBufferingUpdate(percent); + } + } + + protected void pushOnFocusLost() { + for (Listener listener : mListeners) { + listener.onFocusLost(); + } + } + + protected void pushOnNextStarted() { + for (Listener listener : mListeners) { + listener.onNextStarted(); + } + } + + public interface Listener { + public static final int ERROR_LOAD_FAILED = 1770; + public static final int ERROR_PREPARE_ERROR = 1771; + public static final int ERROR_PLAYBACK_FAILED = 1772; + + /** + * When an error occurs onError will be called but not onStateChanged. + * The Manager will remain in the error state until + * {@link #setContent()} is called again. + */ + public void onError(int type, int extra, Bundle extras, + Throwable error); + + /** + * onStateChanged will be called whenever the state of the manager + * transitions except to an error state. + */ + public void onStateChanged(int newState); + + /** + * This is a passthrough of + * {@link MediaPlayer.OnBufferingUpdateListener}. + */ + public void onBufferingUpdate(int percent); + + /** + * Called when audio focus is lost and it is not transient or ducking. + */ + public void onFocusLost(); + + /** + * Called when the next item was started playing. Only called if a next + * item has been set and the current item has ended. + */ + public void onNextStarted(); + } +} diff --git a/tests/OneMedia/src/com/android/onemedia/playback/RequestUtils.java b/tests/OneMedia/src/com/android/onemedia/playback/RequestUtils.java new file mode 100644 index 0000000..1688395 --- /dev/null +++ b/tests/OneMedia/src/com/android/onemedia/playback/RequestUtils.java @@ -0,0 +1,73 @@ +/* + * 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.playback; + +import android.os.Bundle; + +import java.util.HashMap; +import java.util.Map; + +/** + * TODO: Insert description here. (generated by epastern) + */ +public class RequestUtils { + public static final String ACTION_SET_CONTENT = "set_content"; + public static final String ACTION_SET_NEXT_CONTENT = "set_next_content"; + public static final String ACTION_PAUSE = "com.android.onemedia.pause"; + public static final String ACTION_PLAY = "com.android.onemedia.play"; + public static final String ACTION_REW = "com.android.onemedia.rew"; + public static final String ACTION_FFWD = "com.android.onemedia.ffwd"; + public static final String ACTION_PREV = "com.android.onemedia.prev"; + public static final String ACTION_NEXT = "com.android.onemedia.next"; + + public static final String EXTRA_KEY_SOURCE = "source"; + public static final String EXTRA_KEY_METADATA = "metadata"; + public static final String EXTRA_KEY_HEADERS = "headers"; + + private RequestUtils() { + } + + public static class ContentBuilder { + private Bundle mBundle; + + public ContentBuilder() { + mBundle = new Bundle(); + } + + public ContentBuilder setSource(String source) { + mBundle.putString(EXTRA_KEY_SOURCE, source); + return this; + } + + /** + * @see MediaItemMetadata + * @param metadata The metadata for this item + */ + public ContentBuilder setMetadata(Bundle metadata) { + mBundle.putBundle(EXTRA_KEY_METADATA, metadata); + return this; + } + + public ContentBuilder setHeaders(HashMap<String, String> headers) { + mBundle.putSerializable(EXTRA_KEY_HEADERS, headers); + return this; + } + + public Bundle build() { + return mBundle; + } + } +} diff --git a/tests/RenderScriptTests/FountainFbo/Android.mk b/tests/RenderScriptTests/FountainFbo/Android.mk index 4535eb1..c0f3323 100644 --- a/tests/RenderScriptTests/FountainFbo/Android.mk +++ b/tests/RenderScriptTests/FountainFbo/Android.mk @@ -25,5 +25,6 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-fil # LOCAL_SDK_VERSION := current LOCAL_PACKAGE_NAME := RsFountainFbo +LOCAL_SDK_VERSION := 14 include $(BUILD_PACKAGE) diff --git a/tests/RenderThreadTest/Android.mk b/tests/RenderThreadTest/Android.mk new file mode 100644 index 0000000..e07e943 --- /dev/null +++ b/tests/RenderThreadTest/Android.mk @@ -0,0 +1,18 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +# Only compile source java files in this apk. +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PACKAGE_NAME := RenderThreadTest + +LOCAL_STATIC_JAVA_LIBRARIES += android-common + +LOCAL_PROGUARD_ENABLED := disabled + +include $(BUILD_PACKAGE) + +# Use the following include to make our test apk. +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/tests/RenderThreadTest/AndroidManifest.xml b/tests/RenderThreadTest/AndroidManifest.xml new file mode 100644 index 0000000..a7f4f6e --- /dev/null +++ b/tests/RenderThreadTest/AndroidManifest.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.renderthread" + android:versionCode="1" + android:versionName="1.0" > + + <application + android:allowBackup="true" + android:icon="@drawable/ic_launcher" + android:label="@string/app_name" + android:theme="@style/AppTheme" > + <activity + android:name=".MainActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + <activity android:name=".SubActivity" + android:theme="@style/AppTheme.Transparent" /> + </application> + +</manifest> diff --git a/tests/RenderThreadTest/res/drawable-hdpi/ic_launcher.png b/tests/RenderThreadTest/res/drawable-hdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..96a442e --- /dev/null +++ b/tests/RenderThreadTest/res/drawable-hdpi/ic_launcher.png diff --git a/tests/RenderThreadTest/res/drawable-mdpi/ic_launcher.png b/tests/RenderThreadTest/res/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..359047d --- /dev/null +++ b/tests/RenderThreadTest/res/drawable-mdpi/ic_launcher.png diff --git a/tests/RenderThreadTest/res/drawable-xhdpi/ic_launcher.png b/tests/RenderThreadTest/res/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..71c6d76 --- /dev/null +++ b/tests/RenderThreadTest/res/drawable-xhdpi/ic_launcher.png diff --git a/tests/RenderThreadTest/res/drawable-xhdpi/starry_night_bg.jpg b/tests/RenderThreadTest/res/drawable-xhdpi/starry_night_bg.jpg Binary files differnew file mode 100644 index 0000000..755232d --- /dev/null +++ b/tests/RenderThreadTest/res/drawable-xhdpi/starry_night_bg.jpg diff --git a/tests/RenderThreadTest/res/layout/activity_main.xml b/tests/RenderThreadTest/res/layout/activity_main.xml new file mode 100644 index 0000000..1fd5459 --- /dev/null +++ b/tests/RenderThreadTest/res/layout/activity_main.xml @@ -0,0 +1,12 @@ +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + tools:context=".MainActivity" > + + <ListView android:id="@android:id/list" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:divider="@null" /> + +</FrameLayout> diff --git a/tests/RenderThreadTest/res/layout/activity_sub.xml b/tests/RenderThreadTest/res/layout/activity_sub.xml new file mode 100644 index 0000000..713cee4 --- /dev/null +++ b/tests/RenderThreadTest/res/layout/activity_sub.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" > + + <View + android:id="@+id/bg_container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@drawable/starry_night_bg" /> + + <LinearLayout + android:id="@+id/my_container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" > + + <View + android:id="@+id/from_left" + android:layout_width="match_parent" + android:layout_height="48dip" + android:background="#7000FF00" /> + + <View + android:id="@+id/from_right" + android:layout_width="match_parent" + android:layout_height="0dip" + android:layout_margin="80dip" + android:layout_weight="1" + android:background="#90FF0000" /> + + <View + android:id="@+id/from_left" + android:layout_width="match_parent" + android:layout_height="48dip" + android:background="#7000FF00" /> + </LinearLayout> + +</FrameLayout>
\ No newline at end of file diff --git a/tests/RenderThreadTest/res/layout/item_layout.xml b/tests/RenderThreadTest/res/layout/item_layout.xml new file mode 100644 index 0000000..5bdb1ac --- /dev/null +++ b/tests/RenderThreadTest/res/layout/item_layout.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@android:id/text1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceListItemSmall" + android:gravity="center_vertical" + android:paddingStart="?android:attr/listPreferredItemPaddingStart" + android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" + android:minHeight="?android:attr/listPreferredItemHeightSmall" + android:background="#33b5e5" +/>
\ No newline at end of file diff --git a/tests/RenderThreadTest/res/values/strings.xml b/tests/RenderThreadTest/res/values/strings.xml new file mode 100644 index 0000000..f782e98 --- /dev/null +++ b/tests/RenderThreadTest/res/values/strings.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <string name="app_name">Render Thread</string> + <string name="action_settings">Settings</string> + <string name="hello_world">Hello world!</string> + +</resources> diff --git a/tests/RenderThreadTest/res/values/styles.xml b/tests/RenderThreadTest/res/values/styles.xml new file mode 100644 index 0000000..f6b5d6a --- /dev/null +++ b/tests/RenderThreadTest/res/values/styles.xml @@ -0,0 +1,11 @@ +<resources> + <!-- Application theme. --> + <style name="AppTheme" parent="android:Theme.Holo.Light"> + </style> + + <style name="AppTheme.Transparent"> + <item name="android:windowIsTranslucent">true</item> + <item name="android:windowBackground">@android:color/transparent</item> + </style> + +</resources> diff --git a/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java b/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java new file mode 100644 index 0000000..fc5426c --- /dev/null +++ b/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java @@ -0,0 +1,100 @@ + +package com.example.renderthread; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.util.Log; +import android.view.HardwareRenderer; +import android.view.RenderNodeAnimator; +import android.view.View; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.ListView; +import android.widget.SimpleAdapter; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +public class MainActivity extends Activity implements OnItemClickListener { + + static final int DURATION = 400; + + static final String KEY_NAME = "name"; + static final String KEY_CLASS = "clazz"; + + static Map<String,?> make(String name) { + Map<String,Object> ret = new HashMap<String,Object>(); + ret.put(KEY_NAME, name); + return ret; + } + + @SuppressWarnings("serial") + static final ArrayList<Map<String,?>> SAMPLES = new ArrayList<Map<String,?>>() {{ + for (int i = 1; i < 25; i++) { + add(make("List Item: " + i)); + } + }}; + + Handler mHandler = new Handler(); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + ListView lv = (ListView) findViewById(android.R.id.list); + lv.setDrawSelectorOnTop(true); + lv.setAdapter(new SimpleAdapter(this, SAMPLES, + R.layout.item_layout, new String[] { KEY_NAME }, + new int[] { android.R.id.text1 })); + lv.setOnItemClickListener(this); + getActionBar().setTitle("MainActivity"); + } + + @Override + protected void onResume() { + super.onResume(); + ListView lv = (ListView) findViewById(android.R.id.list); + for (int i = 0; i < lv.getChildCount(); i++) { + lv.getChildAt(i).animate().translationY(0).setDuration(DURATION); + } + } + + @Override + public void onItemClick(final AdapterView<?> adapterView, View clickedView, + int clickedPosition, long clickedId) { + int topPosition = adapterView.getFirstVisiblePosition(); + int dy = adapterView.getHeight(); + for (int i = 0; i < adapterView.getChildCount(); i++) { + int pos = topPosition + i; + View child = adapterView.getChildAt(i); + float delta = (pos - clickedPosition) * 1.1f; + if (delta == 0) delta = -1; + RenderNodeAnimator animator = new RenderNodeAnimator( + RenderNodeAnimator.TRANSLATION_Y, dy * delta); + animator.setDuration(DURATION); + if (child == clickedView) logTranslationY(clickedView); + animator.setTarget(child); + animator.start(); + if (child == clickedView) logTranslationY(clickedView); + } + //mHandler.postDelayed(mLaunchActivity, (long) (DURATION * .4)); + mLaunchActivity.run(); + } + + private void logTranslationY(View v) { + Log.d("RTTest", "View has translationY: " + v.getTranslationY()); + } + + private Runnable mLaunchActivity = new Runnable() { + + @Override + public void run() { + startActivity(new Intent(MainActivity.this, SubActivity.class)); + overridePendingTransition(0, 0); + } + }; + +} diff --git a/tests/RenderThreadTest/src/com/example/renderthread/SubActivity.java b/tests/RenderThreadTest/src/com/example/renderthread/SubActivity.java new file mode 100644 index 0000000..892cbae --- /dev/null +++ b/tests/RenderThreadTest/src/com/example/renderthread/SubActivity.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.renderthread; + +import android.app.Activity; +import android.os.Bundle; +import android.os.Process; +import android.os.SystemClock; +import android.view.View; +import android.view.ViewGroup; + +public class SubActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + long before = SystemClock.currentThreadTimeMillis(); + setContentView(R.layout.activity_sub); + getActionBar().setTitle("SubActivity"); + // Simulate being a real app! + while (SystemClock.currentThreadTimeMillis() - before < 100) { + View v = new View(this, null); + } + } + + @Override + protected void onResume() { + super.onResume(); + ViewGroup container = (ViewGroup) findViewById(R.id.my_container); + int dx = getWindowManager().getDefaultDisplay().getWidth(); + for (int i = 0; i < container.getChildCount(); i++) { + View child = container.getChildAt(i); + int dir = child.getId() == R.id.from_left ? 1 : -1; + child.setTranslationX(dx * dir); + child.animate().translationX(0).setDuration(MainActivity.DURATION); + } + View bg = findViewById(R.id.bg_container); + bg.setAlpha(0f); + bg.animate().alpha(1f).setDuration(MainActivity.DURATION); + } + + @Override + public void onBackPressed() { + super.onBackPressed(); + overridePendingTransition(0, 0); + } +} diff --git a/tests/SharedLibrary/client/Android.mk b/tests/SharedLibrary/client/Android.mk index 60ef92a..1d66bb9 100644 --- a/tests/SharedLibrary/client/Android.mk +++ b/tests/SharedLibrary/client/Android.mk @@ -3,7 +3,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) -LOCAL_APK_LIBRARIES := SharedLibrary +LOCAL_RES_LIBRARIES := SharedLibrary LOCAL_PACKAGE_NAME := SharedLibraryClient diff --git a/tests/SharedLibrary/client/AndroidManifest.xml b/tests/SharedLibrary/client/AndroidManifest.xml index c6a43c0..a39c754 100644 --- a/tests/SharedLibrary/client/AndroidManifest.xml +++ b/tests/SharedLibrary/client/AndroidManifest.xml @@ -16,7 +16,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.google.android.test.lib_client"> - <application android:label="@string/app_title"> + <application android:label="@string/app_title" android:theme="@style/Theme"> <uses-library android:name="android.test.runner" /> <uses-library android:name="com.google.android.test.shared_library" /> <activity android:name="ActivityMain"> diff --git a/tests/SharedLibrary/client/res/layout/main.xml b/tests/SharedLibrary/client/res/layout/main.xml new file mode 100644 index 0000000..067ef9f --- /dev/null +++ b/tests/SharedLibrary/client/res/layout/main.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <TextView android:id="@+id/label" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@com.google.android.test.shared_library:string/shared_string" + style="@com.google.android.test.shared_library:style/CodeFont"/> + + <com.google.android.test.shared_library.AddressView + xmlns:custom="http://schemas.android.com/apk/res/com.google.android.test.shared_library" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + custom:name="Professor Android" + custom:streetNumber="44" + custom:streetName="KitKat Lane" + custom:city="AndroidVille" + custom:state="OS" + custom:country="Mobile" + custom:zip="12345"/> +</LinearLayout> diff --git a/tests/SharedLibrary/client/res/values/strings.xml b/tests/SharedLibrary/client/res/values/strings.xml index 3757a25..d9efdc7 100644 --- a/tests/SharedLibrary/client/res/values/strings.xml +++ b/tests/SharedLibrary/client/res/values/strings.xml @@ -16,4 +16,5 @@ <resources> <string name="app_title">SharedLibrary client</string> + <string name="changes">@com.google.android.test.shared_library:string/shared_string</string> </resources> diff --git a/tests/SharedLibrary/client/res/values/themes.xml b/tests/SharedLibrary/client/res/values/themes.xml new file mode 100644 index 0000000..a14f98a --- /dev/null +++ b/tests/SharedLibrary/client/res/values/themes.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> + +<resources> + <style name="Theme" parent="com.google.android.test.shared_library:Theme"> + </style> +</resources> diff --git a/tests/SharedLibrary/client/src/com/google/android/test/lib_client/ActivityMain.java b/tests/SharedLibrary/client/src/com/google/android/test/lib_client/ActivityMain.java index d6121a5..7276b3c 100644 --- a/tests/SharedLibrary/client/src/com/google/android/test/lib_client/ActivityMain.java +++ b/tests/SharedLibrary/client/src/com/google/android/test/lib_client/ActivityMain.java @@ -18,18 +18,33 @@ package com.google.android.test.lib_client; import android.app.Activity; import android.os.Bundle; -import android.widget.TextView; import com.google.android.test.shared_library.SharedLibraryMain; public class ActivityMain extends Activity { + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + setContentView(R.layout.main); + + String[] expectedAnimals = new String[] { + "Racoon", + "Rhino", + "Elephant" + }; + + String[] animals = getResources().getStringArray(com.google.android.test.shared_library.R.array.animals); + if (animals == null || animals.length != expectedAnimals.length) { + throw new AssertionError("Animal list from shared library is null or wrong length."); + } - TextView content = new TextView(this); - content.setText("Library version: " + SharedLibraryMain.getVersion(this) + "!"); + for (int i = 0; i < expectedAnimals.length; i++) { + if (!expectedAnimals[i].equals(animals[i])) { + throw new AssertionError("Expected '" + expectedAnimals[i] + + "' at index " + i + " but got '" + animals[i]); + } + } SharedLibraryMain.ensureVersion(this, SharedLibraryMain.VERSION_BASE); - setContentView(content); } } diff --git a/tests/SharedLibrary/lib/Android.mk b/tests/SharedLibrary/lib/Android.mk index c19e23a..b2fc369 100644 --- a/tests/SharedLibrary/lib/Android.mk +++ b/tests/SharedLibrary/lib/Android.mk @@ -3,8 +3,13 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) +LOCAL_AAPT_FLAGS := --shared-lib LOCAL_PACKAGE_NAME := SharedLibrary -LOCAL_MODULE_TAGS := tests +LOCAL_EXPORT_PACKAGE_RESOURCES := true +LOCAL_PRIVILEGED_MODULE := true +LOCAL_MODULE_TAGS := optional + +LOCAL_PROGUARD_FLAG_FILES := proguard.proguard include $(BUILD_PACKAGE) diff --git a/tests/SharedLibrary/lib/AndroidManifest.xml b/tests/SharedLibrary/lib/AndroidManifest.xml index 31fac20..bb939dd 100644 --- a/tests/SharedLibrary/lib/AndroidManifest.xml +++ b/tests/SharedLibrary/lib/AndroidManifest.xml @@ -19,7 +19,8 @@ android:versionCode="2"> <application android:label="SharedLibrary"> <library android:name="com.google.android.test.shared_library" /> - <activity android:name="ActivityMain"> + <activity android:name="ActivityMain" + android:icon="@drawable/size_48x48"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> diff --git a/tests/SharedLibrary/lib/proguard.proguard b/tests/SharedLibrary/lib/proguard.proguard new file mode 100644 index 0000000..e5dfbe1 --- /dev/null +++ b/tests/SharedLibrary/lib/proguard.proguard @@ -0,0 +1,7 @@ +-keepparameternames +-keepattributes Exceptions,InnerClasses,Signature,Deprecated, + SourceFile,LineNumberTable,*Annotation*,EnclosingMethod + +-keep public class * { + public protected *; +} diff --git a/tests/SharedLibrary/lib/res/drawable/size_48x48.jpg b/tests/SharedLibrary/lib/res/drawable/size_48x48.jpg Binary files differnew file mode 100644 index 0000000..5c2291e --- /dev/null +++ b/tests/SharedLibrary/lib/res/drawable/size_48x48.jpg diff --git a/tests/SharedLibrary/lib/res/layout/address.xml b/tests/SharedLibrary/lib/res/layout/address.xml new file mode 100644 index 0000000..835f43e --- /dev/null +++ b/tests/SharedLibrary/lib/res/layout/address.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> + +<merge xmlns:android="http://schemas.android.com/apk/res/android"> + <TextView android:id="@+id/name" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + <TextView android:id="@+id/street" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + <TextView android:id="@+id/cityStateZip" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + <TextView android:id="@+id/country" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> +</merge> diff --git a/tests/SharedLibrary/lib/res/values/attrs.xml b/tests/SharedLibrary/lib/res/values/attrs.xml new file mode 100644 index 0000000..8cefe92 --- /dev/null +++ b/tests/SharedLibrary/lib/res/values/attrs.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> + +<resources> + <declare-styleable name="AddressView"> + <attr name="name" format="string" /> + <attr name="streetNumber" format="integer" /> + <attr name="streetName" format="string" /> + <attr name="city" format="string" /> + <attr name="state" format="string" /> + <attr name="zip" format="string" /> + <attr name="country" format="string" /> + </declare-styleable> +</resources> diff --git a/tests/SharedLibrary/lib/res/values/public.xml b/tests/SharedLibrary/lib/res/values/public.xml new file mode 100644 index 0000000..37b1ec9 --- /dev/null +++ b/tests/SharedLibrary/lib/res/values/public.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?> + +<resources> + <public type="string" name="shared_string" id="0x00020003" /> + <public type="style" name="CodeFont" id="0x00040000" /> + <public type="style" name="Theme" id="0x00040001" /> + + <public type="attr" name="name" id="0x00010000" /> + <public type="attr" name="streetNumber" id="0x00010001" /> + <public type="attr" name="streetName" id="0x00010002" /> + <public type="attr" name="city" id="0x00010003" /> + <public type="attr" name="state" id="0x00010004" /> + <public type="attr" name="zip" id="0x00010005" /> + <public type="attr" name="country" id="0x00010006" /> + + <public type="array" name="animals" id="0x02050000" /> +</resources> diff --git a/tests/SharedLibrary/lib/res/values/strings.xml b/tests/SharedLibrary/lib/res/values/strings.xml index bbfb0b4..6827f93 100644 --- a/tests/SharedLibrary/lib/res/values/strings.xml +++ b/tests/SharedLibrary/lib/res/values/strings.xml @@ -19,4 +19,13 @@ <string name="upgrade_body"><xliff:g id="app">%1$s</xliff:g> requires a newer version of <xliff:g id="lib">%2$s</xliff:g> to run.</string> <string name="upgrade_button">Upgrade</string> + <string name="shared_string">Shared string!</string> + + <string-array name="animals"> + <item>@string/racoon</item> + <item>Rhino</item> + <item>Elephant</item> + </string-array> + + <string name="racoon">Racoon</string> </resources> diff --git a/tests/SharedLibrary/lib/res/values/themes.xml b/tests/SharedLibrary/lib/res/values/themes.xml new file mode 100644 index 0000000..f1081ac --- /dev/null +++ b/tests/SharedLibrary/lib/res/values/themes.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> + +<resources> + <style name="CodeFont" parent="@android:style/TextAppearance.Medium"> + <item name="android:textColor">#00FF00</item> + <item name="android:typeface">monospace</item> + </style> + + <style name="Theme" parent="android:Theme.Holo.Light"> + <item name="android:actionBarStyle">@style/ActionBar</item> + </style> + + <style name="ActionBar" parent="android:Widget.Holo.Light.ActionBar.Solid.Inverse"> + <item name="android:background">@color/orange</item> + </style> + + <color name="orange">#f0ad4e</color> +</resources> diff --git a/tests/SharedLibrary/lib/src/com/google/android/test/shared_library/AddressView.java b/tests/SharedLibrary/lib/src/com/google/android/test/shared_library/AddressView.java new file mode 100644 index 0000000..dcaf68c --- /dev/null +++ b/tests/SharedLibrary/lib/src/com/google/android/test/shared_library/AddressView.java @@ -0,0 +1,44 @@ +package com.google.android.test.shared_library; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + +public class AddressView extends LinearLayout { + private TextView mNameView; + private TextView mStreetView; + private TextView mCityStateZipView; + private TextView mCountryView; + + public AddressView(Context context, AttributeSet attrs) { + super(context, attrs); + setOrientation(VERTICAL); + + View view = LayoutInflater.from(context).inflate(R.layout.address, this); + mNameView = (TextView) view.findViewById(R.id.name); + mStreetView = (TextView) view.findViewById(R.id.street); + mCityStateZipView = (TextView) view.findViewById(R.id.cityStateZip); + mCountryView = (TextView) view.findViewById(R.id.country); + + TypedArray a = context.getTheme().obtainStyledAttributes( + attrs, + R.styleable.AddressView, + 0, 0); + try { + mNameView.setText(a.getString(R.styleable.AddressView_name)); + int streetNumber = a.getInteger(R.styleable.AddressView_streetNumber, -1); + mStreetView.setText((streetNumber <= 0 ? "" : Integer.toString(streetNumber)) + + " " + a.getString(R.styleable.AddressView_streetName)); + mCityStateZipView.setText(a.getString(R.styleable.AddressView_city) + ", " + + a.getString(R.styleable.AddressView_state) + " " + + a.getString(R.styleable.AddressView_zip)); + mCountryView.setText(a.getString(R.styleable.AddressView_country)); + } finally { + a.recycle(); + } + } +} diff --git a/tests/SoundTriggerTests/Android.mk b/tests/SoundTriggerTests/Android.mk new file mode 100644 index 0000000..407a9d7 --- /dev/null +++ b/tests/SoundTriggerTests/Android.mk @@ -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. +# +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_JAVA_LIBRARIES := android.test.runner + +LOCAL_PACKAGE_NAME := SoundTriggerTests + +include $(BUILD_PACKAGE) diff --git a/tests/SoundTriggerTests/AndroidManifest.xml b/tests/SoundTriggerTests/AndroidManifest.xml new file mode 100644 index 0000000..5e5a108 --- /dev/null +++ b/tests/SoundTriggerTests/AndroidManifest.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.hardware.soundtrigger"> + <application> + <uses-library android:name="android.test.runner" /> + </application> + + <instrumentation android:name="android.test.InstrumentationTestRunner" + android:targetPackage="android.hardware.soundtrigger" + android:label="Tests for android.hardware.soundtrigger" /> +</manifest> diff --git a/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java new file mode 100644 index 0000000..65a3d8a --- /dev/null +++ b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.soundtrigger; + +import android.hardware.soundtrigger.SoundTrigger; +import android.hardware.soundtrigger.SoundTrigger.ConfidenceLevel; +import android.hardware.soundtrigger.SoundTrigger.Keyphrase; +import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionEvent; +import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra; +import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel; +import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent; +import android.media.AudioFormat; +import android.os.Parcel; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.SmallTest; + +import java.util.Arrays; +import java.util.Random; +import java.util.UUID; + +public class SoundTriggerTest extends InstrumentationTestCase { + private Random mRandom = new Random(); + + @SmallTest + public void testKeyphraseParcelUnparcel_noUsers() throws Exception { + Keyphrase keyphrase = new Keyphrase(1, 0, "en-US", "hello", null); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + keyphrase.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + Keyphrase unparceled = Keyphrase.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(keyphrase.id, unparceled.id); + assertNull(unparceled.users); + assertEquals(keyphrase.locale, unparceled.locale); + assertEquals(keyphrase.text, unparceled.text); + } + + @SmallTest + public void testKeyphraseParcelUnparcel_zeroUsers() throws Exception { + Keyphrase keyphrase = new Keyphrase(1, 0, "en-US", "hello", new int[0]); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + keyphrase.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + Keyphrase unparceled = Keyphrase.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(keyphrase.id, unparceled.id); + assertTrue(Arrays.equals(keyphrase.users, unparceled.users)); + assertEquals(keyphrase.locale, unparceled.locale); + assertEquals(keyphrase.text, unparceled.text); + } + + @SmallTest + public void testKeyphraseParcelUnparcel_pos() throws Exception { + Keyphrase keyphrase = new Keyphrase(1, 0, "en-US", "hello", new int[] {1, 2, 3, 4, 5}); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + keyphrase.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + Keyphrase unparceled = Keyphrase.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(keyphrase.id, unparceled.id); + assertTrue(Arrays.equals(keyphrase.users, unparceled.users)); + assertEquals(keyphrase.locale, unparceled.locale); + assertEquals(keyphrase.text, unparceled.text); + } + + @SmallTest + public void testKeyphraseSoundModelParcelUnparcel_noData() throws Exception { + Keyphrase[] keyphrases = new Keyphrase[2]; + keyphrases[0] = new Keyphrase(1, 0, "en-US", "hello", new int[] {0}); + keyphrases[1] = new Keyphrase(2, 0, "fr-FR", "there", new int[] {1, 2}); + KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), UUID.randomUUID(), + null, keyphrases); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + ksm.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + KeyphraseSoundModel unparceled = KeyphraseSoundModel.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(ksm.uuid, unparceled.uuid); + assertNull(unparceled.data); + assertEquals(ksm.type, unparceled.type); + assertTrue(Arrays.equals(keyphrases, unparceled.keyphrases)); + } + + @SmallTest + public void testKeyphraseSoundModelParcelUnparcel_zeroData() throws Exception { + Keyphrase[] keyphrases = new Keyphrase[2]; + keyphrases[0] = new Keyphrase(1, 0, "en-US", "hello", new int[] {0}); + keyphrases[1] = new Keyphrase(2, 0, "fr-FR", "there", new int[] {1, 2}); + KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), UUID.randomUUID(), + new byte[0], keyphrases); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + ksm.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + KeyphraseSoundModel unparceled = KeyphraseSoundModel.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(ksm.uuid, unparceled.uuid); + assertEquals(ksm.type, unparceled.type); + assertTrue(Arrays.equals(ksm.keyphrases, unparceled.keyphrases)); + assertTrue(Arrays.equals(ksm.data, unparceled.data)); + } + + @SmallTest + public void testKeyphraseSoundModelParcelUnparcel_noKeyphrases() throws Exception { + byte[] data = new byte[10]; + mRandom.nextBytes(data); + KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), UUID.randomUUID(), + data, null); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + ksm.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + KeyphraseSoundModel unparceled = KeyphraseSoundModel.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(ksm.uuid, unparceled.uuid); + assertEquals(ksm.type, unparceled.type); + assertNull(unparceled.keyphrases); + assertTrue(Arrays.equals(ksm.data, unparceled.data)); + } + + @SmallTest + public void testKeyphraseSoundModelParcelUnparcel_zeroKeyphrases() throws Exception { + byte[] data = new byte[10]; + mRandom.nextBytes(data); + KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), UUID.randomUUID(), + data, new Keyphrase[0]); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + ksm.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + KeyphraseSoundModel unparceled = KeyphraseSoundModel.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(ksm.uuid, unparceled.uuid); + assertEquals(ksm.type, unparceled.type); + assertTrue(Arrays.equals(ksm.keyphrases, unparceled.keyphrases)); + assertTrue(Arrays.equals(ksm.data, unparceled.data)); + } + + @LargeTest + public void testKeyphraseSoundModelParcelUnparcel_largeData() throws Exception { + Keyphrase[] keyphrases = new Keyphrase[2]; + keyphrases[0] = new Keyphrase(1, 0, "en-US", "hello", new int[] {0}); + keyphrases[1] = new Keyphrase(2, 0, "fr-FR", "there", new int[] {1, 2}); + byte[] data = new byte[200 * 1024]; + mRandom.nextBytes(data); + KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), UUID.randomUUID(), + data, keyphrases); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + ksm.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + KeyphraseSoundModel unparceled = KeyphraseSoundModel.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(ksm.uuid, unparceled.uuid); + assertEquals(ksm.type, unparceled.type); + assertTrue(Arrays.equals(ksm.data, unparceled.data)); + assertTrue(Arrays.equals(ksm.keyphrases, unparceled.keyphrases)); + } + + @SmallTest + public void testRecognitionEventParcelUnparcel_noData() throws Exception { + RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_SUCCESS, 1, + true, 2, 3, 4, false, null, null); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + re.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + RecognitionEvent unparceled = RecognitionEvent.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(re, unparceled); + } + + @SmallTest + public void testRecognitionEventParcelUnparcel_zeroData() throws Exception { + RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_FAILURE, 1, + true, 2, 3, 4, false, null, new byte[1]); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + re.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + RecognitionEvent unparceled = RecognitionEvent.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(re, unparceled); + } + + @SmallTest + public void testRecognitionEventParcelUnparcel_largeData() throws Exception { + byte[] data = new byte[200 * 1024]; + mRandom.nextBytes(data); + RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_ABORT, 1, + false, 2, 3, 4, false, null, data); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + re.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + RecognitionEvent unparceled = RecognitionEvent.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(re, unparceled); + } + + @SmallTest + public void testRecognitionEventParcelUnparcel_largeAudioData() throws Exception { + byte[] data = new byte[200 * 1024]; + mRandom.nextBytes(data); + RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_ABORT, 1, + false, 2, 3, 4, true, + (new AudioFormat.Builder()) + .setChannelMask(AudioFormat.CHANNEL_IN_MONO) + .setEncoding(AudioFormat.ENCODING_PCM_16BIT) + .setSampleRate(16000) + .build(), + data); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + re.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + RecognitionEvent unparceled = RecognitionEvent.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(re, unparceled); + } + + @SmallTest + public void testKeyphraseRecognitionEventParcelUnparcel_noKeyphrases() throws Exception { + KeyphraseRecognitionEvent re = new KeyphraseRecognitionEvent( + SoundTrigger.RECOGNITION_STATUS_SUCCESS, 1, true, 2, 3, 4, false, null, null, null); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + re.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + KeyphraseRecognitionEvent unparceled = + KeyphraseRecognitionEvent.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(re, unparceled); + } + + @SmallTest + public void testKeyphraseRecognitionEventParcelUnparcel_zeroData() throws Exception { + KeyphraseRecognitionExtra[] kpExtra = new KeyphraseRecognitionExtra[0]; + KeyphraseRecognitionEvent re = new KeyphraseRecognitionEvent( + SoundTrigger.RECOGNITION_STATUS_FAILURE, 2, true, 2, 3, 4, false, null, new byte[1], + kpExtra); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + re.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + KeyphraseRecognitionEvent unparceled = + KeyphraseRecognitionEvent.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(re, unparceled); + } + + @LargeTest + public void testKeyphraseRecognitionEventParcelUnparcel_largeData() throws Exception { + byte[] data = new byte[200 * 1024]; + mRandom.nextBytes(data); + KeyphraseRecognitionExtra[] kpExtra = new KeyphraseRecognitionExtra[4]; + ConfidenceLevel cl1 = new ConfidenceLevel(1, 90); + ConfidenceLevel cl2 = new ConfidenceLevel(2, 30); + kpExtra[0] = new KeyphraseRecognitionExtra(1, + SoundTrigger.RECOGNITION_MODE_USER_IDENTIFICATION, 0, + new ConfidenceLevel[] {cl1, cl2}); + kpExtra[1] = new KeyphraseRecognitionExtra(1, + SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER, 0, + new ConfidenceLevel[] {cl2}); + kpExtra[2] = new KeyphraseRecognitionExtra(1, + SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER, 0, null); + kpExtra[3] = new KeyphraseRecognitionExtra(1, + SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER, 0, + new ConfidenceLevel[0]); + + KeyphraseRecognitionEvent re = new KeyphraseRecognitionEvent( + SoundTrigger.RECOGNITION_STATUS_FAILURE, 1, true, 2, 3, 4, false, null, data, + kpExtra); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + re.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + KeyphraseRecognitionEvent unparceled = + KeyphraseRecognitionEvent.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(re, unparceled); + } +} diff --git a/tests/Split/Android.mk b/tests/Split/Android.mk new file mode 100644 index 0000000..b068bef --- /dev/null +++ b/tests/Split/Android.mk @@ -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. +# + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) +LOCAL_PACKAGE_NAME := Split + +LOCAL_PACKAGE_SPLITS := mdpi-v4 hdpi-v4 xhdpi-v4 xxhdpi-v4 + +LOCAL_MODULE_TAGS := tests + +include $(BUILD_PACKAGE) diff --git a/tests/Split/AndroidManifest.xml b/tests/Split/AndroidManifest.xml new file mode 100644 index 0000000..0de8344 --- /dev/null +++ b/tests/Split/AndroidManifest.xml @@ -0,0 +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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.example.split"> + <application android:label="@string/app_title" + android:icon="@mipmap/ic_app"> + <activity android:name="ActivityMain"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/tests/Split/assets/blah.txt b/tests/Split/assets/blah.txt new file mode 100644 index 0000000..1b37e40 --- /dev/null +++ b/tests/Split/assets/blah.txt @@ -0,0 +1 @@ +This is some useful info. diff --git a/tests/Split/assets/statement.xml b/tests/Split/assets/statement.xml new file mode 100644 index 0000000..91750d1 --- /dev/null +++ b/tests/Split/assets/statement.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<statement> + <value>Hello</value> +</statement> diff --git a/tests/Split/res/drawable-hdpi/image.png b/tests/Split/res/drawable-hdpi/image.png Binary files differnew file mode 100644 index 0000000..dcf4242 --- /dev/null +++ b/tests/Split/res/drawable-hdpi/image.png diff --git a/tests/Split/res/drawable-mdpi/image.png b/tests/Split/res/drawable-mdpi/image.png Binary files differnew file mode 100644 index 0000000..3437952 --- /dev/null +++ b/tests/Split/res/drawable-mdpi/image.png diff --git a/tests/Split/res/drawable-xhdpi/image.png b/tests/Split/res/drawable-xhdpi/image.png Binary files differnew file mode 100644 index 0000000..68b2f8e --- /dev/null +++ b/tests/Split/res/drawable-xhdpi/image.png diff --git a/tests/Split/res/drawable-xxhdpi/image.png b/tests/Split/res/drawable-xxhdpi/image.png Binary files differnew file mode 100644 index 0000000..4bff9b9 --- /dev/null +++ b/tests/Split/res/drawable-xxhdpi/image.png diff --git a/tests/Split/res/layout-fr-sw600dp/main.xml b/tests/Split/res/layout-fr-sw600dp/main.xml new file mode 100644 index 0000000..2461c8c --- /dev/null +++ b/tests/Split/res/layout-fr-sw600dp/main.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <FrameLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> +</FrameLayout> diff --git a/tests/Split/res/layout/main.xml b/tests/Split/res/layout/main.xml new file mode 100644 index 0000000..607cdb0 --- /dev/null +++ b/tests/Split/res/layout/main.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <ImageView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerInParent="true" + android:src="@drawable/image"/> +</RelativeLayout> diff --git a/tests/Split/res/mipmap-hdpi/ic_app.png b/tests/Split/res/mipmap-hdpi/ic_app.png Binary files differnew file mode 100644 index 0000000..ffcb9e5 --- /dev/null +++ b/tests/Split/res/mipmap-hdpi/ic_app.png diff --git a/tests/Split/res/mipmap-mdpi/ic_app.png b/tests/Split/res/mipmap-mdpi/ic_app.png Binary files differnew file mode 100644 index 0000000..35f5b45 --- /dev/null +++ b/tests/Split/res/mipmap-mdpi/ic_app.png diff --git a/tests/Split/res/mipmap-xhdpi/ic_app.png b/tests/Split/res/mipmap-xhdpi/ic_app.png Binary files differnew file mode 100644 index 0000000..bfe71fe --- /dev/null +++ b/tests/Split/res/mipmap-xhdpi/ic_app.png diff --git a/tests/Split/res/mipmap-xxhdpi/ic_app.png b/tests/Split/res/mipmap-xxhdpi/ic_app.png Binary files differnew file mode 100644 index 0000000..b65532c --- /dev/null +++ b/tests/Split/res/mipmap-xxhdpi/ic_app.png diff --git a/tests/Split/res/mipmap-xxxhdpi/ic_app.png b/tests/Split/res/mipmap-xxxhdpi/ic_app.png Binary files differnew file mode 100644 index 0000000..2679b49 --- /dev/null +++ b/tests/Split/res/mipmap-xxxhdpi/ic_app.png diff --git a/tests/Split/res/values-de/values.xml b/tests/Split/res/values-de/values.xml new file mode 100644 index 0000000..26d0507 --- /dev/null +++ b/tests/Split/res/values-de/values.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <string name="test">Achtung!</string> +</resources> diff --git a/tests/Split/res/values-fr/values.xml b/tests/Split/res/values-fr/values.xml new file mode 100644 index 0000000..16532da --- /dev/null +++ b/tests/Split/res/values-fr/values.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <string name="app_title">APK Divisé</string> + <string name="test">Bonjour, Monde!</string> + <string name="blah">Bleh..</string> + <string-array name="lotsofstrings"> + <item>Hé là </item> + <item>Au revoir</item> + </string-array> +</resources> diff --git a/tests/Split/res/values-sw600dp/values.xml b/tests/Split/res/values-sw600dp/values.xml new file mode 100644 index 0000000..a8329bb --- /dev/null +++ b/tests/Split/res/values-sw600dp/values.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <dimen name="width">230dp</dimen> +</resources> diff --git a/tests/Split/res/values-xxhdpi/values.xml b/tests/Split/res/values-xxhdpi/values.xml new file mode 100644 index 0000000..0b5f2d8 --- /dev/null +++ b/tests/Split/res/values-xxhdpi/values.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="app_title">Split APK XX-HDPI</string> +</resources> diff --git a/tests/Split/res/values/values.xml b/tests/Split/res/values/values.xml new file mode 100644 index 0000000..68edc77 --- /dev/null +++ b/tests/Split/res/values/values.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <string name="app_title">Split APK</string> + <string name="test">Hello, World!</string> + <string name="boom">Boom!</string> + <string name="blah">Blah...</string> + <string-array name="lotsofstrings"> + <item>Hello there</item> + <item>Good bye</item> + </string-array> + + <plurals name="plur"> + <item quantity="zero">I no haz :(</item> + <item quantity="one">I haz 1!1! :)</item> + <item quantity="many">I haz ALL!</item> + </plurals> + + <bool name="que">true</bool> + <color name="green">#00FF00</color> + <dimen name="width">23dp</dimen> + <item type="id" name="identifier" /> + <integer name="number">123</integer> + <integer-array name="numList"> + <item>1234</item> + </integer-array> + + <array name="ary"> + <item>@string/test</item> + <item>@string/boom</item> + <item>25dp</item> + </array> +</resources> diff --git a/tests/Split/src/java/com/android/example/split/ActivityMain.java b/tests/Split/src/java/com/android/example/split/ActivityMain.java new file mode 100644 index 0000000..63963a2 --- /dev/null +++ b/tests/Split/src/java/com/android/example/split/ActivityMain.java @@ -0,0 +1,29 @@ +/* + * 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.example.split; + +import android.app.Activity; +import android.os.Bundle; +import android.widget.TextView; + +public class ActivityMain extends Activity { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + } +} diff --git a/tests/TtsTests/src/com/android/speech/tts/TextToSpeechTests.java b/tests/TtsTests/src/com/android/speech/tts/TextToSpeechTests.java index 9c2cf41..78d4f96 100644 --- a/tests/TtsTests/src/com/android/speech/tts/TextToSpeechTests.java +++ b/tests/TtsTests/src/com/android/speech/tts/TextToSpeechTests.java @@ -67,13 +67,18 @@ public class TextToSpeechTests extends InstrumentationTestCase { IDelegate delegate = LittleMock.mock(IDelegate.class); MockableTextToSpeechService.setMocker(delegate); + LittleMock.doReturn(TextToSpeech.LANG_COUNTRY_VAR_AVAILABLE).when(delegate).onIsLanguageAvailable( + "eng", "USA", "variant"); + LittleMock.doReturn(TextToSpeech.LANG_COUNTRY_VAR_AVAILABLE).when(delegate).onLoadLanguage( + "eng", "USA", "variant"); + // Test 1 :Tests that calls to onLoadLanguage( ) are delegated through to the // service without any caching or intermediate steps. - mTts.setLanguage(new Locale("eng", "USA", "variant")); - LittleMock.verify(delegate, LittleMock.times(1)).onIsLanguageAvailable( - "eng", "USA", "variant"); + assertEquals(TextToSpeech.LANG_COUNTRY_VAR_AVAILABLE, mTts.setLanguage(new Locale("eng", "USA", "variant"))); + LittleMock.verify(delegate, LittleMock.anyTimes()).onIsLanguageAvailable( + "eng", "USA", "variant"); LittleMock.verify(delegate, LittleMock.times(1)).onLoadLanguage( - "eng", "USA", "variant"); + "eng", "USA", "variant"); } public void testSetLanguage_availableLanguage() throws Exception { @@ -86,8 +91,10 @@ public class TextToSpeechTests extends InstrumentationTestCase { // request language changes from that point on. LittleMock.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).when(delegate).onIsLanguageAvailable( "eng", "USA", "variant"); + LittleMock.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).when(delegate).onIsLanguageAvailable( + "eng", "USA", ""); LittleMock.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).when(delegate).onLoadLanguage( - "eng", "USA", "variant"); + "eng", "USA", ""); mTts.setLanguage(new Locale("eng", "USA", "variant")); blockingCallSpeak("foo bar", delegate); ArgumentCaptor<SynthesisRequest> req = LittleMock.createCaptor(); @@ -97,6 +104,7 @@ public class TextToSpeechTests extends InstrumentationTestCase { assertEquals("eng", req.getValue().getLanguage()); assertEquals("USA", req.getValue().getCountry()); assertEquals("", req.getValue().getVariant()); + assertEquals("en-US", req.getValue().getVoiceName()); } public void testSetLanguage_unavailableLanguage() throws Exception { @@ -120,6 +128,7 @@ public class TextToSpeechTests extends InstrumentationTestCase { assertEquals("eng", req2.getValue().getLanguage()); assertEquals("USA", req2.getValue().getCountry()); assertEquals("", req2.getValue().getVariant()); + assertEquals("en-US", req2.getValue().getVoiceName()); } public void testIsLanguageAvailable() { @@ -135,6 +144,28 @@ public class TextToSpeechTests extends InstrumentationTestCase { "eng", "USA", ""); } + public void testDefaultLanguage_setsVoiceName() throws Exception { + IDelegate delegate = LittleMock.mock(IDelegate.class); + MockableTextToSpeechService.setMocker(delegate); + + // --------------------------------------------------------- + // Test that default language also sets the default voice + // name + LittleMock.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).when(delegate).onIsLanguageAvailable( + LittleMock.anyString(), LittleMock.anyString(), LittleMock.anyString()); + LittleMock.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).when(delegate).onLoadLanguage( + LittleMock.anyString(), LittleMock.anyString(), LittleMock.anyString()); + blockingCallSpeak("foo bar", delegate); + ArgumentCaptor<SynthesisRequest> req = LittleMock.createCaptor(); + LittleMock.verify(delegate, LittleMock.times(1)).onSynthesizeText(req.capture(), + LittleMock.<SynthesisCallback>anyObject()); + + Locale defaultLocale = Locale.getDefault(); + assertEquals(defaultLocale.getISO3Language(), req.getValue().getLanguage()); + assertEquals(defaultLocale.getISO3Country(), req.getValue().getCountry()); + assertEquals("", req.getValue().getVariant()); + assertEquals(defaultLocale.toLanguageTag(), req.getValue().getVoiceName()); + } private void blockingCallSpeak(String speech, IDelegate mock) throws InterruptedException { diff --git a/tests/TtsTests/src/com/android/speech/tts/TtsEnginesTests.java b/tests/TtsTests/src/com/android/speech/tts/TtsEnginesTests.java new file mode 100644 index 0000000..3fbc44b --- /dev/null +++ b/tests/TtsTests/src/com/android/speech/tts/TtsEnginesTests.java @@ -0,0 +1,77 @@ +package com.android.speech.tts; + +import android.speech.tts.TtsEngines; +import android.test.InstrumentationTestCase; + +import java.util.Locale; + +public class TtsEnginesTests extends InstrumentationTestCase { + private TtsEngines mTtsHelper; + + @Override + public void setUp() { + mTtsHelper = new TtsEngines(getInstrumentation().getContext()); + } + + public void testParseLocaleString() { + assertEquals(new Locale("en", "US"), mTtsHelper.parseLocaleString("eng-usa")); + assertEquals(new Locale("en", "US"), mTtsHelper.parseLocaleString("eng-USA")); + assertEquals(new Locale("en", "US"), mTtsHelper.parseLocaleString("en-US")); + assertEquals(new Locale("en", "US"), mTtsHelper.parseLocaleString("en_us")); + assertEquals(new Locale("en", "US"), mTtsHelper.parseLocaleString("eng_US")); + assertEquals(new Locale("en", "US", "foobar"), + mTtsHelper.parseLocaleString("eng_US-foobar")); + assertEquals(new Locale("en", "", "foobar"), mTtsHelper.parseLocaleString("eng__foobar")); + assertNull(mTtsHelper.parseLocaleString("cc_xx_barbar")); + assertNull(mTtsHelper.parseLocaleString("cc--barbar")); + + assertEquals(new Locale("en"), mTtsHelper.parseLocaleString("eng")); + assertEquals(new Locale("en","US","var"), mTtsHelper.parseLocaleString("eng-USA-var")); + } + + public void testToOldLocaleStringFormat() { + assertArraysEqual(new String[]{"deu", "DEU", ""}, + TtsEngines.toOldLocaleStringFormat(new Locale("de", "DE"))); + assertArraysEqual(new String[]{"deu", "", ""}, + TtsEngines.toOldLocaleStringFormat(new Locale("de"))); + assertArraysEqual(new String[]{"eng", "", ""}, + TtsEngines.toOldLocaleStringFormat(new Locale("en"))); + assertArraysEqual(new String[]{"eng", "USA", ""}, + TtsEngines.toOldLocaleStringFormat(new Locale("foo"))); + } + + public void testNormalizeLocale() { + assertEquals(Locale.UK, + TtsEngines.normalizeTTSLocale(new Locale("eng", "gbr"))); + assertEquals(Locale.UK, + TtsEngines.normalizeTTSLocale(new Locale("eng", "GBR"))); + assertEquals(Locale.GERMANY, + TtsEngines.normalizeTTSLocale(new Locale("deu", "deu"))); + assertEquals(Locale.GERMAN, + TtsEngines.normalizeTTSLocale(new Locale("deu"))); + assertEquals(new Locale("yyy", "DE"), + TtsEngines.normalizeTTSLocale(new Locale("yyy", "DE"))); + } + + public void testGetLocalePrefForEngine() { + assertEquals(new Locale("en", "US"), + mTtsHelper.getLocalePrefForEngine("foo","foo:en-US")); + assertEquals(new Locale("en", "US"), + mTtsHelper.getLocalePrefForEngine("foo","foo:eng-usa")); + assertEquals(new Locale("en", "US"), + mTtsHelper.getLocalePrefForEngine("foo","foo:eng_USA")); + assertEquals(new Locale("de", "DE"), + mTtsHelper.getLocalePrefForEngine("foo","foo:deu-deu")); + assertEquals(Locale.getDefault(), + mTtsHelper.getLocalePrefForEngine("foo","foo:,bar:xx")); + assertEquals(Locale.getDefault(), + mTtsHelper.getLocalePrefForEngine("other","foo:,bar:xx")); + } + + private void assertArraysEqual(String[] expected, String[] actual) { + assertEquals("array length", expected.length, actual.length); + for (int i = 0; i < expected.length; i++) { + assertEquals("index " + i, expected[i], actual[i]); + } + } +}
\ No newline at end of file diff --git a/tests/UsageStatsTest/Android.mk b/tests/UsageStatsTest/Android.mk new file mode 100644 index 0000000..69fefeb --- /dev/null +++ b/tests/UsageStatsTest/Android.mk @@ -0,0 +1,11 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +# Only compile source java files in this apk. +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PACKAGE_NAME := UsageStatsTest + +include $(BUILD_PACKAGE) diff --git a/tests/UsageStatsTest/AndroidManifest.xml b/tests/UsageStatsTest/AndroidManifest.xml new file mode 100644 index 0000000..589674a --- /dev/null +++ b/tests/UsageStatsTest/AndroidManifest.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.tests.usagestats"> + + <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" /> + + <application android:label="Usage Access Test"> + <activity android:name=".UsageStatsActivity" + android:label="Device Usage History"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <activity android:name=".UsageLogActivity" /> + </application> +</manifest> diff --git a/tests/UsageStatsTest/res/layout/row_item.xml b/tests/UsageStatsTest/res/layout/row_item.xml new file mode 100644 index 0000000..da50163 --- /dev/null +++ b/tests/UsageStatsTest/res/layout/row_item.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingLeft="16dp" + android:paddingRight="16dp"> + + <TextView android:id="@android:id/text1" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentLeft="true" + android:layout_centerVertical="true" + android:textStyle="bold"/> + + <TextView android:id="@android:id/text2" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentRight="true" + android:layout_alignBaseline="@android:id/text1"/> +</RelativeLayout> diff --git a/tests/UsageStatsTest/res/menu/main.xml b/tests/UsageStatsTest/res/menu/main.xml new file mode 100644 index 0000000..e781058 --- /dev/null +++ b/tests/UsageStatsTest/res/menu/main.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8" ?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/log" + android:title="View Log"/> +</menu> diff --git a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageLogActivity.java b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageLogActivity.java new file mode 100644 index 0000000..5f62ad8 --- /dev/null +++ b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageLogActivity.java @@ -0,0 +1,135 @@ +/** + * 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.tests.usagestats; + +import android.app.ListActivity; +import android.app.usage.UsageEvents; +import android.app.usage.UsageStatsManager; +import android.content.Context; +import android.os.Bundle; +import android.os.Handler; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.TextView; + +import java.util.ArrayList; + +public class UsageLogActivity extends ListActivity implements Runnable { + private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 14; + + private UsageStatsManager mUsageStatsManager; + private Adapter mAdapter; + private Handler mHandler = new Handler(); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mUsageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE); + mAdapter = new Adapter(); + setListAdapter(mAdapter); + } + + @Override + protected void onResume() { + super.onResume(); + run(); + } + + @Override + protected void onPause() { + super.onPause(); + mHandler.removeCallbacks(this); + } + + @Override + public void run() { + long now = System.currentTimeMillis(); + long beginTime = now - USAGE_STATS_PERIOD; + UsageEvents events = mUsageStatsManager.queryEvents(beginTime, now); + mAdapter.update(events); + mHandler.postDelayed(this, 1000 * 5); + } + + private class Adapter extends BaseAdapter { + + private final ArrayList<UsageEvents.Event> mEvents = new ArrayList<>(); + + public void update(UsageEvents results) { + mEvents.clear(); + while (results.hasNextEvent()) { + UsageEvents.Event event = new UsageEvents.Event(); + results.getNextEvent(event); + mEvents.add(event); + } + notifyDataSetChanged(); + } + + @Override + public int getCount() { + return mEvents.size(); + } + + @Override + public Object getItem(int position) { + return mEvents.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + final ViewHolder holder; + if (convertView == null) { + convertView = LayoutInflater.from(UsageLogActivity.this) + .inflate(R.layout.row_item, parent, false); + holder = new ViewHolder(); + holder.packageName = (TextView) convertView.findViewById(android.R.id.text1); + holder.state = (TextView) convertView.findViewById(android.R.id.text2); + convertView.setTag(holder); + } else { + holder = (ViewHolder) convertView.getTag(); + } + + holder.packageName.setText(mEvents.get(position).getPackageName()); + String state; + switch (mEvents.get(position).getEventType()) { + case UsageEvents.Event.MOVE_TO_FOREGROUND: + state = "Foreground"; + break; + + case UsageEvents.Event.MOVE_TO_BACKGROUND: + state = "Background"; + break; + + default: + state = "Unknown: " + mEvents.get(position).getEventType(); + break; + } + holder.state.setText(state); + return convertView; + } + } + + static class ViewHolder { + public TextView packageName; + public TextView state; + } +} diff --git a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java new file mode 100644 index 0000000..b6591bd --- /dev/null +++ b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java @@ -0,0 +1,150 @@ +/* + * 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.tests.usagestats; + +import android.app.ListActivity; +import android.app.usage.UsageStats; +import android.app.usage.UsageStatsManager; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.text.format.DateUtils; +import android.util.ArrayMap; +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.BaseAdapter; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; + +public class UsageStatsActivity extends ListActivity { + private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 14; + private UsageStatsManager mUsageStatsManager; + private Adapter mAdapter; + private Comparator<UsageStats> mComparator = new Comparator<UsageStats>() { + @Override + public int compare(UsageStats o1, UsageStats o2) { + return Long.compare(o2.getTotalTimeInForeground(), o1.getTotalTimeInForeground()); + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mUsageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE); + mAdapter = new Adapter(); + setListAdapter(mAdapter); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.main, menu); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.log: + startActivity(new Intent(this, UsageLogActivity.class)); + return true; + + default: + return super.onOptionsItemSelected(item); + } + } + + @Override + protected void onResume() { + super.onResume(); + updateAdapter(); + } + + private void updateAdapter() { + long now = System.currentTimeMillis(); + long beginTime = now - USAGE_STATS_PERIOD; + ArrayMap<String, UsageStats> stats = mUsageStatsManager.queryAndAggregateUsageStats( + beginTime, now); + mAdapter.update(stats); + } + + private class Adapter extends BaseAdapter { + private ArrayList<UsageStats> mStats = new ArrayList<>(); + + public void update(ArrayMap<String, UsageStats> stats) { + mStats.clear(); + if (stats == null) { + return; + } + + final int packageCount = stats.size(); + for (int i = 0; i < packageCount; i++) { + mStats.add(stats.valueAt(i)); + } + + Collections.sort(mStats, mComparator); + notifyDataSetChanged(); + } + + @Override + public int getCount() { + return mStats.size(); + } + + @Override + public Object getItem(int position) { + return mStats.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + final ViewHolder holder; + if (convertView == null) { + convertView = LayoutInflater.from(UsageStatsActivity.this) + .inflate(R.layout.row_item, parent, false); + holder = new ViewHolder(); + holder.packageName = (TextView) convertView.findViewById(android.R.id.text1); + holder.usageTime = (TextView) convertView.findViewById(android.R.id.text2); + convertView.setTag(holder); + } else { + holder = (ViewHolder) convertView.getTag(); + } + + holder.packageName.setText(mStats.get(position).getPackageName()); + holder.usageTime.setText(DateUtils.formatDuration( + mStats.get(position).getTotalTimeInForeground())); + return convertView; + } + } + + private static class ViewHolder { + TextView packageName; + TextView usageTime; + } +}
\ No newline at end of file diff --git a/tests/UsesFeature2Test/Android.mk b/tests/UsesFeature2Test/Android.mk new file mode 100644 index 0000000..cc784d7 --- /dev/null +++ b/tests/UsesFeature2Test/Android.mk @@ -0,0 +1,25 @@ +# +# 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. +# + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) +LOCAL_PACKAGE_NAME := UsesFeature2Test + +LOCAL_MODULE_TAGS := tests + +include $(BUILD_PACKAGE) diff --git a/tests/UsesFeature2Test/AndroidManifest.xml b/tests/UsesFeature2Test/AndroidManifest.xml new file mode 100644 index 0000000..8caf4a1 --- /dev/null +++ b/tests/UsesFeature2Test/AndroidManifest.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.test.usesfeature2"> + + <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="19" /> + + <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> + <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> + <uses-permission android:name="android.permission.BLUETOOTH" /> + + <uses-feature android:name="android.hardware.sensor.accelerometer" /> + <feature-group android:label="@string/minimal"> + <uses-feature android:name="android.hardware.dpad" /> + <uses-feature android:name="android.hardware.touchscreen.multitouch.distinct" /> + </feature-group> + <feature-group android:label="@string/gamepad"> + <uses-feature android:name="android.hardware.gamepad" /> + <uses-feature android:name="android.hardware.opengles.aep" /> + </feature-group> + + <application android:label="@string/app_title" android:hasCode="false" /> +</manifest> diff --git a/tests/UsesFeature2Test/res/values/values.xml b/tests/UsesFeature2Test/res/values/values.xml new file mode 100644 index 0000000..2ee9107 --- /dev/null +++ b/tests/UsesFeature2Test/res/values/values.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <string name="app_title">Uses Feature 2.0</string> + <string name="minimal">Crippled experience</string> + <string name="gamepad">Gamer experience</string> +</resources> diff --git a/tests/VectorDrawableTest/Android.mk b/tests/VectorDrawableTest/Android.mk new file mode 100644 index 0000000..dd8a4d4 --- /dev/null +++ b/tests/VectorDrawableTest/Android.mk @@ -0,0 +1,26 @@ +# +# 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. +# + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := VectorDrawableTest + +LOCAL_MODULE_TAGS := tests + +include $(BUILD_PACKAGE) diff --git a/tests/VectorDrawableTest/AndroidManifest.xml b/tests/VectorDrawableTest/AndroidManifest.xml new file mode 100644 index 0000000..4c835ec --- /dev/null +++ b/tests/VectorDrawableTest/AndroidManifest.xml @@ -0,0 +1,148 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.test.dynamic" > + + <uses-sdk android:minSdkVersion="20" /> + + <application + android:hardwareAccelerated="true" + android:label="vector" + android:supportsRtl="true" > + <activity + android:name="VectorDrawablePerformance" + android:label="Vector Performance" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="com.android.test.dynamic.TEST" /> + </intent-filter> + </activity> + <activity + android:name="BitmapDrawableDupe" + android:label="Bitmap Performance of clones" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="com.android.test.dynamic.TEST" /> + </intent-filter> + + </activity> + <activity + android:name="VectorDrawableAnimation" + android:label="VectorTestAnimation" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="com.android.test.dynamic.TEST" /> + </intent-filter> + </activity> + <activity + android:name="VectorDrawableTest" + android:label="Vector Icon" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + <activity + android:name="AnimatedVectorDrawableTest" + android:label="AnimatedVectorDrawableTest" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="com.android.test.dynamic.TEST" /> + </intent-filter> + </activity> + <activity + android:name="AnimatedStateVectorDrawableTest" + android:label="AnimatedStateList and AnimatedVectorDrawable" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="com.android.test.dynamic.TEST" /> + </intent-filter> + </activity> + <activity + android:name="VectorDrawable01" + android:label="VectorTest1" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="com.android.test.dynamic.TEST" /> + </intent-filter> + </activity> + <activity + android:name="VectorDrawableDupPerf" + android:label="Vector Performance of clones" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="com.android.test.dynamic.TEST" /> + </intent-filter> + </activity> + <activity + android:name="VectorDrawableStaticPerf" + android:label="System icons" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="com.android.test.dynamic.TEST" /> + </intent-filter> + </activity> + <activity + android:name="VectorCheckbox" + android:label="Basic static vector drawables" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="com.android.test.dynamic.TEST" /> + </intent-filter> + </activity> + <activity + android:name="VectorPathChecking" + android:label="Path Checking graphics" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="com.android.test.dynamic.TEST" /> + </intent-filter> + </activity> + <activity + android:name="ScaleDrawableTests" + android:label="Scale Type Test" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="com.android.test.dynamic.TEST" /> + </intent-filter> + </activity> + <activity + android:name="BoundsCheckTest" + android:label="SetBound check" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="com.android.test.dynamic.TEST" /> + </intent-filter> + </activity> + </application> + +</manifest>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/anim/animation_favorite.xml b/tests/VectorDrawableTest/res/anim/animation_favorite.xml new file mode 100644 index 0000000..c81ba40 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/animation_favorite.xml @@ -0,0 +1,29 @@ +<?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. +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" > + + <objectAnimator + android:duration="8000" + android:interpolator="@interpolator/custom_path_interpolator_favorite" + android:propertyName="pathData" + android:repeatCount="-1" + android:valueFrom="@string/round_box" + android:valueTo="@string/heart" + android:valueType="pathType" /> + +</set>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/anim/animation_favorite02.xml b/tests/VectorDrawableTest/res/anim/animation_favorite02.xml new file mode 100644 index 0000000..15d3b8e --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/animation_favorite02.xml @@ -0,0 +1,35 @@ +<?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. +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" > + + <objectAnimator + android:duration="8000" + android:interpolator="@interpolator/custom_path_interpolator_favorite" + android:propertyName="scaleX" + android:repeatCount="-1" + android:valueFrom="0" + android:valueTo="20" /> + <objectAnimator + android:duration="8000" + android:interpolator="@interpolator/custom_path_interpolator_favorite" + android:propertyName="scaleY" + android:repeatCount="-1" + android:valueFrom="0" + android:valueTo="20" /> + +</set>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/anim/animation_grouping_1_01.xml b/tests/VectorDrawableTest/res/anim/animation_grouping_1_01.xml new file mode 100644 index 0000000..8d82d05 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/animation_grouping_1_01.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" > + + <objectAnimator + android:duration="3300" + android:propertyName="rotation" + android:valueFrom="0" + android:valueTo="360" + android:repeatCount="-1" /> +</set>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/anim/animation_grouping_1_02.xml b/tests/VectorDrawableTest/res/anim/animation_grouping_1_02.xml new file mode 100644 index 0000000..ae63203 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/animation_grouping_1_02.xml @@ -0,0 +1,35 @@ +<?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. +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" > + + <objectAnimator + android:duration="2000" + android:interpolator="@interpolator/custom_path_interpolator_favorite" + android:propertyName="scaleX" + android:repeatCount="-1" + android:valueFrom="0" + android:valueTo="20" /> + <objectAnimator + android:duration="2000" + android:interpolator="@interpolator/custom_path_interpolator_favorite" + android:propertyName="scaleY" + android:repeatCount="-1" + android:valueFrom="0" + android:valueTo="20" /> + +</set>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect1_scale.xml b/tests/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect1_scale.xml new file mode 100644 index 0000000..7347220 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect1_scale.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" > + + <objectAnimator + android:duration="2016" + android:pathData=" + M 0.1 1 l 0 0 l 0.00882427215576 0 l 0.00982859611511 0 l 0.01086503982544 0 l 0.01193084716797 0 l 0.0130220413208 0 l 0.01413340568542 0 l 0.01525821685791 0 l 0.01638801574707 0 l 0.01751272201538 0 l 0.01862035751343 0 l 0.01969732284546 0 l 0.02072854995728 0 l 0.02169786453247 0 l 0.02258871078491 0 l 0.02338474273682 0 l 0.02407070159912 0 l 0.02463348388672 0 l 0.0250626373291 0 l 0.02535140991211 0 l 0.02549694061279 0 l 0.02550048828125 0 l 0.02536708831787 0 l 0.02510528564453 0 l 0.02472625732422 0 l 0.0242431640625 0 l 0.02367015838623 0 l 0.02302188873291 0 l 0.02231246948242 0 l 0.02155555725098 0 l 0.02076324462891 0 l 0.01994682312012 0 l 0.01911575317383 0 l 0.01827827453613 0 l 0.01732414245605 0 l 0.01522109985352 0 l 0.01262580871582 0 l 0.00973388671875 0 l 0.00647575378418 0 l 0.0027661895752 0 l -0.00149223327637 0 l -0.00639404296875 0 l -0.01199066162109 0 l -0.01820671081543 0 l -0.02470901489258 0 l -0.03080444335937 0 l -0.0355574798584 0 l -0.03823974609375 0 l -0.03876884460449 0 l -0.03766212463379 0 l -0.03562252044678 0 l -0.03321434020996 0 l -0.03078151702881 0 l -0.02849582672119 0 l -0.02642543792725 0 l -0.02458423614502 0 l -0.02296115875244 0 l -0.02153518676758 0 l -0.02028285980225 0 l -0.01918155670166 0 l -0.01821084976196 0 l -0.01735286712646 0 l -0.01659231185913 0 l -0.01591604232788 0 l -0.0153129196167 0 l -0.01477350234985 0 l -0.01413362503052 0 l -0.01339265823364 0 l -0.01270362854004 0 l -0.01206108093262 0 l -0.01146033287048 0 l -0.01089729309082 0 l -0.01036835670471 0 l -0.00987038612366 0 l -0.00940062522888 0 l -0.00895661354065 0 l -0.00853617668152 0" + android:propertyXName="scaleX" + android:repeatCount="-1" /> + +</set>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect1_translate.xml b/tests/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect1_translate.xml new file mode 100644 index 0000000..4781ba8 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect1_translate.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" > + + <objectAnimator + android:duration="2016" + android:pathData=" + M -522.599975585938 0 l 0 0 l 0.12939453125 0 l 0.33831787109375 0 l 0.55450439453125 0 l 0.7708740234375 0 l 0.98065185546875 0 l 1.1964111328125 0 l 1.41351318359375 0 l 1.63153076171875 0 l 1.85052490234375 0 l 2.07052612304688 0 l 2.29080200195312 0 l 2.51150512695312 0 l 2.73260498046875 0 l 2.95355224609375 0 l 3.17404174804688 0 l 3.39422607421875 0 l 3.61355590820312 0 l 3.83163452148438 0 l 4.04849243164062 0 l 4.263671875 0 l 5.74725341796875 0 l 6.1026611328125 0 l 6.45980834960938 0 l 6.81781005859375 0 l 7.17654418945312 0 l 7.53366088867188 0 l 7.88861083984375 0 l 8.23974609375 0 l 8.58447265625 0 l 8.92156982421875 0 l 9.24810791015625 0 l 9.56137084960938 0 l 9.85906982421875 0 l 10.1377868652344 0 l 10.3955688476562 0 l 10.6287536621094 0 l 10.8357238769531 0 l 11.0149230957031 0 l 11.1639709472656 0 l 11.2832336425781 0 l 11.3713989257812 0 l 11.4301147460938 0 l 11.4596557617188 0 l 11.4611053466797 0 l 11.4369049072266 0 l 11.3887786865234 0 l 11.3183441162109 0 l 11.2276000976562 0 l 11.1185607910156 0 l 10.9933776855469 0 l 10.8534698486328 0 l 10.6995391845703 0 l 10.533935546875 0 l 10.3744659423828 0 l 10.3707733154297 0 l 10.4309463500977 0 l 10.5275726318359 0 l 10.671501159668 0 l 10.8763961791992 0 l 11.1566543579102 0 l 11.5270767211914 0 l 11.9947967529297 0 l 12.5502433776855 0 l 13.1453399658203 0 l 13.680793762207 0 l 14.0223298072815 0 l 14.0650296211243 0 l 13.798041343689 0 l 13.2949924468994 0 l 12.6584892272949 0 l 11.9693031311035 0 l 11.2772979736328 0 l 10.607666015625 0 l 9.97052764892578 0 l 9.36723327636719 0 l 8.79751586914062 0 l 8.25792694091797 0 l 7.74495697021484 0 l 7.25632476806641 0 l 6.78855895996094 0 l 6.33934020996094 0 l 5.9071044921875 0 l 5.48941040039062 0 l 5.08502197265625 0 l 4.69291687011719 0 l 4.33430480957031 0 l 4.00733947753906 0 l 3.68829345703125 0 l 3.37684631347656 0 l 3.07246398925781 0 l 2.77439880371094 0 l 2.48252868652344 0 l 2.20101928710938 0 l 1.91748046875 0 l 1.63726806640625 0 l 1.36772155761719 0" + android:propertyXName="translateX" + android:repeatCount="-1" /> + +</set>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect2_scale.xml b/tests/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect2_scale.xml new file mode 100644 index 0000000..a61af8f --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect2_scale.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" > + + <objectAnimator + android:duration="2016" + android:pathData=" + M 0.1 1 l 0.00930031776428 0 l 0.01123028755188 0 l 0.01313143730164 0 l 0.01497107505798 0 l 0.01671510696411 0 l 0.01833034515381 0 l 0.01978672027588 0 l 0.02105976104736 0 l 0.02213228225708 0 l 0.02299520492554 0 l 0.02364795684814 0 l 0.02409727096558 0 l 0.02435619354248 0 l 0.02444213867188 0 l 0.02437515258789 0 l 0.02417644500732 0 l 0.02386695861816 0 l 0.02346652984619 0 l 0.02299335479736 0 l 0.0224634552002 0 l 0.02189086914062 0 l 0.02128746032715 0 l 0.02066318511963 0 l 0.02002624511719 0 l 0.01938335418701 0 l 0.01873977661133 0 l 0.01809989929199 0 l 0.01746696472168 0 l 0.01684349060059 0 l 0.01623161315918 0 l 0.0156324005127 0 l 0.0150471496582 0 l 0.01447631835938 0 l 0.01392051696777 0 l 0.01337966918945 0 l 0.0128540802002 0 l 0.01234344482422 0 l 0.01184753417969 0 l 0.0113663482666 0 l 0.01089920043945 0 l 0.01044593811035 0 l 0.00998542785645 0 l 0.00933837890625 0 l 0.00863349914551 0 l 0.00791206359863 0 l 0.00717010498047 0 l 0.00640274047852 0 l 0.00560478210449 0 l 0.00477012634277 0 l 0.00389221191406 0 l 0.00296325683594 0 l 0.0019751739502 0 l 0.00091903686523 0 l -0.00021408081055 0 l -0.00143287658691 0 l -0.00274444580078 0 l -0.00415267944336 0 l -0.00565589904785 0 l -0.00724327087402 0 l -0.00889205932617 0 l -0.01056480407715 0 l -0.01220878601074 0 l -0.01376045227051 0 l -0.01515449523926 0 l -0.01633560180664 0 l -0.01726905822754 0 l -0.01794639587402 0 l -0.0183829498291 0 l -0.01861137390137 0 l -0.01867179870605 0 l -0.01860504150391 0 l -0.01844764709473 0 l -0.01822959899902 0 l -0.01797431945801 0 l -0.0176993560791 0 l -0.0174169921875 0 l -0.01713603973389 0 l -0.01686214447021 0 l -0.01651359558105 0 l -0.01609485626221 0 l -0.01569358825684 0 l -0.01531024932861 0 l -0.0149446105957 0 l -0.01459632873535 0 l -0.01426464080811 0 l -0.0139489364624 0 l -0.01364833831787 0 l -0.01336200714111 0 l -0.01308917999268 0 l -0.01282897949219 0 l -0.01258075714111 0 l -0.01234363555908 0 l -0.01211700439453 0 l -0.01190029144287 0 l -0.01169273376465 0 l -0.01149394989014 0 l -0.01130325317383 0 l -0.01112024307251 0 l -0.01094444274902 0 l -0.01077545166016 0 l -0.0106128692627 0 l -0.01045631408691 0 l -0.01030544281006 0 l -0.01016000747681 0 l -0.01001962661743 0 l -0.0098840713501 0 l -0.00975311279297 0 l -0.00962644577026 0 l -0.00950393676758 0 l -0.00938529968262 0 l -0.00927038192749 0 l -0.00915899276733 0 l -0.00905097961426 0 l -0.00894614219666 0 l -0.00884438514709 0 l -0.00874552726746 0 l -0.00864946365356 0 l -0.00855606079102 0 l -0.00846519470215 0 l -0.00837676048279 0 " + android:propertyXName="scaleX" + android:repeatCount="-1" /> + +</set>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect2_translate.xml b/tests/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect2_translate.xml new file mode 100644 index 0000000..31fa795 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/animation_linear_progress_bar_rect2_translate.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" > + + <objectAnimator + android:duration="2016" + android:pathData=" + M -197.600006103516 0 l 1.42625427246094 0 l 1.80754089355469 0 l 2.18778991699219 0 l 2.56109619140625 0 l 2.91810607910156 0 l 3.25482177734375 0 l 3.57159423828125 0 l 3.862548828125 0 l 4.12493896484375 0 l 4.35758972167969 0 l 4.56034851074219 0 l 4.73426818847656 0 l 4.88090515136719 0 l 5.00271606445312 0 l 5.10273742675781 0 l 5.18400573730469 0 l 5.24911499023438 0 l 5.30097961425781 0 l 5.34226226806641 0 l 5.37535095214844 0 l 5.40180206298828 0 l 5.42322540283203 0 l 5.44123077392578 0 l 5.45704650878906 0 l 5.47099304199219 0 l 5.48395538330078 0 l 5.4967041015625 0 l 5.50949859619141 0 l 5.52214813232422 0 l 5.53528594970703 0 l 5.54912567138672 0 l 5.56306457519531 0 l 5.57742691040039 0 l 5.59244155883789 0 l 5.60744094848633 0 l 5.62243270874023 0 l 5.6376781463623 0 l 5.65262794494629 0 l 5.66689777374268 0 l 5.68069934844971 0 l 5.69401162862778 0 l 5.70898681879044 0 l 5.75169992446899 0 l 5.80327129364014 0 l 5.85710144042969 0 l 5.91399765014648 0 l 5.97450065612793 0 l 6.03849411010742 0 l 6.10729217529297 0 l 6.18125534057617 0 l 6.26116561889648 0 l 6.34840393066406 0 l 6.44406127929688 0 l 6.54866790771484 0 l 6.66371917724609 0 l 6.79020690917969 0 l 6.92859649658203 0 l 7.07807159423828 0 l 7.23712158203125 0 l 7.40253448486328 0 l 7.56884765625 0 l 7.72840881347656 0 l 7.87199401855469 0 l 7.98992919921875 0 l 8.07417297363281 0 l 8.12013244628906 0 l 8.12655639648438 0 l 8.09510803222656 0 l 8.03091430664062 0 l 7.93995666503906 0 l 7.827880859375 0 l 7.69976806640625 0 l 7.56065368652344 0 l 7.41322326660156 0 l 7.26063537597656 0 l 7.10470581054688 0 l 6.94624328613281 0 l 6.78694152832031 0 l 6.6390380859375 0 l 6.50302124023438 0 l 6.36688232421875 0 l 6.23043823242188 0 l 6.09356689453125 0 l 5.95706176757812 0 l 5.82064819335938 0 l 5.6839599609375 0 l 5.5477294921875 0 l 5.41143798828125 0 l 5.27532958984375 0 l 5.13922119140625 0 l 5.00347900390625 0 l 4.8680419921875 0 l 4.73251342773438 0 l 4.59732055664062 0 l 4.46258544921875 0 l 4.328125 0 l 4.1937255859375 0 l 4.0599365234375 0 l 3.92672729492188 0 l 3.79376220703125 0 l 3.66119384765625 0 l 3.52935791015625 0 l 3.398193359375 0 l 3.26748657226562 0 l 3.13726806640625 0 l 3.00796508789062 0 l 2.87939453125 0 l 2.7515869140625 0 l 2.62445068359375 0 l 2.49810791015625 0 l 2.3726806640625 0 l 2.2481689453125 0 l 2.12457275390625 0 l 2.00173950195312 0 l 1.87997436523438 0 l 1.7618408203125 0 l 1.64154052734375 0 l 1.51962280273438 0 l 1.40017700195312 0 l 1.28421020507812 0 " + android:propertyXName="translateX" + android:repeatCount="-1" /> + +</set>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation01.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation01.xml new file mode 100644 index 0000000..d47e019 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/trim_path_animation01.xml @@ -0,0 +1,35 @@ +<?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. +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" > + + <set android:ordering="sequentially" > + <objectAnimator + android:duration="5000" + android:propertyName="trimPathEnd" + android:valueFrom="0" + android:valueTo="1" + android:valueType="floatType" /> + <objectAnimator + android:duration="5000" + android:propertyName="trimPathEnd" + android:valueFrom="1" + android:valueTo="0" + android:valueType="floatType" /> + </set> + +</set>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation02.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation02.xml new file mode 100644 index 0000000..3bf2865 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/trim_path_animation02.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" > + + <objectAnimator + android:duration="5000" + android:propertyName="fill" + android:valueFrom="#FF000000" + android:valueTo="#FFFF0000"/> + +</set>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation03.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation03.xml new file mode 100644 index 0000000..0c1073e --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/trim_path_animation03.xml @@ -0,0 +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. +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" > + + <objectAnimator + android:duration="6000" + android:propertyName="rotation" + android:valueFrom="0" + android:valueTo="360" + android:interpolator="@interpolator/custom_path_interpolator" + /> + +</set>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation04.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation04.xml new file mode 100644 index 0000000..4d0aae1 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/trim_path_animation04.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <objectAnimator + android:duration="9000" + android:propertyXName="translateX" + android:propertyYName="translateY" + android:pathData="m0,0 q 150, 300 150, 0 t 150, 0, t 150, 0 t -150 0 t -150 0 t -150 0 z" /> +</set>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation05.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation05.xml new file mode 100644 index 0000000..92b1ab5 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/trim_path_animation05.xml @@ -0,0 +1,35 @@ +<?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. +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:ordering="sequentially" > + + <objectAnimator + android:duration="3000" + android:propertyName="pathData" + android:valueFrom="M300,70 l 0,-70 70,70 0,0 -70,70z" + android:valueTo= "M300,70 l 0,-70 70,0 0,140 -70,0 z" + android:valueType="pathType"/> + + <objectAnimator + android:duration="3000" + android:propertyName="pathData" + android:valueFrom="@string/rectangle2" + android:valueTo="@string/equal2" + android:valueType="pathType"/> + +</set>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/anim/trim_path_animation_progress_bar.xml b/tests/VectorDrawableTest/res/anim/trim_path_animation_progress_bar.xml new file mode 100644 index 0000000..c9fd676 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/trim_path_animation_progress_bar.xml @@ -0,0 +1,45 @@ +<?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. +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" > + + <objectAnimator + android:duration="1300" + android:interpolator="@interpolator/trim_start_interpolator" + android:propertyName="trimPathStart" + android:repeatCount="-1" + android:valueFrom="0" + android:valueTo="0.75" + android:valueType="floatType" /> + <objectAnimator + android:duration="1300" + android:interpolator="@interpolator/trim_end_interpolator" + android:propertyName="trimPathEnd" + android:repeatCount="-1" + android:valueFrom="0" + android:valueTo="0.75" + android:valueType="floatType" /> + <objectAnimator + android:duration="1300" + android:interpolator="@android:anim/linear_interpolator" + android:propertyName="trimPathOffset" + android:repeatCount="-1" + android:valueFrom="0" + android:valueTo="0.25" + android:valueType="floatType" /> + +</set>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable-hdpi/icon.png b/tests/VectorDrawableTest/res/drawable-hdpi/icon.png Binary files differnew file mode 100644 index 0000000..60fbdf5 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable-hdpi/icon.png diff --git a/tests/VectorDrawableTest/res/drawable-nodpi/bitmap_drawable01.jpg b/tests/VectorDrawableTest/res/drawable-nodpi/bitmap_drawable01.jpg Binary files differnew file mode 100644 index 0000000..dc8c197 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable-nodpi/bitmap_drawable01.jpg diff --git a/tests/VectorDrawableTest/res/drawable/animation_drawable_vector.xml b/tests/VectorDrawableTest/res/drawable/animation_drawable_vector.xml new file mode 100644 index 0000000..a588960 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/animation_drawable_vector.xml @@ -0,0 +1,36 @@ +<!-- + 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. +--> +<animation-list xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/animation_drawable_vector" android:oneshot="false"> + <item android:drawable="@drawable/vector_drawable01" android:duration="300" /> + <item android:drawable="@drawable/vector_drawable02" android:duration="300" /> + <item android:drawable="@drawable/vector_drawable03" android:duration="300" /> + <item android:drawable="@drawable/vector_drawable04" android:duration="300" /> + <item android:drawable="@drawable/vector_drawable05" android:duration="300" /> + <item android:drawable="@drawable/vector_drawable06" android:duration="300" /> + <item android:drawable="@drawable/vector_drawable07" android:duration="300" /> + <item android:drawable="@drawable/vector_drawable08" android:duration="300" /> + <item android:drawable="@drawable/vector_drawable09" android:duration="300" /> + <item android:drawable="@drawable/vector_drawable10" android:duration="300" /> + <item android:drawable="@drawable/vector_drawable11" android:duration="300" /> + <item android:drawable="@drawable/vector_drawable12" android:duration="300" /> + <item android:drawable="@drawable/vector_drawable13" android:duration="300" /> + <item android:drawable="@drawable/vector_drawable14" android:duration="300" /> + <item android:drawable="@drawable/vector_drawable15" android:duration="300" /> + <item android:drawable="@drawable/vector_drawable16" android:duration="300" /> + <item android:drawable="@drawable/vector_drawable17" android:duration="300" /> + <item android:drawable="@drawable/vector_drawable18" android:duration="300" /> + </animation-list> diff --git a/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml new file mode 100644 index 0000000..19b82ad --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/animation_vector_drawable01.xml @@ -0,0 +1,41 @@ +<!-- + 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. +--> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/vector_drawable12" > + + <target + android:name="pie1" + android:animation="@anim/trim_path_animation01" /> + <target + android:name="v" + android:animation="@anim/trim_path_animation02" /> + <target + android:name="v" + android:animation="@anim/trim_path_animation05" /> + <target + android:name="rotationGroup" + android:animation="@anim/trim_path_animation03" /> + <target + android:name="rotationGroup3" + android:animation="@anim/trim_path_animation03" /> + <target + android:name="rotationGroupBlue" + android:animation="@anim/trim_path_animation03" /> + <target + android:name="rotationGroup" + android:animation="@anim/trim_path_animation04" /> + +</animated-vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/animation_vector_drawable_favorite.xml b/tests/VectorDrawableTest/res/drawable/animation_vector_drawable_favorite.xml new file mode 100644 index 0000000..9d8381f --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/animation_vector_drawable_favorite.xml @@ -0,0 +1,26 @@ +<!-- + 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. +--> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/vector_drawable_favorite" > + + <target + android:name="favorite" + android:animation="@anim/animation_favorite" /> + <target + android:name="root" + android:animation="@anim/animation_favorite02" /> + +</animated-vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/animation_vector_drawable_grouping_1.xml b/tests/VectorDrawableTest/res/drawable/animation_vector_drawable_grouping_1.xml new file mode 100644 index 0000000..4a7e4f6 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/animation_vector_drawable_grouping_1.xml @@ -0,0 +1,26 @@ +<!-- + 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. +--> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/vector_drawable_grouping_1" > + + <target + android:name="sun" + android:animation="@anim/animation_grouping_1_01" /> + <target + android:name="earth" + android:animation="@anim/animation_grouping_1_01" /> + +</animated-vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/animation_vector_linear_progress_bar.xml b/tests/VectorDrawableTest/res/drawable/animation_vector_linear_progress_bar.xml new file mode 100644 index 0000000..05bf833 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/animation_vector_linear_progress_bar.xml @@ -0,0 +1,32 @@ +<!-- + 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. +--> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/vector_drawable_linear_progress_bar" > + + <target + android:name="path1" + android:animation="@anim/animation_linear_progress_bar_rect1_translate" /> + <target + android:name="path1" + android:animation="@anim/animation_linear_progress_bar_rect1_scale" /> + + <target + android:name="path2" + android:animation="@anim/animation_linear_progress_bar_rect2_translate" /> + <target + android:name="path2" + android:animation="@anim/animation_linear_progress_bar_rect2_scale" /> +</animated-vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/animation_vector_progress_bar.xml b/tests/VectorDrawableTest/res/drawable/animation_vector_progress_bar.xml new file mode 100644 index 0000000..6621e41 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/animation_vector_progress_bar.xml @@ -0,0 +1,23 @@ +<!-- + 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. +--> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/vector_drawable_progress_bar" > + + <target + android:name="pie1" + android:animation="@anim/trim_path_animation_progress_bar" /> + +</animated-vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/icon.png b/tests/VectorDrawableTest/res/drawable/icon.png Binary files differnew file mode 100644 index 0000000..cb40a19 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/icon.png diff --git a/tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable01.xml new file mode 100644 index 0000000..18d7755 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable01.xml @@ -0,0 +1,47 @@ +<!-- + 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. +--> + +<animated-selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/on" android:state_checked="true" + android:drawable="@drawable/vector_drawable12" /> + <item android:id="@+id/off" + android:drawable="@drawable/vector_drawable12" /> + <transition android:fromId="@+id/off" android:toId="@+id/on" android:reversible="true"> + <animated-vector android:drawable="@drawable/vector_drawable12"> + <target + android:name="pie1" + android:animation="@anim/trim_path_animation01" /> + <target + android:name="v" + android:animation="@anim/trim_path_animation02" /> + <target + android:name="v" + android:animation="@anim/trim_path_animation05" /> + <target + android:name="rotationGroup" + android:animation="@anim/trim_path_animation03" /> + <target + android:name="rotationGroup3" + android:animation="@anim/trim_path_animation03" /> + <target + android:name="rotationGroupBlue" + android:animation="@anim/trim_path_animation03" /> + <target + android:name="rotationGroup" + android:animation="@anim/trim_path_animation04" /> + </animated-vector> + </transition> +</animated-selector> diff --git a/tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable02.xml b/tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable02.xml new file mode 100644 index 0000000..6a67b02 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable02.xml @@ -0,0 +1,26 @@ +<!-- + 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. +--> + +<animated-selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/on" android:state_checked="true" + android:drawable="@drawable/vector_drawable_grouping_1" /> + <item android:id="@+id/off" + android:drawable="@drawable/vector_drawable_grouping_1" /> + <transition android:fromId="@+id/off" android:toId="@+id/on" + android:drawable="@drawable/animation_vector_drawable_grouping_1" + android:reversible="true"> + </transition> +</animated-selector> diff --git a/tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable03.xml b/tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable03.xml new file mode 100644 index 0000000..65cf25b --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/state_animation_vector_drawable03.xml @@ -0,0 +1,26 @@ +<!-- + 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. +--> + +<animated-selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/on" android:state_checked="true" + android:drawable="@drawable/vector_drawable_favorite" /> + <item android:id="@+id/off" + android:drawable="@drawable/vector_drawable_favorite" /> + <transition android:fromId="@+id/off" android:toId="@+id/on" + android:drawable="@drawable/animation_vector_drawable_favorite" + android:reversible="true"> + </transition> +</animated-selector> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml new file mode 100644 index 0000000..705cc34 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml @@ -0,0 +1,31 @@ +<!-- + 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="48dp" + android:width="48dp" + android:viewportHeight="480" + android:viewportWidth="480" > + + <group> + <path + android:name="box1" + android:pathData="m20,200l100,90l180-180l-35-35l-145,145l-60-60l-40,40z" + android:fillColor="?android:attr/colorControlActivated" + android:strokeColor="?android:attr/colorControlActivated" + android:strokeLineCap="round" + android:strokeLineJoin="round" /> + </group> +</vector> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml new file mode 100644 index 0000000..f5d647c --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml @@ -0,0 +1,32 @@ +<!-- 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="64dp" + android:height="64dp" android:viewportWidth="320" + android:viewportHeight="320"> + <group + android:rotation="180" + android:pivotX="70" + android:pivotY="120"> + <path + android:name="house" + android:pathData="M 130,225 L 130,115 L 130,115 L 70,15 L 10,115 L 10,115 L 10,225 z" + android:fillColor="#ff440000" + android:strokeColor="#FF00FF00" + android:strokeWidth="10" + android:trimPathStart=".1" + android:trimPathEnd=".9"/> + </group> +</vector> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml new file mode 100644 index 0000000..a0b0e00 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml @@ -0,0 +1,71 @@ +<!-- + 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="12.25" + android:viewportWidth="7.30625" > + + <group + android:pivotX="3.65" + android:pivotY="6.125" + android:rotation="-30" > + <clip-path + android:name="clip1" + android:pathData=" + M 0, 6.125 + l 7.3, 0 + l 0, 12.25 + l-7.3, 0 + z" /> + </group> + <group> + <path + android:name="one" + android:fillColor="#ff88ff" + android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125 + l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0 + l-5.046875,0.0 0.0-1.0Z" /> + </group> + <group + android:pivotX="3.65" + android:pivotY="6.125" + android:rotation="-30" > + <clip-path + android:name="clip2" + android:pathData=" + M 0, 0 + l 7.3, 0 + l 0, 6.125 + l-7.3, 0 + z" /> + </group> + <group> + <path + android:name="two" + android:fillColor="#ff88ff" + android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375 + q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625 + q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625 + q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875 + q-0.609375,0.1875-1.3125,0.59375l 0.0-1.203125q 0.71875-0.28125 1.328125-0.421875 + q 0.625-0.15625 1.140625-0.15625 1.3593752,0.0 2.1718752,0.6875 + q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125-0.203125,1.015625 + q-0.203125,0.484375-0.734375,1.140625-0.15625,0.171875-0.9375,0.984375 + q-0.78125024,0.8125-2.2187502,2.265625Z" /> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml new file mode 100644 index 0000000..d282fc9 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml @@ -0,0 +1,57 @@ +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="64dp" + android:height="64dp" + android:viewportWidth="7.30625" + android:viewportHeight="12.25" + android:autoMirrored="true"> + + <group> + <clip-path + android:name="clip1" + android:pathData=" + M 3.65, 6.125 + m-.001, 0 + a .001,.001 0 1,0 .002,0 + a .001,.001 0 1,0-.002,0z"/> + <path + android:name="one" + android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125 + l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0 + l-5.046875,0.0 0.0-1.0Z" + android:fillColor="#ff88ff"/> + + <clip-path + android:name="clip2" + android:pathData=" + M 3.65, 6.125 + m-6, 0 + a 6,6 0 1,0 12,0 + a 6,6 0 1,0-12,0z"/> + <path + android:name="two" + android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375 + q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625 + q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625 + q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875 + q-0.609375,0.1875-1.3125,0.59375l 0.0-1.203125q 0.71875-0.28125 1.328125-0.421875 + q 0.625-0.15625 1.140625-0.15625 1.3593752,0.0 2.1718752,0.6875 + q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125-0.203125,1.015625 + q-0.203125,0.484375-0.734375,1.140625-0.15625,0.171875-0.9375,0.984375 + q-0.78125024,0.8125-2.2187502,2.265625Z" + android:fillColor="#ff88ff"/> + </group> +</vector> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml new file mode 100644 index 0000000..bbf1a17 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml @@ -0,0 +1,42 @@ +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="12.25" + android:viewportWidth="7.30625" > + + <group> + <path + android:name="one" + android:fillColor="#ffff00" + android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125 + l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0 + l-5.046875,0.0 0.0-1.0Z" /> + <path + android:name="two" + android:fillColor="#00ffff00" + android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375 + q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625 + q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625 + q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875 + q-0.609375,0.1875-1.3125,0.59375l 0.0-1.203125q 0.71875-0.28125 1.328125-0.421875 + q 0.625-0.15625 1.140625-0.15625 1.3593752,0.0 2.1718752,0.6875 + q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125-0.203125,1.015625 + q-0.203125,0.484375-0.734375,1.140625-0.15625,0.171875-0.9375,0.984375 + q-0.78125024,0.8125-2.2187502,2.265625Z" /> + </group> +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml new file mode 100644 index 0000000..98b6235 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml @@ -0,0 +1,48 @@ +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="64dp" + android:height="64dp" + android:viewportWidth="700" + android:viewportHeight="700"> + + <group> + <path android:pathData="M 569.374 461.472L 569.374 160.658L 160.658 160.658L 160.658 461.472L 569.374 461.472z" + android:name="path2451" + android:fillColor="#00000000" + android:strokeColor="#FF000000" + android:strokeWidth="30.65500000000000"/> + <path android:pathData="M 365.015 311.066" + android:name="path2453" + android:fillColor="#00000000" + android:strokeColor="#FF000000" + android:strokeWidth="30.655000000000001"/> + <path android:pathData="M 164.46 164.49L 340.78 343.158C 353.849 356.328 377.63 356.172 390.423 343.278L 566.622 165.928" + android:name="path2455" + android:strokeColor="#FF000000" + android:fillColor="#FFFFFFFF" + android:strokeWidth="30.655000000000001"/> + <path android:pathData="M 170.515 451.566L 305.61 313.46" + android:name="path2457" + android:fillColor="#00000000" + android:strokeColor="#000000" + android:strokeWidth="30.655000000000001"/> + <path android:pathData="M 557.968 449.974L 426.515 315.375" + android:name="path2459" + android:fillColor="#00000000" + android:strokeColor="#000000" + android:strokeWidth="30.655000000000001"/> + </group> +</vector> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml new file mode 100644 index 0000000..88c4a1e --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml @@ -0,0 +1,29 @@ +<!-- 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="64dp" + android:height="64dp" android:viewportWidth="140" + android:viewportHeight="110"> + + <group> + <path + android:name="back" + android:pathData="M 20,55 l 35.3-35.3 7.07,7.07-35.3,35.3 z + M 27,50 l 97,0 0,10-97,0 z + M 20,55 l 7.07-7.07 35.3,35.3-7.07,7.07 z" + android:fillColor="#ffffffff" + /> + </group> +</vector> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml new file mode 100644 index 0000000..75529e2 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml @@ -0,0 +1,29 @@ +<!-- 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="64dp" + android:height="64dp" android:viewportWidth="600" + android:viewportHeight="600"> + + <group> + <path + android:name="pie1" + android:pathData="M535.441,412.339A280.868,280.868 0 1,1 536.186,161.733L284.493,286.29Z" + android:fillColor="#ffffcc00" + android:strokeColor="#FF00FF00" + android:strokeWidth="1"/> + </group> + +</vector> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml new file mode 100644 index 0000000..853a770 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml @@ -0,0 +1,32 @@ +<!-- + 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="200" + android:viewportWidth="200" > + + <group + android:pivotX="100" + android:pivotY="100" + android:rotation="90"> + <path + android:name="house" + android:fillColor="#ffffffff" + android:pathData="M 100,20 l 0,0 0,140-80,0 z M 100,20 l 0,0 80,140-80,0 z"/> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml new file mode 100644 index 0000000..83ed194 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml @@ -0,0 +1,42 @@ +<?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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportWidth="200" + android:viewportHeight="200"> + + <group> + <path + android:name="bar3" + android:fillColor="#FFFFFFFF" + android:pathData="M49.001,60c-5.466,0-9.899,4.478-9.899,10s4.434,10,9.899,10c5.468,0,9.899-4.478,9.899-10S54.469,60,49.001,60z" /> + <path + android:name="bar2" + android:fillColor="#FFFFFFFF" + android:pathData="M28.001,48.787l7,7.07c7.731-7.811,20.269-7.81,28.001,0l6.999-7.07C58.403,37.071,39.599,37.071,28.001,48.787z" /> + <path + android:name="bar1" + android:fillColor="#FF555555" + android:pathData="M14.001,34.645 L21,41.716c15.464-15.621,40.536-15.621,56,0l7.001-7.071C64.672,15.119,33.33,15.119,14.001,34.645z" /> + <path + android:name="bar0" + android:fillColor="#FF555555" + android:pathData="M0,20.502l6.999,7.071 c23.196-23.431,60.806-23.431,84.002,0L98,20.503C70.938-6.834,27.063-6.834,0,20.502z" /> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml new file mode 100644 index 0000000..b3d7d8e --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml @@ -0,0 +1,35 @@ +<!-- + 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="80" + android:viewportWidth="40" > + + <group> + <path + android:name="battery" + android:fillColor="#3388ff" + android:pathData="M 20.28125,2.0000002 C 17.352748,2.0000002 15,4.3527485 15,7.2812502 L 15,8.0000002 L 13.15625,8.0000002 C 9.7507553,8.0000002 7,10.750759 7,14.15625 L 7,39.84375 C 7,43.24924 9.7507558,46 13.15625,46 L 33.84375,46 C 37.249245,46 39.999999,43.24924 40,39.84375 L 40,14.15625 C 40,10.75076 37.249243,8.0000002 33.84375,8.0000002 L 32,8.0000002 L 32,7.2812502 C 32,4.3527485 29.647252,2.0000002 26.71875,2.0000002 L 20.28125,2.0000002 z" + android:strokeColor="#ff8833" + android:strokeWidth="1" /> + <path + android:name="spark" + android:fillColor="#FFFF0000" + android:pathData="M 30,18.031528 L 25.579581,23.421071 L 29.370621,26.765348 L 20.096792,37 L 21.156922,28.014053 L 17,24.902844 L 20.880632,18 L 30,18.031528 z" /> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml new file mode 100644 index 0000000..2c8b751 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml @@ -0,0 +1,95 @@ +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="600" + android:viewportWidth="600" > + + <group + android:name="rotationGroup" + android:pivotX="300.0" + android:pivotY="300.0" + android:rotation="45.0" > + <path + android:name="pie1" + android:fillColor="#00000000" + android:pathData="M300,70 a230,230 0 1,0 1,0 z" + android:strokeColor="#FF777777" + android:strokeWidth="70" + android:trimPathEnd=".75" + android:trimPathOffset="0" + android:trimPathStart="0" /> + <path + android:name="v" + android:fillColor="#000000" + android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" /> + + <group + android:name="translateToCenterGroup" + android:rotation="0.0" + android:translateX="200.0" + android:translateY="200.0" > + <group + android:name="rotationGroup2" + android:pivotX="0.0" + android:pivotY="0.0" + android:rotation="-45.0" > + <path + android:name="twoLines1" + android:pathData="@string/twoLinePathData" + android:strokeColor="#FFFF0000" + android:strokeWidth="20" /> + + <group + android:name="translateGroupHalf" + android:translateX="65.0" + android:translateY="80.0" > + <group + android:name="rotationGroup3" + android:pivotX="-65.0" + android:pivotY="-80.0" + android:rotation="-45.0" > + <path + android:name="twoLines2" + android:fillColor="#FF00FF00" + android:pathData="@string/twoLinePathData" + android:strokeColor="#FF00FF00" + android:strokeWidth="20" /> + + <group + android:name="translateGroup" + android:translateX="65.0" + android:translateY="80.0" > + <group + android:name="rotationGroupBlue" + android:pivotX="-65.0" + android:pivotY="-80.0" + android:rotation="-45.0" > + <path + android:name="twoLines3" + android:pathData="@string/twoLinePathData" + android:strokeColor="#FF0000FF" + android:strokeWidth="20" /> + </group> + </group> + </group> + </group> + </group> + </group> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml new file mode 100644 index 0000000..2468a1b --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml @@ -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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="400" + android:viewportWidth="600" > + + <group> + <path + android:name="pie1" + android:fillColor="#ffffffff" + android:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z" + android:strokeColor="#FF00FF00" + android:strokeWidth="1" /> + <path + android:name="half" + android:fillColor="#FFFF0000" + android:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z" + android:strokeColor="#FF0000FF" + android:strokeWidth="5" /> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml new file mode 100644 index 0000000..01e24d3 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml @@ -0,0 +1,38 @@ +<!-- + 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="500" + android:viewportWidth="800" > + + <group + android:pivotX="90" + android:pivotY="100" + android:rotation="20"> + <path + android:name="pie2" + android:pathData="M200,350 l 50,-25 + a25,12 -30 0,1 100,-50 l 50,-25 + a25,25 -30 0,1 100,-50 l 50,-25 + a25,37 -30 0,1 100,-50 l 50,-25 + a25,50 -30 0,1 100,-50 l 50,-25" + android:fillColor="#00000000" + android:strokeColor="#FF00FF00" + android:strokeWidth="10" /> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml new file mode 100644 index 0000000..4bab2e3 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml @@ -0,0 +1,34 @@ +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="400" + android:viewportWidth="500" > + + <group + android:pivotX="250" + android:pivotY="200" + android:rotation="180"> + <path + android:name="house" + android:fillColor="#ff440000" + android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200" + android:strokeColor="#FFFF0000" + android:strokeWidth="10" /> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml new file mode 100644 index 0000000..107cda2 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml @@ -0,0 +1,47 @@ +<!-- + 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="200" + android:viewportWidth="200" > + + <group> + <path + android:name="background1" + android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" + android:fillColor="#FF000000"/> + <path + android:name="background2" + android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" + android:fillColor="#FF000000"/> + </group> + <group + android:pivotX="100" + android:pivotY="100" + android:rotation="90" + android:scaleX="0.75" + android:scaleY="0.5" + android:translateX="0.0" + android:translateY="100.0"> + <path + android:name="twoLines" + android:pathData="M 100,10 v 90 M 10,100 h 90" + android:strokeColor="#FF00FF00" + android:strokeWidth="10" /> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml new file mode 100644 index 0000000..8019549 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml @@ -0,0 +1,29 @@ +<!-- 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="64dp" + android:height="64dp" android:viewportWidth="1200" + android:viewportHeight="600"> + + <group> + <path + android:name="house" + android:pathData="M200,300 Q400,50 600,300 T1000,300" + android:fillColor="#00000000" + android:strokeColor="#FFFF0000" + android:strokeWidth="10"/> + </group> + +</vector> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml new file mode 100644 index 0000000..c93bdb9 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml @@ -0,0 +1,31 @@ +<!-- + 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="400" + android:viewportWidth="500" > + + <group> + <path + android:name="house" + android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF00" + android:strokeWidth="10" /> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml new file mode 100644 index 0000000..996b6be --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml @@ -0,0 +1,33 @@ +<!-- + 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="800" + android:viewportWidth="1000" > + + <group> + <path + android:name="house" + android:pathData="M10,300 Q400,550 600,300 T1000,300" + android:pivotX="90" + android:pivotY="100" + android:fillColor="#00000000" + android:strokeColor="#FFFF0000" + android:strokeWidth="60" /> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml new file mode 100644 index 0000000..5802144 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable20.xml @@ -0,0 +1,34 @@ +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="480" + android:viewportWidth="480" > + + <group> + <path + android:name="edit" + android:fillColor="#FF00FFFF" + android:pathData="M406.667,180c0,0 -100 -100 -113.334 -113.333 + c-13.333 -13.334 -33.333,0 -33.333,0l-160,160c0,0 -40,153.333 -40,173.333c0,13.333,13.333,13.333,13.333,13.333l173.334 -40 + c0,0,146.666 -146.666,160 -160C420,200,406.667,180,406.667,180z M226.399,356.823L131.95,378.62l-38.516 -38.522 + c7.848 -34.675,20.152 -82.52,23.538 -95.593l3.027,2.162l106.667,106.666L226.399,356.823z" + android:strokeColor="#FF000000" + android:strokeWidth="10" /> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable21.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable21.xml new file mode 100644 index 0000000..5626b44 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable21.xml @@ -0,0 +1,47 @@ +<!-- + 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="200" + android:viewportWidth="200" > + + <group> + <path + android:name="background1" + android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" + android:fillColor="#FF000000"/> + <path + android:name="background2" + android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" + android:fillColor="#FF000000"/> + </group> + <group + android:pivotX="0" + android:pivotY="0" + android:rotation="90" + android:scaleX="0.75" + android:scaleY="0.5" + android:translateX="100.0" + android:translateY="100.0"> + <path + android:name="twoLines" + android:pathData="M 100,10 v 90 M 10,100 h 90" + android:strokeColor="#FF00FF00" + android:strokeWidth="10" /> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable22.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable22.xml new file mode 100644 index 0000000..5b40d0d --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable22.xml @@ -0,0 +1,68 @@ +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="400" + android:viewportWidth="400" > + + <group android:name="backgroundGroup" > + <path + android:name="background1" + android:fillColor="#80000000" + android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" /> + <path + android:name="background2" + android:fillColor="#80000000" + android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" /> + </group> + <group + android:name="translateToCenterGroup" + android:translateX="50.0" + android:translateY="90.0" > + <path + android:name="twoLines" + android:pathData="M 0,0 v 100 M 0,0 h 100" + android:strokeColor="#FFFF0000" + android:strokeWidth="20" /> + + <group + android:name="rotationGroup" + android:pivotX="0.0" + android:pivotY="0.0" + android:rotation="-45.0" > + <path + android:name="twoLines1" + android:pathData="M 0,0 v 100 M 0,0 h 100" + android:strokeColor="#FF00FF00" + android:strokeWidth="20" /> + + <group + android:name="translateGroup" + android:translateX="130.0" + android:translateY="160.0" > + <group android:name="scaleGroup" > + <path + android:name="twoLines2" + android:pathData="M 0,0 v 100 M 0,0 h 100" + android:strokeColor="#FF0000FF" + android:strokeWidth="20" /> + </group> + </group> + </group> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable23.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable23.xml new file mode 100644 index 0000000..6ab6ffd --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable23.xml @@ -0,0 +1,82 @@ +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="400" + android:viewportWidth="400" > + + <group android:name="backgroundGroup" > + <path + android:name="background1" + android:fillColor="#80000000" + android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" /> + <path + android:name="background2" + android:fillColor="#80000000" + android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" /> + </group> + <group + android:name="translateToCenterGroup" + android:translateX="50.0" + android:translateY="90.0" > + <path + android:name="twoLines" + android:pathData="@string/twoLinePathData" + android:strokeColor="#FFFF0000" + android:strokeWidth="20" /> + + <group + android:name="rotationGroup" + android:pivotX="0.0" + android:pivotY="0.0" + android:rotation="-45.0" > + <path + android:name="twoLines1" + android:pathData="@string/twoLinePathData" + android:strokeColor="#FF00FF00" + android:strokeWidth="20" /> + + <group + android:name="translateGroup" + android:translateX="130.0" + android:translateY="160.0" > + <group android:name="scaleGroup" > + <path + android:name="twoLines3" + android:pathData="@string/twoLinePathData" + android:strokeColor="#FF0000FF" + android:strokeWidth="20" /> + </group> + </group> + + <group + android:name="translateGroupHalf" + android:translateX="65.0" + android:translateY="80.0" > + <group android:name="scaleGroup" > + <path + android:name="twoLines2" + android:pathData="@string/twoLinePathData" + android:fillColor="?android:attr/colorForeground" + android:strokeColor="?android:attr/colorForeground" + android:strokeWidth="20" /> + </group> + </group> + </group> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable24.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable24.xml new file mode 100644 index 0000000..5c1ccaa --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable24.xml @@ -0,0 +1,87 @@ +<!-- + 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="400" + android:viewportWidth="400" > + + <group android:name="backgroundGroup" + android:alpha = "0.5" > + <path + android:name="background1" + android:fillColor="#FF000000" + android:pathData="M 0,0 l 200,0 l 0, 200 l -200, 0 z" /> + <path + android:name="background2" + android:fillColor="#FF000000" + android:pathData="M 200,200 l 200,0 l 0, 200 l -200, 0 z" /> + </group> + <group + android:name="translateToCenterGroup" + android:translateX="50.0" + android:translateY="90.0" + android:alpha = "0.5" > + <path + android:name="twoLines" + android:pathData="@string/twoLinePathData" + android:strokeColor="#FFFF0000" + android:strokeWidth="20" /> + + <group + android:name="rotationGroup" + android:pivotX="0.0" + android:pivotY="0.0" + android:rotation="-45.0" + android:alpha = "0.5" > + <path + android:name="twoLines1" + android:pathData="@string/twoLinePathData" + android:strokeColor="#FF00FF00" + android:strokeWidth="20" /> + + <group + android:name="translateGroup" + android:translateX="130.0" + android:translateY="160.0" + android:alpha = "0.5"> + <group android:name="scaleGroup" > + <path + android:name="twoLines3" + android:pathData="@string/twoLinePathData" + android:strokeColor="#FF0000FF" + android:strokeWidth="20" /> + </group> + </group> + + <group + android:name="translateGroupHalf" + android:translateX="65.0" + android:translateY="80.0" + android:alpha = "0.5"> + <group android:name="scaleGroup" > + <path + android:name="twoLines2" + android:pathData="@string/twoLinePathData" + android:fillColor="?android:attr/colorForeground" + android:strokeColor="?android:attr/colorForeground" + android:strokeWidth="20" /> + </group> + </group> + </group> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable25.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable25.xml new file mode 100644 index 0000000..069a531 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable25.xml @@ -0,0 +1,89 @@ +<!-- + 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="400" + android:viewportWidth="400" > + + <group + android:name="FirstLevelGroup" + android:alpha="0.9" + android:translateX="100.0" + android:translateY="0.0" > + <group + android:name="SecondLevelGroup1" + android:alpha="0.9" + android:translateX="-100.0" + android:translateY="50.0" > + <path + android:fillColor="#FF00FF00" + android:pathData="@string/rectangle200" /> + + <group + android:name="ThridLevelGroup1" + android:alpha="0.9" + android:translateX="-100.0" + android:translateY="50.0" > + <path + android:fillColor="#FF0000FF" + android:pathData="@string/rectangle200" /> + </group> + <group + android:name="ThridLevelGroup2" + android:alpha="0.8" + android:translateX="100.0" + android:translateY="50.0" > + <path + android:fillColor="#FF000000" + android:pathData="@string/rectangle200" /> + </group> + </group> + <group + android:name="SecondLevelGroup2" + android:alpha="0.8" + android:translateX="100.0" + android:translateY="50.0" > + <path + android:fillColor="#FF0000FF" + android:pathData="@string/rectangle200" /> + + <group + android:name="ThridLevelGroup3" + android:alpha="0.9" + android:translateX="-100.0" + android:translateY="50.0" > + <path + android:fillColor="#FFFF0000" + android:pathData="@string/rectangle200" /> + </group> + <group + android:name="ThridLevelGroup4" + android:alpha="0.8" + android:translateX="100.0" + android:translateY="50.0" > + <path + android:fillColor="#FF00FF00" + android:pathData="@string/rectangle200" /> + </group> + </group> + + <path + android:fillColor="#FFFF0000" + android:pathData="@string/rectangle200" /> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable26.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable26.xml new file mode 100644 index 0000000..29cff52 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable26.xml @@ -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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:viewportHeight="200" + android:viewportWidth="200" + android:width="64dp" > + + <group> + <path + android:name="background1" + android:fillColor="#FF000000" + android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" /> + <path + android:name="background2" + android:fillColor="#FF000000" + android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" /> + </group> + <group + android:translateX="50" + android:translateY="50" > + <path + android:name="twoLines" + android:pathData="M 100,20 l 0 80 l -30 -80" + android:strokeColor="#FF00FF00" + android:strokeLineCap="butt" + android:strokeLineJoin="miter" + android:strokeMiterLimit="5" + android:strokeWidth="20" /> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable27.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable27.xml new file mode 100644 index 0000000..b0f0cee --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable27.xml @@ -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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:viewportHeight="200" + android:viewportWidth="200" + android:width="64dp" > + + <group> + <path + android:name="background1" + android:fillColor="#FF000000" + android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" /> + <path + android:name="background2" + android:fillColor="#FF000000" + android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" /> + </group> + <group + android:translateX="50" + android:translateY="50" > + <path + android:name="twoLines" + android:pathData="M 100,20 l 0 80 l -30 -80" + android:strokeColor="#FF00FF00" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeMiterLimit="10" + android:strokeWidth="20" /> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable28.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable28.xml new file mode 100644 index 0000000..2d2783b --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable28.xml @@ -0,0 +1,46 @@ +<!-- + 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:viewportHeight="200" + android:viewportWidth="200" + android:width="64dp" + android:autoMirrored="true" > + + <group> + <path + android:name="background1" + android:fillColor="#FF000000" + android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" /> + <path + android:name="background2" + android:fillColor="#FF000000" + android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" /> + </group> + <group + android:translateX="50" + android:translateY="50" > + <path + android:name="twoLines" + android:pathData="M 100,20 l 0 80 l -30 -80" + android:strokeColor="#FF00FF00" + android:strokeLineCap="square" + android:strokeLineJoin="bevel" + android:strokeMiterLimit="10" + android:strokeWidth="20" /> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_favorite.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable_favorite.xml new file mode 100644 index 0000000..7be49a9 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable_favorite.xml @@ -0,0 +1,38 @@ +<!-- + 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="128dp" + android:width="128dp" + android:viewportHeight="480" + android:viewportWidth="480" > + + <group + android:name="root" + android:translateX="240.0" + android:translateY="240.0" > + <path + android:name="favorite" + android:fillColor="#ff000000" + android:pathData="M2.100006104,-6 + C0.1449127197,-6,1.600006104,-5.975006104,0,-5.975006104 + C-1.574996948,-5.975006104,0.00309753418,-6-1.949996948-6 + C-4.492996216,-6,-5.949996948,-3.718399048,-5.949996948,-1.149993896 + C-5.949996948,2.379302979,-5.699996948,5.100006104,0,5.100006104 + C5.699996948,5.100006104,6,2.379302979,6,-1.149993896 + C6,-3.718399048,4.643005371-6,2.100006104-6" /> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_grouping_1.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable_grouping_1.xml new file mode 100644 index 0000000..7839ad1 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable_grouping_1.xml @@ -0,0 +1,52 @@ +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="256" + android:viewportWidth="256" > + + <group + android:name="shape_layer_1" + android:translateX="128" + android:translateY="128" > + <group android:name="sun" > + <path + android:name="ellipse_path_1" + android:fillColor="#ffff8000" + android:pathData="m -25 0 a 25,25 0 1,0 50,0 a 25,25 0 1,0 -50,0" /> + + <group + android:name="earth" + android:translateX="75" > + <path + android:name="ellipse_path_1_1" + android:fillColor="#ff5656ea" + android:pathData="m -10 0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0" /> + + <group + android:name="moon" + android:translateX="25" > + <path + android:name="ellipse_path_1_2" + android:fillColor="#ffadadad" + android:pathData="m -5 0 a 5,5 0 1,0 10,0 a 5,5 0 1,0 -10,0" /> + </group> + </group> + </group> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_linear_progress_bar.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable_linear_progress_bar.xml new file mode 100644 index 0000000..96fd70e --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable_linear_progress_bar.xml @@ -0,0 +1,46 @@ +<!-- + 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="4dp" + android:viewportHeight="4" + android:viewportWidth="360" + android:width="360dp" > + + <group + android:name="linear_indeterminate" + android:translateX="180.0" + android:translateY="0.0" > + <group + android:name="path1" + android:scaleX="0.1" + android:translateX="-522.59" > + <path + android:name="rect1" + android:fillColor="#FF000000" + android:pathData="l 288 0 l 0 4 l -288 0 z" /> + </group> + <group + android:name="path2" + android:scaleX="0.1" + android:translateX="-197.6" > + <path + android:name="rect2" + android:fillColor="#FF000000" + android:pathData="l 288 0 l 0 4 l -288 0 z" /> + </group> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_progress_bar.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable_progress_bar.xml new file mode 100644 index 0000000..4544cae --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable_progress_bar.xml @@ -0,0 +1,48 @@ +<!-- + Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="64" + android:viewportWidth="64" > + + <group + android:name="root" + android:pivotX="0.0" + android:pivotY="0.0" + android:rotation="0" + android:translateX="32.0" + android:translateY="32.0" > + <group + android:name="rotationGroup" + android:pivotX="0.0" + android:pivotY="0.0" + android:rotation="0" > + <path + android:name="pie1" + android:fillColor="#00000000" + android:pathData="M0, 0 m 0, -9.5 a 9.5,9.5 0 1,1 0,19 a 9.5,9.5 0 1,1 0,-19" + android:strokeColor="?android:attr/colorControlActivated" + android:strokeLineCap="round" + android:strokeLineJoin="miter" + android:strokeWidth="2" + android:trimPathEnd="0.1" + android:trimPathOffset="0" + android:trimPathStart="0" /> + </group> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml new file mode 100644 index 0000000..0a6cedc --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_icon_create.xml @@ -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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="24" + android:viewportWidth="24" > + + <group> + <path + android:fillColor="#FF000000" + android:pathData="M3.0,17.25L3.0,21.0l3.75,0.0L17.813995,9.936001l-3.75,-3.75L3.0,17.25zM20.707,7.0429993c0.391,-0.391 0.391,-1.023 0.0,-1.414l-2.336,-2.336c-0.391,-0.391 -1.023,-0.391 -1.414,0.0l-1.832,1.832l3.75,3.75L20.707,7.0429993z" /> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml new file mode 100644 index 0000000..94c10df --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_icon_delete.xml @@ -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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="24" + android:viewportWidth="24" > + + <group> + <path + android:fillColor="#FF000000" + android:pathData="M6.0,19.0c0.0,1.104 0.896,2.0 2.0,2.0l8.0,0.0c1.104,0.0 2.0,-0.896 2.0,-2.0l0.0,-12.0L6.0,7.0L6.0,19.0zM18.0,4.0l-2.5,0.0l-1.0,-1.0l-5.0,0.0l-1.0,1.0L6.0,4.0C5.4469986,4.0 5.0,4.4469986 5.0,5.0l0.0,1.0l14.0,0.0l0.0,-1.0C19.0,4.4469986 18.552002,4.0 18.0,4.0z" /> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml new file mode 100644 index 0000000..870e508 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_icon_heart.xml @@ -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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="24" + android:viewportWidth="24" > + + <group> + <path + android:fillColor="#FF000000" + android:pathData="M16.0,5.0c-1.955,0.0 -3.83,1.268 -4.5,3.0c-0.67,-1.732 -2.547,-3.0 -4.5,-3.0C4.4570007,5.0 2.5,6.931999 2.5,9.5c0.0,3.529 3.793,6.258 9.0,11.5c5.207,-5.242 9.0,-7.971 9.0,-11.5C20.5,6.931999 18.543,5.0 16.0,5.0z" /> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml new file mode 100644 index 0000000..1aad743 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_icon_schedule.xml @@ -0,0 +1,31 @@ +<!-- + 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="24" + android:viewportWidth="24" > + + <group> + <path + android:fillColor="#E6000000" + android:pathData="M11.994999,2.0C6.4679985,2.0 2.0,6.4780006 2.0,12.0s4.468,10.0 9.995,10.0S22.0,17.522 22.0,12.0S17.521,2.0 11.994999,2.0zM12.0,20.0c-4.42,0.0 -8.0,-3.582 -8.0,-8.0s3.58,-8.0 8.0,-8.0s8.0,3.582 8.0,8.0S16.419998,20.0 12.0,20.0z" /> + <path + android:fillColor="#E6000000" + android:pathData="M12.5,6.0l-1.5,0.0 0.0,7.0 5.3029995,3.1819992 0.75,-1.249999 -4.5529995,-2.7320004z" /> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml new file mode 100644 index 0000000..7bd6304 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_icon_settings.xml @@ -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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="24" + android:viewportWidth="24" > + + <group> + <path + android:fillColor="#FF000000" + android:pathData="M19.429,12.975998c0.042,-0.32 0.07,-0.645 0.07,-0.976s-0.029,-0.655 -0.07,-0.976l2.113,-1.654c0.188,-0.151 0.243,-0.422 0.118,-0.639l-2.0,-3.463c-0.125,-0.217 -0.386,-0.304 -0.612,-0.218l-2.49,1.004c-0.516,-0.396 -1.081,-0.731 -1.69,-0.984l-0.375,-2.648C14.456,2.1829987 14.25,2.0 14.0,2.0l-4.0,0.0C9.75,2.0 9.544,2.1829987 9.506,2.422001L9.131,5.0699997C8.521,5.322998 7.957,5.6570015 7.44,6.054001L4.952,5.0509987C4.726,4.965 4.464,5.052002 4.34,5.269001l-2.0,3.463C2.2150002,8.947998 2.27,9.219002 2.4580002,9.369999l2.112,1.653C4.528,11.344002 4.5,11.668999 4.5,12.0s0.029,0.656 0.071,0.977L2.4580002,14.630001c-0.188,0.151 -0.243,0.422 -0.118,0.639l2.0,3.463c0.125,0.217 0.386,0.304 0.612,0.218l2.489,-1.004c0.516,0.396 1.081,0.731 1.69,0.984l0.375,2.648C9.544,21.817001 9.75,22.0 10.0,22.0l4.0,0.0c0.25,0.0 0.456,-0.183 0.494,-0.422l0.375,-2.648c0.609,-0.253 1.174,-0.588 1.689,-0.984l2.49,1.004c0.226,0.086 0.487,-0.001 0.612,-0.218l2.0,-3.463c0.125,-0.217 0.07,-0.487 -0.118,-0.639L19.429,12.975998zM12.0,16.0c-2.21,0.0 -4.0,-1.791 -4.0,-4.0c0.0,-2.21 1.79,-4.0 4.0,-4.0c2.208,0.0 4.0,1.79 4.0,4.0C16.0,14.209 14.208,16.0 12.0,16.0z" /> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_test01.xml b/tests/VectorDrawableTest/res/drawable/vector_test01.xml new file mode 100644 index 0000000..dd71ef0 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_test01.xml @@ -0,0 +1,31 @@ +<!-- + 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="128dp" + android:width="128dp" + android:viewportHeight="512" + android:viewportWidth="512" > + + <group> + <path + android:name="002b" + android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0t-200,299" + android:strokeColor="#FF0000FF" + android:strokeWidth="4" + android:fillColor="#00000000" /> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/vector_test02.xml b/tests/VectorDrawableTest/res/drawable/vector_test02.xml new file mode 100644 index 0000000..e4f48de --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_test02.xml @@ -0,0 +1,31 @@ +<!-- + 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="128dp" + android:width="128dp" + android:viewportHeight="512" + android:viewportWidth="512" > + + <group> + <path + android:name="002b" + android:pathData="M100,200c0,-100 150,-100 150,0s150,100 150,0T-200,299" + android:strokeColor="#FF0000FF" + android:strokeWidth="4" + android:fillColor="#00000000" /> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator.xml b/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator.xml new file mode 100644 index 0000000..0cffa0a --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator.xml @@ -0,0 +1,2 @@ +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="m0,0q0.4,0.05 0.6,0.3t0.3,0.3l0.1,0.4" />
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_favorite.xml b/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_favorite.xml new file mode 100644 index 0000000..935d5b5 --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_favorite.xml @@ -0,0 +1,2 @@ +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="L0.1, 0 C0.10066,0 0.198,1 0.2, 1 L 1,1" />
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_grouping_1_01.xml b/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_grouping_1_01.xml new file mode 100644 index 0000000..8c57395 --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_grouping_1_01.xml @@ -0,0 +1,2 @@ +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="L 0.09 1 L 1,1" />
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/interpolator/trim_end_interpolator.xml b/tests/VectorDrawableTest/res/interpolator/trim_end_interpolator.xml new file mode 100644 index 0000000..b2770cd --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/trim_end_interpolator.xml @@ -0,0 +1,2 @@ +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="C0.2,0 0.1,1 0.5, 1 L 1,1" />
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/interpolator/trim_start_interpolator.xml b/tests/VectorDrawableTest/res/interpolator/trim_start_interpolator.xml new file mode 100644 index 0000000..798f7e6 --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/trim_start_interpolator.xml @@ -0,0 +1,2 @@ +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="L0.5,0 C 0.7,0 0.6,1 1, 1" />
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/values/strings.xml b/tests/VectorDrawableTest/res/values/strings.xml new file mode 100644 index 0000000..a550549 --- /dev/null +++ b/tests/VectorDrawableTest/res/values/strings.xml @@ -0,0 +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> + + <string name="twoLinePathData">"M 0,0 v 100 M 0,0 h 100"</string> + <string name="triangle"> "M300,70 l 0,-70 70,70 0,0 -70,70z"</string> + <string name="rectangle">"M300,70 l 0,-70 70,0 0,140 -70,0 z"</string> + <string name="rectangle2">"M300,70 l 0,-70 70,0 0,70z M300,70 l 70,0 0,70 -70,0z"</string> + <string name="equal2"> "M300,35 l 0,-35 70,0 0,35z M300,105 l 70,0 0,35 -70,0z"</string> + <string name="round_box">"m2.10001,-6c-1.9551,0 -0.5,0.02499 -2.10001,0.02499c-1.575,0 0.0031,-0.02499 -1.95,-0.02499c-2.543,0 -4,2.2816 -4,4.85001c0,3.52929 0.25,6.25 5.95,6.25c5.7,0 6,-2.72071 6,-6.25c0,-2.56841 -1.35699,-4.85001 -3.89999,-4.85001"</string> + <string name="heart"> "m4.5,-7c-1.95509,0 -3.83009,1.26759 -4.5,3c-0.66991,-1.73241 -2.54691,-3 -4.5,-3c-2.543,0 -4.5,1.93159 -4.5,4.5c0,3.5293 3.793,6.2578 9,11.5c5.207,-5.2422 9,-7.9707 9,-11.5c0,-2.56841 -1.957,-4.5 -4.5,-4.5"</string> + <string name="rectangle200">"M 0,0 l 200,0 l 0, 200 l -200, 0 z"</string> +</resources>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/values/styles.xml b/tests/VectorDrawableTest/res/values/styles.xml new file mode 100644 index 0000000..460c0db --- /dev/null +++ b/tests/VectorDrawableTest/res/values/styles.xml @@ -0,0 +1,16 @@ +<!-- 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> +</resources> diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedStateVectorDrawableTest.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedStateVectorDrawableTest.java new file mode 100644 index 0000000..566cc4b --- /dev/null +++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedStateVectorDrawableTest.java @@ -0,0 +1,54 @@ +/* + * 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.test.dynamic; + +import android.app.Activity; +import android.graphics.drawable.AnimatedVectorDrawable; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.GridLayout; +import android.widget.ScrollView; + +public class AnimatedStateVectorDrawableTest extends Activity { + private static final String LOGCAT = "AnimatedStateVectorDrawableTest"; + + protected int[] icon = { + R.drawable.state_animation_vector_drawable01, + R.drawable.state_animation_vector_drawable02, + R.drawable.state_animation_vector_drawable03, + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + ScrollView scrollView = new ScrollView(this); + GridLayout container = new GridLayout(this); + scrollView.addView(container); + container.setColumnCount(5); + + for (int i = 0; i < icon.length; i++) { + CheckBox button = new CheckBox(this); + button.setWidth(400); + button.setHeight(400); + button.setBackgroundResource(icon[i]); + container.addView(button); + } + + setContentView(scrollView); + } +} diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java new file mode 100644 index 0000000..f165cde --- /dev/null +++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java @@ -0,0 +1,62 @@ +/* + * 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.test.dynamic; + +import android.app.Activity; +import android.graphics.drawable.AnimatedVectorDrawable; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.GridLayout; +import android.widget.ScrollView; + +public class AnimatedVectorDrawableTest extends Activity implements View.OnClickListener { + private static final String LOGCAT = "AnimatedVectorDrawableTest"; + + protected int[] icon = { + R.drawable.animation_vector_linear_progress_bar, + R.drawable.animation_vector_drawable_grouping_1, + R.drawable.animation_vector_progress_bar, + R.drawable.animation_vector_drawable_favorite, + R.drawable.animation_vector_drawable01, + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + ScrollView scrollView = new ScrollView(this); + GridLayout container = new GridLayout(this); + scrollView.addView(container); + container.setColumnCount(1); + + for (int i = 0; i < icon.length; i++) { + Button button = new Button(this); + button.setWidth(400); + button.setHeight(400); + button.setBackgroundResource(icon[i]); + container.addView(button); + button.setOnClickListener(this); + } + + setContentView(scrollView); + } + + @Override + public void onClick(View v) { + AnimatedVectorDrawable d = (AnimatedVectorDrawable) v.getBackground(); + d.start(); + } +} diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/BitmapDrawableDupe.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/BitmapDrawableDupe.java new file mode 100644 index 0000000..36c8f2b --- /dev/null +++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/BitmapDrawableDupe.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.android.test.dynamic; + +import android.app.Activity; +import android.content.res.Resources; +import android.graphics.drawable.BitmapDrawable; +import android.os.Bundle; +import android.widget.TextView; +import android.widget.Button; +import android.widget.GridLayout; +import android.widget.ScrollView; + +import java.text.DecimalFormat; + +@SuppressWarnings({"UnusedDeclaration"}) +public class BitmapDrawableDupe extends Activity { + private static final String LOGCAT = "VectorDrawable1"; + protected int[] icon = { + R.drawable.bitmap_drawable01, + R.drawable.bitmap_drawable01, + R.drawable.bitmap_drawable01, + R.drawable.bitmap_drawable01, + R.drawable.bitmap_drawable01, + R.drawable.bitmap_drawable01, + R.drawable.bitmap_drawable01, + R.drawable.bitmap_drawable01, + R.drawable.bitmap_drawable01, + R.drawable.bitmap_drawable01, + R.drawable.bitmap_drawable01, + R.drawable.bitmap_drawable01, + R.drawable.bitmap_drawable01, + R.drawable.bitmap_drawable01, + R.drawable.bitmap_drawable01, + R.drawable.bitmap_drawable01, + R.drawable.bitmap_drawable01, + R.drawable.bitmap_drawable01, + R.drawable.bitmap_drawable01, + R.drawable.bitmap_drawable01, + R.drawable.bitmap_drawable01, + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ScrollView scrollView = new ScrollView(this); + GridLayout container = new GridLayout(this); + scrollView.addView(container); + container.setColumnCount(5); + container.setBackgroundColor(0xFF888888); + + DecimalFormat df = new DecimalFormat("#.##"); + long time = android.os.SystemClock.elapsedRealtimeNanos(); + for (int i = 0; i < icon.length; i++) { + Button button = new Button(this); + button.setWidth(200); + button.setBackgroundResource(icon[i]); + container.addView(button); + } + + setContentView(scrollView); + time = android.os.SystemClock.elapsedRealtimeNanos()-time; + TextView t = new TextView(this); + t.setText("avgS=" + df.format(time / (icon.length * 1000000.)) + " ms"); + container.addView(t); + } +} diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/BoundsCheckTest.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/BoundsCheckTest.java new file mode 100644 index 0000000..e2d77ca --- /dev/null +++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/BoundsCheckTest.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.test.dynamic; + +import android.app.Activity; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.VectorDrawable; +import android.os.Bundle; +import android.view.View; + +public class BoundsCheckTest extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + final BitmapsView view = new BitmapsView(this); + setContentView(view); + } + + static class BitmapsView extends View { + private final BitmapDrawable mBitmap1; + private final VectorDrawable mVector1; + + BitmapsView(Context c) { + super(c); + Resources res = c.getResources(); + mBitmap1 = (BitmapDrawable) res.getDrawable(R.drawable.icon); + mVector1 = (VectorDrawable) res.getDrawable(R.drawable.vector_drawable28); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + mBitmap1.setBounds(100, 100, 400, 400); + mBitmap1.draw(canvas); + + mVector1.setBounds(100, 100, 400, 400); + mVector1.draw(canvas); + } + } +}
\ No newline at end of file diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/ScaleDrawableTests.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/ScaleDrawableTests.java new file mode 100644 index 0000000..3787843 --- /dev/null +++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/ScaleDrawableTests.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.android.test.dynamic; + +import android.app.Activity; +import android.os.Bundle; +import android.view.ViewGroup.LayoutParams; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.GridLayout; +import android.widget.ScrollView; + +@SuppressWarnings({"UnusedDeclaration"}) +public class ScaleDrawableTests extends Activity { + private static final String LOGCAT = "VectorDrawable1"; + + private String[] scaleTypes = { + "MATRIX (0)", + "FIT_XY (1)", + "FIT_START (2)", + "FIT_CENTER (3)", + "FIT_END (4)", + "CENTER (5)", + "CENTER_CROP (6)", + "CENTER_INSIDE (7)" + }; + + protected int icon = R.drawable.bitmap_drawable01; + + protected int vector_icon = R.drawable.vector_drawable16; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ScrollView scrollView = new ScrollView(this); + GridLayout container = new GridLayout(this); + scrollView.addView(container); + container.setColumnCount(3); + container.setBackgroundColor(0xFF888888); + + LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + params.width = 400; + params.height = 300; + + for (int i = 0; i < scaleTypes.length; i++) { + TextView t = new TextView(this); + t.setText(scaleTypes[i]); + container.addView(t); + + ImageView.ScaleType scaleType = ImageView.ScaleType.values()[i]; + + ImageView png_view = new ImageView(this); + png_view.setLayoutParams(params); + png_view.setScaleType(scaleType); + png_view.setImageResource(icon); + container.addView(png_view); + + ImageView view = new ImageView(this); + view.setLayoutParams(params); + view.setScaleType(scaleType); + view.setImageResource(vector_icon); + container.addView(view); + } + + setContentView(scrollView); + } +} diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorCheckbox.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorCheckbox.java new file mode 100644 index 0000000..0b3ea4d --- /dev/null +++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorCheckbox.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.android.test.dynamic; + +import android.app.Activity; +import android.graphics.drawable.VectorDrawable; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.GridLayout; + +@SuppressWarnings({"UnusedDeclaration"}) +public class VectorCheckbox extends Activity { + private static final String LOGCAT = "VectorDrawable1"; + int[] icon = { + R.drawable.vector_drawable01, + R.drawable.vector_drawable02, + R.drawable.vector_drawable03, + R.drawable.vector_drawable04, + R.drawable.vector_drawable05, + R.drawable.vector_drawable06, + R.drawable.vector_drawable07, + R.drawable.vector_drawable08, + R.drawable.vector_drawable09, + R.drawable.vector_drawable10, + R.drawable.vector_drawable11, + R.drawable.vector_drawable12, + R.drawable.vector_drawable13, + R.drawable.vector_drawable14, + R.drawable.vector_drawable15, + R.drawable.vector_drawable16, + R.drawable.vector_drawable17, + R.drawable.vector_drawable18, + R.drawable.vector_drawable19, + R.drawable.vector_drawable20 + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + GridLayout container = new GridLayout(this); + container.setColumnCount(5); + container.setBackgroundColor(0xFF888888); + final Button []bArray = new Button[icon.length]; + + for (int i = 0; i < icon.length; i++) { + CheckBox checkBox = new CheckBox(this); + bArray[i] = checkBox; + checkBox.setWidth(200); + checkBox.setButtonDrawable(icon[i]); + container.addView(checkBox); + } + setContentView(container); + } +} diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java new file mode 100644 index 0000000..a23d819 --- /dev/null +++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawable01.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.android.test.dynamic; + +import android.app.Activity; +import android.graphics.drawable.VectorDrawable; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.GridLayout; + +@SuppressWarnings({"UnusedDeclaration"}) +public class VectorDrawable01 extends Activity { + private static final String LOGCAT = "VectorDrawable1"; + int[] icon = { + R.drawable.vector_drawable01, + R.drawable.vector_drawable02, + R.drawable.vector_drawable03, + R.drawable.vector_drawable04, + R.drawable.vector_drawable05, + R.drawable.vector_drawable06, + R.drawable.vector_drawable07, + R.drawable.vector_drawable08, + R.drawable.vector_drawable09, + R.drawable.vector_drawable10, + R.drawable.vector_drawable11, + R.drawable.vector_drawable12, + R.drawable.vector_drawable13, + R.drawable.vector_drawable14, + R.drawable.vector_drawable15, + R.drawable.vector_drawable16, + R.drawable.vector_drawable17, + R.drawable.vector_drawable18, + R.drawable.vector_drawable19, + R.drawable.vector_drawable20 + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + GridLayout container = new GridLayout(this); + container.setColumnCount(5); + container.setBackgroundColor(0xFF888888); + final Button []bArray = new Button[icon.length]; + + for (int i = 0; i < icon.length; i++) { + Button button = new Button(this); + bArray[i] = button; + button.setWidth(200); + button.setBackgroundResource(icon[i]); + container.addView(button); + VectorDrawable vd = (VectorDrawable) button.getBackground(); + vd.setAlpha((i + 1) * (0xFF / (icon.length + 1))); + } + + setContentView(container); + + } + +} diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableAnimation.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableAnimation.java new file mode 100644 index 0000000..93b06b6 --- /dev/null +++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableAnimation.java @@ -0,0 +1,46 @@ +/* + * 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.test.dynamic; + +import android.animation.ValueAnimator; +import android.app.Activity; +import android.graphics.drawable.AnimationDrawable; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; + +public class VectorDrawableAnimation extends Activity { + private static final String LOGCAT = "VectorDrawableAnimation"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final Button button = new Button(this); + button.setBackgroundResource(R.drawable.animation_drawable_vector); + + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + AnimationDrawable frameAnimation = (AnimationDrawable) v.getBackground(); + // Start the animation (looped playback by default). + frameAnimation.start(); + } + }); + + setContentView(button); + } + +} diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableDupPerf.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableDupPerf.java new file mode 100644 index 0000000..a00bc5e --- /dev/null +++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableDupPerf.java @@ -0,0 +1,43 @@ +/* + * 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.test.dynamic; + + +@SuppressWarnings({"UnusedDeclaration"}) +public class VectorDrawableDupPerf extends VectorDrawablePerformance { + { + icon = new int[]{ + R.drawable.vector_drawable04, + R.drawable.vector_drawable04, + R.drawable.vector_drawable04, + R.drawable.vector_drawable04, + R.drawable.vector_drawable04, + R.drawable.vector_drawable04, + R.drawable.vector_drawable04, + R.drawable.vector_drawable04, + R.drawable.vector_drawable04, + R.drawable.vector_drawable04, + R.drawable.vector_drawable04, + R.drawable.vector_drawable04, + R.drawable.vector_drawable04, + R.drawable.vector_drawable04, + R.drawable.vector_drawable04, + R.drawable.vector_drawable04, + R.drawable.vector_drawable04, + R.drawable.vector_drawable04, + R.drawable.vector_drawable04, + R.drawable.vector_drawable04, + }; + } +} diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java new file mode 100644 index 0000000..37e0435 --- /dev/null +++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java @@ -0,0 +1,93 @@ +/* + * 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.test.dynamic; + +import android.app.Activity; +import android.content.res.Resources; +import android.graphics.drawable.VectorDrawable; +import android.os.Bundle; +import android.widget.TextView; +import android.widget.Button; +import android.widget.GridLayout; +import android.widget.ScrollView; + +import java.text.DecimalFormat; + +@SuppressWarnings({"UnusedDeclaration"}) +public class VectorDrawablePerformance extends Activity { + private static final String LOGCAT = "VectorDrawable1"; + protected int[] icon = { + R.drawable.vector_drawable01, + R.drawable.vector_drawable02, + R.drawable.vector_drawable03, + R.drawable.vector_drawable04, + R.drawable.vector_drawable05, + R.drawable.vector_drawable06, + R.drawable.vector_drawable07, + R.drawable.vector_drawable08, + R.drawable.vector_drawable09, + R.drawable.vector_drawable10, + R.drawable.vector_drawable11, + R.drawable.vector_drawable12, + R.drawable.vector_drawable13, + R.drawable.vector_drawable14, + R.drawable.vector_drawable15, + R.drawable.vector_drawable16, + R.drawable.vector_drawable17, + R.drawable.vector_drawable18, + R.drawable.vector_drawable19, + R.drawable.vector_drawable20, + R.drawable.vector_drawable21, + R.drawable.vector_drawable22, + R.drawable.vector_drawable23, + R.drawable.vector_drawable24, + R.drawable.vector_drawable25, + R.drawable.vector_drawable26, + R.drawable.vector_drawable27, + R.drawable.vector_drawable28, + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ScrollView scrollView = new ScrollView(this); + GridLayout container = new GridLayout(this); + scrollView.addView(container); + container.setColumnCount(5); + Resources res = this.getResources(); + container.setBackgroundColor(0xFF888888); + VectorDrawable []d = new VectorDrawable[icon.length]; + long time = android.os.SystemClock.elapsedRealtimeNanos(); + for (int i = 0; i < icon.length; i++) { + d[i] = VectorDrawable.create(res,icon[i]); + } + time = android.os.SystemClock.elapsedRealtimeNanos()-time; + TextView t = new TextView(this); + DecimalFormat df = new DecimalFormat("#.##"); + t.setText("avgL=" + df.format(time / (icon.length * 1000000.)) + " ms"); + container.addView(t); + time = android.os.SystemClock.elapsedRealtimeNanos(); + for (int i = 0; i < icon.length; i++) { + Button button = new Button(this); + button.setWidth(200); + button.setBackgroundResource(icon[i]); + container.addView(button); + } + setContentView(scrollView); + time = android.os.SystemClock.elapsedRealtimeNanos()-time; + t = new TextView(this); + t.setText("avgS=" + df.format(time / (icon.length * 1000000.)) + " ms"); + container.addView(t); + } +} diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableStaticPerf.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableStaticPerf.java new file mode 100644 index 0000000..9d3eded --- /dev/null +++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableStaticPerf.java @@ -0,0 +1,36 @@ +/* + * 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.test.dynamic; + +import android.app.Activity; +import android.content.res.Resources; +import android.graphics.drawable.VectorDrawable; +import android.os.Bundle; +import android.view.View; +import android.widget.TextView; +import android.widget.Button; +import android.widget.GridLayout; + +@SuppressWarnings({"UnusedDeclaration"}) +public class VectorDrawableStaticPerf extends VectorDrawablePerformance { + { + icon = new int[]{ + R.drawable.vector_icon_create, + R.drawable.vector_icon_delete, + R.drawable.vector_icon_heart, + R.drawable.vector_icon_schedule, + R.drawable.vector_icon_settings, + }; + } +} diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableTest.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableTest.java new file mode 100644 index 0000000..704d3d7 --- /dev/null +++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawableTest.java @@ -0,0 +1,152 @@ +/* + * 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.test.dynamic; + +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.Bundle; +import android.view.View; +import android.widget.ListView; +import android.widget.SimpleAdapter; + +import java.text.Collator; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@SuppressWarnings("UnusedDeclaration") +public class VectorDrawableTest extends android.app.ListActivity { + private static final String EXTRA_PATH = "com.android.test.dynamic.Path"; + private static final String CATEGORY_HWUI_TEST = "com.android.test.dynamic.TEST"; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Intent intent = getIntent(); + String path = intent.getStringExtra("com.android.test.hwui.Path"); + + if (path == null) { + path = ""; + } + + setListAdapter(new SimpleAdapter(this, getData(path), + android.R.layout.simple_list_item_1, new String[] { "title" }, + new int[] { android.R.id.text1 })); + getListView().setTextFilterEnabled(true); + } + + protected List<Map<String, Object>> getData(String prefix) { + List<Map<String, Object>> myData = new ArrayList<Map<String, Object>>(); + + Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); + mainIntent.addCategory(CATEGORY_HWUI_TEST); + + PackageManager pm = getPackageManager(); + List<ResolveInfo> list = pm.queryIntentActivities(mainIntent, 0); + + if (null == list) + return myData; + + String[] prefixPath; + String prefixWithSlash = prefix; + + if (prefix.equals("")) { + prefixPath = null; + } else { + prefixPath = prefix.split("/"); + prefixWithSlash = prefix + "/"; + } + + int len = list.size(); + + Map<String, Boolean> entries = new HashMap<String, Boolean>(); + + for (int i = 0; i < len; i++) { + ResolveInfo info = list.get(i); + CharSequence labelSeq = info.loadLabel(pm); + String label = labelSeq != null + ? labelSeq.toString() + : info.activityInfo.name; + + if (prefixWithSlash.length() == 0 || label.startsWith(prefixWithSlash)) { + + String[] labelPath = label.split("/"); + + String nextLabel = prefixPath == null ? labelPath[0] : labelPath[prefixPath.length]; + + if ((prefixPath != null ? prefixPath.length : 0) == labelPath.length - 1) { + addItem(myData, nextLabel, activityIntent( + info.activityInfo.applicationInfo.packageName, + info.activityInfo.name)); + } else { + if (entries.get(nextLabel) == null) { + addItem(myData, nextLabel, browseIntent(prefix.equals("") ? + nextLabel : prefix + "/" + nextLabel)); + entries.put(nextLabel, true); + } + } + } + } + + Collections.sort(myData, sDisplayNameComparator); + + return myData; + } + + private final static Comparator<Map<String, Object>> sDisplayNameComparator = + new Comparator<Map<String, Object>>() { + private final Collator collator = Collator.getInstance(); + + public int compare(Map<String, Object> map1, Map<String, Object> map2) { + return collator.compare(map1.get("title"), map2.get("title")); + } + }; + + protected Intent activityIntent(String pkg, String componentName) { + Intent result = new Intent(); + result.setClassName(pkg, componentName); + return result; + } + + protected Intent browseIntent(String path) { + Intent result = new Intent(); + result.setClass(this, VectorDrawableTest.class); + result.putExtra(EXTRA_PATH, path); + return result; + } + + protected void addItem(List<Map<String, Object>> data, String name, Intent intent) { + Map<String, Object> temp = new HashMap<String, Object>(); + temp.put("title", name); + temp.put("intent", intent); + data.add(temp); + } + + @Override + @SuppressWarnings({ "unchecked", "UnusedParameters" }) + protected void onListItemClick(ListView l, View v, int position, long id) { + Map<String, Object> map = (Map<String, Object>)l.getItemAtPosition(position); + + Intent intent = (Intent) map.get("intent"); + startActivity(intent); + } +} diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorPathChecking.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorPathChecking.java new file mode 100644 index 0000000..3430192 --- /dev/null +++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorPathChecking.java @@ -0,0 +1,25 @@ +/* + * 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.test.dynamic; + + +@SuppressWarnings({"UnusedDeclaration"}) +public class VectorPathChecking extends VectorDrawablePerformance { + { + icon = new int[]{ + R.drawable.vector_test01, + R.drawable.vector_test02 + }; + } +} diff --git a/tests/VoiceEnrollment/Android.mk b/tests/VoiceEnrollment/Android.mk new file mode 100644 index 0000000..2ab3d02 --- /dev/null +++ b/tests/VoiceEnrollment/Android.mk @@ -0,0 +1,12 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := VoiceEnrollment + +LOCAL_MODULE_TAGS := optional + +LOCAL_PRIVILEGED_MODULE := true + +include $(BUILD_PACKAGE) diff --git a/tests/VoiceEnrollment/AndroidManifest.xml b/tests/VoiceEnrollment/AndroidManifest.xml new file mode 100644 index 0000000..6321222 --- /dev/null +++ b/tests/VoiceEnrollment/AndroidManifest.xml @@ -0,0 +1,16 @@ +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.test.voiceenrollment"> + + <application + android:permission="android.permission.MANAGE_VOICE_KEYPHRASES"> + <activity android:name="TestEnrollmentActivity" android:label="Voice Enrollment Application" + android:theme="@android:style/Theme.Material.Light.Voice"> + <intent-filter> + <action android:name="com.android.intent.action.MANAGE_VOICE_KEYPHRASES" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + <meta-data android:name="android.voice_enrollment" + android:resource="@xml/enrollment_application"/> + </application> +</manifest> diff --git a/tests/VoiceEnrollment/res/xml/enrollment_application.xml b/tests/VoiceEnrollment/res/xml/enrollment_application.xml new file mode 100644 index 0000000..70a6e0c --- /dev/null +++ b/tests/VoiceEnrollment/res/xml/enrollment_application.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> + +<voice-enrollment-application xmlns:android="http://schemas.android.com/apk/res/android" + android:searchKeyphraseId="101" + android:searchKeyphrase="Hello There" + android:searchKeyphraseSupportedLocales="en-US,en-GB,fr-FR,de-DE" + android:searchKeyphraseRecognitionFlags="voiceTrigger" /> diff --git a/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java b/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java new file mode 100644 index 0000000..7fbd965 --- /dev/null +++ b/tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java @@ -0,0 +1,23 @@ +/* + * 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.test.voiceenrollment; + +import android.app.Activity; + +public class TestEnrollmentActivity extends Activity { + // TODO(sansid): Add a test enrollment flow here. +} diff --git a/tests/VoiceInteraction/Android.mk b/tests/VoiceInteraction/Android.mk new file mode 100644 index 0000000..8decca7 --- /dev/null +++ b/tests/VoiceInteraction/Android.mk @@ -0,0 +1,10 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := VoiceInteraction + +include $(BUILD_PACKAGE) diff --git a/tests/VoiceInteraction/AndroidManifest.xml b/tests/VoiceInteraction/AndroidManifest.xml new file mode 100644 index 0000000..06d31a4 --- /dev/null +++ b/tests/VoiceInteraction/AndroidManifest.xml @@ -0,0 +1,55 @@ +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.test.voiceinteraction"> + + <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" /> + + <application> + <activity android:name="VoiceInteractionMain" android:label="Voice Interaction" + android:theme="@android:style/Theme.Material"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + <activity android:name="SettingsActivity" + android:label="Voice Interaction Settings" + android:excludeFromRecents="true" + android:noHistory="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + <service android:name="MainInteractionService" + android:label="Test Voice Interaction Service" + android:permission="android.permission.BIND_VOICE_INTERACTION" + android:process=":interactor"> + <meta-data android:name="android.voice_interaction" + android:resource="@xml/interaction_service" /> + <intent-filter> + <action android:name="android.service.voice.VoiceInteractionService" /> + </intent-filter> + </service> + <service android:name="MainInteractionSessionService" + android:permission="android.permission.BIND_VOICE_INTERACTION" + android:process=":session"> + </service> + <service android:name="MainRecognitionService" + android:label="Test Voice Interaction Service"> + <intent-filter> + <action android:name="android.speech.RecognitionService" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + <meta-data android:name="android.speech" android:resource="@xml/recognition_service" /> + </service> + <activity android:name="TestInteractionActivity" android:label="Voice Interaction Target" + android:theme="@android:style/Theme.Material.Light.Voice"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.DEFAULT" /> + <category android:name="android.intent.category.VOICE" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/tests/VoiceInteraction/res/layout/main.xml b/tests/VoiceInteraction/res/layout/main.xml new file mode 100644 index 0000000..3d7a418 --- /dev/null +++ b/tests/VoiceInteraction/res/layout/main.xml @@ -0,0 +1,31 @@ +<?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" + > + + <Button android:id="@+id/start" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/start" + /> + +</LinearLayout> + + diff --git a/tests/VoiceInteraction/res/layout/settings.xml b/tests/VoiceInteraction/res/layout/settings.xml new file mode 100644 index 0000000..e123449 --- /dev/null +++ b/tests/VoiceInteraction/res/layout/settings.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" + android:text="Preferences placeholder" /> diff --git a/tests/VoiceInteraction/res/layout/test_interaction.xml b/tests/VoiceInteraction/res/layout/test_interaction.xml new file mode 100644 index 0000000..d55736f --- /dev/null +++ b/tests/VoiceInteraction/res/layout/test_interaction.xml @@ -0,0 +1,52 @@ +<?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:padding="8dp" + > + + <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" + android:text="We are interacting!" + /> + + <TextView android:id="@+id/log" + android:layout_width="match_parent" + android:layout_height="0px" + android:layout_weight="1" + android:layout_marginTop="16dp" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textColor="#ffffffff" + /> + + <Button android:id="@+id/complete" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:text="@string/completeVoice" + /> + + <Button android:id="@+id/abort" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:text="@string/abortVoice" + /> + +</LinearLayout> diff --git a/tests/VoiceInteraction/res/layout/voice_interaction_session.xml b/tests/VoiceInteraction/res/layout/voice_interaction_session.xml new file mode 100644 index 0000000..002f350 --- /dev/null +++ b/tests/VoiceInteraction/res/layout/voice_interaction_session.xml @@ -0,0 +1,67 @@ +<?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:layout_width="fill_parent" + android:layout_height="match_parent" + android:fitsSystemWindows="true"> + + <FrameLayout android:layout_width="fill_parent" + android:layout_height="match_parent" + android:padding="8dp"> + + <LinearLayout android:id="@+id/content" + android:layout_width="fill_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:background="#ffffffff" + android:elevation="8dp" + > + + <TextView android:id="@+id/text" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="16dp" + android:textAppearance="?android:attr/textAppearanceMedium" + /> + + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" + android:orientation="horizontal"> + <Button android:id="@+id/start" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/start" + /> + <Button android:id="@+id/confirm" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/confirm" + /> + <Button android:id="@+id/complete" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/complete" + /> + <Button android:id="@+id/abort" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/abort" + /> + </LinearLayout> + + </LinearLayout> + </FrameLayout> +</FrameLayout> diff --git a/tests/VoiceInteraction/res/values/strings.xml b/tests/VoiceInteraction/res/values/strings.xml new file mode 100644 index 0000000..7eec90c --- /dev/null +++ b/tests/VoiceInteraction/res/values/strings.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2014 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + + <string name="start">Start</string> + <string name="confirm">Confirm</string> + <string name="abort">Abort</string> + <string name="complete">Complete</string> + <string name="abortVoice">Abort Voice</string> + <string name="completeVoice">Complete Voice</string> + +</resources> + diff --git a/tests/VoiceInteraction/res/xml/interaction_service.xml b/tests/VoiceInteraction/res/xml/interaction_service.xml new file mode 100644 index 0000000..ce5669c --- /dev/null +++ b/tests/VoiceInteraction/res/xml/interaction_service.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. + */ +--> + +<voice-interaction-service xmlns:android="http://schemas.android.com/apk/res/android" + android:sessionService="com.android.test.voiceinteraction.MainInteractionSessionService" + android:recognitionService="com.android.test.voiceinteraction.MainRecognitionService" + android:settingsActivity="com.android.test.voiceinteraction.SettingsActivity" /> diff --git a/tests/VoiceInteraction/res/xml/recognition_service.xml b/tests/VoiceInteraction/res/xml/recognition_service.xml new file mode 100644 index 0000000..b720fc4 --- /dev/null +++ b/tests/VoiceInteraction/res/xml/recognition_service.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright (c) 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +--> + +<recognition-service xmlns:android="http://schemas.android.com/apk/res/android" + android:settingsActivity="com.android.test.voiceinteraction.SettingsActivity" /> diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java new file mode 100644 index 0000000..e1a579c --- /dev/null +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java @@ -0,0 +1,110 @@ +/* + * 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.test.voiceinteraction; + +import android.content.Intent; +import android.os.Bundle; +import android.service.voice.AlwaysOnHotwordDetector; +import android.service.voice.AlwaysOnHotwordDetector.Callback; +import android.service.voice.AlwaysOnHotwordDetector.EventPayload; +import android.service.voice.VoiceInteractionService; +import android.util.Log; + +import java.util.Arrays; +import java.util.Locale; + +public class MainInteractionService extends VoiceInteractionService { + static final String TAG = "MainInteractionService"; + + private final Callback mHotwordCallback = new Callback() { + @Override + public void onAvailabilityChanged(int status) { + Log.i(TAG, "onAvailabilityChanged(" + status + ")"); + hotwordAvailabilityChangeHelper(status); + } + + @Override + public void onDetected(EventPayload eventPayload) { + Log.i(TAG, "onDetected"); + } + + @Override + public void onError() { + Log.i(TAG, "onError"); + } + + @Override + public void onRecognitionPaused() { + Log.i(TAG, "onRecognitionPaused"); + } + + @Override + public void onRecognitionResumed() { + Log.i(TAG, "onRecognitionResumed"); + } + }; + + private AlwaysOnHotwordDetector mHotwordDetector; + + @Override + public void onReady() { + super.onReady(); + Log.i(TAG, "Creating " + this); + Log.i(TAG, "Keyphrase enrollment error? " + getKeyphraseEnrollmentInfo().getParseError()); + Log.i(TAG, "Keyphrase enrollment meta-data: " + + Arrays.toString(getKeyphraseEnrollmentInfo().listKeyphraseMetadata())); + + mHotwordDetector = createAlwaysOnHotwordDetector( + "Hello There", Locale.forLanguageTag("en-US"), mHotwordCallback); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Bundle args = new Bundle(); + args.putParcelable("intent", new Intent(this, TestInteractionActivity.class)); + startSession(args); + stopSelf(startId); + return START_NOT_STICKY; + } + + private void hotwordAvailabilityChangeHelper(int availability) { + Log.i(TAG, "Hotword availability = " + availability); + switch (availability) { + case AlwaysOnHotwordDetector.STATE_HARDWARE_UNAVAILABLE: + Log.i(TAG, "STATE_HARDWARE_UNAVAILABLE"); + break; + case AlwaysOnHotwordDetector.STATE_KEYPHRASE_UNSUPPORTED: + Log.i(TAG, "STATE_KEYPHRASE_UNSUPPORTED"); + break; + case AlwaysOnHotwordDetector.STATE_KEYPHRASE_UNENROLLED: + Log.i(TAG, "STATE_KEYPHRASE_UNENROLLED"); + Intent enroll = mHotwordDetector.getManageIntent( + AlwaysOnHotwordDetector.MANAGE_ACTION_ENROLL); + Log.i(TAG, "Need to enroll with " + enroll); + break; + case AlwaysOnHotwordDetector.STATE_KEYPHRASE_ENROLLED: + Log.i(TAG, "STATE_KEYPHRASE_ENROLLED - starting recognition"); + if (mHotwordDetector.startRecognition( + AlwaysOnHotwordDetector.RECOGNITION_FLAG_NONE)) { + Log.i(TAG, "startRecognition succeeded"); + } else { + Log.i(TAG, "startRecognition failed"); + } + break; + } + } +} diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java new file mode 100644 index 0000000..d20906e --- /dev/null +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java @@ -0,0 +1,159 @@ +/* + * 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.test.voiceinteraction; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.service.voice.VoiceInteractionSession; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; + +public class MainInteractionSession extends VoiceInteractionSession + implements View.OnClickListener { + static final String TAG = "MainInteractionSession"; + + Intent mStartIntent; + View mContentView; + TextView mText; + Button mStartButton; + Button mConfirmButton; + Button mCompleteButton; + Button mAbortButton; + + static final int STATE_IDLE = 0; + static final int STATE_LAUNCHING = 1; + static final int STATE_CONFIRM = 2; + static final int STATE_COMMAND = 3; + static final int STATE_ABORT_VOICE = 4; + static final int STATE_COMPLETE_VOICE = 5; + + int mState = STATE_IDLE; + Request mPendingRequest; + + MainInteractionSession(Context context) { + super(context); + } + + @Override + public void onCreate(Bundle args) { + super.onCreate(args); + showWindow(); + mStartIntent = args.getParcelable("intent"); + } + + @Override + public View onCreateContentView() { + mContentView = getLayoutInflater().inflate(R.layout.voice_interaction_session, null); + mText = (TextView)mContentView.findViewById(R.id.text); + mStartButton = (Button)mContentView.findViewById(R.id.start); + mStartButton.setOnClickListener(this); + mConfirmButton = (Button)mContentView.findViewById(R.id.confirm); + mConfirmButton.setOnClickListener(this); + mCompleteButton = (Button)mContentView.findViewById(R.id.complete); + mCompleteButton.setOnClickListener(this); + mAbortButton = (Button)mContentView.findViewById(R.id.abort); + mAbortButton.setOnClickListener(this); + updateState(); + return mContentView; + } + + void updateState() { + mStartButton.setEnabled(mState == STATE_IDLE); + mConfirmButton.setEnabled(mState == STATE_CONFIRM || mState == STATE_COMMAND); + mAbortButton.setEnabled(mState == STATE_ABORT_VOICE); + mCompleteButton.setEnabled(mState == STATE_COMPLETE_VOICE); + } + + public void onClick(View v) { + if (v == mStartButton) { + mState = STATE_LAUNCHING; + updateState(); + startVoiceActivity(mStartIntent); + } else if (v == mConfirmButton) { + if (mState == STATE_CONFIRM) { + mPendingRequest.sendConfirmResult(true, null); + } else { + mPendingRequest.sendCommandResult(true, null); + } + mPendingRequest = null; + mState = STATE_IDLE; + updateState(); + } else if (v == mAbortButton) { + mPendingRequest.sendAbortVoiceResult(null); + mPendingRequest = null; + mState = STATE_IDLE; + updateState(); + } else if (v== mCompleteButton) { + mPendingRequest.sendCompleteVoiceResult(null); + mPendingRequest = null; + mState = STATE_IDLE; + updateState(); + } + } + + @Override + public boolean[] onGetSupportedCommands(Caller caller, String[] commands) { + return new boolean[commands.length]; + } + + @Override + public void onConfirm(Caller caller, Request request, CharSequence prompt, Bundle extras) { + Log.i(TAG, "onConfirm: prompt=" + prompt + " extras=" + extras); + mText.setText(prompt); + mStartButton.setText("Confirm"); + mPendingRequest = request; + mState = STATE_CONFIRM; + updateState(); + } + + @Override + public void onCompleteVoice(Caller caller, Request request, CharSequence message, Bundle extras) { + Log.i(TAG, "onCompleteVoice: message=" + message + " extras=" + extras); + mText.setText(message); + mPendingRequest = request; + mState = STATE_COMPLETE_VOICE; + updateState(); + } + + @Override + public void onAbortVoice(Caller caller, Request request, CharSequence message, Bundle extras) { + Log.i(TAG, "onAbortVoice: message=" + message + " extras=" + extras); + mText.setText(message); + mPendingRequest = request; + mState = STATE_ABORT_VOICE; + updateState(); + } + + @Override + public void onCommand(Caller caller, Request request, String command, Bundle extras) { + Log.i(TAG, "onCommand: command=" + command + " extras=" + extras); + mText.setText("Command: " + command); + mStartButton.setText("Finish Command"); + mPendingRequest = request; + mState = STATE_COMMAND; + updateState(); + } + + @Override + public void onCancel(Request request) { + Log.i(TAG, "onCancel"); + request.sendCancelResult(); + } +} diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSessionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSessionService.java new file mode 100644 index 0000000..7cf8178 --- /dev/null +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSessionService.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.android.test.voiceinteraction; + +import android.os.Bundle; +import android.service.voice.VoiceInteractionSession; +import android.service.voice.VoiceInteractionSessionService; + +public class MainInteractionSessionService extends VoiceInteractionSessionService { + @Override + public VoiceInteractionSession onNewSession(Bundle args) { + return new MainInteractionSession(this); + } +} diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainRecognitionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainRecognitionService.java new file mode 100644 index 0000000..c716e7a --- /dev/null +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainRecognitionService.java @@ -0,0 +1,56 @@ +/* + * 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.test.voiceinteraction; + +import android.content.Intent; +import android.speech.RecognitionService; +import android.util.Log; + +/** + * Stub recognition service needed to be a complete voice interactor. + */ +public class MainRecognitionService extends RecognitionService { + + private static final String TAG = "MainRecognitionService"; + + @Override + public void onCreate() { + super.onCreate(); + Log.i(TAG, "onCreate"); + } + + @Override + protected void onStartListening(Intent recognizerIntent, Callback listener) { + Log.d(TAG, "onStartListening"); + } + + @Override + protected void onCancel(Callback listener) { + Log.d(TAG, "onCancel"); + } + + @Override + protected void onStopListening(Callback listener) { + Log.d(TAG, "onStopListening"); + } + + @Override + public void onDestroy() { + super.onDestroy(); + Log.d(TAG, "onDestroy"); + } +} diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/SettingsActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/SettingsActivity.java new file mode 100644 index 0000000..8b346ff --- /dev/null +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/SettingsActivity.java @@ -0,0 +1,31 @@ +/* + * 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.test.voiceinteraction; + +import android.app.Activity; +import android.os.Bundle; + +/** + * Stub activity to test out settings selection for voice interactor. + */ +public class SettingsActivity extends Activity { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.settings); + } +} diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java new file mode 100644 index 0000000..d64eefa --- /dev/null +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java @@ -0,0 +1,118 @@ +/* + * 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.test.voiceinteraction; + +import android.app.Activity; +import android.app.VoiceInteractor; +import android.os.Bundle; +import android.util.Log; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; + +public class TestInteractionActivity extends Activity implements View.OnClickListener { + static final String TAG = "TestInteractionActivity"; + + VoiceInteractor mInteractor; + Button mAbortButton; + Button mCompleteButton; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + if (!isVoiceInteraction()) { + Log.w(TAG, "Not running as a voice interaction!"); + finish(); + return; + } + + setContentView(R.layout.test_interaction); + mAbortButton = (Button)findViewById(R.id.abort); + mAbortButton.setOnClickListener(this); + mCompleteButton = (Button)findViewById(R.id.complete); + mCompleteButton.setOnClickListener(this); + + // Framework should take care of these. + getWindow().setGravity(Gravity.TOP); + getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + + mInteractor = getVoiceInteractor(); + VoiceInteractor.ConfirmationRequest req = new VoiceInteractor.ConfirmationRequest( + "This is a confirmation", null) { + @Override + public void onCancel() { + Log.i(TAG, "Canceled!"); + getActivity().finish(); + } + + @Override + public void onConfirmationResult(boolean confirmed, Bundle result) { + Log.i(TAG, "Confirmation result: confirmed=" + confirmed + " result=" + result); + getActivity().finish(); + } + }; + mInteractor.submitRequest(req); + } + + @Override + public void onResume() { + super.onResume(); + } + + @Override + public void onClick(View v) { + if (v == mAbortButton) { + VoiceInteractor.AbortVoiceRequest req = new VoiceInteractor.AbortVoiceRequest( + "Dammit, we suck :(", null) { + @Override + public void onCancel() { + Log.i(TAG, "Canceled!"); + } + + @Override + public void onAbortResult(Bundle result) { + Log.i(TAG, "Abort result: result=" + result); + getActivity().finish(); + } + }; + mInteractor.submitRequest(req); + } else if (v == mCompleteButton) { + VoiceInteractor.CompleteVoiceRequest req = new VoiceInteractor.CompleteVoiceRequest( + "Woohoo, completed!", null) { + @Override + public void onCancel() { + Log.i(TAG, "Canceled!"); + } + + @Override + public void onCompleteResult(Bundle result) { + Log.i(TAG, "Complete result: result=" + result); + getActivity().finish(); + } + }; + mInteractor.submitRequest(req); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + } +} diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/VoiceInteractionMain.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/VoiceInteractionMain.java new file mode 100644 index 0000000..5d212a4 --- /dev/null +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/VoiceInteractionMain.java @@ -0,0 +1,49 @@ +/* + * 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.test.voiceinteraction; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; + +public class VoiceInteractionMain extends Activity { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.main); + findViewById(R.id.start).setOnClickListener(mStartListener); + } + + @Override + public void onResume() { + super.onResume(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + View.OnClickListener mStartListener = new View.OnClickListener() { + public void onClick(View v) { + startService(new Intent(VoiceInteractionMain.this, MainInteractionService.class)); + } + }; +} diff --git a/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java index cceed16..3bd35a7 100644 --- a/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java +++ b/tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java @@ -37,7 +37,7 @@ public class ActivityManagerPermissionTests extends TestCase { } @SmallTest - public void testREORDER_TASKS() { + public void testREORDER_TASKS() { try { mAm.moveTaskToFront(0, 0, null); fail("IActivityManager.moveTaskToFront did not throw SecurityException as" @@ -67,7 +67,7 @@ public class ActivityManagerPermissionTests extends TestCase { } catch (RemoteException e) { fail("Unexpected remote exception"); } - } + } @SmallTest public void testCHANGE_CONFIGURATION() { diff --git a/tests/permission/src/com/android/framework/permission/tests/PmPermissionsTests.java b/tests/permission/src/com/android/framework/permission/tests/PmPermissionsTests.java index b690c45..93aa555 100644 --- a/tests/permission/src/com/android/framework/permission/tests/PmPermissionsTests.java +++ b/tests/permission/src/com/android/framework/permission/tests/PmPermissionsTests.java @@ -16,7 +16,7 @@ package com.android.framework.permission.tests; -import junit.framework.TestCase; +import android.app.PackageInstallObserver; import android.content.pm.PackageManager; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; @@ -68,10 +68,14 @@ public class PmPermissionsTests extends AndroidTestCase { * This test verifies that PackageManger.installPackage enforces permission * android.permission.INSTALL_PACKAGES */ + private class TestInstallObserver extends PackageInstallObserver { + } + @SmallTest public void testInstallPackage() { + TestInstallObserver observer = new TestInstallObserver(); try { - mPm.installPackage(null, null, 0, null); + mPm.installPackage(null, observer, 0, null); fail("PackageManager.installPackage" + "did not throw SecurityException as expected"); } catch (SecurityException e) { diff --git a/tests/permission/src/com/android/framework/permission/tests/ServiceManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/ServiceManagerPermissionTests.java index 4dfe0fe..322b853 100644 --- a/tests/permission/src/com/android/framework/permission/tests/ServiceManagerPermissionTests.java +++ b/tests/permission/src/com/android/framework/permission/tests/ServiceManagerPermissionTests.java @@ -32,7 +32,7 @@ import junit.framework.TestCase; */ public class ServiceManagerPermissionTests extends TestCase { @SmallTest - public void testAddService() { + public void testAddService() { try { // The security in the service manager is that you can't replace // a service that is already published. @@ -43,7 +43,7 @@ public class ServiceManagerPermissionTests extends TestCase { } catch (SecurityException e) { // expected } - } + } @SmallTest public void testSetPermissionController() { diff --git a/tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java b/tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java index 90b6abc..b12ed94 100644 --- a/tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java +++ b/tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java @@ -18,6 +18,7 @@ package com.android.framework.permission.tests; import junit.framework.TestCase; +import android.media.AudioManager; import android.os.Binder; import android.os.IVibratorService; import android.os.Process; @@ -47,7 +48,8 @@ public class VibratorServicePermissionTest extends TestCase { */ public void testVibrate() throws RemoteException { try { - mVibratorService.vibrate(Process.myUid(), null, 2000, new Binder()); + mVibratorService.vibrate(Process.myUid(), null, 2000, AudioManager.STREAM_ALARM, + new Binder()); fail("vibrate did not throw SecurityException as expected"); } catch (SecurityException e) { // expected @@ -63,7 +65,8 @@ public class VibratorServicePermissionTest extends TestCase { */ public void testVibratePattern() throws RemoteException { try { - mVibratorService.vibratePattern(Process.myUid(), null, new long[] {0}, 0, new Binder()); + mVibratorService.vibratePattern(Process.myUid(), null, new long[] {0}, 0, + AudioManager.STREAM_ALARM, new Binder()); fail("vibratePattern did not throw SecurityException as expected"); } catch (SecurityException e) { // expected diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java index df32ee1..62c92a1 100644 --- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java +++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java @@ -41,7 +41,7 @@ public class WindowManagerPermissionTests extends TestCase { } @SmallTest - public void testMANAGE_APP_TOKENS() { + public void testMANAGE_APP_TOKENS() { try { mWm.pauseKeyDispatching(null); fail("IWindowManager.pauseKeyDispatching did not throw SecurityException as" @@ -93,7 +93,7 @@ public class WindowManagerPermissionTests extends TestCase { } try { - mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0); + mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0, false, false); fail("IWindowManager.addAppToken did not throw SecurityException as" + " expected"); } catch (SecurityException e) { |