diff options
Diffstat (limited to 'src/com/android/settings/blacklist/BlacklistSettings.java')
-rw-r--r-- | src/com/android/settings/blacklist/BlacklistSettings.java | 396 |
1 files changed, 396 insertions, 0 deletions
diff --git a/src/com/android/settings/blacklist/BlacklistSettings.java b/src/com/android/settings/blacklist/BlacklistSettings.java new file mode 100644 index 0000000..db7fe5a --- /dev/null +++ b/src/com/android/settings/blacklist/BlacklistSettings.java @@ -0,0 +1,396 @@ +/* + * Copyright (C) 2013 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.blacklist; + +import android.app.ListFragment; +import android.content.ContentResolver; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.database.ContentObserver; +import android.database.Cursor; +import android.location.CountryDetector; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.os.Process; +import android.provider.ContactsContract.PhoneLookup; +import android.provider.Settings; +import android.provider.Telephony.Blacklist; +import android.telephony.PhoneNumberUtils; +import android.text.TextUtils; +import android.util.SparseArray; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ListView; +import android.widget.ResourceCursorAdapter; +import android.widget.TextView; + +import com.android.internal.telephony.util.BlacklistUtils; +import com.android.settings.R; +import com.android.settings.SettingsActivity; +import com.android.settings.SubSettings; +import com.android.settings.cyanogenmod.BaseSystemSettingSwitchBar; + +import java.util.HashMap; + +/** + * Blacklist settings UI for the Phone app. + */ +public class BlacklistSettings extends ListFragment + implements BaseSystemSettingSwitchBar.SwitchBarChangeCallback { + + private static final String[] BLACKLIST_PROJECTION = { + Blacklist._ID, + Blacklist.NUMBER, + Blacklist.PHONE_MODE, + Blacklist.MESSAGE_MODE + }; + private static final int COLUMN_ID = 0; + private static final int COLUMN_NUMBER = 1; + private static final int COLUMN_PHONE = 2; + private static final int COLUMN_MESSAGE = 3; + + private BaseSystemSettingSwitchBar mEnabledSwitch; + private boolean mLastEnabledState; + + private BlacklistAdapter mAdapter; + private Cursor mCursor; + private TextView mEmptyView; + private Context mContext; + private View mFab; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mContext = getActivity(); + } + + @Override + public View onCreateView(LayoutInflater inflater, + ViewGroup container, Bundle savedInstanceState) { + return inflater.inflate(R.layout.preference_blacklist, container, false); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + mFab = view.findViewById(R.id.floating_action_button); + mFab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showEntryEditDialog(-1); + } + }); + } + + @Override + public void onActivityCreated(Bundle icicle) { + super.onActivityCreated(icicle); + + setHasOptionsMenu(true); + + mCursor = getActivity().managedQuery(Blacklist.CONTENT_URI, + BLACKLIST_PROJECTION, null, null, null); + mAdapter = new BlacklistAdapter(getActivity(), null); + + mEmptyView = (TextView) getView().findViewById(android.R.id.empty); + + final ListView listView = getListView(); + listView.setAdapter(mAdapter); + listView.setEmptyView(mEmptyView); + + // Add a footer to avoid a situation where the FAB would cover the last + // item's options in a non-scrollable listview. + View footer = LayoutInflater.from(getActivity()) + .inflate(R.layout.empty_list_entry_footer, listView, false); + listView.addFooterView(footer); + listView.setFooterDividersEnabled(false); + footer.setOnClickListener(null); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + inflater.inflate(R.menu.blacklist, menu); + } + + @Override + public void onPrepareOptionsMenu(Menu menu) { + super.onPrepareOptionsMenu(menu); + menu.findItem(R.id.blacklist_prefs).setVisible(mLastEnabledState); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.blacklist_prefs: + SettingsActivity pa = (SettingsActivity) getActivity(); + pa.startPreferencePanel(BlacklistPreferences.class.getCanonicalName(), null, + 0, null, this, 0); + return true; + } + + return super.onOptionsItemSelected(item); + } + + @Override + public void onStart() { + super.onStart(); + final SettingsActivity activity = (SettingsActivity) getActivity(); + mEnabledSwitch = new BaseSystemSettingSwitchBar(activity, activity.getSwitchBar(), + Settings.System.PHONE_BLACKLIST_ENABLED, true, this); + } + + @Override + public void onResume() { + super.onResume(); + + final SettingsActivity activity = (SettingsActivity) getActivity(); + if (mEnabledSwitch != null) { + mEnabledSwitch.resume(activity); + } + } + + @Override + public void onPause() { + super.onPause(); + if (mEnabledSwitch != null) { + mEnabledSwitch.pause(); + } + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + if (mEnabledSwitch != null) { + mEnabledSwitch.teardownSwitchBar(); + } + } + + @Override + public void onListItemClick(ListView l, View v, int position, long id) { + showEntryEditDialog(id); + } + + private void showEntryEditDialog(long id) { + EntryEditDialogFragment fragment = EntryEditDialogFragment.newInstance(id); + fragment.show(getFragmentManager(), "blacklist_edit"); + } + + private void updateEnabledState() { + mFab.setVisibility(mLastEnabledState ? View.VISIBLE : View.GONE); + getListView().setEnabled(mLastEnabledState); + getActivity().invalidateOptionsMenu(); + + mEmptyView.setText(mLastEnabledState + ? R.string.blacklist_empty_text + : R.string.blacklist_disabled_empty_text); + mAdapter.swapCursor(mLastEnabledState ? mCursor : null); + } + + @Override + public void onEnablerChanged(boolean isEnabled) { + mLastEnabledState = BlacklistUtils.isBlacklistEnabled(mContext); + updateEnabledState(); + } + + private static class BlacklistAdapter extends ResourceCursorAdapter + implements ToggleImageView.OnCheckedChangeListener { + private Object mLock = new Object(); + private ContentResolver mResolver; + private String mCurrentCountryIso; + private SparseArray<String> mRequestedLookups = new SparseArray<String>(); + private HashMap<String, String> mContactNameCache = new HashMap<String, String>(); + + private Handler mMainHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + int lookupIndex = msg.arg1; + String name = (String) msg.obj; + mContactNameCache.put(mRequestedLookups.get(lookupIndex), + name == null ? "" : name); + mRequestedLookups.delete(lookupIndex); + notifyDataSetChanged(); + } + }; + private Handler mQueryHandler; + + private class QueryHandler extends Handler { + public static final int MSG_LOOKUP = 1; + private static final int MSG_FINISH = 2; + + public QueryHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_LOOKUP: + String name = lookupNameForNumber((String) msg.obj); + mMainHandler.obtainMessage(0, msg.arg1, 0, name).sendToTarget(); + synchronized (mLock) { + if (mQueryHandler != null) { + Message finishMessage = mQueryHandler.obtainMessage(MSG_FINISH); + mQueryHandler.sendMessageDelayed(finishMessage, 3000); + } + } + break; + case MSG_FINISH: + synchronized (mLock) { + if (mQueryHandler != null) { + mQueryHandler.getLooper().quit(); + mQueryHandler = null; + } + } + break; + } + } + + private String lookupNameForNumber(String number) { + if (!TextUtils.isEmpty(mCurrentCountryIso)) { + // Normalise the number: this is needed because the PhoneLookup query + // below does not accept a country code as an input. + String numberE164 = PhoneNumberUtils.formatNumberToE164(number, + mCurrentCountryIso); + if (!TextUtils.isEmpty(numberE164)) { + // Only use it if the number could be formatted to E164. + number = numberE164; + } + } + + String result = null; + final String[] projection = new String[] { PhoneLookup.DISPLAY_NAME }; + Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)); + Cursor cursor = mResolver.query(uri, projection, null, null, null); + if (cursor != null) { + if (cursor.moveToFirst()) { + result = cursor.getString(0); + } + cursor.close(); + } + + return result; + } + } + + public BlacklistAdapter(Context context, Cursor cursor) { + super(context, R.layout.blacklist_entry_row, cursor); + + final CountryDetector detector = + (CountryDetector) context.getSystemService(Context.COUNTRY_DETECTOR); + mCurrentCountryIso = detector.detectCountry().getCountryIso(); + mResolver = context.getContentResolver(); + } + + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + View view = super.newView(context, cursor, parent); + + ViewHolder holder = new ViewHolder(); + holder.mainText = (TextView) view.findViewById(R.id.number); + holder.subText = (TextView) view.findViewById(R.id.name); + holder.callStatus = (ToggleImageView) view.findViewById(R.id.block_calls); + holder.messageStatus = (ToggleImageView) view.findViewById(R.id.block_messages); + + holder.callStatus.setTag(Blacklist.PHONE_MODE); + holder.callStatus.setOnCheckedChangeListener(this); + + holder.messageStatus.setTag(Blacklist.MESSAGE_MODE); + holder.messageStatus.setOnCheckedChangeListener(this); + + view.setTag(holder); + + return view; + } + + @Override + public void bindView(View view, Context context, Cursor cursor) { + ViewHolder holder = (ViewHolder) view.getTag(); + String number = cursor.getString(COLUMN_NUMBER); + String name = mContactNameCache.get(number); + String formattedNumber = PhoneNumberUtils.formatNumber(number, + null, mCurrentCountryIso); + + if (TextUtils.isEmpty(name)) { + holder.mainText.setText(formattedNumber); + holder.subText.setVisibility(View.GONE); + } else { + holder.mainText.setText(name); + holder.subText.setText(formattedNumber); + holder.subText.setVisibility(View.VISIBLE); + } + + if (name == null) { + int id = cursor.getInt(COLUMN_ID); + scheduleNameLookup(id, number); + } + + holder.callStatus.setCheckedInternal(cursor.getInt(COLUMN_PHONE) != 0, false); + holder.messageStatus.setCheckedInternal(cursor.getInt(COLUMN_MESSAGE) != 0, false); + holder.position = cursor.getPosition(); + } + + @Override + public void onCheckedChanged(ToggleImageView view, boolean isChecked) { + View parent = (View) view.getParent(); + ViewHolder holder = (ViewHolder) parent.getTag(); + String column = (String) view.getTag(); + long id = getItemId(holder.position); + Uri uri = ContentUris.withAppendedId(Blacklist.CONTENT_URI, id); + ContentValues cv = new ContentValues(); + + cv.put(column, view.isChecked() ? 1 : 0); + if (mResolver.update(uri, cv, null, null) <= 0) { + // something went wrong, force an update to the correct state + notifyDataSetChanged(); + } + } + + private void scheduleNameLookup(int id, String number) { + synchronized (mLock) { + if (mQueryHandler == null) { + HandlerThread thread = new HandlerThread("blacklist_contact_query", + Process.THREAD_PRIORITY_BACKGROUND); + thread.start(); + mQueryHandler = new QueryHandler(thread.getLooper()); + } + } + + mRequestedLookups.put(id, number); + Message msg = mQueryHandler.obtainMessage(QueryHandler.MSG_LOOKUP, id, 0, number); + msg.sendToTarget(); + } + + private static class ViewHolder { + TextView mainText; + TextView subText; + ToggleImageView callStatus; + ToggleImageView messageStatus; + int position; + } + } +} |