12019a976f07ff418dde2dfc7cc74667ef66d7764sewardj/* 22019a976f07ff418dde2dfc7cc74667ef66d7764sewardj * Copyright (C) 2014 The Android Open Source Project 32019a976f07ff418dde2dfc7cc74667ef66d7764sewardj * 42019a976f07ff418dde2dfc7cc74667ef66d7764sewardj * Licensed under the Apache License, Version 2.0 (the "License"); 52019a976f07ff418dde2dfc7cc74667ef66d7764sewardj * you may not use this file except in compliance with the License. 62019a976f07ff418dde2dfc7cc74667ef66d7764sewardj * You may obtain a copy of the License at 72019a976f07ff418dde2dfc7cc74667ef66d7764sewardj * 82019a976f07ff418dde2dfc7cc74667ef66d7764sewardj * http://www.apache.org/licenses/LICENSE-2.0 92019a976f07ff418dde2dfc7cc74667ef66d7764sewardj * 102019a976f07ff418dde2dfc7cc74667ef66d7764sewardj * Unless required by applicable law or agreed to in writing, software 1189ae8477745fd2a15453557d729a50e627325ee2sewardj * distributed under the License is distributed on an "AS IS" BASIS, 122019a976f07ff418dde2dfc7cc74667ef66d7764sewardj * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132019a976f07ff418dde2dfc7cc74667ef66d7764sewardj * See the License for the specific language governing permissions and 142019a976f07ff418dde2dfc7cc74667ef66d7764sewardj * limitations under the License 152019a976f07ff418dde2dfc7cc74667ef66d7764sewardj */ 162019a976f07ff418dde2dfc7cc74667ef66d7764sewardj 172019a976f07ff418dde2dfc7cc74667ef66d7764sewardjpackage com.android.server.telecom.testapps; 182019a976f07ff418dde2dfc7cc74667ef66d7764sewardj 192019a976f07ff418dde2dfc7cc74667ef66d7764sewardjimport android.os.ConditionVariable; 202019a976f07ff418dde2dfc7cc74667ef66d7764sewardjimport android.os.Handler; 212019a976f07ff418dde2dfc7cc74667ef66d7764sewardjimport android.os.Looper; 222019a976f07ff418dde2dfc7cc74667ef66d7764sewardjimport android.util.Log; 232019a976f07ff418dde2dfc7cc74667ef66d7764sewardj 242019a976f07ff418dde2dfc7cc74667ef66d7764sewardjimport java.lang.AutoCloseable; 252019a976f07ff418dde2dfc7cc74667ef66d7764sewardjimport java.lang.Exception; 262019a976f07ff418dde2dfc7cc74667ef66d7764sewardjimport java.lang.Override; 272019a976f07ff418dde2dfc7cc74667ef66d7764sewardjimport java.lang.String; 282019a976f07ff418dde2dfc7cc74667ef66d7764sewardjimport java.lang.Thread; 292019a976f07ff418dde2dfc7cc74667ef66d7764sewardjimport java.lang.Throwable; 302019a976f07ff418dde2dfc7cc74667ef66d7764sewardjimport java.util.concurrent.TimeoutException; 312019a976f07ff418dde2dfc7cc74667ef66d7764sewardj 322019a976f07ff418dde2dfc7cc74667ef66d7764sewardj/** 332019a976f07ff418dde2dfc7cc74667ef66d7764sewardj * Camera thread class used for handling camera callbacks. 3433b024301d2311965cc68dc4cc900f3d0fdd8085florian */ 352019a976f07ff418dde2dfc7cc74667ef66d7764sewardjpublic class CameraThread implements AutoCloseable { 362019a976f07ff418dde2dfc7cc74667ef66d7764sewardj private static final String TAG = "CameraThread"; 372019a976f07ff418dde2dfc7cc74667ef66d7764sewardj private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 38933065d4f3548466da4666c5cfda7e5eaff93759florian 392019a976f07ff418dde2dfc7cc74667ef66d7764sewardj // Timeout for initializing looper and opening camera in Milliseconds. 402019a976f07ff418dde2dfc7cc74667ef66d7764sewardj private static final long WAIT_FOR_COMMAND_TO_COMPLETE = 5000; 416c46befd9eb90c1b6e739926c1fa335cba75bf46philippe private Looper mLooper = null; 422019a976f07ff418dde2dfc7cc74667ef66d7764sewardj private Handler mHandler = null; 432019a976f07ff418dde2dfc7cc74667ef66d7764sewardj 44b0b6710aa770763fd1fd5005075de8a8d5a269fbflorian /** 452019a976f07ff418dde2dfc7cc74667ef66d7764sewardj * Create and start a looper thread, return the Handler 462019a976f07ff418dde2dfc7cc74667ef66d7764sewardj */ 472019a976f07ff418dde2dfc7cc74667ef66d7764sewardj public synchronized Handler start() throws Exception { 482019a976f07ff418dde2dfc7cc74667ef66d7764sewardj final ConditionVariable startDone = new ConditionVariable(); 492019a976f07ff418dde2dfc7cc74667ef66d7764sewardj if (mHandler != null) { 502019a976f07ff418dde2dfc7cc74667ef66d7764sewardj Log.w(TAG, "Looper thread already started"); 512019a976f07ff418dde2dfc7cc74667ef66d7764sewardj return mHandler; 522019a976f07ff418dde2dfc7cc74667ef66d7764sewardj } 532019a976f07ff418dde2dfc7cc74667ef66d7764sewardj 542019a976f07ff418dde2dfc7cc74667ef66d7764sewardj new Thread() { 552019a976f07ff418dde2dfc7cc74667ef66d7764sewardj @Override 562019a976f07ff418dde2dfc7cc74667ef66d7764sewardj public void run() { 572019a976f07ff418dde2dfc7cc74667ef66d7764sewardj if (VERBOSE) Log.v(TAG, "start loopRun"); 582019a976f07ff418dde2dfc7cc74667ef66d7764sewardj Looper.prepare(); 592019a976f07ff418dde2dfc7cc74667ef66d7764sewardj // Save the looper so that we can terminate this thread 602019a976f07ff418dde2dfc7cc74667ef66d7764sewardj // after we are done with it. 612019a976f07ff418dde2dfc7cc74667ef66d7764sewardj mLooper = Looper.myLooper(); 622019a976f07ff418dde2dfc7cc74667ef66d7764sewardj mHandler = new Handler(); 632019a976f07ff418dde2dfc7cc74667ef66d7764sewardj startDone.open(); 642019a976f07ff418dde2dfc7cc74667ef66d7764sewardj Looper.loop(); 652019a976f07ff418dde2dfc7cc74667ef66d7764sewardj if (VERBOSE) Log.v(TAG, "createLooperThread: finished"); 662019a976f07ff418dde2dfc7cc74667ef66d7764sewardj } 672019a976f07ff418dde2dfc7cc74667ef66d7764sewardj }.start(); 682019a976f07ff418dde2dfc7cc74667ef66d7764sewardj 692019a976f07ff418dde2dfc7cc74667ef66d7764sewardj if (VERBOSE) Log.v(TAG, "start waiting for looper"); 702019a976f07ff418dde2dfc7cc74667ef66d7764sewardj if (!startDone.block(WAIT_FOR_COMMAND_TO_COMPLETE)) { 712019a976f07ff418dde2dfc7cc74667ef66d7764sewardj throw new TimeoutException("createLooperThread: start timeout"); 722019a976f07ff418dde2dfc7cc74667ef66d7764sewardj } 732019a976f07ff418dde2dfc7cc74667ef66d7764sewardj return mHandler; 742019a976f07ff418dde2dfc7cc74667ef66d7764sewardj } 752019a976f07ff418dde2dfc7cc74667ef66d7764sewardj 762019a976f07ff418dde2dfc7cc74667ef66d7764sewardj /** 772019a976f07ff418dde2dfc7cc74667ef66d7764sewardj * Terminate the looper thread 782019a976f07ff418dde2dfc7cc74667ef66d7764sewardj */ 792019a976f07ff418dde2dfc7cc74667ef66d7764sewardj public synchronized void close() throws Exception { 802019a976f07ff418dde2dfc7cc74667ef66d7764sewardj if (mLooper == null || mHandler == null) { 812019a976f07ff418dde2dfc7cc74667ef66d7764sewardj Log.w(TAG, "Looper thread doesn't start yet"); 822019a976f07ff418dde2dfc7cc74667ef66d7764sewardj return; 832019a976f07ff418dde2dfc7cc74667ef66d7764sewardj } 842019a976f07ff418dde2dfc7cc74667ef66d7764sewardj 852019a976f07ff418dde2dfc7cc74667ef66d7764sewardj if (VERBOSE) Log.v(TAG, "Terminate looper thread"); 862019a976f07ff418dde2dfc7cc74667ef66d7764sewardj mLooper.quit(); 872019a976f07ff418dde2dfc7cc74667ef66d7764sewardj mLooper.getThread().join(); 882019a976f07ff418dde2dfc7cc74667ef66d7764sewardj mLooper = null; 892019a976f07ff418dde2dfc7cc74667ef66d7764sewardj mHandler = null; 902019a976f07ff418dde2dfc7cc74667ef66d7764sewardj } 912019a976f07ff418dde2dfc7cc74667ef66d7764sewardj 922019a976f07ff418dde2dfc7cc74667ef66d7764sewardj @Override 932019a976f07ff418dde2dfc7cc74667ef66d7764sewardj protected void finalize() throws Throwable { 942019a976f07ff418dde2dfc7cc74667ef66d7764sewardj try { 952019a976f07ff418dde2dfc7cc74667ef66d7764sewardj close(); 962019a976f07ff418dde2dfc7cc74667ef66d7764sewardj } finally { 972019a976f07ff418dde2dfc7cc74667ef66d7764sewardj super.finalize(); 982019a976f07ff418dde2dfc7cc74667ef66d7764sewardj } 992019a976f07ff418dde2dfc7cc74667ef66d7764sewardj } 1002019a976f07ff418dde2dfc7cc74667ef66d7764sewardj} 1012019a976f07ff418dde2dfc7cc74667ef66d7764sewardj