CarRadioManager.java revision e423804f896d2374d3427c861295961bcbf50620
1/* 2 * Copyright (C) 2015 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 17package android.car.hardware.radio; 18 19import android.annotation.SystemApi; 20import android.car.Car; 21import android.car.CarManagerBase; 22import android.car.CarNotConnectedException; 23import android.content.Context; 24import android.hardware.radio.RadioManager; 25import android.os.Handler; 26import android.os.IBinder; 27import android.os.Looper; 28import android.os.Message; 29import android.os.RemoteException; 30import android.util.Log; 31 32import com.android.internal.annotations.GuardedBy; 33 34import java.lang.ref.WeakReference; 35 36/** 37 * Car Radio manager. 38 * 39 * This API works in conjunction with the {@link RadioManager.java} and provides 40 * features additional to the ones provided in there. It supports: 41 * 42 * 1. Capability to control presets. 43 * @hide 44 */ 45@SystemApi 46public class CarRadioManager implements CarManagerBase { 47 public final static boolean DBG = true; 48 public final static String TAG = "CarRadioManager"; 49 50 // Constants handled in the handler (see mHandler below). 51 private final static int MSG_RADIO_EVENT = 0; 52 53 private int mCount = 0; 54 private final ICarRadio mService; 55 @GuardedBy("this") 56 private CarRadioEventListener mListener = null; 57 @GuardedBy("this") 58 private CarRadioEventListenerToService mListenerToService = null; 59 private static final class EventCallbackHandler extends Handler { 60 WeakReference<CarRadioManager> mMgr; 61 62 EventCallbackHandler(CarRadioManager mgr, Looper looper) { 63 super(looper); 64 mMgr = new WeakReference<CarRadioManager>(mgr); 65 } 66 67 @Override 68 public void handleMessage(Message msg) { 69 switch (msg.what) { 70 case MSG_RADIO_EVENT: 71 CarRadioManager mgr = mMgr.get(); 72 if (mgr != null) { 73 mgr.dispatchEventToClient((CarRadioEvent) msg.obj); 74 } 75 break; 76 default: 77 Log.e(TAG, "Event type not handled?" + msg); 78 } 79 } 80 } 81 82 private final Handler mHandler; 83 84 private static class CarRadioEventListenerToService extends ICarRadioEventListener.Stub { 85 private final WeakReference<CarRadioManager> mManager; 86 87 public CarRadioEventListenerToService(CarRadioManager manager) { 88 mManager = new WeakReference<CarRadioManager>(manager); 89 } 90 91 @Override 92 public void onEvent(CarRadioEvent event) { 93 CarRadioManager manager = mManager.get(); 94 if (manager != null) { 95 manager.handleEvent(event); 96 } 97 } 98 } 99 100 101 /** Listener for car radio events. 102 */ 103 public interface CarRadioEventListener { 104 /** 105 * Called when there is a preset value is reprogrammed. 106 */ 107 void onEvent(final CarRadioEvent event); 108 } 109 110 /** 111 * Get an instance of the CarRadioManager. 112 * 113 * Should not be obtained directly by clients, use {@link Car.getCarManager()} instead. 114 * @hide 115 */ 116 public CarRadioManager(IBinder service, Looper looper) { 117 mService = ICarRadio.Stub.asInterface(service); 118 mHandler = new EventCallbackHandler(this, looper); 119 120 // Populate the fixed values. 121 try { 122 mCount = mService.getPresetCount(); 123 } catch (RemoteException ex) { 124 // Do nothing. 125 Log.e(TAG, "Could not connect: " + ex.toString()); 126 } 127 } 128 129 /** 130 * Register {@link CarRadioEventListener} to get radio unit changes. 131 */ 132 public synchronized void registerListener(CarRadioEventListener listener) 133 throws CarNotConnectedException { 134 if (mListener != null) { 135 throw new IllegalStateException("Listener already registered. Did you call " + 136 "registerListener() twice?"); 137 } 138 139 mListener = listener; 140 try { 141 mListenerToService = new CarRadioEventListenerToService(this); 142 mService.registerListener(mListenerToService); 143 } catch (RemoteException ex) { 144 // Do nothing. 145 Log.e(TAG, "Could not connect: " + ex.toString()); 146 throw new CarNotConnectedException(ex); 147 } catch (IllegalStateException ex) { 148 Car.checkCarNotConnectedExceptionFromCarService(ex); 149 } 150 } 151 152 /** 153 * Unregister {@link CarRadioEventListener}. 154 */ 155 public synchronized void unregisterListener() { 156 if (DBG) { 157 Log.d(TAG, "unregisterListener"); 158 } 159 try { 160 mService.unregisterListener(mListenerToService); 161 } catch (RemoteException ex) { 162 // do nothing. 163 Log.e(TAG, "Could not connect: " + ex.toString()); 164 } 165 mListenerToService = null; 166 mListener = null; 167 } 168 169 /** 170 * Get the number of (hard) presets supported by car radio unit. 171 * 172 * @return: A positive value if the call succeeded, -1 if it failed. 173 */ 174 public int getPresetCount() { 175 return mCount; 176 } 177 178 /** 179 * Get preset value for a specific radio preset. 180 * @return: a {@link CarRadioPreset} object, {@link null} if the call failed. 181 */ 182 public CarRadioPreset getPreset(int presetNumber) { 183 if (DBG) { 184 Log.d(TAG, "getPreset"); 185 } 186 try { 187 CarRadioPreset preset = mService.getPreset(presetNumber); 188 return preset; 189 } catch (RemoteException ex) { 190 Log.e(TAG, "getPreset failed with " + ex.toString()); 191 return null; 192 } 193 } 194 195 /** 196 * Set the preset value to a specific radio preset. 197 * 198 * In order to ensure that the preset value indeed get updated, wait for event on the listener 199 * registered via registerListener(). 200 * 201 * @return: {@link boolean} value which returns true if the request succeeded and false 202 * otherwise. Common reasons for the failure could be: 203 * a) Preset is invalid (the preset number is out of range from {@link getPresetCount()}. 204 * b) Listener is not set correctly, since otherwise the user of this API cannot confirm if the 205 * request succeeded. 206 */ 207 public boolean setPreset(CarRadioPreset preset) throws IllegalArgumentException { 208 try { 209 return mService.setPreset(preset); 210 } catch (RemoteException ex) { 211 // do nothing. 212 return false; 213 } 214 } 215 216 private void dispatchEventToClient(CarRadioEvent event) { 217 CarRadioEventListener listener; 218 synchronized (this) { 219 listener = mListener; 220 } 221 if (listener != null) { 222 listener.onEvent(event); 223 } else { 224 Log.e(TAG, "Listener died, not dispatching event."); 225 } 226 } 227 228 private void handleEvent(CarRadioEvent event) { 229 mHandler.sendMessage(mHandler.obtainMessage(MSG_RADIO_EVENT, event)); 230 } 231 232 /** @hide */ 233 @Override 234 public synchronized void onCarDisconnected() { 235 mListener = null; 236 mListenerToService = null; 237 } 238} 239