summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2011-04-07 00:48:02 -0700
committerJeff Sharkey <jsharkey@android.com>2011-04-08 13:44:27 -0700
commitcde7389187ebc6816bd73d4704f1ca1b4ee39ac3 (patch)
treec4455f596a83aa7277b06752c1b7e1099bec2db1
parentf6c62c03f64d14f2f84d847d97ac0657f7adf2f6 (diff)
downloadpackages_apps_Contacts-cde7389187ebc6816bd73d4704f1ca1b4ee39ac3.tar.gz
packages_apps_Contacts-cde7389187ebc6816bd73d4704f1ca1b4ee39ac3.tar.bz2
packages_apps_Contacts-cde7389187ebc6816bd73d4704f1ca1b4ee39ac3.zip
Move QuickContact to Activity instead of Window.
QuickContact has traditionally used a Window to show a bubble with callout centered around a target area. This change moves away from private Window APIs, and instead creates FloatingChildLayout to layout the bubble. Using onLayout() is more flexible than a PopupWindow or Dialog, since it gives us access to getWindowVisibleDisplayFrame() to correctly handle system windows. (Similar to FLAG_LAYOUT_INSET_DECOR.) Changes background Drawable to use state_first and state_last to select above/below callout arrow. Also moves to using setLevel() to set arrow horizontal location. Removes recycling chiclet code, and brings in Guava library. Bug: 3362647 Change-Id: Iae953bae71db76e91e05996fe4c0dcea38bb446f
-rw-r--r--Android.mk6
-rw-r--r--AndroidManifest.xml9
-rw-r--r--res/drawable/quickactions_arrow_left_holo_light.xml21
-rw-r--r--res/drawable/quickactions_arrow_middle_holo_light.xml21
-rw-r--r--res/drawable/quickactions_arrow_right_holo_light.xml21
-rw-r--r--res/layout/quickcontact.xml12
-rw-r--r--res/layout/quickcontact_activity.xml28
-rwxr-xr-xres/layout/quickcontact_default_item.xml4
-rwxr-xr-xres/layout/quickcontact_resolve_item.xml4
-rw-r--r--res/values/styles.xml37
-rw-r--r--src/com/android/contacts/quickcontact/FloatingChildLayout.java231
-rw-r--r--src/com/android/contacts/quickcontact/QuickContactActivity.java121
-rw-r--r--src/com/android/contacts/quickcontact/QuickContactBackgroundDrawable.java86
-rw-r--r--src/com/android/contacts/quickcontact/QuickContactRootLayout.java54
-rw-r--r--src/com/android/contacts/quickcontact/QuickContactWindow.java828
-rw-r--r--src/com/android/contacts/util/NotifyingAsyncQueryHandler.java2
16 files changed, 589 insertions, 896 deletions
diff --git a/Android.mk b/Android.mk
index ff1b7e25b..1c9dcc475 100644
--- a/Android.mk
+++ b/Android.mk
@@ -5,7 +5,11 @@ LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := com.android.phone.common com.android.vcard android-common
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ com.android.phone.common \
+ com.android.vcard \
+ android-common \
+ guava
LOCAL_PACKAGE_NAME := Contacts
LOCAL_CERTIFICATE := shared
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 20641f226..458553e01 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -326,7 +326,7 @@
<activity
android:name=".activities.ShowOrCreateActivity"
- android:theme="@style/FullyTranslucent">
+ android:theme="@android:style/Theme.Translucent.NoTitleBar">
<intent-filter>
<action android:name="com.android.contacts.action.SHOW_OR_CREATE_CONTACT" />
@@ -339,13 +339,12 @@
<!-- Used to show QuickContact window over a translucent activity, which is a
temporary hack until we add better framework support. -->
<activity
- android:name=".quickcontact.QuickContactActivity"
- android:theme="@style/FullyTranslucent.QuickContact"
+ android:name=".quickcontact.QuickContactWindow"
+ android:theme="@style/Theme.QuickContact"
android:launchMode="singleTop"
android:excludeFromRecents="true"
android:taskAffinity="android.task.quickcontact"
- android:windowSoftInputMode="stateUnchanged"
- >
+ android:windowSoftInputMode="stateUnchanged">
<intent-filter>
<action android:name="com.android.contacts.action.QUICK_CONTACT" />
diff --git a/res/drawable/quickactions_arrow_left_holo_light.xml b/res/drawable/quickactions_arrow_left_holo_light.xml
new file mode 100644
index 000000000..c1e18bd1d
--- /dev/null
+++ b/res/drawable/quickactions_arrow_left_holo_light.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_first="true" android:drawable="@drawable/quickactions_arrowdown_left_holo_light" />
+ <item android:state_last="true" android:drawable="@drawable/quickactions_arrowup_left_holo_light" />
+ <!-- TODO: provide callout-less state -->
+ <item android:drawable="@drawable/quickactions_arrowup_left_holo_light" />
+</selector>
diff --git a/res/drawable/quickactions_arrow_middle_holo_light.xml b/res/drawable/quickactions_arrow_middle_holo_light.xml
new file mode 100644
index 000000000..f88b513f3
--- /dev/null
+++ b/res/drawable/quickactions_arrow_middle_holo_light.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_first="true" android:drawable="@drawable/quickactions_arrowdown_middle_holo_light" />
+ <item android:state_last="true" android:drawable="@drawable/quickactions_arrowup_middle_holo_light" />
+ <!-- TODO: provide callout-less state -->
+ <item android:drawable="@drawable/quickactions_arrowup_middle_holo_light" />
+</selector>
diff --git a/res/drawable/quickactions_arrow_right_holo_light.xml b/res/drawable/quickactions_arrow_right_holo_light.xml
new file mode 100644
index 000000000..3e309fe28
--- /dev/null
+++ b/res/drawable/quickactions_arrow_right_holo_light.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_first="true" android:drawable="@drawable/quickactions_arrowdown_right_holo_light" />
+ <item android:state_last="true" android:drawable="@drawable/quickactions_arrowup_right_holo_light" />
+ <!-- TODO: provide callout-less state -->
+ <item android:drawable="@drawable/quickactions_arrowup_right_holo_light" />
+</selector>
diff --git a/res/layout/quickcontact.xml b/res/layout/quickcontact.xml
index a74424c7b..e2b291c8f 100644
--- a/res/layout/quickcontact.xml
+++ b/res/layout/quickcontact.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,13 +13,12 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<view
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- class="com.android.contacts.quickcontact.QuickContactRootLayout"
- android:id="@+id/root"
- android:layout_width="match_parent"
+ android:id="@android:id/content"
+ android:layout_width="@dimen/quick_contact_width"
android:layout_height="wrap_content"
+ android:visibility="invisible"
android:orientation="vertical">
<FrameLayout
@@ -133,4 +133,4 @@
android:text="@string/quickcontact_clear_defaults_button" />
</LinearLayout>
</FrameLayout>
-</view>
+</LinearLayout>
diff --git a/res/layout/quickcontact_activity.xml b/res/layout/quickcontact_activity.xml
new file mode 100644
index 000000000..aced4a8eb
--- /dev/null
+++ b/res/layout/quickcontact_activity.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<view
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ class="com.android.contacts.quickcontact.FloatingChildLayout"
+ android:id="@+id/floating_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:descendantFocusability="afterDescendants">
+
+ <include layout="@layout/quickcontact" />
+
+</view>
diff --git a/res/layout/quickcontact_default_item.xml b/res/layout/quickcontact_default_item.xml
index 25b69100e..3a918f0f9 100755
--- a/res/layout/quickcontact_default_item.xml
+++ b/res/layout/quickcontact_default_item.xml
@@ -28,13 +28,13 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
- android:textAppearance="?android:attr/textAppearanceMediumInverse" />
+ android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@android:id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="-4dip"
- android:textAppearance="?android:attr/textAppearanceSmallInverse" />
+ android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
diff --git a/res/layout/quickcontact_resolve_item.xml b/res/layout/quickcontact_resolve_item.xml
index 55de80e4c..280572208 100755
--- a/res/layout/quickcontact_resolve_item.xml
+++ b/res/layout/quickcontact_resolve_item.xml
@@ -28,13 +28,13 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
- android:textAppearance="?android:attr/textAppearanceMediumInverse" />
+ android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@android:id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="-4dip"
- android:textAppearance="?android:attr/textAppearanceSmallInverse" />
+ android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index b8e987483..c776e1d3e 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -38,38 +38,19 @@
<item name="android:windowIsFloating">true</item>
</style>
- <style name="FullyTranslucent" parent="android:Theme.Translucent.NoTitleBar">
- <item name="android:windowContentOverlay">@null</item>
- </style>
-
- <style name="FullyTranslucent.QuickContact">
- <!-- This is a hack because we want to be able to animate away the
- QuickContact window, and we close its containing activity at the
- same time. So put in a dummy animation so this guy sticks around
- while the fast track window is animating. -->
- <item name="android:windowAnimationStyle">@style/DummyAnimation</item>
+ <style name="Theme">
</style>
- <style name="QuickContact" parent="@android:Theme.Holo.Light">
- <item name="android:windowNoTitle">true</item>
- <item name="android:windowFrame">@null</item>
+ <style name="Theme.QuickContact" parent="@android:style/Theme.Holo.Light">
<item name="android:windowBackground">@android:color/transparent</item>
- <item name="android:windowIsFloating">true</item>
+ <item name="android:colorBackgroundCacheHint">@null</item>
+ <item name="android:windowFrame">@null</item>
<item name="android:windowContentOverlay">@null</item>
- <!-- TODO: create our own animation style in framework -->
- <!--
- <item name="android:windowAnimationStyle">@*android:style/Animation.ZoomButtons</item>
- -->
- </style>
-
- <style name="QuickContactAboveAnimation">
- <item name="android:windowEnterAnimation">@anim/quickcontact_above_enter</item>
- <item name="android:windowExitAnimation">@anim/quickcontact_above_exit</item>
- </style>
-
- <style name="QuickContactBelowAnimation">
- <item name="android:windowEnterAnimation">@anim/quickcontact_below_enter</item>
- <item name="android:windowExitAnimation">@anim/quickcontact_below_exit</item>
+ <item name="android:windowAnimationStyle">@null</item>
+ <item name="android:windowIsFloating">false</item>
+ <item name="android:backgroundDimEnabled">false</item>
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:windowNoTitle">true</item>
</style>
<style name="ContactsSearchAnimation">
diff --git a/src/com/android/contacts/quickcontact/FloatingChildLayout.java b/src/com/android/contacts/quickcontact/FloatingChildLayout.java
new file mode 100644
index 000000000..ddba609f5
--- /dev/null
+++ b/src/com/android/contacts/quickcontact/FloatingChildLayout.java
@@ -0,0 +1,231 @@
+/*
+ * 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.quickcontact;
+
+import com.android.contacts.R;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
+import android.view.animation.AnimationUtils;
+import android.widget.FrameLayout;
+import android.widget.PopupWindow;
+
+/**
+ * Layout containing single child {@link View} which it attempts to center
+ * around {@link #setChildTargetScreen(Rect)}.
+ * <p>
+ * Updates drawable state to be {@link android.R.attr#state_first} when child is
+ * above target, and {@link android.R.attr#state_last} when child is below
+ * target. Also updates {@link Drawable#setLevel(int)} on child
+ * {@link View#getBackground()} to reflect horizontal center of target.
+ * <p>
+ * The reason for this approach is because target {@link Rect} is in screen
+ * coordinates disregarding decor insets; otherwise something like
+ * {@link PopupWindow} might work better.
+ */
+public class FloatingChildLayout extends FrameLayout {
+ private static final String TAG = "FloatingChild";
+
+ public FloatingChildLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ private View mChild;
+
+ private Rect mTargetScreen = new Rect();
+
+ private int mCalloutState = 0;
+ private int mCalloutLeft;
+
+ @Override
+ protected void onFinishInflate() {
+ mChild = findViewById(android.R.id.content);
+ mChild.setDuplicateParentStateEnabled(true);
+ }
+
+ public View getChild() {
+ return mChild;
+ }
+
+ /**
+ * Set {@link Rect} in screen coordinates that {@link #getChild()} should be
+ * centered around.
+ */
+ public void setChildTargetScreen(Rect targetScreen) {
+ mTargetScreen = targetScreen;
+ requestLayout();
+ }
+
+ /**
+ * Return {@link #mTargetScreen} in local window coordinates, taking any
+ * decor insets into account.
+ */
+ private Rect getTargetInWindow() {
+ final Rect windowScreen = new Rect();
+ getWindowVisibleDisplayFrame(windowScreen);
+
+ final Rect target = new Rect(mTargetScreen);
+ target.offset(-windowScreen.left, -windowScreen.top);
+ return target;
+ }
+
+ private void updateCallout(int calloutState, int calloutLeft) {
+ if (mCalloutState != calloutState) {
+ mCalloutState = calloutState;
+ mChild.refreshDrawableState();
+ }
+
+ final Drawable background = mChild.getBackground();
+ if (background != null && mCalloutLeft != calloutLeft) {
+ mCalloutLeft = calloutLeft;
+ background.setLevel(calloutLeft);
+ }
+ }
+
+ @Override
+ protected int[] onCreateDrawableState(int extraSpace) {
+ final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
+ mergeDrawableStates(drawableState, new int[] { mCalloutState });
+ return drawableState;
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+
+ final View child = mChild;
+ final Rect target = getTargetInWindow();
+
+ final int childWidth = child.getMeasuredWidth();
+ final int childHeight = child.getMeasuredHeight();
+
+ // default is no callout, left-aligned, and vertically centered
+ int calloutState = 0;
+ int childLeft = target.left;
+ int childTop = target.centerY() - (childHeight / 2);
+
+ // when target is wide, horizontally center instead of left-align
+ if (target.width() > childWidth / 2) {
+ childLeft = target.centerX() - (childWidth / 2);
+ }
+
+ final int areaAboveTarget = target.top;
+ final int areaBelowTarget = getHeight() - target.bottom;
+
+ if (areaAboveTarget >= childHeight) {
+ // enough room above target, place above and callout down
+ calloutState = android.R.attr.state_first;
+ childTop = target.top - childHeight;
+
+ } else if (areaBelowTarget >= childHeight) {
+ // enough room below target, place below and callout up
+ calloutState = android.R.attr.state_last;
+ childTop = target.bottom;
+ }
+
+ // when child is outside bounds, nudge back inside
+ childLeft = clampDimension(childLeft, childWidth, getWidth());
+ childTop = clampDimension(childTop, childHeight, getHeight());
+
+ final int calloutLeft = target.centerX() - childLeft;
+ updateCallout(calloutState, calloutLeft);
+ layoutChild(child, childLeft, childTop);
+
+ }
+
+ private static int clampDimension(int value, int size, int max) {
+ // when larger than bounds, just center
+ if (size > max) {
+ return (max - size) / 2;
+ }
+
+ // clamp to lower bound
+ value = Math.max(value, 0);
+ // clamp to higher bound
+ value = Math.min(value, max - size);
+
+ return value;
+ }
+
+ private static void layoutChild(View child, int left, int top) {
+ child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight());
+ }
+
+ /**
+ * Begin animating {@link #getChild()} visible.
+ */
+ public void showChild() {
+ final boolean calloutAbove = mCalloutState == android.R.attr.state_first;
+ final Animation anim = AnimationUtils.loadAnimation(getContext(),
+ calloutAbove ? R.anim.quickcontact_above_enter : R.anim.quickcontact_below_enter);
+ mChild.startAnimation(anim);
+ mChild.setVisibility(View.VISIBLE);
+ }
+
+ /**
+ * Begin animating {@link #getChild()} invisible.
+ */
+ public void hideChild(final Runnable onAnimationEnd) {
+ final boolean calloutAbove = mCalloutState == android.R.attr.state_first;
+ final Animation anim = AnimationUtils.loadAnimation(getContext(),
+ calloutAbove ? R.anim.quickcontact_above_exit : R.anim.quickcontact_below_exit);
+
+ if (onAnimationEnd != null) {
+ anim.setAnimationListener(new AnimationListener() {
+ /** {@inheritDoc} */
+ public void onAnimationStart(Animation animation) {
+ // ignored
+ }
+
+ /** {@inheritDoc} */
+ public void onAnimationRepeat(Animation animation) {
+ // ignored
+ }
+
+ /** {@inheritDoc} */
+ public void onAnimationEnd(Animation animation) {
+ onAnimationEnd.run();
+ }
+ });
+ }
+
+ mChild.startAnimation(anim);
+ mChild.setVisibility(View.INVISIBLE);
+ }
+
+ private View.OnTouchListener mOutsideTouchListener;
+
+ public void setOnOutsideTouchListener(View.OnTouchListener listener) {
+ mOutsideTouchListener = listener;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ // at this point, touch wasn't handled by child view; assume outside
+ if (mOutsideTouchListener != null) {
+ return mOutsideTouchListener.onTouch(this, event);
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
deleted file mode 100644
index 503238680..000000000
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2009 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.quickcontact;
-
-import com.android.contacts.ContactsActivity;
-
-import android.content.ContentUris;
-import android.content.Intent;
-import android.graphics.Rect;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.ContactsContract.QuickContact;
-import android.provider.ContactsContract.RawContacts;
-import android.util.Log;
-
-/**
- * Stub translucent activity that just shows {@link QuickContactWindow} floating
- * above the caller. This temporary hack should eventually be replaced with
- * direct framework support.
- */
-public final class QuickContactActivity extends ContactsActivity
- implements QuickContactWindow.OnDismissListener {
- private static final String TAG = "QuickContactActivity";
-
- static final boolean LOGV = false;
- static final boolean FORCE_CREATE = true;
-
- private QuickContactWindow mQuickContact;
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- if (LOGV) Log.d(TAG, "onCreate");
-
- this.onNewIntent(getIntent());
- }
-
- @Override
- public void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
- if (LOGV) Log.d(TAG, "onNewIntent");
-
- if (QuickContactWindow.TRACE_LAUNCH) {
- android.os.Debug.startMethodTracing(QuickContactWindow.TRACE_TAG);
- }
-
- if (mQuickContact == null || FORCE_CREATE) {
- if (LOGV) Log.d(TAG, "Preparing window");
- mQuickContact = new QuickContactWindow(this, this);
- }
-
- // Use our local window token for now
- Uri lookupUri = intent.getData();
- // Check to see whether it comes from the old version.
- if (android.provider.Contacts.AUTHORITY.equals(lookupUri.getAuthority())) {
- final long rawContactId = ContentUris.parseId(lookupUri);
- lookupUri = RawContacts.getContactLookupUri(getContentResolver(),
- ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
- }
- final Bundle extras = intent.getExtras();
-
- // Read requested parameters for displaying
- final Rect target = intent.getSourceBounds();
- final int mode = extras.getInt(QuickContact.EXTRA_MODE, QuickContact.MODE_MEDIUM);
- final String[] excludeMimes = extras.getStringArray(QuickContact.EXTRA_EXCLUDE_MIMES);
-
- mQuickContact.show(lookupUri, target, mode, excludeMimes);
- }
-
- /** {@inheritDoc} */
- @Override
- public void onBackPressed() {
- if (LOGV) Log.w(TAG, "Unexpected back captured by stub activity");
- finish();
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- if (LOGV) Log.d(TAG, "onPause");
-
- // Dismiss any dialog when pausing
- mQuickContact.dismiss();
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- if (LOGV) Log.d(TAG, "onDestroy");
- }
-
- /** {@inheritDoc} */
- @Override
- public void onDismiss(QuickContactWindow dialog) {
- if (LOGV) Log.d(TAG, "onDismiss");
-
- if (isTaskRoot() && !FORCE_CREATE) {
- // Instead of stopping, simply push this to the back of the stack.
- // This is only done when running at the top of the stack;
- // otherwise, we have been launched by someone else so need to
- // allow the user to go back to the caller.
- moveTaskToBack(false);
- } else {
- finish();
- }
- }
-}
diff --git a/src/com/android/contacts/quickcontact/QuickContactBackgroundDrawable.java b/src/com/android/contacts/quickcontact/QuickContactBackgroundDrawable.java
index 911848032..15311f9d5 100644
--- a/src/com/android/contacts/quickcontact/QuickContactBackgroundDrawable.java
+++ b/src/com/android/contacts/quickcontact/QuickContactBackgroundDrawable.java
@@ -26,37 +26,43 @@ import android.graphics.Rect;
import android.graphics.drawable.Drawable;
/**
- * Drawable that draws three pictures for the QuickContact-Background. ColorFilter is ignored
+ * Background {@link Drawable} for {@link QuickContactWindow} that draws arrow
+ * centered around requested position.
*/
public class QuickContactBackgroundDrawable extends Drawable {
private Drawable mLeftDrawable;
private Drawable mMiddleDrawable;
private Drawable mRightDrawable;
- private int mRequestedX = Integer.MIN_VALUE;
- private boolean mBoundsSet = false;
- private int mAlpha = -1;
+
private int mBottomOverride = Integer.MIN_VALUE;
+ public QuickContactBackgroundDrawable(Resources res) {
+ mLeftDrawable = res.getDrawable(R.drawable.quickactions_arrow_left_holo_light);
+ mMiddleDrawable = res.getDrawable(R.drawable.quickactions_arrow_middle_holo_light);
+ mRightDrawable = res.getDrawable(R.drawable.quickactions_arrow_right_holo_light);
+ }
+
@Override
public void setAlpha(int alpha) {
- mAlpha = alpha;
- setChildAlpha();
+ mLeftDrawable.setAlpha(alpha);
+ mMiddleDrawable.setAlpha(alpha);
+ mRightDrawable.setAlpha(alpha);
}
/**
- * Overrides the bottom bounds. This is used for the animation when the QuickContact
- * expands/collapses options
+ * Overrides the bottom bounds. This is used for the animation when the
+ * QuickContact expands/collapses options
*/
public void setBottomOverride(int value) {
mBottomOverride = value;
- setChildBounds();
+ onBoundsChange(getBounds());
invalidateSelf();
}
public void clearBottomOverride() {
mBottomOverride = Integer.MIN_VALUE;
+ onBoundsChange(getBounds());
invalidateSelf();
- setChildBounds();
}
public float getBottomOverride() {
@@ -64,62 +70,52 @@ public class QuickContactBackgroundDrawable extends Drawable {
}
@Override
- public void setColorFilter(ColorFilter cf) {
+ public boolean isStateful() {
+ return true;
}
@Override
- public int getOpacity() {
- return PixelFormat.TRANSLUCENT;
+ protected boolean onStateChange(int[] state) {
+ super.onStateChange(state);
+ mLeftDrawable.setState(state);
+ mMiddleDrawable.setState(state);
+ mRightDrawable.setState(state);
+ return true;
}
- public void configure(Resources resources, boolean arrowUp, int requestedX) {
- mLeftDrawable = resources.getDrawable(arrowUp
- ? R.drawable.quickactions_arrowup_left_holo_light
- : R.drawable.quickactions_arrowdown_left_holo_light);
- mMiddleDrawable = resources.getDrawable(arrowUp
- ? R.drawable.quickactions_arrowup_middle_holo_light
- : R.drawable.quickactions_arrowdown_middle_holo_light);
- mRightDrawable = resources.getDrawable(arrowUp
- ? R.drawable.quickactions_arrowup_right_holo_light
- : R.drawable.quickactions_arrowdown_right_holo_light);
-
- mRequestedX = requestedX;
-
- setChildAlpha();
- setChildBounds();
+ @Override
+ protected boolean onLevelChange(int level) {
+ return true;
}
@Override
- protected void onBoundsChange(Rect bounds) {
- mBoundsSet = true;
- setChildBounds();
+ public void setColorFilter(ColorFilter cf) {
+ mLeftDrawable.setColorFilter(cf);
+ mMiddleDrawable.setColorFilter(cf);
+ mRightDrawable.setColorFilter(cf);
}
- private void setChildAlpha() {
- if (mAlpha == -1) return;
-
- if (mLeftDrawable != null) mLeftDrawable.setAlpha(mAlpha);
- if (mMiddleDrawable != null) mMiddleDrawable.setAlpha(mAlpha);
- if (mRightDrawable != null) mRightDrawable.setAlpha(mAlpha);
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
}
- private void setChildBounds() {
- if (mRequestedX == Integer.MIN_VALUE) return;
- if (!mBoundsSet) return;
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ final int requestedX = getLevel();
- final Rect bounds = getBounds();
- int middleLeft = mRequestedX - mMiddleDrawable.getIntrinsicWidth() / 2;
- int middleRight = mRequestedX + mMiddleDrawable.getIntrinsicWidth() / 2;
+ int middleLeft = requestedX - mMiddleDrawable.getIntrinsicWidth() / 2;
+ int middleRight = requestedX + mMiddleDrawable.getIntrinsicWidth() / 2;
// ensure left drawable is not smaller than its Intrinsic Width
- final int leftExtra = (middleLeft - bounds.left) - mLeftDrawable.getIntrinsicWidth();
+ final int leftExtra = (middleLeft - bounds.left) - mLeftDrawable.getIntrinsicWidth();
if (leftExtra < 0) {
middleLeft -= leftExtra;
middleRight -= leftExtra;
}
// ensure right drawable is not smaller than its Intrinsic Width
- final int rightExtra = (bounds.right - middleRight) - mRightDrawable.getIntrinsicWidth();
+ final int rightExtra = (bounds.right - middleRight) - mRightDrawable.getIntrinsicWidth();
if (rightExtra < 0) {
middleLeft += rightExtra;
middleRight += rightExtra;
diff --git a/src/com/android/contacts/quickcontact/QuickContactRootLayout.java b/src/com/android/contacts/quickcontact/QuickContactRootLayout.java
deleted file mode 100644
index 007783a96..000000000
--- a/src/com/android/contacts/quickcontact/QuickContactRootLayout.java
+++ /dev/null
@@ -1,54 +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.quickcontact;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.widget.LinearLayout;
-
-/**
- * Custom layout for Quick Contact. It intercepts the BACK key and
- * close QC even when the soft keyboard is open.
- */
-public class QuickContactRootLayout extends LinearLayout {
- private Listener mListener;
-
- public QuickContactRootLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public void setListener(Listener value) {
- mListener = value;
- }
-
- /**
- * Intercepts the BACK key event and dismisses QuickContact window.
- */
- @Override
- public boolean dispatchKeyEventPreIme(KeyEvent event) {
- if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
- if (mListener != null) mListener.onBackPressed();
- return true;
- }
- return super.dispatchKeyEventPreIme(event);
- }
-
- public interface Listener {
- void onBackPressed();
- }
-}
diff --git a/src/com/android/contacts/quickcontact/QuickContactWindow.java b/src/com/android/contacts/quickcontact/QuickContactWindow.java
index 2a6dd2f7b..5f4bcc98e 100644
--- a/src/com/android/contacts/quickcontact/QuickContactWindow.java
+++ b/src/com/android/contacts/quickcontact/QuickContactWindow.java
@@ -25,13 +25,15 @@ import com.android.contacts.model.DataKind;
import com.android.contacts.util.Constants;
import com.android.contacts.util.DataStatus;
import com.android.contacts.util.NotifyingAsyncQueryHandler;
-import com.android.internal.policy.PolicyManager;
import com.google.android.collect.Lists;
+import com.google.common.base.Preconditions;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
+import android.app.Activity;
import android.content.ActivityNotFoundException;
+import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -41,6 +43,7 @@ import android.graphics.BitmapFactory;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Handler;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Im;
@@ -54,30 +57,16 @@ import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.QuickContact;
import android.provider.ContactsContract.RawContacts;
import android.text.TextUtils;
-import android.util.Log;
-import android.view.ActionMode;
-import android.view.ContextThemeWrapper;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
-import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewStub;
-import android.view.ViewTreeObserver.OnGlobalLayoutListener;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.accessibility.AccessibilityEvent;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.FrameLayout;
-import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
@@ -88,72 +77,44 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.LinkedList;
import java.util.List;
import java.util.Set;
/**
- * Window that shows QuickContact dialog for a specific {@link Contacts#_ID}.
+ * Mostly translucent {@link Activity} that shows QuickContact dialog. It loads
+ * data asynchronously, and then shows a popup with details centered around
+ * {@link Intent#getSourceBounds()}.
*/
-public class QuickContactWindow implements Window.Callback,
+public class QuickContactWindow extends Activity implements
NotifyingAsyncQueryHandler.AsyncQueryListener, View.OnClickListener,
- AbsListView.OnItemClickListener, KeyEvent.Callback, OnGlobalLayoutListener,
- QuickContactRootLayout.Listener {
+ AbsListView.OnItemClickListener {
+ private static final String TAG = "QuickContact";
- private static final String TAG = "QuickContactWindow";
+ private static final boolean TRACE_LAUNCH = false;
+ private static final String TRACE_TAG = "quickcontact";
- /**
- * Interface used to allow the person showing a {@link QuickContactWindow} to
- * know when the window has been dismissed.
- */
- public interface OnDismissListener {
- public void onDismiss(QuickContactWindow dialog);
- }
-
- private final static int ANIMATION_FADE_IN_TIME = 100;
- private final static int ANIMATION_FADE_OUT_TIME = 100;
- private final static int ANIMATION_EXPAND_TIME = 100;
- private final static int ANIMATION_COLLAPSE_TIME = 100;
-
- /**
- * If the anchor is wider than (quick contact width * this constant) then
- * center quick contact. Otherwise, left-align.
- */
- private static final double MIN_RELATIVE_ANCHOR_WIDTH_TO_CENTER = 0.5;
-
- private final Context mContext;
- private final LayoutInflater mInflater;
- private final WindowManager mWindowManager;
- private Window mWindow;
- private View mDecor;
- private final Rect mRect = new Rect();
-
- private boolean mDismissed = false;
- private boolean mQuerying = false;
- private boolean mShowing = false;
+ private static final int ANIMATION_FADE_IN_TIME = 100;
+ private static final int ANIMATION_FADE_OUT_TIME = 100;
+ private static final int ANIMATION_EXPAND_TIME = 100;
+ private static final int ANIMATION_COLLAPSE_TIME = 100;
private NotifyingAsyncQueryHandler mHandler;
- private OnDismissListener mDismissListener;
private Uri mLookupUri;
- private Rect mAnchor;
-
- private int mScreenWidth;
- private int mUseableScreenHeight;
- private int mRequestedY;
+ private int mMode;
+ private String[] mExcludeMimes;
private boolean mHasValidSocial = false;
- private int mMode;
- private QuickContactRootLayout mRootView;
+ private FloatingChildLayout mFloatingLayout;
private QuickContactBackgroundDrawable mBackground;
+
private View mHeader;
- private HorizontalScrollView mTrackScroll;
private ViewGroup mTrack;
-
private FrameLayout mFooter;
private LinearLayout mFooterDisambig;
private LinearLayout mFooterClearDefaults;
+
private ListView mResolveList;
private CheckableImageView mLastAction;
private CheckBox mSetPrimaryCheckBox;
@@ -165,9 +126,6 @@ public class QuickContactWindow implements Window.Callback,
*/
private HashMap<String, Action> mDefaultsMap = new HashMap<String, Action>();
- private int mWindowRecycled = 0;
- private int mActionRecycled = 0;
-
/**
* Set of {@link Action} that are associated with the aggregate currently
* displayed by this dialog, represented as a map from {@link String}
@@ -176,14 +134,6 @@ public class QuickContactWindow implements Window.Callback,
private ActionMultiMap mActions = new ActionMultiMap();
/**
- * Pool of unused {@link CheckableImageView} that have previously been
- * inflated, and are ready to be recycled through {@link #obtainView()}.
- */
- private LinkedList<CheckableImageView> mActionPool = new LinkedList<CheckableImageView>();
-
- private String[] mExcludeMimes;
-
- /**
* {@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,
@@ -221,82 +171,48 @@ public class QuickContactWindow implements Window.Callback,
});
private static final int TOKEN_DATA = 1;
- static final boolean TRACE_LAUNCH = false;
- static final String TRACE_TAG = "quickcontact";
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
- /**
- * Prepare a dialog to show in the given {@link Context}.
- */
- public QuickContactWindow(Context context) {
- mContext = new ContextThemeWrapper(context, R.style.QuickContact);
- mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
-
- 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 = (QuickContactRootLayout)mWindow.findViewById(R.id.root);
- mRootView.setListener(this);
- mRootView.setFocusable(true);
- mRootView.setFocusableInTouchMode(true);
- mRootView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
-
- mBackground = new QuickContactBackgroundDrawable();
- mRootView.setBackgroundDrawable(mBackground);
-
- mScreenWidth = mWindowManager.getDefaultDisplay().getWidth();
- // Status bar height
- final int screenMarginBottom = context.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.screen_margin_bottom);
- mUseableScreenHeight = mWindowManager.getDefaultDisplay().getHeight() - screenMarginBottom;
-
- mTrack = (ViewGroup) mWindow.findViewById(R.id.quickcontact);
- mTrackScroll = (HorizontalScrollView) mWindow.findViewById(R.id.scroll);
-
- mFooter = (FrameLayout) mWindow.findViewById(R.id.footer);
- mFooterDisambig = (LinearLayout) mWindow.findViewById(R.id.footer_disambig);
- mFooterClearDefaults = (LinearLayout) mWindow.findViewById(R.id.footer_clear_defaults);
- mResolveList = (ListView) mWindow.findViewById(android.R.id.list);
- mSetPrimaryCheckBox = (CheckBox) mWindow.findViewById(android.R.id.checkbox);
-
- mDefaultsListView = (ListView) mWindow.findViewById(R.id.defaults_list);
- mClearDefaultsButton = (Button) mWindow.findViewById(R.id.clear_defaults_button);
- mClearDefaultsButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- clearDefaults();
- }
- });
+ setContentView(R.layout.quickcontact_activity);
- mResolveList.setOnItemClickListener(QuickContactWindow.this);
+ mBackground = new QuickContactBackgroundDrawable(getResources());
- mHandler = new NotifyingAsyncQueryHandler(mContext, this);
- }
+ mFloatingLayout = findTypedViewById(R.id.floating_layout);
+ mFloatingLayout.getChild().setBackgroundDrawable(mBackground);
+ mFloatingLayout.setOnOutsideTouchListener(mOnOutsideTouchListener);
- /**
- * Prepare a dialog to show in the given {@link Context}, and notify the
- * given {@link OnDismissListener} each time this dialog is dismissed.
- */
- public QuickContactWindow(Context context, OnDismissListener dismissListener) {
- this(context);
- mDismissListener = dismissListener;
+ mTrack = findTypedViewById(R.id.quickcontact);
+ mFooter = findTypedViewById(R.id.footer);
+ mFooterDisambig = findTypedViewById(R.id.footer_disambig);
+ mFooterClearDefaults = findTypedViewById(R.id.footer_clear_defaults);
+ mResolveList = findTypedViewById(android.R.id.list);
+ mSetPrimaryCheckBox = findTypedViewById(android.R.id.checkbox);
+
+ mDefaultsListView = findTypedViewById(R.id.defaults_list);
+
+ mClearDefaultsButton = findTypedViewById(R.id.clear_defaults_button);
+ mClearDefaultsButton.setOnClickListener(mOnClearDefaultsClickListener);
+
+ mResolveList.setOnItemClickListener(this);
+
+ mHandler = new NotifyingAsyncQueryHandler(this, this);
+
+ show();
}
private View getHeaderView(int mode) {
View header = null;
switch (mode) {
case QuickContact.MODE_SMALL:
- header = mWindow.findViewById(R.id.header_small);
+ header = findViewById(R.id.header_small);
break;
case QuickContact.MODE_MEDIUM:
- header = mWindow.findViewById(R.id.header_medium);
+ header = findViewById(R.id.header_medium);
break;
case QuickContact.MODE_LARGE:
- header = mWindow.findViewById(R.id.header_large);
+ header = findViewById(R.id.header_large);
break;
}
@@ -311,60 +227,52 @@ public class QuickContactWindow implements Window.Callback,
return header;
}
- /**
- * Start showing a dialog for the given {@link Contacts#_ID} pointing
- * towards the given location.
- */
- public synchronized void show(Uri lookupUri, Rect anchor, int mode, String[] excludeMimes) {
- if (mQuerying || mShowing) {
- Log.w(TAG, "dismissing before showing");
- dismissInternal();
- }
+ private void show() {
- if (TRACE_LAUNCH && !android.os.Debug.isMethodTracingActive()) {
+ if (TRACE_LAUNCH) {
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");
- }
+ final Intent intent = getIntent();
+
+ Uri lookupUri = intent.getData();
- if (anchor == null) {
- throw new IllegalArgumentException("Missing anchor rectangle");
+ // Check to see whether it comes from the old version.
+ if (android.provider.Contacts.AUTHORITY.equals(lookupUri.getAuthority())) {
+ final long rawContactId = ContentUris.parseId(lookupUri);
+ lookupUri = RawContacts.getContactLookupUri(getContentResolver(),
+ ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
}
- // Prepare header view for requested mode
- mLookupUri = lookupUri;
- mAnchor = new Rect(anchor);
- mMode = mode;
- mExcludeMimes = excludeMimes;
+ mLookupUri = Preconditions.checkNotNull(lookupUri, "missing lookupUri");
- mHeader = getHeaderView(mode);
+ // Read requested parameters for displaying
+ final Rect targetScreen = intent.getSourceBounds();
+ Preconditions.checkNotNull(targetScreen, "missing targetScreen");
+ mFloatingLayout.setChildTargetScreen(targetScreen);
- setHeaderText(R.id.name, R.string.quickcontact_missing_name);
+ mMode = intent.getIntExtra(QuickContact.EXTRA_MODE, QuickContact.MODE_MEDIUM);
+ mExcludeMimes = intent.getStringArrayExtra(QuickContact.EXTRA_EXCLUDE_MIMES);
+
+ switch (mMode) {
+ case QuickContact.MODE_SMALL:
+ case QuickContact.MODE_MEDIUM:
+ case QuickContact.MODE_LARGE:
+ break;
+ default:
+ throw new IllegalArgumentException("Unexpected mode: " + mMode);
+ }
+ // find and prepare correct header view
+ mHeader = getHeaderView(mMode);
+ setHeaderText(R.id.name, R.string.quickcontact_missing_name);
setHeaderText(R.id.status, null);
setHeaderText(R.id.timestamp, null);
-
setHeaderImage(R.id.presence, null);
- 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;
-
// Start background query for data, but only select photo rows when they
// directly match the super-primary PHOTO_ID.
- final Uri dataUri = getDataUri(lookupUri);
+ final Uri dataUri = Uri.withAppendedPath(lookupUri, Contacts.Data.CONTENT_DIRECTORY);
mHandler.cancelOperation(TOKEN_DATA);
// Only request photo data when required by mode
@@ -380,226 +288,85 @@ public class QuickContactWindow implements Window.Callback,
}
}
- /**
- * Build a {@link Uri} into the {@link Data} table for the requested
- * {@link Contacts#CONTENT_LOOKUP_URI} style {@link Uri}.
- */
- private Uri getDataUri(Uri lookupUri) {
- return Uri.withAppendedPath(lookupUri, Contacts.Data.CONTENT_DIRECTORY);
+ @SuppressWarnings("unchecked")
+ private <T> T findTypedViewById(int id) {
+ return (T) super.findViewById(id);
}
- /**
- * Creates and configures the background resource
- */
- private void configureBackground(boolean arrowUp, int requestedX) {
- mBackground.configure(mContext.getResources(), arrowUp, requestedX);
- }
-
- /**
- * Actual internal method to show this dialog. Called only by
- * {@link #considerShowing()} when all data requirements have been met.
- */
- private void showInternal() {
- mDecor = mWindow.getDecorView();
- mDecor.getViewTreeObserver().addOnGlobalLayoutListener(this);
- WindowManager.LayoutParams layoutParams = mWindow.getAttributes();
-
- layoutParams.width = mContext.getResources().getDimensionPixelSize(
- R.dimen.quick_contact_width);
- layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
-
- // Try to left align with the anchor control or center if the anchor is wide
- if (mAnchor.left + layoutParams.width <= mScreenWidth) {
- if (mAnchor.width() > layoutParams.width * MIN_RELATIVE_ANCHOR_WIDTH_TO_CENTER) {
- layoutParams.x = mAnchor.left + (mAnchor.width() - layoutParams.width) / 2;
- } else {
- layoutParams.x = mAnchor.left;
- }
- } else {
- // Not enough space. Try to right align to the anchor
- if (mAnchor.right - layoutParams.width >= 0) {
- layoutParams.x = mAnchor.right - layoutParams.width;
- } else {
- // Also not enough space. Use the whole screen width available
- layoutParams.x = 0;
- layoutParams.width = mScreenWidth;
- }
+ private View.OnTouchListener mOnOutsideTouchListener = new View.OnTouchListener() {
+ /** {@inheritDoc} */
+ public boolean onTouch(View v, MotionEvent event) {
+ hide(true);
+ return true;
}
+ };
- // Force layout measuring pass so we have baseline numbers
- mDecor.measure(layoutParams.width, layoutParams.height);
- final int blockHeight = mDecor.getMeasuredHeight();
-
- layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
-
- if (mUseableScreenHeight - mAnchor.bottom > blockHeight) {
- // Show downwards callout when enough room, aligning block top with bottom of
- // anchor area, and adjusting to inset arrow.
- configureBackground(true, mAnchor.centerX() - layoutParams.x);
- layoutParams.y = mAnchor.bottom;
- layoutParams.windowAnimations = R.style.QuickContactBelowAnimation;
- } else {
- // Show upwards callout, aligning bottom block
- // edge with top of anchor area, and adjusting to inset arrow.
- configureBackground(false, mAnchor.centerX() - layoutParams.x);
- layoutParams.y = mAnchor.top - blockHeight;
- layoutParams.windowAnimations = R.style.QuickContactAboveAnimation;
+ private View.OnClickListener mOnClearDefaultsClickListener = new View.OnClickListener() {
+ /** {@inheritDoc} */
+ public void onClick(View v) {
+ clearDefaults();
}
+ };
- layoutParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
-
- mRequestedY = layoutParams.y;
- mWindowManager.addView(mDecor, layoutParams);
- mShowing = true;
- mQuerying = false;
- mDismissed = false;
+ private void hide(boolean withAnimation) {
+ // cancel any pending queries
+ mHandler.cancelOperation(TOKEN_DATA);
- if (TRACE_LAUNCH) {
- android.os.Debug.stopMethodTracing();
- Log.d(TAG, "Window recycled " + mWindowRecycled + " times, chiclets "
- + mActionRecycled + " times");
+ if (withAnimation) {
+ mFloatingLayout.hideChild(new Runnable() {
+ /** {@inheritDoc} */
+ public void run() {
+ finish();
+ }
+ });
+ } else {
+ mFloatingLayout.hideChild(null);
+ finish();
}
}
- /** {@inheritDoc} */
@Override
- public void onGlobalLayout() {
- layoutInScreen();
- }
-
- /**
- * Adjust vertical {@link WindowManager.LayoutParams} to fit window as best
- * as possible, shifting up to display content as needed.
- */
- private void layoutInScreen() {
- if (!mShowing) return;
-
- final WindowManager.LayoutParams l = mWindow.getAttributes();
- final int originalY = l.y;
-
- final int blockHeight = mDecor.getHeight();
-
- l.y = mRequestedY;
- if (mRequestedY + blockHeight > mUseableScreenHeight) {
- // Shift up from bottom when overflowing
- l.y = mUseableScreenHeight - blockHeight;
- }
-
- if (originalY != l.y) {
- // Only update when value is changed
- mWindow.setAttributes(l);
- }
- }
-
- /**
- * Dismiss this dialog if showing.
- */
- public synchronized void dismiss() {
- // Notify any listeners that we've been dismissed
- if (mDismissListener != null) {
- mDismissListener.onDismiss(this);
- }
-
- dismissInternal();
- }
-
- private void dismissInternal() {
- // Remove any attached window decor for recycling
- boolean hadDecor = mDecor != null;
- if (hadDecor) {
- mWindowManager.removeView(mDecor);
- mWindowRecycled++;
- mDecor.getViewTreeObserver().removeGlobalOnLayoutListener(this);
- mDecor = null;
- mWindow.closeAllPanels();
- }
- mShowing = false;
- mDismissed = true;
-
- // Cancel any pending queries
- mHandler.cancelOperation(TOKEN_DATA);
- mQuerying = false;
-
- // Completely hide header and reset track
- mHeader.setVisibility(View.GONE);
- resetTrack();
+ public void onBackPressed() {
+ hide(true);
}
- /**
- * Reset track to initial state, recycling any chiclets.
- */
- private void resetTrack() {
- // Clear background height-animation override
- mBackground.clearBottomOverride();
-
- // Release reference to last chiclet
- mLastAction = null;
-
- // Clear track actions and scroll to hard left
- mActions.clear();
-
- // Recycle any chiclets in use
- for (int i = mTrack.getChildCount() - 1; i >= 0; i--) {
- final View child = mTrack.getChildAt(i);
- // there can be non-CheckableImageView children, e.g. a "No Data" label
- if (child instanceof CheckableImageView) {
- releaseView((CheckableImageView)child);
+ /** {@inheritDoc} */
+ public synchronized void onQueryComplete(int token, Object cookie, Cursor cursor) {
+ try {
+ if (isFinishing()) {
+ hide(false);
+ return;
+ } else if (cursor == null || cursor.getCount() == 0) {
+ Toast.makeText(this, R.string.invalidContactMessage, Toast.LENGTH_LONG).show();
+ hide(false);
+ return;
}
- mTrack.removeViewAt(i);
- }
- mTrackScroll.fullScroll(View.FOCUS_LEFT);
+ bindData(cursor);
- // Clear any primary requests
- mSetPrimaryCheckBox.setChecked(false);
-
- setNewActionViewChecked(null);
- mFooter.setVisibility(View.GONE);
- }
-
- /**
- * Consider showing this window, which will only call through to
- * {@link #showInternal()} when all data items are present.
- */
- private void considerShowing() {
- if (!mShowing && !mDismissed) {
if (mMode == QuickContact.MODE_MEDIUM && !mHasValidSocial) {
// Missing valid social, swap medium for small header
mHeader.setVisibility(View.GONE);
mHeader = getHeaderView(QuickContact.MODE_SMALL);
}
- // All queries have returned, pull curtain
- showInternal();
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public synchronized void onQueryComplete(int token, Object cookie, Cursor cursor) {
- // Bail early when query is stale
- if (cookie != mLookupUri) return;
-
- if (cursor == null) {
- // Problem while running query, so bail without showing
- Log.w(TAG, "Missing cursor for token=" + token);
- this.dismiss();
- return;
- }
+ if (TRACE_LAUNCH) {
+ android.os.Debug.stopMethodTracing();
+ }
- handleData(cursor);
+ // data bound and ready, pull curtain to show
+ mFloatingLayout.showChild();
- if (!cursor.isClosed()) {
- cursor.close();
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
-
- considerShowing();
}
/** Assign this string to the view, if found in {@link #mHeader}. */
private void setHeaderText(int id, int resId) {
- setHeaderText(id, mContext.getResources().getText(resId));
+ setHeaderText(id, getText(resId));
}
/** Assign this string to the view, if found in {@link #mHeader}. */
@@ -637,26 +404,22 @@ public class QuickContactWindow implements Window.Callback,
/**
* Handle the result from the {@link #TOKEN_DATA} query.
*/
- private void handleData(Cursor cursor) {
- final ResolveCache cache = ResolveCache.getInstance(mContext);
- if (cursor == null) return;
- if (cursor.getCount() == 0) {
- Toast.makeText(mContext, R.string.invalidContactMessage, Toast.LENGTH_LONG).show();
- dismiss();
- return;
- }
+ private void bindData(Cursor cursor) {
+ final ResolveCache cache = ResolveCache.getInstance(this);
+ final Context context = this;
if (!isMimeExcluded(Contacts.CONTENT_ITEM_TYPE)) {
// Add the profile shortcut action
- final Action action = new ProfileAction(mContext, mLookupUri);
+ final Action action = new ProfileAction(context, mLookupUri);
mActions.put(Contacts.CONTENT_ITEM_TYPE, action);
}
mDefaultsMap.clear();
final DataStatus status = new DataStatus();
- final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
- final ImageView photoView = (ImageView)mHeader.findViewById(R.id.photo);
+ final AccountTypeManager accountTypes = AccountTypeManager.getInstance(
+ context.getApplicationContext());
+ final ImageView photoView = (ImageView) mHeader.findViewById(R.id.photo);
Bitmap photoBitmap = null;
while (cursor.moveToNext()) {
@@ -688,7 +451,7 @@ public class QuickContactWindow implements Window.Callback,
// Build an action for this data entry, find a mapping to a UI
// element, build its summary from the cursor, and collect it
// along with all others of this MIME-type.
- final Action action = new DataAction(mContext, mimeType, kind, dataId, cursor);
+ final Action action = new DataAction(context, mimeType, kind, dataId, cursor);
final boolean wasAdded = considerAdd(action, cache);
if (wasAdded) {
// Remember the default
@@ -700,7 +463,7 @@ public class QuickContactWindow implements Window.Callback,
// If phone number, also insert as text message action
if (Phone.CONTENT_ITEM_TYPE.equals(mimeType) && kind != null) {
- final DataAction action = new DataAction(mContext, Constants.MIME_TYPE_SMS_ADDRESS,
+ final DataAction action = new DataAction(context, Constants.MIME_TYPE_SMS_ADDRESS,
kind, dataId, cursor);
considerAdd(action, cache);
}
@@ -713,7 +476,7 @@ public class QuickContactWindow implements Window.Callback,
final DataKind imKind = accountTypes.getKindOrFallback(accountType,
Im.CONTENT_ITEM_TYPE);
if (imKind != null) {
- final DataAction action = new DataAction(mContext, Im.CONTENT_ITEM_TYPE, imKind,
+ final DataAction action = new DataAction(context, Im.CONTENT_ITEM_TYPE, imKind,
dataId, cursor);
considerAdd(action, cache);
isIm = true;
@@ -726,7 +489,7 @@ public class QuickContactWindow implements Window.Callback,
final DataKind imKind = accountTypes.getKindOrFallback(accountType,
Im.CONTENT_ITEM_TYPE);
if (imKind != null) {
- final DataAction chatAction = new DataAction(mContext,
+ final DataAction chatAction = new DataAction(context,
Constants.MIME_TYPE_VIDEO_CHAT, imKind, dataId, cursor);
considerAdd(chatAction, cache);
}
@@ -760,7 +523,7 @@ public class QuickContactWindow implements Window.Callback,
final int presence = cursor.getInt(DataQuery.CONTACT_PRESENCE);
final int chatCapability = cursor.getInt(DataQuery.CONTACT_CHAT_CAPABILITY);
final Drawable statusIcon = ContactPresenceIconUtil.getChatCapabilityIcon(
- mContext, presence, chatCapability);
+ context, presence, chatCapability);
setHeaderText(R.id.name, name);
setHeaderImage(R.id.presence, statusIcon);
@@ -776,7 +539,7 @@ public class QuickContactWindow implements Window.Callback,
if (mHasValidSocial && mMode != QuickContact.MODE_SMALL) {
// Update status when valid was found
setHeaderText(R.id.status, status.getStatus());
- setHeaderText(R.id.timestamp, status.getTimestampLabel(mContext));
+ setHeaderText(R.id.timestamp, status.getTimestampLabel(context));
}
// Turn our list of actions into UI elements
@@ -790,7 +553,7 @@ public class QuickContactWindow implements Window.Callback,
for (String mimeType : PRECEDING_MIMETYPES) {
if (containedTypes.contains(mimeType)) {
hasData = true;
- mTrack.addView(inflateAction(mimeType, cache));
+ mTrack.addView(inflateAction(mimeType, cache, mTrack));
containedTypes.remove(mimeType);
}
}
@@ -802,7 +565,7 @@ public class QuickContactWindow implements Window.Callback,
for (String mimeType : FOLLOWING_MIMETYPES) {
if (containedTypes.contains(mimeType)) {
hasData = true;
- mTrack.addView(inflateAction(mimeType, cache));
+ mTrack.addView(inflateAction(mimeType, cache, mTrack));
containedTypes.remove(mimeType);
}
}
@@ -811,9 +574,11 @@ public class QuickContactWindow implements Window.Callback,
if (containedTypes.contains(ClearDefaultsAction.PSEUDO_MIME_TYPE)) {
final ClearDefaultsAction action = (ClearDefaultsAction) mActions.get(
ClearDefaultsAction.PSEUDO_MIME_TYPE).get(0);
- final CheckableImageView view = obtainView();
+ final CheckableImageView view = (CheckableImageView) getLayoutInflater().inflate(
+ R.layout.quickcontact_item, mTrack, false);
+
view.setChecked(false);
- final String description = mContext.getResources().getString(
+ final String description = context.getResources().getString(
R.string.quickcontact_clear_defaults_description);
view.setContentDescription(description);
view.setImageResource(R.drawable.ic_menu_settings_holo_light);
@@ -829,12 +594,13 @@ public class QuickContactWindow implements Window.Callback,
if (remainingTypes.length > 0) hasData = true;
Arrays.sort(remainingTypes);
for (String mimeType : remainingTypes) {
- mTrack.addView(inflateAction(mimeType, cache), index++);
+ mTrack.addView(inflateAction(mimeType, cache, mTrack), index++);
}
if (!hasData) {
// When there is no data to display, add a TextView to show the user there's no data
- View view = mInflater.inflate(R.layout.quickcontact_item_nodata, mTrack, false);
+ View view = getLayoutInflater().inflate(
+ R.layout.quickcontact_item_nodata, mTrack, false);
mTrack.addView(view, index++);
}
}
@@ -843,7 +609,9 @@ public class QuickContactWindow implements Window.Callback,
* Clears the defaults currently set on the Contact
*/
private void clearDefaults() {
+ final Context context = this;
final Set<String> mimeTypesKeySet = mDefaultsMap.keySet();
+
// Copy to array so that we can modify the HashMap below
final String[] mimeTypes = new String[mimeTypesKeySet.size()];
mimeTypesKeySet.toArray(mimeTypes);
@@ -851,9 +619,9 @@ public class QuickContactWindow implements Window.Callback,
// Send clear default Intents, one by one
for (String mimeType : mimeTypes) {
final Action action = mDefaultsMap.get(mimeType);
- final Intent intent =
- ContactSaveService.createClearPrimaryIntent(mContext, action.getDataId());
- mContext.startService(intent);
+ final Intent intent = ContactSaveService.createClearPrimaryIntent(
+ context, action.getDataId());
+ context.startService(intent);
mDefaultsMap.remove(mimeType);
}
@@ -864,7 +632,6 @@ public class QuickContactWindow implements Window.Callback,
for (int i = mTrack.getChildCount() - 1; i >= 0; i--) {
final CheckableImageView button = (CheckableImageView) mTrack.getChildAt(i);
if (button.getTag() instanceof ClearDefaultsAction) {
- releaseView(button);
mTrack.removeViewAt(i);
break;
}
@@ -888,35 +655,12 @@ public class QuickContactWindow implements Window.Callback,
}
/**
- * Obtain a new {@link CheckableImageView} for a new chiclet, either by
- * recycling one from {@link #mActionPool}, or by inflating a new one. When
- * finished, use {@link #releaseView(CheckableImageView)} to return back into the pool for
- * later recycling.
- */
- private synchronized CheckableImageView obtainView() {
- CheckableImageView view = mActionPool.poll();
- if (view == null || QuickContactActivity.FORCE_CREATE) {
- view = (CheckableImageView) mInflater.inflate(R.layout.quickcontact_item, mTrack,
- false);
- }
- return view;
- }
-
- /**
- * Return the given {@link CheckableImageView} into our internal pool for
- * possible recycling during another pass.
- */
- private synchronized void releaseView(CheckableImageView view) {
- mActionPool.offer(view);
- mActionRecycled++;
- }
-
- /**
* Inflate the in-track view for the action of the given MIME-type, collapsing duplicate values.
* Will use the icon provided by the {@link DataKind}.
*/
- private View inflateAction(String mimeType, ResolveCache resolveCache) {
- final CheckableImageView view = obtainView();
+ private View inflateAction(String mimeType, ResolveCache resolveCache, ViewGroup root) {
+ final CheckableImageView view = (CheckableImageView) getLayoutInflater().inflate(
+ R.layout.quickcontact_item, root, false);
// Add direct intent if single child, otherwise flag for multiple
List<Action> children = mActions.get(mimeType);
@@ -996,6 +740,13 @@ public class QuickContactWindow implements Window.Callback,
expandAnimator.setDuration(ANIMATION_EXPAND_TIME);
expandAnimator.start();
+ expandAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mBackground.clearBottomOverride();
+ }
+ });
+
final ObjectAnimator fadeInAnimator = ObjectAnimator.ofFloat(mFooter,
"alpha", 0.0f, 1.0f);
fadeInAnimator.setDuration(ANIMATION_FADE_IN_TIME);
@@ -1008,9 +759,12 @@ public class QuickContactWindow implements Window.Callback,
/** {@inheritDoc} */
@Override
public void onClick(View view) {
+ final Context context = this;
+
final boolean isActionView = (view instanceof CheckableImageView);
final CheckableImageView actionView = isActionView ? (CheckableImageView)view : null;
final Object tag = view.getTag();
+
if (tag instanceof ClearDefaultsAction) {
// Do nothing if already open
if (actionView == mLastAction) return;
@@ -1051,29 +805,28 @@ public class QuickContactWindow implements Window.Callback,
@Override
public View getView(int position, View convertView, ViewGroup parent) {
- final View result = convertView != null ? convertView :
- mInflater.inflate(R.layout.quickcontact_default_item,
- parent, false);
+ if (convertView == null) {
+ convertView = getLayoutInflater().inflate(
+ R.layout.quickcontact_default_item, parent, false);
+ }
+
// Set action title based on summary value
final Action defaultAction = actions[position];
- TextView text1 = (TextView)result.findViewById(android.R.id.text1);
- TextView text2 = (TextView)result.findViewById(android.R.id.text2);
+ final TextView text1 = (TextView) convertView.findViewById(
+ android.R.id.text1);
+ final TextView text2 = (TextView) convertView.findViewById(
+ android.R.id.text2);
text1.setText(defaultAction.getHeader());
text2.setText(defaultAction.getBody());
- result.setTag(defaultAction);
- return result;
+ convertView.setTag(defaultAction);
+ return convertView;
}
});
animateExpand(true);
- // Make sure we resize to make room for ListView
- if (mDecor != null) {
- mDecor.forceLayout();
- mDecor.invalidate();
- }
}
};
if (mFooter.getVisibility() == View.VISIBLE) {
@@ -1122,24 +875,24 @@ public class QuickContactWindow implements Window.Callback,
public void run() {
// Incoming tag is concrete intent, so try launching
try {
- mContext.startActivity(action.getIntent());
+ context.startActivity(action.getIntent());
} catch (ActivityNotFoundException e) {
- Toast.makeText(mContext, R.string.quickcontact_missing_app,
+ Toast.makeText(context, R.string.quickcontact_missing_app,
Toast.LENGTH_SHORT).show();
}
// Hide the resolution list, if present
setNewActionViewChecked(null);
- dismiss();
- mFooter.setVisibility(View.GONE);
// Set default?
final long dataId = action.getDataId();
if (makePrimary && dataId != -1) {
Intent serviceIntent = ContactSaveService.createSetSuperPrimaryIntent(
- mContext, dataId);
- mContext.startService(serviceIntent);
+ context, dataId);
+ context.startService(serviceIntent);
}
+
+ hide(false);
}
};
if (isActionView && mFooter.getVisibility() == View.VISIBLE) {
@@ -1184,31 +937,31 @@ public class QuickContactWindow implements Window.Callback,
@Override
public View getView(int position, View convertView, ViewGroup parent) {
- final View result = convertView != null ? convertView :
- mInflater.inflate(R.layout.quickcontact_resolve_item,
- parent, false);
+ if (convertView == null) {
+ convertView = getLayoutInflater().inflate(
+ R.layout.quickcontact_resolve_item, parent, false);
+ }
+
// Set action title based on summary value
final Action listAction = actionList.get(position);
- TextView text1 = (TextView)result.findViewById(android.R.id.text1);
- TextView text2 = (TextView)result.findViewById(android.R.id.text2);
+ final TextView text1 = (TextView) convertView.findViewById(
+ android.R.id.text1);
+ final TextView text2 = (TextView) convertView.findViewById(
+ android.R.id.text2);
text1.setText(listAction.getHeader());
text2.setText(listAction.getBody());
- result.setTag(listAction);
- return result;
+ convertView.setTag(listAction);
+ return convertView;
}
});
animateExpand(false);
- // Make sure we resize to make room for ListView
- if (mDecor != null) {
- mDecor.forceLayout();
- mDecor.invalidate();
- }
}
};
+
if (mFooter.getVisibility() == View.VISIBLE) {
// If the expansion list is currently opened, animate its collapse and then
// execute the target app
@@ -1219,191 +972,6 @@ public class QuickContactWindow implements Window.Callback,
}
}
- @Override
- public void onBackPressed() {
- dismiss();
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- if (mWindow.superDispatchKeyEvent(event)) {
- return true;
- }
- return event.dispatch(this, mDecor != null
- ? mDecor.getKeyDispatcherState() : null, this);
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK) {
- event.startTracking();
- return true;
- }
-
- return false;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()
- && !event.isCanceled()) {
- onBackPressed();
- return true;
- }
-
- return false;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean onKeyLongPress(int keyCode, KeyEvent event) {
- return false;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
- return false;
- }
-
- /** {@inheritDoc} */
- public boolean dispatchKeyShortcutEvent(KeyEvent event) {
- return mWindow.superDispatchKeyShortcutEvent(event);
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- // TODO: make this window accessible
- return false;
- }
-
- /**
- * Detect if the given {@link MotionEvent} is outside the boundaries of this
- * window, which usually means we should dismiss.
- */
- protected void detectEventOutside(MotionEvent event) {
- if (event.getAction() == MotionEvent.ACTION_DOWN && mDecor != null) {
- // Only try detecting outside events on down-press
- mDecor.getHitRect(mRect);
- final int x = (int)event.getX();
- final int y = (int)event.getY();
- if (!mRect.contains(x, y)) {
- event.setAction(MotionEvent.ACTION_OUTSIDE);
- }
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean dispatchTouchEvent(MotionEvent event) {
- detectEventOutside(event);
- if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
- dismiss();
- return true;
- }
- return mWindow.superDispatchTouchEvent(event);
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean dispatchTrackballEvent(MotionEvent event) {
- return mWindow.superDispatchTrackballEvent(event);
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean dispatchGenericMotionEvent(MotionEvent event) {
- return mWindow.superDispatchGenericMotionEvent(event);
- }
-
- /** {@inheritDoc} */
- @Override
- public void onContentChanged() {
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean onCreatePanelMenu(int featureId, Menu menu) {
- return false;
- }
-
- /** {@inheritDoc} */
- @Override
- public View onCreatePanelView(int featureId) {
- return null;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean onMenuItemSelected(int featureId, MenuItem item) {
- return false;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean onMenuOpened(int featureId, Menu menu) {
- return false;
- }
-
- /** {@inheritDoc} */
- @Override
- public void onPanelClosed(int featureId, Menu menu) {
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean onPreparePanel(int featureId, View view, Menu menu) {
- return false;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean onSearchRequested() {
- return false;
- }
-
- /** {@inheritDoc} */
- @Override
- public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams attrs) {
- if (mDecor != null) {
- mWindowManager.updateViewLayout(mDecor, attrs);
- }
- }
-
- /** {@inheritDoc} */
- @Override
- public void onWindowFocusChanged(boolean hasFocus) {
- }
-
- /** {@inheritDoc} */
- @Override
- public void onAttachedToWindow() {
- // No actions
- }
-
- /** {@inheritDoc} */
- @Override
- public void onDetachedFromWindow() {
- // No actions
- }
-
- /** {@inheritDoc} */
- @Override
- public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
- return null;
- }
-
- @Override
- public void onActionModeStarted(ActionMode mode) {
- }
-
- @Override
- public void onActionModeFinished(ActionMode mode) {
- }
private interface DataQuery {
final String[] PROJECTION = new String[] {
diff --git a/src/com/android/contacts/util/NotifyingAsyncQueryHandler.java b/src/com/android/contacts/util/NotifyingAsyncQueryHandler.java
index 83fae2928..c8cfc8dcb 100644
--- a/src/com/android/contacts/util/NotifyingAsyncQueryHandler.java
+++ b/src/com/android/contacts/util/NotifyingAsyncQueryHandler.java
@@ -29,8 +29,6 @@ import java.lang.ref.WeakReference;
* <p>
* This pattern can be used to perform background queries without leaking
* {@link Context} objects.
- *
- * @hide pending API council review
*/
public class NotifyingAsyncQueryHandler extends AsyncQueryHandler {
private WeakReference<AsyncQueryListener> mListener;