From 34252baa8622878f2c28858a16508978da3fcdcb Mon Sep 17 00:00:00 2001
From: "Tadashi G. Takaoka" <takaoka@google.com>
Date: Tue, 1 Feb 2011 14:03:12 +0900
Subject: [PATCH] Use custom dialog builder building url link clickable from
 service

This change is derived from I7611ebc1 (Honeycomb).

Bug: 3246715
Change-Id: I6446bd785f1bd3d7b901e86661c91ca5a823f30e
---
 .../inputmethod/voice/VoiceIMEConnector.java  | 136 ++++++++----------
 1 file changed, 61 insertions(+), 75 deletions(-)

diff --git a/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java b/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java
index 61a194a8d..4ceaa1bb9 100644
--- a/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java
+++ b/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java
@@ -38,16 +38,13 @@ import android.os.IBinder;
 import android.preference.PreferenceManager;
 import android.provider.Browser;
 import android.speech.SpeechRecognizer;
-import android.text.Layout;
-import android.text.Selection;
-import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
 import android.text.TextUtils;
 import android.text.method.LinkMovementMethod;
-import android.text.style.ClickableSpan;
 import android.text.style.URLSpan;
 import android.util.Log;
 import android.view.LayoutInflater;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewParent;
@@ -83,8 +80,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
     private static final String IME_OPTION_NO_MICROPHONE = "nm";
     private static final int RECOGNITIONVIEW_HEIGHT_THRESHOLD_RATIO = 6;
 
-    @SuppressWarnings("unused")
-    private static final String TAG = "VoiceIMEConnector";
+    private static final String TAG = VoiceIMEConnector.class.getSimpleName();
     private static boolean DEBUG = LatinImeLogger.sDBG;
 
     private boolean mAfterVoiceInput;
@@ -177,7 +173,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
         if (mVoiceWarningDialog != null && mVoiceWarningDialog.isShowing()) {
             return;
         }
-        AlertDialog.Builder builder = new AlertDialog.Builder(mService);
+        AlertDialog.Builder builder = new UrlLinkAlertDialogBuilder(mService);
         builder.setCancelable(true);
         builder.setIcon(R.drawable.ic_mic_dialog);
         builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@@ -215,90 +211,80 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
                                     mService.getText(R.string.voice_warning_how_to_turn_off));
         }
         builder.setMessage(message);
-
         builder.setTitle(R.string.voice_warning_title);
         mVoiceWarningDialog = builder.create();
-        Window window = mVoiceWarningDialog.getWindow();
-        WindowManager.LayoutParams lp = window.getAttributes();
+        final Window window = mVoiceWarningDialog.getWindow();
+        final WindowManager.LayoutParams lp = window.getAttributes();
         lp.token = token;
         lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
         window.setAttributes(lp);
         window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
         mVoiceInput.logKeyboardWarningDialogShown();
         mVoiceWarningDialog.show();
-        // Make URL in the dialog message clickable
-        TextView textView = (TextView) mVoiceWarningDialog.findViewById(android.R.id.message);
-        if (textView != null) {
-            final CustomLinkMovementMethod method = CustomLinkMovementMethod.getInstance();
-            method.setVoiceWarningDialog(mVoiceWarningDialog);
-            textView.setMovementMethod(method);
-        }
     }
 
