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 
16 package com.android.bluetooth.map;
17 
18 import android.app.Activity;
19 import android.content.ContentResolver;
20 import android.content.ContentValues;
21 import android.net.Uri;
22 import android.os.Handler;
23 import android.util.Log;
24 import android.view.LayoutInflater;
25 import android.view.View;
26 import android.view.ViewGroup;
27 import android.widget.BaseExpandableListAdapter;
28 import android.widget.CheckBox;
29 import android.widget.CompoundButton;
30 import android.widget.CompoundButton.OnCheckedChangeListener;
31 import android.widget.ExpandableListView;
32 import android.widget.ExpandableListView.OnGroupExpandListener;
33 import android.widget.ImageView;
34 import android.widget.TextView;
35 import android.widget.Toast;
36 
37 import com.android.bluetooth.R;
38 import com.android.bluetooth.mapapi.BluetoothMapContract;
39 
40 import java.util.ArrayList;
41 import java.util.LinkedHashMap;
42 import java.util.Map;
43 
44 public 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 
BluetoothMapSettingsAdapter(Activity act, ExpandableListView listView, LinkedHashMap<BluetoothMapAccountItem, ArrayList<BluetoothMapAccountItem>> groupsList, int enabledAccountsCounts)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
getChild(int groupPosition, int childPosition)89     public BluetoothMapAccountItem getChild(int groupPosition, int childPosition) {
90         BluetoothMapAccountItem item = mMainGroup.get(groupPosition);
91         return mProupList.get(item).get(childPosition);
92     }
93 
getChild(BluetoothMapAccountItem group)94     private ArrayList<BluetoothMapAccountItem> getChild(BluetoothMapAccountItem group) {
95         return mProupList.get(group);
96     }
97 
98     @Override
getChildId(int groupPosition, int childPosition)99     public long getChildId(int groupPosition, int childPosition) {
100         return 0;
101     }
102 
103     @Override
getChildView(final int groupPosition, final int childPosition, boolean isLastChild, View convertView, ViewGroup parent)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
getChildrenCount(int groupPosition)194     public int getChildrenCount(int groupPosition) {
195         BluetoothMapAccountItem item = mMainGroup.get(groupPosition);
196         return mProupList.get(item).size();
197     }
198 
199     @Override
getGroup(int groupPosition)200     public BluetoothMapAccountItem getGroup(int groupPosition) {
201         return mMainGroup.get(groupPosition);
202     }
203 
204     @Override
getGroupCount()205     public int getGroupCount() {
206         return mMainGroup.size();
207     }
208 
209     @Override
onGroupCollapsed(int groupPosition)210     public void onGroupCollapsed(int groupPosition) {
211         super.onGroupCollapsed(groupPosition);
212     }
213 
214     @Override
onGroupExpanded(int groupPosition)215     public void onGroupExpanded(int groupPosition) {
216         super.onGroupExpanded(groupPosition);
217     }
218 
219     @Override
getGroupId(int groupPosition)220     public long getGroupId(int groupPosition) {
221         return 0;
222     }
223 
224     @Override
getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent)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
hasStableIds()291     public boolean hasStableIds() {
292         return true;
293     }
294 
295     @Override
isChildSelectable(int groupPosition, int childPosition)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 
updateAccount(BluetoothMapAccountItem account)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 
updateSlotCounter(boolean isChecked)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 
showWarning(String text)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