OSDN Git Service

Follow-up on preventing QC from hiding soft keyboard.
[android-x86/packages-apps-Contacts.git] / src / com / android / contacts / ui / QuickContactWindow.java
index f43c17e..6d4ff9b 100644 (file)
@@ -17,6 +17,7 @@
 package com.android.contacts.ui;
 
 import com.android.contacts.Collapser;
+import com.android.contacts.ContactPresenceIconUtil;
 import com.android.contacts.ContactsUtils;
 import com.android.contacts.R;
 import com.android.contacts.model.ContactsSource;
@@ -29,12 +30,10 @@ import com.android.contacts.util.NotifyingAsyncQueryHandler;
 import com.android.internal.policy.PolicyManager;
 import com.google.android.collect.Sets;
 
-import android.app.Activity;
 import android.content.ActivityNotFoundException;
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
-import android.content.EntityIterator;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
@@ -56,8 +55,10 @@ import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.CommonDataKinds.Im;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.provider.ContactsContract.CommonDataKinds.Website;
 import android.text.TextUtils;
-import android.text.format.DateUtils;
+import android.util.AttributeSet;
 import android.util.Log;
 import android.view.ContextThemeWrapper;
 import android.view.Gravity;
@@ -84,6 +85,7 @@ import android.widget.CompoundButton;
 import android.widget.HorizontalScrollView;
 import android.widget.ImageView;
 import android.widget.ListView;
+import android.widget.RelativeLayout;
 import android.widget.TextView;
 import android.widget.Toast;
 
@@ -113,6 +115,32 @@ public class QuickContactWindow implements Window.Callback,
         public void onDismiss(QuickContactWindow dialog);
     }
 
+    /**
+     * Custom layout the sole purpose of which is to intercept the BACK key and
+     * close QC even when the soft keyboard is open.
+     */
+    public static class RootLayout extends RelativeLayout {
+
+        QuickContactWindow mQuickContactWindow;
+
+        public RootLayout(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        /**
+         * Intercepts the BACK key event and dismisses QuickContact window.
+         */
+        @Override
+        public boolean dispatchKeyEventPreIme(KeyEvent event) {
+            if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+                mQuickContactWindow.onBackPressed();
+                return true;
+            } else {
+                return super.dispatchKeyEventPreIme(event);
+            }
+        }
+    }
+
     private final Context mContext;
     private final LayoutInflater mInflater;
     private final WindowManager mWindowManager;
@@ -147,6 +175,7 @@ public class QuickContactWindow implements Window.Callback,
     private ImageView mArrowDown;
 
     private int mMode;
+    private RootLayout mRootView;
     private View mHeader;
     private HorizontalScrollView mTrackScroll;
     private ViewGroup mTrack;
@@ -177,10 +206,17 @@ public class QuickContactWindow implements Window.Callback,
     private String[] mExcludeMimes;
 
     /**
-     * Specific MIME-types that should be bumped to the front of the dialog.
-     * Other MIME-types not appearing in this list follow in alphabetic order.
+     * {@link #PRECEDING_MIMETYPES} and {@link #FOLLOWING_MIMETYPES} are used to sort MIME-types.
+     *
+     * <p>The MIME-types in {@link #PRECEDING_MIMETYPES} appear in the front of the dialog,
+     * in the order in the array.
+     *
+     * <p>The ones in {@link #FOLLOWING_MIMETYPES} appear in the end of the dialog, in alphabetical
+     * order.
+     *
+     * <p>The rest go between them, in the order in the array.
      */
-    private static final String[] ORDERED_MIMETYPES = new String[] {
+    private static final String[] PRECEDING_MIMETYPES = new String[] {
             Phone.CONTENT_ITEM_TYPE,
             Contacts.CONTENT_ITEM_TYPE,
             Constants.MIME_SMS_ADDRESS,
@@ -188,19 +224,27 @@ public class QuickContactWindow implements Window.Callback,
     };
 
     /**
+     * See {@link #PRECEDING_MIMETYPES}.
+     */
+    private static final String[] FOLLOWING_MIMETYPES = new String[] {
+            StructuredPostal.CONTENT_ITEM_TYPE,
+            Website.CONTENT_ITEM_TYPE,
+    };
+
+    /**
      * Specific list {@link ApplicationInfo#packageName} of apps that are
      * prefered <strong>only</strong> for the purposes of default icons when
      * multiple {@link ResolveInfo} are found to match. This only happens when
      * the user has not selected a default app yet, and they will still be
      * presented with the system disambiguation dialog.
      */
-    private static final HashSet<String> sPreferResolve = Sets.newHashSet(new String[] {
+    private static final HashSet<String> sPreferResolve = Sets.newHashSet(
             "com.android.email",
             "com.android.calendar",
             "com.android.contacts",
             "com.android.mms",
             "com.android.phone",
-    });
+            "com.android.browser");
 
     private static final int TOKEN_DATA = 1;
 
@@ -220,9 +264,16 @@ public class QuickContactWindow implements Window.Callback,
         mWindow = PolicyManager.makeNewWindow(mContext);
         mWindow.setCallback(this);
         mWindow.setWindowManager(mWindowManager, null, null);
+        mWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED);
 
         mWindow.setContentView(R.layout.quickcontact);
 
