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