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