+        mRootView = (RootLayout)mWindow.findViewById(R.id.root);
+        mRootView.mQuickContactWindow = this;
+        mRootView.setFocusable(true);
+        mRootView.setFocusableInTouchMode(true);
+        mRootView.setDescendantFocusability(RootLayout.FOCUS_AFTER_DESCENDANTS);
+
         mArrowUp = (ImageView)mWindow.findViewById(R.id.arrow_up);
         mArrowDown = (ImageView)mWindow.findViewById(R.id.arrow_down);
 
@@ -287,7 +338,7 @@ public class QuickContactWindow implements Window.Callback,
             // Inflate actual header if we picked a stub
             final ViewStub stub = (ViewStub)header;
             header = stub.inflate();
-        } else {
+        } else if (header != null) {
             header.setVisibility(View.VISIBLE);
         }
 
@@ -308,6 +359,18 @@ public class QuickContactWindow implements Window.Callback,
             android.os.Debug.startMethodTracing(TRACE_TAG);
         }
 
+        // Validate incoming parameters
+        final boolean validMode = (mode == QuickContact.MODE_SMALL
+                || mode == QuickContact.MODE_MEDIUM || mode == QuickContact.MODE_LARGE);
+        if (!validMode) {
+            throw new IllegalArgumentException("Invalid mode, expecting MODE_LARGE, "
+                    + "MODE_MEDIUM, or MODE_SMALL");
+        }
+
+        if (anchor == null) {
+            throw new IllegalArgumentException("Missing anchor rectangle");
+        }
+
         // Prepare header view for requested mode
         mLookupUri = lookupUri;
         mAnchor = new Rect(anchor);
@@ -325,6 +388,10 @@ public class QuickContactWindow implements Window.Callback,
 
         resetTrack();
 
+        // We need to have a focused view inside the QuickContact window so
+        // that the BACK key event can be intercepted
+        mRootView.requestFocus();
+
         mHasValidSocial = false;
         mDismissed = false;
         mQuerying = true;
@@ -581,11 +648,6 @@ public class QuickContactWindow implements Window.Callback,
     }
 
     /** Assign this image to the view, if found in {@link #mHeader}. */
