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 com.android.server.telecom;
18
19import android.content.BroadcastReceiver;
20import android.content.Context;
21import android.content.Intent;
22import android.content.IntentFilter;
23
24import com.android.internal.util.IndentingPrintWriter;
25
26import java.util.Collections;
27import java.util.Set;
28import java.util.concurrent.ConcurrentHashMap;
29
30/** Listens for and caches car dock state. */
31class DockManager {
32    interface Listener {
33        void onDockChanged(boolean isDocked);
34    }
35
36    /** Receiver for car dock plugged and unplugged events. */
37    private class DockBroadcastReceiver extends BroadcastReceiver {
38        @Override
39        public void onReceive(Context context, Intent intent) {
40            if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())) {
41                int dockState = intent.getIntExtra(
42                        Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED);
43                onDockChanged(dockState);
44            }
45        }
46    }
47
48    private final DockBroadcastReceiver mReceiver;
49
50    /**
51     * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
52     * load factor before resizing, 1 means we only expect a single thread to
53     * access the map so make only a single shard
54     */
55    private final Set<Listener> mListeners = Collections.newSetFromMap(
56            new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1));
57
58    private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
59
60    DockManager(Context context) {
61        mReceiver = new DockBroadcastReceiver();
62
63        // Register for misc other intent broadcasts.
64        IntentFilter intentFilter = new IntentFilter(Intent.ACTION_DOCK_EVENT);
65        context.registerReceiver(mReceiver, intentFilter);
66    }
67
68    void addListener(Listener listener) {
69        mListeners.add(listener);
70    }
71
72    void removeListener(Listener listener) {
73        if (listener != null) {
74            mListeners.remove(listener);
75        }
76    }
77
78    boolean isDocked() {
79        switch (mDockState) {
80            case Intent.EXTRA_DOCK_STATE_DESK:
81            case Intent.EXTRA_DOCK_STATE_HE_DESK:
82            case Intent.EXTRA_DOCK_STATE_LE_DESK:
83            case Intent.EXTRA_DOCK_STATE_CAR:
84                return true;
85            default:
86                return false;
87        }
88    }
89
90    private void onDockChanged(int dockState) {
91        if (mDockState != dockState) {
92            Log.v(this, "onDockChanged: is docked?%b", dockState == Intent.EXTRA_DOCK_STATE_CAR);
93            mDockState = dockState;
94            for (Listener listener : mListeners) {
95                listener.onDockChanged(isDocked());
96            }
97        }
98    }
99
100    /**
101     * Dumps the state of the {@link DockManager}.
102     *
103     * @param pw The {@code IndentingPrintWriter} to write the state to.
104     */
105    public void dump(IndentingPrintWriter pw) {
106        pw.println("mIsDocked: " + isDocked());
107    }
108}
109