1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.media.cts; 18 19 import android.app.Presentation; 20 import android.app.Service; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.graphics.drawable.ColorDrawable; 24 import android.hardware.display.DisplayManager; 25 import android.hardware.display.VirtualDisplay; 26 import android.os.Binder; 27 import android.os.Bundle; 28 import android.os.Handler; 29 import android.os.IBinder; 30 import android.os.Looper; 31 import android.os.Parcel; 32 import android.os.RemoteException; 33 import android.util.Log; 34 import android.view.Display; 35 import android.view.Surface; 36 import android.view.ViewGroup.LayoutParams; 37 import android.view.WindowManager; 38 import android.widget.ImageView; 39 40 public class RemoteVirtualDisplayService extends Service { 41 private static final String TAG = "RemoteVirtualDisplayService"; 42 private static final boolean DBG = false; 43 /** argument: Surface, int w, int h, return none */ 44 private static final int BINDER_CMD_START = IBinder.FIRST_CALL_TRANSACTION; 45 /** argument: int color, return none */ 46 private static final int BINDER_CMD_RENDER = IBinder.FIRST_CALL_TRANSACTION + 1; 47 private final Handler mHandlerForRunOnMain = new Handler(Looper.getMainLooper());; 48 private IBinder mBinder; 49 private VirtualDisplayPresentation mPresentation; 50 51 @Override 52 public void onCreate() { 53 Log.i(TAG, "onCreate"); 54 mBinder = new Binder() { 55 @Override 56 protected boolean onTransact(int code, Parcel data, Parcel reply, 57 int flags) throws RemoteException { 58 switch(code) { 59 case BINDER_CMD_START: { 60 Surface surface = Surface.CREATOR.createFromParcel(data); 61 int w = data.readInt(); 62 int h = data.readInt(); 63 start(surface, w, h); 64 break; 65 } 66 case BINDER_CMD_RENDER: { 67 int color = data.readInt(); 68 render(color); 69 break; 70 } 71 default: 72 Log.e(TAG, "unrecognized binder command " + code); 73 return false; 74 } 75 return true; 76 } 77 }; 78 } 79 80 @Override 81 public IBinder onBind(Intent intent) { 82 Log.i(TAG, "onBind"); 83 return mBinder; 84 } 85 86 @Override 87 public void onDestroy() { 88 Log.i(TAG, "onDestroy"); 89 if (mPresentation != null) { 90 mPresentation.dismissPresentation(); 91 mPresentation.destroyVirtualDisplay(); 92 mPresentation = null; 93 } 94 } 95 96 private void start(Surface surface, int w, int h) { 97 Log.i(TAG, "start"); 98 mPresentation = new VirtualDisplayPresentation(this, surface, w, h); 99 mPresentation.createVirtualDisplay(); 100 mPresentation.createPresentation(); 101 } 102 103 private void render(int color) { 104 if (DBG) { 105 Log.i(TAG, "render " + Integer.toHexString(color)); 106 } 107 mPresentation.doRendering(color); 108 } 109 110 private class VirtualDisplayPresentation { 111 private Context mContext; 112 private Surface mSurface; 113 private int mWidth; 114 private int mHeight; 115 private final DisplayManager mDisplayManager; 116 private VirtualDisplay mVirtualDisplay; 117 private TestPresentation mPresentation; 118 119 VirtualDisplayPresentation(Context context, Surface surface, int w, int h) { 120 mContext = context; 121 mSurface = surface; 122 mWidth = w; 123 mHeight = h; 124 mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); 125 } 126 127 void createVirtualDisplay() { 128 runOnMainSync(new Runnable() { 129 @Override 130 public void run() { 131 mVirtualDisplay = mDisplayManager.createVirtualDisplay( 132 TAG, mWidth, mHeight, 200, mSurface, 0); 133 } 134 }); 135 } 136 137 void destroyVirtualDisplay() { 138 if (mVirtualDisplay != null) { 139 mVirtualDisplay.release(); 140 } 141 } 142 143 void createPresentation() { 144 runOnMainSync(new Runnable() { 145 @Override 146 public void run() { 147 mPresentation = new TestPresentation(RemoteVirtualDisplayService.this, 148 mVirtualDisplay.getDisplay()); 149 mPresentation.show(); 150 } 151 }); 152 } 153 154 void dismissPresentation() { 155 if (mPresentation != null) { 156 mPresentation.dismiss(); 157 } 158 } 159 160 public void doRendering(final int color) { 161 runOnMainSync(new Runnable() { 162 @Override 163 public void run() { 164 mPresentation.doRendering(color); 165 } 166 }); 167 } 168 169 private class TestPresentation extends Presentation { 170 private ImageView mImageView; 171 172 public TestPresentation(Context outerContext, Display display) { 173 // This theme is required to prevent an extra view from obscuring the presentation 174 super(outerContext, display, 175 android.R.style.Theme_Holo_Light_NoActionBar_TranslucentDecor); 176 getWindow().setType(WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION); 177 getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); 178 } 179 180 @Override 181 protected void onCreate(Bundle savedInstanceState) { 182 super.onCreate(savedInstanceState); 183 mImageView = new ImageView(getContext()); 184 mImageView.setImageDrawable(new ColorDrawable(0)); 185 mImageView.setLayoutParams(new LayoutParams( 186 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); 187 setContentView(mImageView); 188 } 189 190 public void doRendering(int color) { 191 mImageView.setImageDrawable(new ColorDrawable(color)); 192 } 193 } 194 } 195 196 private void runOnMainSync(Runnable runner) { 197 SyncRunnable sr = new SyncRunnable(runner); 198 mHandlerForRunOnMain.post(sr); 199 sr.waitForComplete(); 200 } 201 202 private static final class SyncRunnable implements Runnable { 203 private final Runnable mTarget; 204 private boolean mComplete; 205 206 public SyncRunnable(Runnable target) { 207 mTarget = target; 208 } 209 210 public void run() { 211 mTarget.run(); 212 synchronized (this) { 213 mComplete = true; 214 notifyAll(); 215 } 216 } 217 218 public void waitForComplete() { 219 synchronized (this) { 220 while (!mComplete) { 221 try { 222 wait(); 223 } catch (InterruptedException e) { 224 //ignore 225 } 226 } 227 } 228 } 229 } 230 } 231