package com.dozuki.ifixit.ui; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import com.dozuki.ifixit.App; import com.dozuki.ifixit.model.dozuki.Site; import com.dozuki.ifixit.ui.guide.view.GuideViewActivity; import com.dozuki.ifixit.ui.search.SearchActivity; import com.dozuki.ifixit.ui.topic_view.TopicActivity; import com.dozuki.ifixit.ui.topic_view.TopicViewActivity; import com.dozuki.ifixit.util.api.Api; import com.dozuki.ifixit.util.api.ApiCall; import com.dozuki.ifixit.util.api.ApiError; import com.dozuki.ifixit.util.api.ApiEvent; import com.squareup.otto.Subscribe; import java.util.List; /** * This Activity handles Intent filtering for other Activities. All intent-filters * point at this Activity so it can perform site validation, figure out which * Activity can handle the URI and launches it. */ public class IntentFilterActivity extends BaseActivity { private static final String VIEW_URL = "VIEW_URL"; private static final String URI_KEY = "URI_KEY"; private static final String DOMAIN = "DOMAIN"; private static final String INTENT_FILTERED = "INTENT_FILTERED"; private String mDomain; private Uri mUri; private boolean mIntentFiltered; public static Intent viewUrl(Context context, String url) { Intent intent = new Intent(context, IntentFilterActivity.class); intent.putExtra(VIEW_URL, url); return intent; } @Override public void onCreate(Bundle savedState) { super.onCreate(savedState); // TODO: Show loading. This is only important if we need to do the sites // API call. Otherwise the URI parsing is pretty much instantaneous. Intent intent = getIntent(); if (savedState != null) { mDomain = savedState.getString(DOMAIN); mUri = savedState.getParcelable(URI_KEY); mIntentFiltered = savedState.getBoolean(INTENT_FILTERED); } else if (Intent.ACTION_VIEW.equals(intent.getAction())) { handleUriView(intent.getData()); } else { Bundle extras = intent.getExtras(); String url = (String) extras.get(VIEW_URL); handleUriView(Uri.parse(url)); } } @Override public void onResume() { super.onResume(); if (mIntentFiltered) { // Finish this empty Activity if the Intent has been dealt with. finish(); } } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putString(DOMAIN, mDomain); outState.putParcelable(URI_KEY, mUri); outState.putBoolean(INTENT_FILTERED, mIntentFiltered); } private void handleUriView(Uri uri) { mUri = uri; List<String> segments = mUri.getPathSegments(); Site currentSite = App.get().getSite(); mDomain = uri.getHost(); if (currentSite.hostMatches(mDomain)) { handlePathNavigation(); } else if (App.isDozukiApp()) { // Only switch to the other site in the Dozuki app. // Set site to dozuki before API call. // TODO: Set the current site in the APICall rather than changing it // globally. App.get().setSite(Site.getSite("dozuki")); Api.call(this, ApiCall.sites()); } else { displayNotFoundDialog(); return; } } private void handlePathNavigation() { Intent intent = null; List<String> segments = mUri.getPathSegments(); if (segments.size() == 0) { intent = new Intent(this, TopicActivity.class); App.sendEvent("ui_action", "intent_filter", "category", null); } else { String prefix = segments.get(0); try { if (prefix.equalsIgnoreCase("guide") || prefix.equalsIgnoreCase("teardown")) { if (segments.get(1).equalsIgnoreCase("search")) { String query = segments.get(2); intent = SearchActivity.viewSearch(this, query); App.sendEvent("ui_action", "intent_filter", "search", null); } else { int guideid = Integer.parseInt(segments.get(2).trim()); intent = GuideViewActivity.viewGuideid(this, guideid); App.sendEvent("ui_action", "intent_filter", "guide", null); } } else if (prefix.equalsIgnoreCase("c") || prefix.equalsIgnoreCase("device")) { String topicName = segments.get(1); intent = TopicViewActivity.viewTopic(this, topicName); App.sendEvent("ui_action", "intent_filter", "category", null); } } catch (Exception e) { App.sendException("IntentFilterActivity", "Problem parsing Uri", e); displayNotFoundDialog(); } } if (intent != null) { /** * Don't call finish here. It results in some very very strange behavior * with DeadEvents in the Activity being launched. This flag indicates * that this Activity should be finished when it resumes. */ mIntentFiltered = true; startActivity(intent); } else { displayNotFoundDialog(); } } @Subscribe public void onSites(ApiEvent.Sites event) { if (!event.hasError()) { Site selectedSite = null; for (Site site : event.getResult()) { if (site.hostMatches(mDomain)) { selectedSite = site; break; } } if (selectedSite != null) { // Set the site and then fetch the guide. App.get().setSite(selectedSite); handlePathNavigation(); } else { App.sendException("IntentFilterActivity", "Didn't find site!", new Exception()); displayNotFoundDialog(); } } else { Api.getErrorDialog(this, event).show(); } } public void displayNotFoundDialog() { // The ApiEvent type doesn't matter. Api.getErrorDialog(this, new ApiEvent.ViewGuide(). setCode(404). setError(ApiError.getByStatusCode(404))).show(); } }