1/*
2 * Copyright (C) 2016 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 */
16package android.support.car.app.menu.compat;
17
18import android.car.app.menu.RootMenu;
19import android.car.app.menu.SubscriptionCallbacks;
20import android.os.Bundle;
21import android.os.Handler;
22import android.support.annotation.NonNull;
23import android.support.car.app.menu.CarDrawerActivity;
24import android.support.car.app.menu.CarMenu;
25import android.support.car.app.menu.CarMenuCallbacks;
26
27import java.util.ArrayList;
28import java.util.HashMap;
29import java.util.List;
30import java.util.Map;
31
32public class EmbeddedCarMenuCallbacksCompat extends android.car.app.menu.CarMenuCallbacks {
33
34    private final CarMenuCallbacks mCallbacks;
35    private final CarDrawerActivity mActivity;
36
37    // Map of subscribed ids to their respective callbacks.
38    // @GuardedBy("this")
39    private final Map<String, List<SubscriptionCallbacks>> mSubscriptionMap =
40            new HashMap<String, List<SubscriptionCallbacks>>();
41
42    private final Handler mHandler = new Handler();
43
44    public EmbeddedCarMenuCallbacksCompat(CarDrawerActivity activity,
45                                          CarMenuCallbacks callbacks) {
46        mActivity = activity;
47        mCallbacks = callbacks;
48    }
49
50    @Override
51    public RootMenu getRootMenu(Bundle hint) {
52        android.support.car.app.menu.RootMenu rootMenu = mCallbacks.onGetRoot(hint);
53        return new RootMenu(rootMenu.getId(), rootMenu.getBundle());
54    }
55
56    @Override
57    public void subscribe(String parentId, SubscriptionCallbacks callbacks) {
58        synchronized (this) {
59            if (!mSubscriptionMap.containsKey(parentId)) {
60                mSubscriptionMap.put(parentId, new ArrayList<SubscriptionCallbacks>());
61            }
62            mSubscriptionMap.get(parentId).add(callbacks);
63            loadResultsForClient(parentId, callbacks);
64        }
65    }
66
67    @Override
68    public void unsubscribe(String parentId, SubscriptionCallbacks callbacks) {
69        synchronized (this) {
70            mSubscriptionMap.get(parentId).remove(callbacks);
71        }
72    }
73
74    @Override
75    public void onCarMenuOpened() {
76        mActivity.setDrawerShowing(true);
77        mCallbacks.onCarMenuOpened();
78    }
79
80    @Override
81    public void onCarMenuClosed() {
82        mActivity.setDrawerShowing(false);
83        mActivity.restoreSearchBox();
84    }
85
86    @Override
87    public void onItemClicked(String id) {
88        mCallbacks.onItemClicked(id);
89        mActivity.stopInput();
90    }
91
92    @Override
93    public boolean onItemLongClicked(String id) {
94        return mCallbacks.onItemLongClicked(id);
95    }
96
97    @Override
98    public boolean onMenuClicked() {
99
100        return mActivity.onMenuClicked();
101    }
102
103    @Override
104    public void onCarMenuOpening() {
105        mActivity.stopInput();
106    }
107
108    @Override
109    public void onCarMenuClosing() {
110        mActivity.restoreSearchBox();
111    }
112
113    public void onChildrenChanged(final String parentId) {
114        synchronized (this) {
115            if (mSubscriptionMap.containsKey(parentId)) {
116                final List<SubscriptionCallbacks> callbacks = new ArrayList<>();
117                callbacks.addAll(mSubscriptionMap.get(parentId));
118                mHandler.post(new Runnable() {
119                    @Override
120                    public void run() {
121                        loadResultsForAllClients(parentId, callbacks);
122                    }
123                });
124            }
125        }
126    }
127
128    public void onChildChanged(final String parentId, final Bundle item) {
129        synchronized (this) {
130            if (mSubscriptionMap.containsKey(parentId)) {
131                final List<SubscriptionCallbacks> callbacks = new ArrayList<>();
132                callbacks.addAll(mSubscriptionMap.get(parentId));
133                mHandler.post(new Runnable() {
134                    @Override
135                    public void run() {
136                        for (SubscriptionCallbacks callback : callbacks) {
137                            callback.onChildChanged(parentId, item);
138                        }
139                    }
140                });
141
142            }
143        }
144    }
145
146    private void loadResultsForAllClients(final String parentId,
147            @NonNull final List<SubscriptionCallbacks> callbacks) {
148        final CarMenu result = new CarMenu(mActivity.getResources().getDisplayMetrics()) {
149            @Override
150            protected void onResultReady(List<Bundle> list) {
151                for (SubscriptionCallbacks callback : callbacks) {
152                    callback.onChildrenLoaded(parentId, list);
153                }
154            }
155        };
156
157        mCallbacks.onLoadChildren(parentId, result);
158        if (!result.isDone()) {
159            throw new IllegalStateException("You must either call sendResult() or detach() " +
160                    "before returning!");
161        }
162    }
163
164    private void loadResultsForClient(final String parentId,
165            final SubscriptionCallbacks callbacks) {
166        final CarMenu result = new CarMenu(mActivity.getResources().getDisplayMetrics()) {
167            @Override
168            protected void onResultReady(List<Bundle> list) {
169                callbacks.onChildrenLoaded(parentId, list);
170            }
171        };
172
173        mCallbacks.onLoadChildren(parentId, result);
174        if (!result.isDone()) {
175            throw new IllegalStateException("You must either call sendResult() or detach() " +
176                    "before returning!");
177        }
178    }
179}
180