Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No Activity found (browser) with valid http:// prefix

So I got an exception from my app as follows:

android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=http://google.com (has extras) }
    at  android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1512)
    at  android.app.Instrumentation.execStartActivity(Instrumentation.java:1384)
    at  android.app.Activity.startActivityForResult(Activity.java:3248)
    at  android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:839)
    at  android.app.Activity.startActivity(Activity.java:3359)
    at  android.text.style.URLSpan.onClick(URLSpan.java:62)
    at  android.text.method.LinkMovementMethod.onTouchEvent(LinkMovementMethod.java:212)
    at  android.widget.TextView.onTouchEvent(TextView.java:8704)
    at  android.view.View.dispatchTouchEvent(View.java:5556)
    at  android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1957)
    at  android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1726)
    at  android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1957)
    at  android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1726)
    at  android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1957)
    at  android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1726)
    at  android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1957)
    at  android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1726)
    at  android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1957)
    at  android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1726)
    at  android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:1957)
    at  android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1726)
    at  com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1940)
    at  com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1390)
    at  android.app.Activity.dispatchTouchEvent(Activity.java:2414)
    at  com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1888)
    at  android.view.View.dispatchPointerEvent(View.java:5736)
    at  android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3017)
    at  android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2582)
    at  android.view.ViewRootImpl.processInputEvents(ViewRootImpl.java:887)
    at  android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2591)
    at  android.os.Handler.dispatchMessage(Handler.java:99)
    at  android.os.Looper.loop(Looper.java:137)
    at  android.app.ActivityThread.main(ActivityThread.java:4697)
    at  java.lang.reflect.Method.invokeNative(Native Method)
    at  java.lang.reflect.Method.invoke(Method.java:511)
    at  com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:787)
    at  com.android.internal.os.ZygoteInit.main(ZygoteInit.java:554)
    at  dalvik.system.NativeStart.main(Native Method)

This doesn't lead to my code. I assume this happens when user clicks URL in the text (and there are texts with URLs in app). What it's about? How could it be that Android device doesn't have a browser? How to bypass this or at least to catch (I need URLs be clickable in text)?

UPDATE
Actually I found that this exception happens in TextView which is intended to be an empty list view stub:

listView = (ListView) findViewById(R.id.listView);
// empty pass list with clickable url inside
final TextView listEmptyView = (TextView) findViewById(R.id.txtNoPasses);
listEmptyView.setMovementMethod(LinkMovementMethod.getInstance());
listView.setEmptyView(listEmptyView);

So I tried this (following CommonsWare's article) but my URL remains completely unclickable in this case:

    listView = (ListView) findViewById(R.id.listView);
    // empty pass list with clickable url inside
    final TextView listEmptyView = (TextView) findViewById(R.id.txtNoPasses);
    fixTextView(listEmptyView);
    listView.setEmptyView(listEmptyView);
}

private void fixTextView(TextView textView) {
    final SpannableString current = new SpannableString(textView.getText());
    final URLSpan[] spans = current.getSpans(0, current.length(), URLSpan.class);
    int start, end;
    for (URLSpan span : spans) {
        start = current.getSpanStart(span);
        end = current.getSpanEnd(span);
        current.removeSpan(span);
        current.setSpan(new DefensiveURLSpan(span.getURL()), start, end, 0);
    }
}

private static class DefensiveURLSpan extends URLSpan {
      public DefensiveURLSpan(String url) {
        super(url);
      }

      @Override
      public void onClick(View widget) {
        try {
          android.util.Log.d(getClass().getSimpleName(), "Got here!");
          super.onClick(widget);
        }
        catch (ActivityNotFoundException e) {
          // do something useful here
          // android.text.SpannedString cannot be cast to android.text.SpannableString
        }
      }
}

And TextView:

<TextView
        android:id="@+id/txtNoPasses"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:visibility="gone"
        android:gravity="center"
        android:padding="15dp"
        android:text="@string/no_passes"
        android:textAppearance="?android:attr/textAppearanceMedium"/>

And no_passes string is following:

<string name="no_passes">Currently you have no cards to use.\n<a href="http://cardz.website.com">You could add some cards from our website</a></string>
like image 816
Stan Avatar asked Mar 17 '23 23:03

Stan


2 Answers

I assume that this is a TextView with android:autolink set, or that otherwise displays HTML (for example, using Html.fromHtml()).

The problems is that this creates URLSpan instances for embedded URIs, and this class "blindly" calls startActivity() with the supplied URI. This crashes whenever the URI does not match with any registered activity. For "http" URLS this can happen when the device doesn't have a browser application, or (more likely) when using a restricted profile that blocks access to it.

The problem and its solution is well explained in this CommonsWare post. You can replace the URLSpan instances with a custom derived class that intercepts onClick() to avoid the exception.

See also this answer for a related issue.

like image 152
matiash Avatar answered Apr 02 '23 11:04

matiash


It's possible for an Android device not to have a browser. It is not required, per say, but obviously pretty rare. Android-ish devices like Kindles come to mind, although they still would have a browser...

Nonetheless, you can disable URL linking in your TextView as follows:

textView.setLinksClickable(false);

Also, related question.

Edit

See this answer:

String url = "http://www.example.com";
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
PackageManager manager = mContext.getPackageManager();
List<ResolveInfo> list = manager.queryIntentActivities(intent, 0);

if (list != null && list.size() > 0) {
    //You have at least one activity to handle the intent
} else {
    //No activity to handle the intent.
}

Create a new intent with ACTION_VIEW and a url and use this pattern to determine whether or not the device has any apps which can handle a url. If it doesn't, then you disable clicking links on the TextView for that user.

like image 44
Jeffrey Mixon Avatar answered Apr 02 '23 13:04

Jeffrey Mixon