1/*
2* Copyright (C) 2014 Samsung System LSI
3* Licensed under the Apache License, Version 2.0 (the "License");
4* you may not use this file except in compliance with the License.
5* You may obtain a copy of the License at
6*
7*      http://www.apache.org/licenses/LICENSE-2.0
8*
9* Unless required by applicable law or agreed to in writing, software
10* distributed under the License is distributed on an "AS IS" BASIS,
11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12* See the License for the specific language governing permissions and
13* limitations under the License.
14*/
15
16package com.android.bluetooth.map;
17
18import android.app.Activity;
19import android.content.ContentResolver;
20import android.content.ContentValues;
21import android.net.Uri;
22import android.os.Handler;
23import android.util.Log;
24import android.view.LayoutInflater;
25import android.view.View;
26import android.view.ViewGroup;
27import android.widget.BaseExpandableListAdapter;
28import android.widget.CheckBox;
29import android.widget.CompoundButton;
30import android.widget.CompoundButton.OnCheckedChangeListener;
31import android.widget.ExpandableListView;
32import android.widget.ExpandableListView.OnGroupExpandListener;
33import android.widget.ImageView;
34import android.widget.TextView;
35import android.widget.Toast;
36
37import com.android.bluetooth.R;
38import com.android.bluetooth.mapapi.BluetoothMapContract;
39
40import java.util.ArrayList;
41import java.util.LinkedHashMap;
42import java.util.Map;
43
44public class BluetoothMapSettingsAdapter extends BaseExpandableListAdapter {
45    private static final boolean D = BluetoothMapService.DEBUG;
46    private static final boolean V = BluetoothMapService.VERBOSE;
47    private static final String TAG = "BluetoothMapSettingsAdapter";
48    private boolean mCheckAll = true;
49    public LayoutInflater mInflater;
50    public Activity mActivity;
51    /*needed to prevent random checkbox toggles due to item reuse */ ArrayList<Boolean>
52            mPositionArray;
53    private LinkedHashMap<BluetoothMapAccountItem, ArrayList<BluetoothMapAccountItem>> mProupList;
54    private ArrayList<BluetoothMapAccountItem> mMainGroup;
55    private int[] mGroupStatus;
56    /* number of accounts possible to share */
57    private int mSlotsLeft = 10;
58
59
60    public BluetoothMapSettingsAdapter(Activity act, ExpandableListView listView,
61            LinkedHashMap<BluetoothMapAccountItem, ArrayList<BluetoothMapAccountItem>> groupsList,
62            int enabledAccountsCounts) {
63        mActivity = act;
64        this.mProupList = groupsList;
65        mInflater = act.getLayoutInflater();
66        mGroupStatus = new int[groupsList.size()];
67        mSlotsLeft = mSlotsLeft - enabledAccountsCounts;
68
69        listView.setOnGroupExpandListener(new OnGroupExpandListener() {
70
71            @Override
72            public void onGroupExpand(int groupPosition) {
73                BluetoothMapAccountItem group = mMainGroup.get(groupPosition);
74                if (mProupList.get(group).size() > 0) {
75                    mGroupStatus[groupPosition] = 1;
76                }
77
78            }
79        });
80        mMainGroup = new ArrayList<BluetoothMapAccountItem>();
81        for (Map.Entry<BluetoothMapAccountItem, ArrayList<BluetoothMapAccountItem>> mapEntry :
82                mProupList
83                .entrySet()) {
84            mMainGroup.add(mapEntry.getKey());
85        }
86    }
87
88    @Override
89    public BluetoothMapAccountItem getChild(int groupPosition, int childPosition) {
90        BluetoothMapAccountItem item = mMainGroup.get(groupPosition);
91        return mProupList.get(item).get(childPosition);
92    }
93
94    private ArrayList<BluetoothMapAccountItem> getChild(BluetoothMapAccountItem group) {
95        return mProupList.get(group);
96    }
97
98    @Override
99    public long getChildId(int groupPosition, int childPosition) {
100        return 0;
101    }
102
103    @Override
104    public View getChildView(final int groupPosition, final int childPosition, boolean isLastChild,
105            View convertView, ViewGroup parent) {
106
107
108        final ChildHolder holder;
109        if (convertView == null) {
110            convertView = mInflater.inflate(R.layout.bluetooth_map_settings_account_item, null);
111            holder = new ChildHolder();
112            holder.cb = (CheckBox) convertView.findViewById(R.id.bluetooth_map_settings_item_check);
113            holder.title =
114                    (TextView) convertView.findViewById(R.id.bluetooth_map_settings_item_text_view);
115            convertView.setTag(holder);
116        } else {
117            holder = (ChildHolder) convertView.getTag();
118        }
119        final BluetoothMapAccountItem child = getChild(groupPosition, childPosition);
120        holder.cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
121
122            @Override
123            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
124                BluetoothMapAccountItem parentGroup =
125                        (BluetoothMapAccountItem) getGroup(groupPosition);
126                boolean oldIsChecked = child.mIsChecked; // needed to prevent updates on UI redraw
127                child.mIsChecked = isChecked;
128                if (isChecked) {
129                    ArrayList<BluetoothMapAccountItem> childList = getChild(parentGroup);
130                    int childIndex = childList.indexOf(child);
131                    boolean isAllChildClicked = true;
132                    if (mSlotsLeft - childList.size() >= 0) {
133
134                        for (int i = 0; i < childList.size(); i++) {
135                            if (i != childIndex) {
136                                BluetoothMapAccountItem siblings = childList.get(i);
137                                if (!siblings.mIsChecked) {
138                                    isAllChildClicked = false;
139                                    BluetoothMapSettingsDataHolder.sCheckedChilds.put(
140                                            child.getName(), parentGroup.getName());
141                                    break;
142
143                                }
144                            }
145                        }
146                    } else {
147                        showWarning(mActivity.getString(
148                                R.string.bluetooth_map_settings_no_account_slots_left));
149                        isAllChildClicked = false;
150                        child.mIsChecked = false;
151                    }
152                    if (isAllChildClicked) {
153                        parentGroup.mIsChecked = true;
154                        if (!(BluetoothMapSettingsDataHolder.sCheckedChilds.containsKey(
155                                child.getName()))) {
156                            BluetoothMapSettingsDataHolder.sCheckedChilds.put(child.getName(),
157                                    parentGroup.getName());
158                        }
159                        mCheckAll = false;
160                    }
161
162
163                } else {
164                    if (parentGroup.mIsChecked) {
165                        parentGroup.mIsChecked = false;
166                        mCheckAll = false;
167                        BluetoothMapSettingsDataHolder.sCheckedChilds.remove(child.getName());
168                    } else {
169                        mCheckAll = true;
170                        BluetoothMapSettingsDataHolder.sCheckedChilds.remove(child.getName());
171                    }
172                    // child.isChecked =false;
173                }
174                notifyDataSetChanged();
175                if (child.mIsChecked != oldIsChecked) {
176                    updateAccount(child);
177                }
178
179            }
180
181        });
182
183        holder.cb.setChecked(child.mIsChecked);
184        holder.title.setText(child.getName());
185        if (D) {
186            Log.i("childs are", BluetoothMapSettingsDataHolder.sCheckedChilds.toString());
187        }
188        return convertView;
189
190    }
191
192
193    @Override
194    public int getChildrenCount(int groupPosition) {
195        BluetoothMapAccountItem item = mMainGroup.get(groupPosition);
196        return mProupList.get(item).size();
197    }
198
199    @Override
200    public BluetoothMapAccountItem getGroup(int groupPosition) {
201        return mMainGroup.get(groupPosition);
202    }
203
204    @Override
205    public int getGroupCount() {
206        return mMainGroup.size();
207    }
208
209    @Override
210    public void onGroupCollapsed(int groupPosition) {
211        super.onGroupCollapsed(groupPosition);
212    }
213
214    @Override
215    public void onGroupExpanded(int groupPosition) {
216        super.onGroupExpanded(groupPosition);
217    }
218
219    @Override
220    public long getGroupId(int groupPosition) {
221        return 0;
222    }
223
224    @Override
225    public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
226            ViewGroup parent) {
227
228        final GroupHolder holder;
229
230        if (convertView == null) {
231            convertView = mInflater.inflate(R.layout.bluetooth_map_settings_account_group, null);
232            holder = new GroupHolder();
233            holder.cb =
234                    (CheckBox) convertView.findViewById(R.id.bluetooth_map_settings_group_checkbox);
235            holder.imageView =
236                    (ImageView) convertView.findViewById(R.id.bluetooth_map_settings_group_icon);
237            holder.title = (TextView) convertView.findViewById(
238                    R.id.bluetooth_map_settings_group_text_view);
239            convertView.setTag(holder);
240        } else {
241            holder = (GroupHolder) convertView.getTag();
242        }
243
244        final BluetoothMapAccountItem groupItem = getGroup(groupPosition);
245        holder.imageView.setImageDrawable(groupItem.getIcon());
246
247
248        holder.title.setText(groupItem.getName());
249
250        holder.cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
251
252            @Override
253            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
254                if (mCheckAll) {
255                    ArrayList<BluetoothMapAccountItem> childItem = getChild(groupItem);
256                    for (BluetoothMapAccountItem children : childItem) {
257                        boolean oldIsChecked = children.mIsChecked;
258                        if (mSlotsLeft > 0) {
259                            children.mIsChecked = isChecked;
260                            if (oldIsChecked != children.mIsChecked) {
261                                updateAccount(children);
262                            }
263                        } else {
264                            showWarning(mActivity.getString(
265                                    R.string.bluetooth_map_settings_no_account_slots_left));
266                            isChecked = false;
267                        }
268                    }
269                }
270                groupItem.mIsChecked = isChecked;
271                notifyDataSetChanged();
272                new Handler().postDelayed(new Runnable() {
273
274                    @Override
275                    public void run() {
276                        if (!mCheckAll) {
277                            mCheckAll = true;
278                        }
279                    }
280                }, 50);
281
282            }
283
284        });
285        holder.cb.setChecked(groupItem.mIsChecked);
286        return convertView;
287
288    }
289
290    @Override
291    public boolean hasStableIds() {
292        return true;
293    }
294
295    @Override
296    public boolean isChildSelectable(int groupPosition, int childPosition) {
297        return true;
298    }
299
300    private class GroupHolder {
301        public ImageView imageView;
302        public CheckBox cb;
303        public TextView title;
304
305    }
306
307    private class ChildHolder {
308        public TextView title;
309        public CheckBox cb;
310    }
311
312    public void updateAccount(BluetoothMapAccountItem account) {
313        updateSlotCounter(account.mIsChecked);
314        if (D) {
315            Log.d(TAG, "Updating account settings for " + account.getName() + ". Value is:"
316                    + account.mIsChecked);
317        }
318        ContentResolver mResolver = mActivity.getContentResolver();
319        Uri uri =
320                Uri.parse(account.mBase_uri_no_account + "/" + BluetoothMapContract.TABLE_ACCOUNT);
321        ContentValues values = new ContentValues();
322        values.put(BluetoothMapContract.AccountColumns.FLAG_EXPOSE, ((account.mIsChecked) ? 1 : 0));
323        values.put(BluetoothMapContract.AccountColumns._ID, account.getId()); // get title
324        mResolver.update(uri, values, null, null);
325
326    }
327
328    private void updateSlotCounter(boolean isChecked) {
329        if (isChecked) {
330            mSlotsLeft--;
331        } else {
332            mSlotsLeft++;
333        }
334        CharSequence text;
335
336        if (mSlotsLeft <= 0) {
337            text = mActivity.getString(R.string.bluetooth_map_settings_no_account_slots_left);
338        } else {
339            text = mActivity.getString(R.string.bluetooth_map_settings_count) + " "
340                    + String.valueOf(mSlotsLeft);
341        }
342
343        int duration = Toast.LENGTH_SHORT;
344
345        Toast toast = Toast.makeText(mActivity, text, duration);
346        toast.show();
347    }
348
349    private void showWarning(String text) {
350        int duration = Toast.LENGTH_SHORT;
351
352        Toast toast = Toast.makeText(mActivity, text, duration);
353        toast.show();
354
355    }
356
357
358}
359