Moving classes used only by dialer into dialer package.
Bug: 6993891
Change-Id: If45ddc47c668301936595dfd0a9a7fd08569322e
diff --git a/proguard.flags b/proguard.flags
index 39784b1..19f746a 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -18,3 +18,4 @@
}
-verbose
+-printusage usage.txt
diff --git a/src/com/android/contacts/BackScrollManager.java b/src/com/android/contacts/BackScrollManager.java
deleted file mode 100644
index 192b79e..0000000
--- a/src/com/android/contacts/BackScrollManager.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source 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.contacts;
-
-import android.view.View;
-import android.widget.AbsListView;
-import android.widget.ListView;
-
-/**
- * Handles scrolling back of a list tied to a header.
- * <p>
- * This is used to implement a header that scrolls up with the content of a list to be partially
- * obscured.
- */
-public class BackScrollManager {
- /** Defines the header to be scrolled. */
- public interface ScrollableHeader {
- /** Sets the offset by which to scroll. */
- public void setOffset(int offset);
- /** Gets the maximum offset that should be applied to the header. */
- public int getMaximumScrollableHeaderOffset();
- }
-
- private final ScrollableHeader mHeader;
- private final ListView mListView;
-
- private final AbsListView.OnScrollListener mScrollListener =
- new AbsListView.OnScrollListener() {
- @Override
- public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
- int totalItemCount) {
- if (firstVisibleItem != 0) {
- // The first item is not shown, the header should be pinned at the top.
- mHeader.setOffset(mHeader.getMaximumScrollableHeaderOffset());
- return;
- }
-
- View firstVisibleItemView = view.getChildAt(firstVisibleItem);
- if (firstVisibleItemView == null) {
- return;
- }
- // We scroll the header up, but at most pin it to the top of the screen.
- int offset = Math.min(
- (int) -view.getChildAt(firstVisibleItem).getY(),
- mHeader.getMaximumScrollableHeaderOffset());
- mHeader.setOffset(offset);
- }
-
- @Override
- public void onScrollStateChanged(AbsListView view, int scrollState) {
- // Nothing to do here.
- }
- };
-
- /**
- * Creates a new instance of a {@link BackScrollManager} that connected the header and the list
- * view.
- */
- public static void bind(ScrollableHeader header, ListView listView) {
- BackScrollManager backScrollManager = new BackScrollManager(header, listView);
- backScrollManager.bind();
- }
-
- private BackScrollManager(ScrollableHeader header, ListView listView) {
- mHeader = header;
- mListView = listView;
- }
-
- private void bind() {
- mListView.setOnScrollListener(mScrollListener);
- // We disable the scroll bar because it would otherwise be incorrect because of the hidden
- // header.
- mListView.setVerticalScrollBarEnabled(false);
- }
-}
diff --git a/src/com/android/contacts/ProximitySensorAware.java b/src/com/android/contacts/ProximitySensorAware.java
deleted file mode 100644
index 0fb233d..0000000
--- a/src/com/android/contacts/ProximitySensorAware.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source 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.contacts;
-
-/**
- * An object that is aware of the state of the proximity sensor.
- */
-public interface ProximitySensorAware {
- /** Start tracking the state of the proximity sensor. */
- public void enableProximitySensor();
-
- /**
- * Stop tracking the state of the proximity sensor.
- *
- * @param waitForFarState if true and the sensor is currently in the near state, it will wait
- * until it is again in the far state before stopping to track its state.
- */
- public void disableProximitySensor(boolean waitForFarState);
-}
diff --git a/src/com/android/contacts/ProximitySensorManager.java b/src/com/android/contacts/ProximitySensorManager.java
deleted file mode 100644
index 69601bf..0000000
--- a/src/com/android/contacts/ProximitySensorManager.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source 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.contacts;
-
-import android.content.Context;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
-import android.hardware.SensorManager;
-
-import javax.annotation.concurrent.GuardedBy;
-
-/**
- * Manages the proximity sensor and notifies a listener when enabled.
- */
-public class ProximitySensorManager {
- /**
- * Listener of the state of the proximity sensor.
- * <p>
- * This interface abstracts two possible states for the proximity sensor, near and far.
- * <p>
- * The actual meaning of these states depends on the actual sensor.
- */
- public interface Listener {
- /** Called when the proximity sensor transitions from the far to the near state. */
- public void onNear();
- /** Called when the proximity sensor transitions from the near to the far state. */
- public void onFar();
- }
-
- public static enum State {
- NEAR, FAR
- }
-
- private final ProximitySensorEventListener mProximitySensorListener;
-
- /**
- * The current state of the manager, i.e., whether it is currently tracking the state of the
- * sensor.
- */
- private boolean mManagerEnabled;
-
- /**
- * The listener to the state of the sensor.
- * <p>
- * Contains most of the logic concerning tracking of the sensor.
- * <p>
- * After creating an instance of this object, one should call {@link #register()} and
- * {@link #unregister()} to enable and disable the notifications.
- * <p>
- * Instead of calling unregister, one can call {@link #unregisterWhenFar()} to unregister the
- * listener the next time the sensor reaches the {@link State#FAR} state if currently in the
- * {@link State#NEAR} state.
- */
- private static class ProximitySensorEventListener implements SensorEventListener {
- private static final float FAR_THRESHOLD = 5.0f;
-
- private final SensorManager mSensorManager;
- private final Sensor mProximitySensor;
- private final float mMaxValue;
- private final Listener mListener;
-
- /**
- * The last state of the sensor.
- * <p>
- * Before registering and after unregistering we are always in the {@link State#FAR} state.
- */
- @GuardedBy("this") private State mLastState;
- /**
- * If this flag is set to true, we are waiting to reach the {@link State#FAR} state and
- * should notify the listener and unregister when that happens.
- */
- @GuardedBy("this") private boolean mWaitingForFarState;
-
- public ProximitySensorEventListener(SensorManager sensorManager, Sensor proximitySensor,
- Listener listener) {
- mSensorManager = sensorManager;
- mProximitySensor = proximitySensor;
- mMaxValue = proximitySensor.getMaximumRange();
- mListener = listener;
- // Initialize at far state.
- mLastState = State.FAR;
- mWaitingForFarState = false;
- }
-
- @Override
- public void onSensorChanged(SensorEvent event) {
- // Make sure we have a valid value.
- if (event.values == null) return;
- if (event.values.length == 0) return;
- float value = event.values[0];
- // Convert the sensor into a NEAR/FAR state.
- State state = getStateFromValue(value);
- synchronized (this) {
- // No change in state, do nothing.
- if (state == mLastState) return;
- // Keep track of the current state.
- mLastState = state;
- // If we are waiting to reach the far state and we are now in it, unregister.
- if (mWaitingForFarState && mLastState == State.FAR) {
- unregisterWithoutNotification();
- }
- }
- // Notify the listener of the state change.
- switch (state) {
- case NEAR:
- mListener.onNear();
- break;
-
- case FAR:
- mListener.onFar();
- break;
- }
- }
-
- @Override
- public void onAccuracyChanged(Sensor sensor, int accuracy) {
- // Nothing to do here.
- }
-
- /** Returns the state of the sensor given its current value. */
- private State getStateFromValue(float value) {
- // Determine if the current value corresponds to the NEAR or FAR state.
- // Take case of the case where the proximity sensor is binary: if the current value is
- // equal to the maximum, we are always in the FAR state.
- return (value > FAR_THRESHOLD || value == mMaxValue) ? State.FAR : State.NEAR;
- }
-
- /**
- * Unregister the next time the sensor reaches the {@link State#FAR} state.
- */
- public synchronized void unregisterWhenFar() {
- if (mLastState == State.FAR) {
- // We are already in the far state, just unregister now.
- unregisterWithoutNotification();
- } else {
- mWaitingForFarState = true;
- }
- }
-
- /** Register the listener and call the listener as necessary. */
- public synchronized void register() {
- // It is okay to register multiple times.
- mSensorManager.registerListener(this, mProximitySensor, SensorManager.SENSOR_DELAY_UI);
- // We should no longer be waiting for the far state if we are registering again.
- mWaitingForFarState = false;
- }
-
- public void unregister() {
- State lastState;
- synchronized (this) {
- unregisterWithoutNotification();
- lastState = mLastState;
- // Always go back to the FAR state. That way, when we register again we will get a
- // transition when the sensor gets into the NEAR state.
- mLastState = State.FAR;
- }
- // Notify the listener if we changed the state to FAR while unregistering.
- if (lastState != State.FAR) {
- mListener.onFar();
- }
- }
-
- @GuardedBy("this")
- private void unregisterWithoutNotification() {
- mSensorManager.unregisterListener(this);
- mWaitingForFarState = false;
- }
- }
-
- public ProximitySensorManager(Context context, Listener listener) {
- SensorManager sensorManager =
- (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
- Sensor proximitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
- if (proximitySensor == null) {
- // If there is no sensor, we should not do anything.
- mProximitySensorListener = null;
- } else {
- mProximitySensorListener =
- new ProximitySensorEventListener(sensorManager, proximitySensor, listener);
- }
- }
-
- /**
- * Enables the proximity manager.
- * <p>
- * The listener will start getting notifications of events.
- * <p>
- * This method is idempotent.
- */
- public void enable() {
- if (mProximitySensorListener != null && !mManagerEnabled) {
- mProximitySensorListener.register();
- mManagerEnabled = true;
- }
- }
-
- /**
- * Disables the proximity manager.
- * <p>
- * The listener will stop receiving notifications of events, possibly after receiving a last
- * {@link Listener#onFar()} callback.
- * <p>
- * If {@code waitForFarState} is true, if the sensor is not currently in the {@link State#FAR}
- * state, the listener will receive a {@link Listener#onFar()} callback the next time the sensor
- * actually reaches the {@link State#FAR} state.
- * <p>
- * If {@code waitForFarState} is false, the listener will receive a {@link Listener#onFar()}
- * callback immediately if the sensor is currently not in the {@link State#FAR} state.
- * <p>
- * This method is idempotent.
- */
- public void disable(boolean waitForFarState) {
- if (mProximitySensorListener != null && mManagerEnabled) {
- if (waitForFarState) {
- mProximitySensorListener.unregisterWhenFar();
- } else {
- mProximitySensorListener.unregister();
- }
- mManagerEnabled = false;
- }
- }
-}
diff --git a/src/com/android/contacts/SpecialCharSequenceMgr.java b/src/com/android/contacts/SpecialCharSequenceMgr.java
deleted file mode 100644
index 4902fde..0000000
--- a/src/com/android/contacts/SpecialCharSequenceMgr.java
+++ /dev/null
@@ -1,406 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source 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.contacts;
-
-import com.android.internal.telephony.ITelephony;
-import com.android.internal.telephony.TelephonyCapabilities;
-import com.android.internal.telephony.TelephonyIntents;
-
-import android.app.AlertDialog;
-import android.app.KeyguardManager;
-import android.app.ProgressDialog;
-import android.content.AsyncQueryHandler;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.telephony.PhoneNumberUtils;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-import android.view.WindowManager;
-import android.widget.EditText;
-import android.widget.Toast;
-
-/**
- * Helper class to listen for some magic character sequences
- * that are handled specially by the dialer.
- *
- * Note the Phone app also handles these sequences too (in a couple of
- * relativly obscure places in the UI), so there's a separate version of
- * this class under apps/Phone.
- *
- * TODO: there's lots of duplicated code between this class and the
- * corresponding class under apps/Phone. Let's figure out a way to
- * unify these two classes (in the framework? in a common shared library?)
- */
-public class SpecialCharSequenceMgr {
- private static final String TAG = "SpecialCharSequenceMgr";
- private static final String MMI_IMEI_DISPLAY = "*#06#";
-
- /**
- * Remembers the previous {@link QueryHandler} and cancel the operation when needed, to
- * prevent possible crash.
- *
- * QueryHandler may call {@link ProgressDialog#dismiss()} when the screen is already gone,
- * which will cause the app crash. This variable enables the class to prevent the crash
- * on {@link #cleanup()}.
- *
- * TODO: Remove this and replace it (and {@link #cleanup()}) with better implementation.
- * One complication is that we have SpecialCharSequencMgr in Phone package too, which has
- * *slightly* different implementation. Note that Phone package doesn't have this problem,
- * so the class on Phone side doesn't have this functionality.
- * Fundamental fix would be to have one shared implementation and resolve this corner case more
- * gracefully.
- */
- private static QueryHandler sPreviousAdnQueryHandler;
-
- /** This class is never instantiated. */
- private SpecialCharSequenceMgr() {
- }
-
- public static boolean handleChars(Context context, String input, EditText textField) {
- return handleChars(context, input, false, textField);
- }
-
- static boolean handleChars(Context context, String input) {
- return handleChars(context, input, false, null);
- }
-
- static boolean handleChars(Context context, String input, boolean useSystemWindow,
- EditText textField) {
-
- //get rid of the separators so that the string gets parsed correctly
- String dialString = PhoneNumberUtils.stripSeparators(input);
-
- if (handleIMEIDisplay(context, dialString, useSystemWindow)
- || handlePinEntry(context, dialString)
- || handleAdnEntry(context, dialString, textField)
- || handleSecretCode(context, dialString)) {
- return true;
- }
-
- return false;
- }
-
- /**
- * Cleanup everything around this class. Must be run inside the main thread.
- *
- * This should be called when the screen becomes background.
- */
- public static void cleanup() {
- if (Looper.myLooper() != Looper.getMainLooper()) {
- Log.wtf(TAG, "cleanup() is called outside the main thread");
- return;
- }
-
- if (sPreviousAdnQueryHandler != null) {
- sPreviousAdnQueryHandler.cancel();
- sPreviousAdnQueryHandler = null;
- }
- }
-
- /**
- * Handles secret codes to launch arbitrary activities in the form of *#*#<code>#*#*.
- * If a secret code is encountered an Intent is started with the android_secret_code://<code>
- * URI.
- *
- * @param context the context to use
- * @param input the text to check for a secret code in
- * @return true if a secret code was encountered
- */
- static boolean handleSecretCode(Context context, String input) {
- // Secret codes are in the form *#*#<code>#*#*
- int len = input.length();
- if (len > 8 && input.startsWith("*#*#") && input.endsWith("#*#*")) {
- Intent intent = new Intent(TelephonyIntents.SECRET_CODE_ACTION,
- Uri.parse("android_secret_code://" + input.substring(4, len - 4)));
- context.sendBroadcast(intent);
- return true;
- }
-
- return false;
- }
-
- /**
- * Handle ADN requests by filling in the SIM contact number into the requested
- * EditText.
- *
- * This code works alongside the Asynchronous query handler {@link QueryHandler}
- * and query cancel handler implemented in {@link SimContactQueryCookie}.
- */
- static boolean handleAdnEntry(Context context, String input, EditText textField) {
- /* ADN entries are of the form "N(N)(N)#" */
-
- TelephonyManager telephonyManager =
- (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
- if (telephonyManager == null
- || !TelephonyCapabilities.supportsAdn(telephonyManager.getCurrentPhoneType())) {
- return false;
- }
-
- // if the phone is keyguard-restricted, then just ignore this
- // input. We want to make sure that sim card contacts are NOT
- // exposed unless the phone is unlocked, and this code can be
- // accessed from the emergency dialer.
- KeyguardManager keyguardManager =
- (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
- if (keyguardManager.inKeyguardRestrictedInputMode()) {
- return false;
- }
-
- int len = input.length();
- if ((len > 1) && (len < 5) && (input.endsWith("#"))) {
- try {
- // get the ordinal number of the sim contact
- int index = Integer.parseInt(input.substring(0, len-1));
-
- // The original code that navigated to a SIM Contacts list view did not
- // highlight the requested contact correctly, a requirement for PTCRB
- // certification. This behaviour is consistent with the UI paradigm
- // for touch-enabled lists, so it does not make sense to try to work
- // around it. Instead we fill in the the requested phone number into
- // the dialer text field.
-
- // create the async query handler
- QueryHandler handler = new QueryHandler (context.getContentResolver());
-
- // create the cookie object
- SimContactQueryCookie sc = new SimContactQueryCookie(index - 1, handler,
- ADN_QUERY_TOKEN);
-
- // setup the cookie fields
- sc.contactNum = index - 1;
- sc.setTextField(textField);
-
- // create the progress dialog
- sc.progressDialog = new ProgressDialog(context);
- sc.progressDialog.setTitle(R.string.simContacts_title);
- sc.progressDialog.setMessage(context.getText(R.string.simContacts_emptyLoading));
- sc.progressDialog.setIndeterminate(true);
- sc.progressDialog.setCancelable(true);
- sc.progressDialog.setOnCancelListener(sc);
- sc.progressDialog.getWindow().addFlags(
- WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
-
- // display the progress dialog
- sc.progressDialog.show();
-
- // run the query.
- handler.startQuery(ADN_QUERY_TOKEN, sc, Uri.parse("content://icc/adn"),
- new String[]{ADN_PHONE_NUMBER_COLUMN_NAME}, null, null, null);
-
- if (sPreviousAdnQueryHandler != null) {
- // It is harmless to call cancel() even after the handler's gone.
- sPreviousAdnQueryHandler.cancel();
- }
- sPreviousAdnQueryHandler = handler;
- return true;
- } catch (NumberFormatException ex) {
- // Ignore
- }
- }
- return false;
- }
-
- static boolean handlePinEntry(Context context, String input) {
- if ((input.startsWith("**04") || input.startsWith("**05")) && input.endsWith("#")) {
- try {
- return ITelephony.Stub.asInterface(ServiceManager.getService("phone"))
- .handlePinMmi(input);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to handlePinMmi due to remote exception");
- return false;
- }
- }
- return false;
- }
-
- static boolean handleIMEIDisplay(Context context, String input, boolean useSystemWindow) {
- TelephonyManager telephonyManager =
- (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
- if (telephonyManager != null && input.equals(MMI_IMEI_DISPLAY)) {
- int phoneType = telephonyManager.getCurrentPhoneType();
- if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
- showIMEIPanel(context, useSystemWindow, telephonyManager);
- return true;
- } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
- showMEIDPanel(context, useSystemWindow, telephonyManager);
- return true;
- }
- }
-
- return false;
- }
-
- // TODO: Combine showIMEIPanel() and showMEIDPanel() into a single
- // generic "showDeviceIdPanel()" method, like in the apps/Phone
- // version of SpecialCharSequenceMgr.java. (This will require moving
- // the phone app's TelephonyCapabilities.getDeviceIdLabel() method
- // into the telephony framework, though.)
-
- private static void showIMEIPanel(Context context, boolean useSystemWindow,
- TelephonyManager telephonyManager) {
- String imeiStr = telephonyManager.getDeviceId();
-
- AlertDialog alert = new AlertDialog.Builder(context)
- .setTitle(R.string.imei)
- .setMessage(imeiStr)
- .setPositiveButton(android.R.string.ok, null)
- .setCancelable(false)
- .show();
- }
-
- private static void showMEIDPanel(Context context, boolean useSystemWindow,
- TelephonyManager telephonyManager) {
- String meidStr = telephonyManager.getDeviceId();
-
- AlertDialog alert = new AlertDialog.Builder(context)
- .setTitle(R.string.meid)
- .setMessage(meidStr)
- .setPositiveButton(android.R.string.ok, null)
- .setCancelable(false)
- .show();
- }
-
- /*******
- * This code is used to handle SIM Contact queries
- *******/
- private static final String ADN_PHONE_NUMBER_COLUMN_NAME = "number";
- private static final String ADN_NAME_COLUMN_NAME = "name";
- private static final int ADN_QUERY_TOKEN = -1;
-
- /**
- * Cookie object that contains everything we need to communicate to the
- * handler's onQuery Complete, as well as what we need in order to cancel
- * the query (if requested).
- *
- * Note, access to the textField field is going to be synchronized, because
- * the user can request a cancel at any time through the UI.
- */
- private static class SimContactQueryCookie implements DialogInterface.OnCancelListener{
- public ProgressDialog progressDialog;
- public int contactNum;
-
- // Used to identify the query request.
- private int mToken;
- private QueryHandler mHandler;
-
- // The text field we're going to update
- private EditText textField;
-
- public SimContactQueryCookie(int number, QueryHandler handler, int token) {
- contactNum = number;
- mHandler = handler;
- mToken = token;
- }
-
- /**
- * Synchronized getter for the EditText.
- */
- public synchronized EditText getTextField() {
- return textField;
- }
-
- /**
- * Synchronized setter for the EditText.
- */
- public synchronized void setTextField(EditText text) {
- textField = text;
- }
-
- /**
- * Cancel the ADN query by stopping the operation and signaling
- * the cookie that a cancel request is made.
- */
- public synchronized void onCancel(DialogInterface dialog) {
- // close the progress dialog
- if (progressDialog != null) {
- progressDialog.dismiss();
- }
-
- // setting the textfield to null ensures that the UI does NOT get
- // updated.
- textField = null;
-
- // Cancel the operation if possible.
- mHandler.cancelOperation(mToken);
- }
- }
-
- /**
- * Asynchronous query handler that services requests to look up ADNs
- *
- * Queries originate from {@link handleAdnEntry}.
- */
- private static class QueryHandler extends AsyncQueryHandler {
-
- private boolean mCanceled;
-
- public QueryHandler(ContentResolver cr) {
- super(cr);
- }
-
- /**
- * Override basic onQueryComplete to fill in the textfield when
- * we're handed the ADN cursor.
- */
- @Override
- protected void onQueryComplete(int token, Object cookie, Cursor c) {
- sPreviousAdnQueryHandler = null;
- if (mCanceled) {
- return;
- }
-
- SimContactQueryCookie sc = (SimContactQueryCookie) cookie;
-
- // close the progress dialog.
- sc.progressDialog.dismiss();
-
- // get the EditText to update or see if the request was cancelled.
- EditText text = sc.getTextField();
-
- // if the textview is valid, and the cursor is valid and postionable
- // on the Nth number, then we update the text field and display a
- // toast indicating the caller name.
- if ((c != null) && (text != null) && (c.moveToPosition(sc.contactNum))) {
- String name = c.getString(c.getColumnIndexOrThrow(ADN_NAME_COLUMN_NAME));
- String number = c.getString(c.getColumnIndexOrThrow(ADN_PHONE_NUMBER_COLUMN_NAME));
-
- // fill the text in.
- text.getText().replace(0, 0, number);
-
- // display the name as a toast
- Context context = sc.progressDialog.getContext();
- name = context.getString(R.string.menu_callNumber, name);
- Toast.makeText(context, name, Toast.LENGTH_SHORT)
- .show();
- }
- }
-
- public void cancel() {
- mCanceled = true;
- // Ask AsyncQueryHandler to cancel the whole request. This will fails when the
- // query already started.
- cancelOperation(ADN_QUERY_TOKEN);
- }
- }
-}
diff --git a/src/com/android/contacts/list/PhoneFavoriteFragment.java b/src/com/android/contacts/list/PhoneFavoriteFragment.java
deleted file mode 100644
index 5ef19ff..0000000
--- a/src/com/android/contacts/list/PhoneFavoriteFragment.java
+++ /dev/null
@@ -1,563 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source 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.contacts.list;
-
-import android.app.Activity;
-import android.app.Fragment;
-import android.app.LoaderManager;
-import android.content.CursorLoader;
-import android.content.Intent;
-import android.content.Loader;
-import android.database.Cursor;
-import android.graphics.Rect;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.Directory;
-import android.provider.Settings;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.AbsListView;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.FrameLayout;
-import android.widget.ListView;
-import android.widget.TextView;
-
-import com.android.contacts.ContactPhotoManager;
-import com.android.contacts.ContactTileLoaderFactory;
-import com.android.contacts.R;
-import com.android.contacts.dialog.ClearFrequentsDialog;
-import com.android.contacts.interactions.ImportExportDialogFragment;
-import com.android.contacts.preference.ContactsPreferences;
-import com.android.contacts.util.AccountFilterUtil;
-
-/**
- * Fragment for Phone UI's favorite screen.
- *
- * This fragment contains three kinds of contacts in one screen: "starred", "frequent", and "all"
- * contacts. To show them at once, this merges results from {@link ContactTileAdapter} and
- * {@link PhoneNumberListAdapter} into one unified list using {@link PhoneFavoriteMergedAdapter}.
- * A contact filter header is also inserted between those adapters' results.
- */
-public class PhoneFavoriteFragment extends Fragment implements OnItemClickListener {
- private static final String TAG = PhoneFavoriteFragment.class.getSimpleName();
- private static final boolean DEBUG = false;
-
- /**
- * Used with LoaderManager.
- */
- private static int LOADER_ID_CONTACT_TILE = 1;
- private static int LOADER_ID_ALL_CONTACTS = 2;
-
- private static final String KEY_FILTER = "filter";
-
- private static final int REQUEST_CODE_ACCOUNT_FILTER = 1;
-
- public interface Listener {
- public void onContactSelected(Uri contactUri);
- public void onCallNumberDirectly(String phoneNumber);
- }
-
- private class ContactTileLoaderListener implements LoaderManager.LoaderCallbacks<Cursor> {
- @Override
- public CursorLoader onCreateLoader(int id, Bundle args) {
- if (DEBUG) Log.d(TAG, "ContactTileLoaderListener#onCreateLoader.");
- return ContactTileLoaderFactory.createStrequentPhoneOnlyLoader(getActivity());
- }
-
- @Override
- public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
- if (DEBUG) Log.d(TAG, "ContactTileLoaderListener#onLoadFinished");
- mContactTileAdapter.setContactCursor(data);
-
- if (mAllContactsForceReload) {
- mAllContactsAdapter.onDataReload();
- // Use restartLoader() to make LoaderManager to load the section again.
- getLoaderManager().restartLoader(
- LOADER_ID_ALL_CONTACTS, null, mAllContactsLoaderListener);
- } else if (!mAllContactsLoaderStarted) {
- // Load "all" contacts if not loaded yet.
- getLoaderManager().initLoader(
- LOADER_ID_ALL_CONTACTS, null, mAllContactsLoaderListener);
- }
- mAllContactsForceReload = false;
- mAllContactsLoaderStarted = true;
-
- // Show the filter header with "loading" state.
- updateFilterHeaderView();
- mAccountFilterHeader.setVisibility(View.VISIBLE);
-
- // invalidate the options menu if needed
- invalidateOptionsMenuIfNeeded();
- }
-
- @Override
- public void onLoaderReset(Loader<Cursor> loader) {
- if (DEBUG) Log.d(TAG, "ContactTileLoaderListener#onLoaderReset. ");
- }
- }
-
- private class AllContactsLoaderListener implements LoaderManager.LoaderCallbacks<Cursor> {
- @Override
- public Loader<Cursor> onCreateLoader(int id, Bundle args) {
- if (DEBUG) Log.d(TAG, "AllContactsLoaderListener#onCreateLoader");
- CursorLoader loader = new CursorLoader(getActivity(), null, null, null, null, null);
- mAllContactsAdapter.configureLoader(loader, Directory.DEFAULT);
- return loader;
- }
-
- @Override
- public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
- if (DEBUG) Log.d(TAG, "AllContactsLoaderListener#onLoadFinished");
- mAllContactsAdapter.changeCursor(0, data);
- updateFilterHeaderView();
- mHandler.removeMessages(MESSAGE_SHOW_LOADING_EFFECT);
- mLoadingView.setVisibility(View.VISIBLE);
- }
-
- @Override
- public void onLoaderReset(Loader<Cursor> loader) {
- if (DEBUG) Log.d(TAG, "AllContactsLoaderListener#onLoaderReset. ");
- }
- }
-
- private class ContactTileAdapterListener implements ContactTileView.Listener {
- @Override
- public void onContactSelected(Uri contactUri, Rect targetRect) {
- if (mListener != null) {
- mListener.onContactSelected(contactUri);
- }
- }
-
- @Override
- public void onCallNumberDirectly(String phoneNumber) {
- if (mListener != null) {
- mListener.onCallNumberDirectly(phoneNumber);
- }
- }
-
- @Override
- public int getApproximateTileWidth() {
- return getView().getWidth() / mContactTileAdapter.getColumnCount();
- }
- }
-
- private class FilterHeaderClickListener implements OnClickListener {
- @Override
- public void onClick(View view) {
- AccountFilterUtil.startAccountFilterActivityForResult(
- PhoneFavoriteFragment.this,
- REQUEST_CODE_ACCOUNT_FILTER,
- mFilter);
- }
- }
-
- private class ContactsPreferenceChangeListener
- implements ContactsPreferences.ChangeListener {
- @Override
- public void onChange() {
- if (loadContactsPreferences()) {
- requestReloadAllContacts();
- }
- }
- }
-
- private class ScrollListener implements ListView.OnScrollListener {
- private boolean mShouldShowFastScroller;
- @Override
- public void onScroll(AbsListView view,
- int firstVisibleItem, int visibleItemCount, int totalItemCount) {
- // FastScroller should be visible only when the user is seeing "all" contacts section.
- final boolean shouldShow = mAdapter.shouldShowFirstScroller(firstVisibleItem);
- if (shouldShow != mShouldShowFastScroller) {
- mListView.setVerticalScrollBarEnabled(shouldShow);
- mListView.setFastScrollEnabled(shouldShow);
- mListView.setFastScrollAlwaysVisible(shouldShow);
- mShouldShowFastScroller = shouldShow;
- }
- }
-
- @Override
- public void onScrollStateChanged(AbsListView view, int scrollState) {
- }
- }
-
- private static final int MESSAGE_SHOW_LOADING_EFFECT = 1;
- private static final int LOADING_EFFECT_DELAY = 500; // ms
- private final Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MESSAGE_SHOW_LOADING_EFFECT:
- mLoadingView.setVisibility(View.VISIBLE);
- break;
- }
- }
- };
-
- private Listener mListener;
- private PhoneFavoriteMergedAdapter mAdapter;
- private ContactTileAdapter mContactTileAdapter;
- private PhoneNumberListAdapter mAllContactsAdapter;
-
- /**
- * true when the loader for {@link PhoneNumberListAdapter} has started already.
- */
- private boolean mAllContactsLoaderStarted;
- /**
- * true when the loader for {@link PhoneNumberListAdapter} must reload "all" contacts again.
- * It typically happens when {@link ContactsPreferences} has changed its settings
- * (display order and sort order)
- */
- private boolean mAllContactsForceReload;
-
- private ContactsPreferences mContactsPrefs;
- private ContactListFilter mFilter;
-
- private TextView mEmptyView;
- private ListView mListView;
- /**
- * Layout containing {@link #mAccountFilterHeader}. Used to limit area being "pressed".
- */
- private FrameLayout mAccountFilterHeaderContainer;
- private View mAccountFilterHeader;
-
- /**
- * Layout used when contacts load is slower than expected and thus "loading" view should be
- * shown.
- */
- private View mLoadingView;
-
- private final ContactTileView.Listener mContactTileAdapterListener =
- new ContactTileAdapterListener();
- private final LoaderManager.LoaderCallbacks<Cursor> mContactTileLoaderListener =
- new ContactTileLoaderListener();
- private final LoaderManager.LoaderCallbacks<Cursor> mAllContactsLoaderListener =
- new AllContactsLoaderListener();
- private final OnClickListener mFilterHeaderClickListener = new FilterHeaderClickListener();
- private final ContactsPreferenceChangeListener mContactsPreferenceChangeListener =
- new ContactsPreferenceChangeListener();
- private final ScrollListener mScrollListener = new ScrollListener();
-
- private boolean mOptionsMenuHasFrequents;
-
- @Override
- public void onAttach(Activity activity) {
- if (DEBUG) Log.d(TAG, "onAttach()");
- super.onAttach(activity);
-
- mContactsPrefs = new ContactsPreferences(activity);
-
- // Construct two base adapters which will become part of PhoneFavoriteMergedAdapter.
- // We don't construct the resultant adapter at this moment since it requires LayoutInflater
- // that will be available on onCreateView().
-
- mContactTileAdapter = new ContactTileAdapter(activity, mContactTileAdapterListener,
- getResources().getInteger(R.integer.contact_tile_column_count_in_favorites),
- ContactTileAdapter.DisplayType.STREQUENT_PHONE_ONLY);
- mContactTileAdapter.setPhotoLoader(ContactPhotoManager.getInstance(activity));
-
- // Setup the "all" adapter manually. See also the setup logic in ContactEntryListFragment.
- mAllContactsAdapter = new PhoneNumberListAdapter(activity);
- mAllContactsAdapter.setDisplayPhotos(true);
- mAllContactsAdapter.setQuickContactEnabled(true);
- mAllContactsAdapter.setSearchMode(false);
- mAllContactsAdapter.setIncludeProfile(false);
- mAllContactsAdapter.setSelectionVisible(false);
- mAllContactsAdapter.setDarkTheme(true);
- mAllContactsAdapter.setPhotoLoader(ContactPhotoManager.getInstance(activity));
- // Disable directory header.
- mAllContactsAdapter.setHasHeader(0, false);
- // Show A-Z section index.
- mAllContactsAdapter.setSectionHeaderDisplayEnabled(true);
- // Disable pinned header. It doesn't work with this fragment.
- mAllContactsAdapter.setPinnedPartitionHeadersEnabled(false);
- // Put photos on left for consistency with "frequent" contacts section.
- mAllContactsAdapter.setPhotoPosition(ContactListItemView.PhotoPosition.LEFT);
-
- // Use Callable.CONTENT_URI which will include not only phone numbers but also SIP
- // addresses.
- mAllContactsAdapter.setUseCallableUri(true);
-
- mAllContactsAdapter.setContactNameDisplayOrder(mContactsPrefs.getDisplayOrder());
- mAllContactsAdapter.setSortOrder(mContactsPrefs.getSortOrder());
- }
-
- @Override
- public void onCreate(Bundle savedState) {
- if (DEBUG) Log.d(TAG, "onCreate()");
- super.onCreate(savedState);
- if (savedState != null) {
- mFilter = savedState.getParcelable(KEY_FILTER);
-
- if (mFilter != null) {
- mAllContactsAdapter.setFilter(mFilter);
- }
- }
- setHasOptionsMenu(true);
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putParcelable(KEY_FILTER, mFilter);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- final View listLayout = inflater.inflate(
- R.layout.phone_contact_tile_list, container, false);
-
- mListView = (ListView) listLayout.findViewById(R.id.contact_tile_list);
- mListView.setItemsCanFocus(true);
- mListView.setOnItemClickListener(this);
- mListView.setVerticalScrollBarEnabled(false);
- mListView.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_RIGHT);
- mListView.setScrollBarStyle(ListView.SCROLLBARS_OUTSIDE_OVERLAY);
-
- // Create the account filter header but keep it hidden until "all" contacts are loaded.
- mAccountFilterHeaderContainer = new FrameLayout(getActivity(), null);
- mAccountFilterHeader = inflater.inflate(R.layout.account_filter_header_for_phone_favorite,
- mListView, false);
- mAccountFilterHeader.setOnClickListener(mFilterHeaderClickListener);
- mAccountFilterHeaderContainer.addView(mAccountFilterHeader);
-
- mLoadingView = inflater.inflate(R.layout.phone_loading_contacts, mListView, false);
-
- mAdapter = new PhoneFavoriteMergedAdapter(getActivity(),
- mContactTileAdapter, mAccountFilterHeaderContainer, mAllContactsAdapter,
- mLoadingView);
-
- mListView.setAdapter(mAdapter);
-
- mListView.setOnScrollListener(mScrollListener);
- mListView.setFastScrollEnabled(false);
- mListView.setFastScrollAlwaysVisible(false);
-
- mEmptyView = (TextView) listLayout.findViewById(R.id.contact_tile_list_empty);
- mEmptyView.setText(getString(R.string.listTotalAllContactsZero));
- mListView.setEmptyView(mEmptyView);
-
- updateFilterHeaderView();
-
- return listLayout;
- }
-
- private boolean isOptionsMenuChanged() {
- return mOptionsMenuHasFrequents != hasFrequents();
- }
-
- private void invalidateOptionsMenuIfNeeded() {
- if (isOptionsMenuChanged()) {
- getActivity().invalidateOptionsMenu();
- }
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- super.onCreateOptionsMenu(menu, inflater);
- inflater.inflate(R.menu.phone_favorite_options, menu);
- }
-
- @Override
- public void onPrepareOptionsMenu(Menu menu) {
- final MenuItem clearFrequents = menu.findItem(R.id.menu_clear_frequents);
- mOptionsMenuHasFrequents = hasFrequents();
- clearFrequents.setVisible(mOptionsMenuHasFrequents);
- }
-
- private boolean hasFrequents() {
- return mContactTileAdapter.getNumFrequents() > 0;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.menu_import_export:
- // We hard-code the "contactsAreAvailable" argument because doing it properly would
- // involve querying a {@link ProviderStatusLoader}, which we don't want to do right
- // now in Dialtacts for (potential) performance reasons. Compare with how it is
- // done in {@link PeopleActivity}.
- ImportExportDialogFragment.show(getFragmentManager(), true);
- return true;
- case R.id.menu_accounts:
- final Intent intent = new Intent(Settings.ACTION_SYNC_SETTINGS);
- intent.putExtra(Settings.EXTRA_AUTHORITIES, new String[] {
- ContactsContract.AUTHORITY
- });
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
- startActivity(intent);
- return true;
- case R.id.menu_clear_frequents:
- ClearFrequentsDialog.show(getFragmentManager());
- return true;
- }
- return false;
- }
-
- @Override
- public void onStart() {
- super.onStart();
-
- mContactsPrefs.registerChangeListener(mContactsPreferenceChangeListener);
-
- // If ContactsPreferences has changed, we need to reload "all" contacts with the new
- // settings. If mAllContactsFoarceReload is already true, it should be kept.
- if (loadContactsPreferences()) {
- mAllContactsForceReload = true;
- }
-
- // Use initLoader() instead of restartLoader() to refraining unnecessary reload.
- // This method call implicitly assures ContactTileLoaderListener's onLoadFinished() will
- // be called, on which we'll check if "all" contacts should be reloaded again or not.
- getLoaderManager().initLoader(LOADER_ID_CONTACT_TILE, null, mContactTileLoaderListener);
-
- // Delay showing "loading" view until certain amount of time so that users won't see
- // instant flash of the view when the contacts load is fast enough.
- // This will be kept shown until both tile and all sections are loaded.
- mLoadingView.setVisibility(View.INVISIBLE);
- mHandler.sendEmptyMessageDelayed(MESSAGE_SHOW_LOADING_EFFECT, LOADING_EFFECT_DELAY);
- }
-
- @Override
- public void onStop() {
- super.onStop();
- mContactsPrefs.unregisterChangeListener();
- }
-
- /**
- * {@inheritDoc}
- *
- * This is only effective for elements provided by {@link #mContactTileAdapter}.
- * {@link #mContactTileAdapter} has its own logic for click events.
- */
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- final int contactTileAdapterCount = mContactTileAdapter.getCount();
- if (position <= contactTileAdapterCount) {
- Log.e(TAG, "onItemClick() event for unexpected position. "
- + "The position " + position + " is before \"all\" section. Ignored.");
- } else {
- final int localPosition = position - mContactTileAdapter.getCount() - 1;
- if (mListener != null) {
- mListener.onContactSelected(mAllContactsAdapter.getDataUri(localPosition));
- }
- }
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == REQUEST_CODE_ACCOUNT_FILTER) {
- if (getActivity() != null) {
- AccountFilterUtil.handleAccountFilterResult(
- ContactListFilterController.getInstance(getActivity()), resultCode, data);
- } else {
- Log.e(TAG, "getActivity() returns null during Fragment#onActivityResult()");
- }
- }
- }
-
- private boolean loadContactsPreferences() {
- if (mContactsPrefs == null || mAllContactsAdapter == null) {
- return false;
- }
-
- boolean changed = false;
- final int currentDisplayOrder = mContactsPrefs.getDisplayOrder();
- if (mAllContactsAdapter.getContactNameDisplayOrder() != currentDisplayOrder) {
- mAllContactsAdapter.setContactNameDisplayOrder(currentDisplayOrder);
- changed = true;
- }
-
- final int currentSortOrder = mContactsPrefs.getSortOrder();
- if (mAllContactsAdapter.getSortOrder() != currentSortOrder) {
- mAllContactsAdapter.setSortOrder(currentSortOrder);
- changed = true;
- }
-
- return changed;
- }
-
- /**
- * Requests to reload "all" contacts. If the section is already loaded, this method will
- * force reloading it now. If the section isn't loaded yet, the actual load may be done later
- * (on {@link #onStart()}.
- */
- private void requestReloadAllContacts() {
- if (DEBUG) {
- Log.d(TAG, "requestReloadAllContacts()"
- + " mAllContactsAdapter: " + mAllContactsAdapter
- + ", mAllContactsLoaderStarted: " + mAllContactsLoaderStarted);
- }
-
- if (mAllContactsAdapter == null || !mAllContactsLoaderStarted) {
- // Remember this request until next load on onStart().
- mAllContactsForceReload = true;
- return;
- }
-
- if (DEBUG) Log.d(TAG, "Reload \"all\" contacts now.");
-
- mAllContactsAdapter.onDataReload();
- // Use restartLoader() to make LoaderManager to load the section again.
- getLoaderManager().restartLoader(LOADER_ID_ALL_CONTACTS, null, mAllContactsLoaderListener);
- }
-
- private void updateFilterHeaderView() {
- final ContactListFilter filter = getFilter();
- if (mAccountFilterHeader == null || mAllContactsAdapter == null || filter == null) {
- return;
- }
- AccountFilterUtil.updateAccountFilterTitleForPhone(mAccountFilterHeader, filter, true);
- }
-
- public ContactListFilter getFilter() {
- return mFilter;
- }
-
- public void setFilter(ContactListFilter filter) {
- if ((mFilter == null && filter == null) || (mFilter != null && mFilter.equals(filter))) {
- return;
- }
-
- if (DEBUG) {
- Log.d(TAG, "setFilter(). old filter (" + mFilter
- + ") will be replaced with new filter (" + filter + ")");
- }
-
- mFilter = filter;
-
- if (mAllContactsAdapter != null) {
- mAllContactsAdapter.setFilter(mFilter);
- requestReloadAllContacts();
- updateFilterHeaderView();
- }
- }
-
- public void setListener(Listener listener) {
- mListener = listener;
- }
-}
diff --git a/src/com/android/contacts/list/PhoneFavoriteMergedAdapter.java b/src/com/android/contacts/list/PhoneFavoriteMergedAdapter.java
deleted file mode 100644
index 3aa9fe5..0000000
--- a/src/com/android/contacts/list/PhoneFavoriteMergedAdapter.java
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc.
- * Licensed to The Android Open Source 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.contacts.list;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.database.DataSetObserver;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.FrameLayout;
-import android.widget.SectionIndexer;
-
-import com.android.contacts.R;
-
-/**
- * An adapter that combines items from {@link ContactTileAdapter} and
- * {@link ContactEntryListAdapter} into a single list. In between those two results,
- * an account filter header will be inserted.
- */
-public class PhoneFavoriteMergedAdapter extends BaseAdapter implements SectionIndexer {
-
- private class CustomDataSetObserver extends DataSetObserver {
- @Override
- public void onChanged() {
- notifyDataSetChanged();
- }
- }
-
- private final ContactTileAdapter mContactTileAdapter;
- private final ContactEntryListAdapter mContactEntryListAdapter;
- private final View mAccountFilterHeaderContainer;
- private final View mLoadingView;
-
- private final int mItemPaddingLeft;
- private final int mItemPaddingRight;
-
- // Make frequent header consistent with account filter header.
- private final int mFrequentHeaderPaddingTop;
-
- private final DataSetObserver mObserver;
-
- public PhoneFavoriteMergedAdapter(Context context,
- ContactTileAdapter contactTileAdapter,
- View accountFilterHeaderContainer,
- ContactEntryListAdapter contactEntryListAdapter,
- View loadingView) {
- Resources resources = context.getResources();
- mItemPaddingLeft = resources.getDimensionPixelSize(R.dimen.detail_item_side_margin);
- mItemPaddingRight = resources.getDimensionPixelSize(R.dimen.list_visible_scrollbar_padding);
- mFrequentHeaderPaddingTop = resources.getDimensionPixelSize(
- R.dimen.contact_browser_list_top_margin);
- mContactTileAdapter = contactTileAdapter;
- mContactEntryListAdapter = contactEntryListAdapter;
-
- mAccountFilterHeaderContainer = accountFilterHeaderContainer;
-
- mObserver = new CustomDataSetObserver();
- mContactTileAdapter.registerDataSetObserver(mObserver);
- mContactEntryListAdapter.registerDataSetObserver(mObserver);
-
- mLoadingView = loadingView;
- }
-
- @Override
- public boolean isEmpty() {
- // Cannot use the super's method here because we add extra rows in getCount() to account
- // for headers
- return mContactTileAdapter.getCount() + mContactEntryListAdapter.getCount() == 0;
- }
-
- @Override
- public int getCount() {
- final int contactTileAdapterCount = mContactTileAdapter.getCount();
- final int contactEntryListAdapterCount = mContactEntryListAdapter.getCount();
- if (mContactEntryListAdapter.isLoading()) {
- // Hide "all" contacts during its being loaded. Instead show "loading" view.
- //
- // "+2" for mAccountFilterHeaderContainer and mLoadingView
- return contactTileAdapterCount + 2;
- } else {
- // "+1" for mAccountFilterHeaderContainer
- return contactTileAdapterCount + contactEntryListAdapterCount + 1;
- }
- }
-
- @Override
- public Object getItem(int position) {
- final int contactTileAdapterCount = mContactTileAdapter.getCount();
- final int contactEntryListAdapterCount = mContactEntryListAdapter.getCount();
- if (position < contactTileAdapterCount) { // For "tile" and "frequent" sections
- return mContactTileAdapter.getItem(position);
- } else if (position == contactTileAdapterCount) { // For "all" section's account header
- return mAccountFilterHeaderContainer;
- } else { // For "all" section
- if (mContactEntryListAdapter.isLoading()) { // "All" section is being loaded.
- return mLoadingView;
- } else {
- // "-1" for mAccountFilterHeaderContainer
- final int localPosition = position - contactTileAdapterCount - 1;
- return mContactTileAdapter.getItem(localPosition);
- }
- }
- }
-
- @Override
- public long getItemId(int position) {
- return position;
- }
-
- @Override
- public int getViewTypeCount() {
- // "+2" for mAccountFilterHeaderContainer and mLoadingView
- return (mContactTileAdapter.getViewTypeCount()
- + mContactEntryListAdapter.getViewTypeCount()
- + 2);
- }
-
- @Override
- public int getItemViewType(int position) {
- final int contactTileAdapterCount = mContactTileAdapter.getCount();
- final int contactEntryListAdapterCount = mContactEntryListAdapter.getCount();
- // There should be four kinds of types that are usually used, and one more exceptional
- // type (IGNORE_ITEM_VIEW_TYPE), which sometimes comes from mContactTileAdapter.
- //
- // The four ordinary view types have the index equal to or more than 0, and less than
- // mContactTileAdapter.getViewTypeCount()+ mContactEntryListAdapter.getViewTypeCount() + 2.
- // (See also this class's getViewTypeCount())
- //
- // We have those values for:
- // - The view types mContactTileAdapter originally has
- // - The view types mContactEntryListAdapter originally has
- // - mAccountFilterHeaderContainer ("all" section's account header), and
- // - mLoadingView
- //
- // Those types should not be mixed, so we have a different range for each kinds of types:
- // - Types for mContactTileAdapter ("tile" and "frequent" sections)
- // They should have the index, >=0 and <mContactTileAdapter.getViewTypeCount()
- //
- // - Types for mContactEntryListAdapter ("all" sections)
- // They should have the index, >=mContactTileAdapter.getViewTypeCount() and
- // <(mContactTileAdapter.getViewTypeCount() + mContactEntryListAdapter.getViewTypeCount())
- //
- // - Type for "all" section's account header
- // It should have the exact index
- // mContactTileAdapter.getViewTypeCount()+ mContactEntryListAdapter.getViewTypeCount()
- //
- // - Type for "loading" view used during "all" section is being loaded.
- // It should have the exact index
- // mContactTileAdapter.getViewTypeCount()+ mContactEntryListAdapter.getViewTypeCount() + 1
- //
- // As an exception, IGNORE_ITEM_VIEW_TYPE (-1) will be remained as is, which will be used
- // by framework's Adapter implementation and thus should be left as is.
- if (position < contactTileAdapterCount) { // For "tile" and "frequent" sections
- return mContactTileAdapter.getItemViewType(position);
- } else if (position == contactTileAdapterCount) { // For "all" section's account header
- return mContactTileAdapter.getViewTypeCount()
- + mContactEntryListAdapter.getViewTypeCount();
- } else { // For "all" section
- if (mContactEntryListAdapter.isLoading()) { // "All" section is being loaded.
- return mContactTileAdapter.getViewTypeCount()
- + mContactEntryListAdapter.getViewTypeCount() + 1;
- } else {
- // "-1" for mAccountFilterHeaderContainer
- final int localPosition = position - contactTileAdapterCount - 1;
- final int type = mContactEntryListAdapter.getItemViewType(localPosition);
- // IGNORE_ITEM_VIEW_TYPE must be handled differently.
- return (type < 0) ? type : type + mContactTileAdapter.getViewTypeCount();
- }
- }
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- final int contactTileAdapterCount = mContactTileAdapter.getCount();
- final int contactEntryListAdapterCount = mContactEntryListAdapter.getCount();
-
- // Obtain a View relevant for that position, and adjust its horizontal padding. Each
- // View has different implementation, so we use different way to control those padding.
- if (position < contactTileAdapterCount) { // For "tile" and "frequent" sections
- final View view = mContactTileAdapter.getView(position, convertView, parent);
- final int frequentHeaderPosition = mContactTileAdapter.getFrequentHeaderPosition();
- if (position < frequentHeaderPosition) { // "starred" contacts
- // No padding adjustment.
- } else if (position == frequentHeaderPosition) {
- view.setPadding(mItemPaddingLeft, mFrequentHeaderPaddingTop,
- mItemPaddingRight, view.getPaddingBottom());
- } else {
- // Views for "frequent" contacts use FrameLayout's margins instead of padding.
- final FrameLayout frameLayout = (FrameLayout) view;
- final View child = frameLayout.getChildAt(0);
- FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.WRAP_CONTENT,
- FrameLayout.LayoutParams.WRAP_CONTENT);
- params.setMargins(mItemPaddingLeft, 0, mItemPaddingRight, 0);
- child.setLayoutParams(params);
- }
- return view;
- } else if (position == contactTileAdapterCount) { // For "all" section's account header
- mAccountFilterHeaderContainer.setPadding(mItemPaddingLeft,
- mAccountFilterHeaderContainer.getPaddingTop(),
- mItemPaddingRight,
- mAccountFilterHeaderContainer.getPaddingBottom());
- return mAccountFilterHeaderContainer;
- } else { // For "all" section
- if (mContactEntryListAdapter.isLoading()) { // "All" section is being loaded.
- mLoadingView.setPadding(mItemPaddingLeft,
- mLoadingView.getPaddingTop(),
- mItemPaddingRight,
- mLoadingView.getPaddingBottom());
- return mLoadingView;
- } else {
- // "-1" for mAccountFilterHeaderContainer
- final int localPosition = position - contactTileAdapterCount - 1;
- final ContactListItemView itemView = (ContactListItemView)
- mContactEntryListAdapter.getView(localPosition, convertView, null);
- itemView.setPadding(mItemPaddingLeft, itemView.getPaddingTop(),
- mItemPaddingRight, itemView.getPaddingBottom());
- itemView.setSelectionBoundsHorizontalMargin(mItemPaddingLeft, mItemPaddingRight);
- return itemView;
- }
- }
- }
-
- @Override
- public boolean areAllItemsEnabled() {
- // If "all" section is being loaded we'll show mLoadingView, which is not enabled.
- // Otherwise check the all the other components in the ListView and return appropriate
- // result.
- return !mContactEntryListAdapter.isLoading()
- && (mContactTileAdapter.areAllItemsEnabled()
- && mAccountFilterHeaderContainer.isEnabled()
- && mContactEntryListAdapter.areAllItemsEnabled());
- }
-
- @Override
- public boolean isEnabled(int position) {
- final int contactTileAdapterCount = mContactTileAdapter.getCount();
- final int contactEntryListAdapterCount = mContactEntryListAdapter.getCount();
- if (position < contactTileAdapterCount) { // For "tile" and "frequent" sections
- return mContactTileAdapter.isEnabled(position);
- } else if (position == contactTileAdapterCount) { // For "all" section's account header
- // This will be handled by View's onClick event instead of ListView's onItemClick event.
- return false;
- } else { // For "all" section
- if (mContactEntryListAdapter.isLoading()) { // "All" section is being loaded.
- return false;
- } else {
- // "-1" for mAccountFilterHeaderContainer
- final int localPosition = position - contactTileAdapterCount - 1;
- return mContactEntryListAdapter.isEnabled(localPosition);
- }
- }
- }
-
- @Override
- public int getPositionForSection(int sectionIndex) {
- final int contactTileAdapterCount = mContactTileAdapter.getCount();
- final int localPosition = mContactEntryListAdapter.getPositionForSection(sectionIndex);
- return contactTileAdapterCount + 1 + localPosition;
- }
-
- @Override
- public int getSectionForPosition(int position) {
- final int contactTileAdapterCount = mContactTileAdapter.getCount();
- if (position <= contactTileAdapterCount) {
- return 0;
- } else {
- // "-1" for mAccountFilterHeaderContainer
- final int localPosition = position - contactTileAdapterCount - 1;
- return mContactEntryListAdapter.getSectionForPosition(localPosition);
- }
- }
-
- @Override
- public Object[] getSections() {
- return mContactEntryListAdapter.getSections();
- }
-
- public boolean shouldShowFirstScroller(int firstVisibleItem) {
- final int contactTileAdapterCount = mContactTileAdapter.getCount();
- return firstVisibleItem > contactTileAdapterCount;
- }
-}
diff --git a/src/com/android/contacts/util/AsyncTaskExecutor.java b/src/com/android/contacts/util/AsyncTaskExecutor.java
deleted file mode 100644
index f202949..0000000
--- a/src/com/android/contacts/util/AsyncTaskExecutor.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source 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.contacts.util;
-
-import android.os.AsyncTask;
-
-import java.util.concurrent.Executor;
-
-/**
- * Interface used to submit {@link AsyncTask} objects to run in the background.
- * <p>
- * This interface has a direct parallel with the {@link Executor} interface. It exists to decouple
- * the mechanics of AsyncTask submission from the description of how that AsyncTask will execute.
- * <p>
- * One immediate benefit of this approach is that testing becomes much easier, since it is easy to
- * introduce a mock or fake AsyncTaskExecutor in unit/integration tests, and thus inspect which
- * tasks have been submitted and control their execution in an orderly manner.
- * <p>
- * Another benefit in due course will be the management of the submitted tasks. An extension to this
- * interface is planned to allow Activities to easily cancel all the submitted tasks that are still
- * pending in the onDestroy() method of the Activity.
- */
-public interface AsyncTaskExecutor {
- /**
- * Executes the given AsyncTask with the default Executor.
- * <p>
- * This method <b>must only be called from the ui thread</b>.
- * <p>
- * The identifier supplied is any Object that can be used to identify the task later. Most
- * commonly this will be an enum which the tests can also refer to. {@code null} is also
- * accepted, though of course this won't help in identifying the task later.
- */
- <T> AsyncTask<T, ?, ?> submit(Object identifier, AsyncTask<T, ?, ?> task, T... params);
-}
diff --git a/src/com/android/contacts/util/AsyncTaskExecutors.java b/src/com/android/contacts/util/AsyncTaskExecutors.java
deleted file mode 100644
index 36b05c7..0000000
--- a/src/com/android/contacts/util/AsyncTaskExecutors.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source 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.contacts.util;
-
-import android.os.AsyncTask;
-import android.os.Looper;
-
-import com.android.contacts.test.NeededForTesting;
-import com.google.common.base.Preconditions;
-
-import java.util.concurrent.Executor;
-
-/**
- * Factory methods for creating AsyncTaskExecutors.
- * <p>
- * All of the factory methods on this class check first to see if you have set a static
- * {@link AsyncTaskExecutorFactory} set through the
- * {@link #setFactoryForTest(AsyncTaskExecutorFactory)} method, and if so delegate to that instead,
- * which is one way of injecting dependencies for testing classes whose construction cannot be
- * controlled such as {@link android.app.Activity}.
- */
-public final class AsyncTaskExecutors {
- /**
- * A single instance of the {@link AsyncTaskExecutorFactory}, to which we delegate if it is
- * non-null, for injecting when testing.
- */
- private static AsyncTaskExecutorFactory mInjectedAsyncTaskExecutorFactory = null;
-
- /**
- * Creates an AsyncTaskExecutor that submits tasks to run with
- * {@link AsyncTask#SERIAL_EXECUTOR}.
- */
- public static AsyncTaskExecutor createAsyncTaskExecutor() {
- synchronized (AsyncTaskExecutors.class) {
- if (mInjectedAsyncTaskExecutorFactory != null) {
- return mInjectedAsyncTaskExecutorFactory.createAsyncTaskExeuctor();
- }
- return new SimpleAsyncTaskExecutor(AsyncTask.SERIAL_EXECUTOR);
- }
- }
-
- /**
- * Creates an AsyncTaskExecutor that submits tasks to run with
- * {@link AsyncTask#THREAD_POOL_EXECUTOR}.
- */
- public static AsyncTaskExecutor createThreadPoolExecutor() {
- synchronized (AsyncTaskExecutors.class) {
- if (mInjectedAsyncTaskExecutorFactory != null) {
- return mInjectedAsyncTaskExecutorFactory.createAsyncTaskExeuctor();
- }
- return new SimpleAsyncTaskExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
- }
-
- /** Interface for creating AsyncTaskExecutor objects. */
- public interface AsyncTaskExecutorFactory {
- AsyncTaskExecutor createAsyncTaskExeuctor();
- }
-
- @NeededForTesting
- public static void setFactoryForTest(AsyncTaskExecutorFactory factory) {
- synchronized (AsyncTaskExecutors.class) {
- mInjectedAsyncTaskExecutorFactory = factory;
- }
- }
-
- public static void checkCalledFromUiThread() {
- Preconditions.checkState(Thread.currentThread() == Looper.getMainLooper().getThread(),
- "submit method must be called from ui thread, was: " + Thread.currentThread());
- }
-
- private static class SimpleAsyncTaskExecutor implements AsyncTaskExecutor {
- private final Executor mExecutor;
-
- public SimpleAsyncTaskExecutor(Executor executor) {
- mExecutor = executor;
- }
-
- @Override
- public <T> AsyncTask<T, ?, ?> submit(Object identifer, AsyncTask<T, ?, ?> task,
- T... params) {
- checkCalledFromUiThread();
- return task.executeOnExecutor(mExecutor, params);
- }
- }
-}
diff --git a/src/com/android/contacts/util/EmptyLoader.java b/src/com/android/contacts/util/EmptyLoader.java
deleted file mode 100644
index 97478bd..0000000
--- a/src/com/android/contacts/util/EmptyLoader.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source 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.contacts.util;
-
-import android.app.LoaderManager.LoaderCallbacks;
-import android.content.Context;
-import android.content.Loader;
-import android.os.Bundle;
-
-/**
- * A {@link Loader} only used to make use of the {@link android.app.Fragment#setStartDeferred}
- * feature from an old-style fragment which doesn't use {@link Loader}s to load data.
- *
- * This loader never delivers results. A caller fragment must destroy it when deferred fragments
- * should be started.
- */
-public class EmptyLoader extends Loader<Object> {
- public EmptyLoader(Context context) {
- super(context);
- }
-
- /**
- * {@link LoaderCallbacks} which just generates {@link EmptyLoader}. {@link #onLoadFinished}
- * and {@link #onLoaderReset} are no-op.
- */
- public static class Callback implements LoaderCallbacks<Object> {
- private final Context mContext;
-
- public Callback(Context context) {
- mContext = context.getApplicationContext();
- }
-
- @Override
- public Loader<Object> onCreateLoader(int id, Bundle args) {
- return new EmptyLoader(mContext);
- }
-
- @Override
- public void onLoadFinished(Loader<Object> loader, Object data) {
- }
-
- @Override
- public void onLoaderReset(Loader<Object> loader) {
- }
- }
-}
diff --git a/src/com/android/contacts/vcard/ThreadStarter.java b/src/com/android/contacts/vcard/ThreadStarter.java
deleted file mode 100644
index d7adad6..0000000
--- a/src/com/android/contacts/vcard/ThreadStarter.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source 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.contacts.vcard;
-
-public interface ThreadStarter {
- public void start();
-}
\ No newline at end of file