-    private void setHeaderImage(int id, int resId) {
-        setHeaderImage(id, mContext.getResources().getDrawable(resId));
-    }
-
-    /** Assign this image to the view, if found in {@link #mHeader}. */
     private void setHeaderImage(int id, Drawable drawable) {
         final View view = mHeader.findViewById(id);
         if (view instanceof ImageView) {
@@ -595,34 +657,10 @@ public class QuickContactWindow implements Window.Callback,
     }
 
     /**
-     * Find the presence icon for showing in summary header.
-     */
-    private Drawable getPresenceIcon(int status) {
-        int resId = -1;
-        switch (status) {
-            case StatusUpdates.AVAILABLE:
-                resId = android.R.drawable.presence_online;
-                break;
-            case StatusUpdates.IDLE:
-            case StatusUpdates.AWAY:
-                resId = android.R.drawable.presence_away;
-                break;
-            case StatusUpdates.DO_NOT_DISTURB:
-                resId = android.R.drawable.presence_busy;
-                break;
-        }
-        if (resId != -1) {
-            return mContext.getResources().getDrawable(resId);
-        } else {
-            return null;
-        }
-    }
-
-    /**
      * Find the QuickContact-specific presence icon for showing in chiclets.
      */
     private Drawable getTrackPresenceIcon(int status) {
-        int resId = -1;
+        int resId;
         switch (status) {
             case StatusUpdates.AVAILABLE:
                 resId = R.drawable.quickcontact_slider_presence_active;
@@ -749,6 +787,12 @@ public class QuickContactWindow implements Window.Callback,
                     mIntent = new Intent(Intent.ACTION_SENDTO, mailUri);
                 }
 
+            } else if (Website.CONTENT_ITEM_TYPE.equals(mimeType)) {
+                final String url = getAsString(cursor, Website.URL);
+                if (!TextUtils.isEmpty(url)) {
+                    mIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+                }
+
             } else if (Im.CONTENT_ITEM_TYPE.equals(mimeType)) {
                 final boolean isEmail = Email.CONTENT_ITEM_TYPE.equals(
                         getAsString(cursor, Data.MIMETYPE));
@@ -946,7 +990,6 @@ public class QuickContactWindow implements Window.Callback,
      * queries, keyed internally on MIME-type.
      */
     private static class ResolveCache {
-        private Context mContext;
         private PackageManager mPackageManager;
 
         /**
@@ -961,7 +1004,6 @@ public class QuickContactWindow implements Window.Callback,
         private HashMap<String, Entry> mCache = new HashMap<String, Entry>();
 
         public ResolveCache(Context context) {
-            mContext = context;
             mPackageManager = context.getPackageManager();
         }
 
@@ -1136,7 +1178,6 @@ public class QuickContactWindow implements Window.Callback,
         while (cursor.moveToNext()) {
             final long dataId = cursor.getLong(DataQuery._ID);
             final String accountType = cursor.getString(DataQuery.ACCOUNT_TYPE);
-            final String resPackage = cursor.getString(DataQuery.RES_PACKAGE);
             final String mimeType = cursor.getString(DataQuery.MIMETYPE);
 
             // Handle any social status updates from this row
@@ -1190,7 +1231,7 @@ public class QuickContactWindow implements Window.Callback,
             // Read contact information from last data row
             final String name = cursor.getString(DataQuery.DISPLAY_NAME);
             final int presence = cursor.getInt(DataQuery.CONTACT_PRESENCE);
-            final Drawable statusIcon = getPresenceIcon(presence);
+            final Drawable statusIcon = ContactPresenceIconUtil.getPresenceIcon(mContext, presence);
 
             setHeaderText(R.id.name, name);
             setHeaderImage(R.id.presence, statusIcon);
@@ -1209,22 +1250,39 @@ public class QuickContactWindow implements Window.Callback,
             setHeaderText(R.id.timestamp, status.getTimestampLabel(mContext));
         }
 
-        // Turn our list of actions into UI elements, starting with common types
-        final Set<String> containedTypes = mActions.keySet();
-        for (String mimeType : ORDERED_MIMETYPES) {
+        // Turn our list of actions into UI elements
+
+        // Index where we start adding child views.
+        int index = mTrack.getChildCount() - 1;
+
+        // All the mime-types to add.
+        final Set<String> containedTypes = new HashSet<String>(mActions.keySet());
+
+        // First, add PRECEDING_MIMETYPES, which are most common.
+        for (String mimeType : PRECEDING_MIMETYPES) {
             if (containedTypes.contains(mimeType)) {
-                final int index = mTrack.getChildCount() - 1;
-                mTrack.addView(inflateAction(mimeType), index);
+                mTrack.addView(inflateAction(mimeType), index++);
                 containedTypes.remove(mimeType);
             }
         }
 
-        // Then continue with remaining MIME-types in alphabetical order
+        // Keep the current index to append non PRECEDING/FOLLOWING items.
+        final int indexAfterPreceding = index;
+
+        // Then, add FOLLOWING_MIMETYPES, which are least common.
+        for (String mimeType : FOLLOWING_MIMETYPES) {
+            if (containedTypes.contains(mimeType)) {
+                mTrack.addView(inflateAction(mimeType), index++);
+                containedTypes.remove(mimeType);
+            }
+        }
+
+        // Go back to just after PRECEDING_MIMETYPES, and append the rest.
+        index = indexAfterPreceding;
         final String[] remainingTypes = containedTypes.toArray(new String[containedTypes.size()]);
         Arrays.sort(remainingTypes);
         for (String mimeType : remainingTypes) {
-            final int index = mTrack.getChildCount() - 1;
-            mTrack.addView(inflateAction(mimeType), index);
+            mTrack.addView(inflateAction(mimeType), index++);
         }
     }
 
@@ -1400,7 +1458,6 @@ public class QuickContactWindow implements Window.Callback,
 
                     // Set action title based on summary value
                     final Action action = (Action)getItem(position);
-                    final Drawable icon = mResolveCache.getIcon(action);
 
                     TextView text1 = (TextView)convertView.findViewById(android.R.id.text1);
                     TextView text2 = (TextView)convertView.findViewById(android.R.id.text2);
@@ -1487,7 +1544,7 @@ public class QuickContactWindow implements Window.Callback,
      * window, which usually means we should dismiss.
      */
     protected void detectEventOutside(MotionEvent event) {
-        if (event.getAction() == MotionEvent.ACTION_DOWN) {
+        if (event.getAction() == MotionEvent.ACTION_DOWN && mDecor != null) {
             // Only try detecting outside events on down-press
             mDecor.getHitRect(mRect);
             mRect.top = mRect.top + mShadowTouch;
@@ -1566,11 +1623,6 @@ public class QuickContactWindow implements Window.Callback,
     }
 
     /** {@inheritDoc} */
-    public void onQueryEntitiesComplete(int token, Object cookie, EntityIterator iterator) {
-        // No actions
-    }
-
-    /** {@inheritDoc} */
     public void onAttachedToWindow() {
         // No actions
     }