-    private static class CustomLinkMovementMethod extends LinkMovementMethod {
-        private static CustomLinkMovementMethod sLinkMovementMethodInstance =
-                new CustomLinkMovementMethod();
+    private static class UrlLinkAlertDialogBuilder extends AlertDialog.Builder {
         private AlertDialog mAlertDialog;
 
-        public void setVoiceWarningDialog(AlertDialog alertDialog) {
-            mAlertDialog = alertDialog;
+        public UrlLinkAlertDialogBuilder(Context context) {
+            super(context);
         }
 
-        public static CustomLinkMovementMethod getInstance() {
-            return sLinkMovementMethodInstance;
-        }
-
-        // Almost the same as LinkMovementMethod.onTouchEvent(), but overrides it for
-        // FLAG_ACTIVITY_NEW_TASK and mAlertDialog.cancel().
         @Override
-        public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
-            int action = event.getAction();
+        public AlertDialog.Builder setMessage(CharSequence message) {
+            return super.setMessage(replaceURLSpan(message));
+        }
 
-            if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
-                int x = (int) event.getX();
-                int y = (int) event.getY();
-
-                x -= widget.getTotalPaddingLeft();
-                y -= widget.getTotalPaddingTop();
-
-                x += widget.getScrollX();
-                y += widget.getScrollY();
-
-                Layout layout = widget.getLayout();
-                int line = layout.getLineForVertical(y);
-                int off = layout.getOffsetForHorizontal(line, x);
-
-                ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
-
-                if (link.length != 0) {
-                    if (action == MotionEvent.ACTION_UP) {
-                        if (link[0] instanceof URLSpan) {
-                            URLSpan urlSpan = (URLSpan) link[0];
-                            Uri uri = Uri.parse(urlSpan.getURL());
-                            Context context = widget.getContext();
-                            Intent intent = new Intent(Intent.ACTION_VIEW, uri);
-                            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                            intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
-                            if (mAlertDialog != null) {
-                                // Go back to the previous IME for now.
-                                // TODO: If we can find a way to bring the new activity to front
-                                // while keeping the warning dialog, we don't need to cancel here.
-                                mAlertDialog.cancel();
-                            }
-                            context.startActivity(intent);
-                        } else {
-                            link[0].onClick(widget);
-                        }
-                    } else if (action == MotionEvent.ACTION_DOWN) {
-                        Selection.setSelection(buffer, buffer.getSpanStart(link[0]),
-                                buffer.getSpanEnd(link[0]));
-                    }
-                    return true;
-                } else {
-                    Selection.removeSelection(buffer);
-                }
+        private Spanned replaceURLSpan(CharSequence message) {
+            // Replace all spans with the custom span
+            final SpannableStringBuilder ssb = new SpannableStringBuilder(message);
+            for (URLSpan span : ssb.getSpans(0, ssb.length(), URLSpan.class)) {
+                int spanStart = ssb.getSpanStart(span);
+                int spanEnd = ssb.getSpanEnd(span);
+                int spanFlags = ssb.getSpanFlags(span);
+                ssb.removeSpan(span);
+                ssb.setSpan(new ClickableSpan(span.getURL()), spanStart, spanEnd, spanFlags);
+            }
+            return ssb;
+        }
+
+        @Override
+        public AlertDialog create() {
+            final AlertDialog dialog = super.create();
+
+            dialog.setOnShowListener(new DialogInterface.OnShowListener() {
+                @Override
+                public void onShow(DialogInterface dialogInterface) {
+                    // Make URL in the dialog message click-able.
+                    TextView textView = (TextView) mAlertDialog.findViewById(android.R.id.message);
+                    if (textView != null) {
+                        textView.setMovementMethod(LinkMovementMethod.getInstance());
+                    }
+                }
+            });
+            mAlertDialog = dialog;
+            return dialog;
+        }
+
+        class ClickableSpan extends URLSpan {
+            public ClickableSpan(String url) {
+                super(url);
+            }
+
+            @Override
+            public void onClick(View widget) {
+                Uri uri = Uri.parse(getURL());
+                Context context = widget.getContext();
+                Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+                // Add this flag to start an activity from service
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
+                // Dismiss the warning dialog and go back to the previous IME.
+                // TODO: If we can find a way to bring the new activity to front while keeping
+                // the warning dialog, we don't need to dismiss it here.
+                mAlertDialog.cancel();
+                context.startActivity(intent);
             }
-            return super.onTouchEvent(widget, buffer, event);
         }
     }