public class Constants {
    public static final String LIGHTNINGTALK = "lightning-talk";
    public static final String WORKSHOP = "workshop";

    // session feedback key for passing data to intent
    public static final String SESSION_FEEDBACK_TITLE = "SESSION_FEEDBACK_TITLE";
    public static final String SESSION_FEEDBACK_SUBTITLE = "SESSION_FEEDBACK_SUBTITLE";
    public static final String SESSION_ID = "SESSION_ID";

    public static final String SESSION_FEEDBACK_WEB_URI_TEST = "http://test.javazone.no/devnull/server";
    public static final String SESSION_FEEDBACK_WEB_URI = "http://javazone.no/devnull/server";

} public static class Blocks implements BlocksColumns, BaseColumns {
    public static final Uri CONTENT_URI =
            BASE_CONTENT_URI.buildUpon().appendPath(PATH_BLOCKS).build();

    public static final String CONTENT_TYPE =
            "vnd.android.cursor.dir/vnd.androidito-iosched.block";
    public static final String CONTENT_ITEM_TYPE =
            "vnd.android.cursor.item/vnd.androidito-iosched.block";

    /** Count of {@link Sessions} inside given block. */
    public static final String SESSIONS_COUNT = "sessions_count";

    /**
     * Flag indicating the number of sessions inside this block that have
     * {@link Sessions#SESSION_STARRED} set.
     */
    public static final String NUM_STARRED_SESSIONS = "num_starred_sessions";

    /**
     * The {@link Sessions#SESSION_ID} of the first starred session in this
     * block.
     */
    public static final String STARRED_SESSION_ID = "starred_session_id";

    /**
     * The {@link Sessions#SESSION_TITLE} of the first starred session in
     * this block.
     */
    public static final String STARRED_SESSION_TITLE = "starred_session_title";

    /**
     * The {@link Sessions#SESSION_LIVESTREAM_URL} of the first starred
     * session in this block.
     */
    public static final String STARRED_SESSION_LIVESTREAM_URL =
            "starred_session_livestream_url";

    /**
     * The {@link Rooms#ROOM_NAME} of the first starred session in this
     * block.
     */
    public static final String STARRED_SESSION_ROOM_NAME = "starred_session_room_name";

    /**
     * The {@link Rooms#ROOM_ID} of the first starred session in this block.
     */
    public static final String STARRED_SESSION_ROOM_ID = "starred_session_room_id";

    /**
     * The {@link Sessions#SESSION_HASHTAGS} of the first starred session in
     * this block.
     */
    public static final String STARRED_SESSION_HASHTAGS = "starred_session_hashtags";

    /**
     * The {@link Sessions#SESSION_URL} of the first starred session in this
     * block.
     */
    public static final String STARRED_SESSION_URL = "starred_session_url";

    /** Default "ORDER BY" clause. */
    public static final String DEFAULT_SORT = BlocksColumns.BLOCK_START + " ASC, "
            + BlocksColumns.BLOCK_END + " ASC";

    public static final String EMPTY_SESSIONS_SELECTION = "(" + BLOCK_TYPE
            + " = '" + ParserUtils.BLOCK_TYPE_SESSION + "' OR " + BLOCK_TYPE
            + " = '" + ParserUtils.BLOCK_TYPE_CODE_LAB + "') AND "
            + SESSIONS_COUNT + " = 0";

    /** Build {@link Uri} for requested {@link #BLOCK_ID}. */
    public static Uri buildBlockUri(String blockId) {
        return CONTENT_URI.buildUpon().appendPath(blockId).build();
    }

    /**
     * Build {@link Uri} that references any {@link Sessions} associated
     * with the requested {@link #BLOCK_ID}.
     */
    public static Uri buildSessionsUri(String blockId) {
        return CONTENT_URI.buildUpon().appendPath(blockId).appendPath(PATH_SESSIONS).build();
    }

    /**
     * Build {@link Uri} that references starred {@link Sessions} associated
     * with the requested {@link #BLOCK_ID}.
     */
    public static Uri buildStarredSessionsUri(String blockId) {
        return CONTENT_URI.buildUpon().appendPath(blockId).appendPath(PATH_SESSIONS)
                .appendPath(PATH_STARRED).build();
    }

    /**
     * Build {@link Uri} that references any {@link Blocks} that occur
     * between the requested time boundaries.
     */
    public static Uri buildBlocksBetweenDirUri(long startTime, long endTime) {
        return CONTENT_URI.buildUpon().appendPath(PATH_BETWEEN).appendPath(
                String.valueOf(startTime)).appendPath(String.valueOf(endTime)).build();
    }

    /** Read {@link #BLOCK_ID} from {@link Blocks} {@link Uri}. */
    public static String getBlockId(Uri uri) {
        return uri.getPathSegments().get(1);
    }

    /**
     * Generate a {@link #BLOCK_ID} that will always match the requested
     * {@link Blocks} details.
     */
    public static String generateBlockId(long startTime, long endTime) {
        startTime /= DateUtils.SECOND_IN_MILLIS;
        endTime /= DateUtils.SECOND_IN_MILLIS;
        return ParserUtils.sanitizeId(startTime + "-" + endTime);
    }
} public static class Rooms implements RoomsColumns, BaseColumns {
    public static final Uri CONTENT_URI =
            BASE_CONTENT_URI.buildUpon().appendPath(PATH_ROOMS).build();

    public static final String CONTENT_TYPE =
            "vnd.android.cursor.dir/vnd.androidito-iosched.room";
    public static final String CONTENT_ITEM_TYPE =
            "vnd.android.cursor.item/vnd.androidito-iosched.room";

    /** Default "ORDER BY" clause. */
    public static final String DEFAULT_SORT = RoomsColumns.ROOM_FLOOR + " ASC, "
            + RoomsColumns.ROOM_NAME + " COLLATE NOCASE ASC";

    /** Build {@link Uri} for requested {@link #ROOM_ID}. */
    public static Uri buildRoomUri(String roomId) {
        return CONTENT_URI.buildUpon().appendPath(roomId).build();
    }

    /**
     * Build {@link Uri} that references any {@link Sessions} associated
     * with the requested {@link #ROOM_ID}.
     */
    public static Uri buildSessionsDirUri(String roomId) {
        return CONTENT_URI.buildUpon().appendPath(roomId).appendPath(PATH_SESSIONS).build();
    }

    /** Read {@link #ROOM_ID} from {@link Rooms} {@link Uri}. */
    public static String getRoomId(Uri uri) {
        return uri.getPathSegments().get(1);
    }
} public class MapActivity extends SimpleSinglePaneActivity implements
        MapFragment.Callbacks,
        LoaderManager.LoaderCallbacks<Cursor> {
    @Override
    protected Fragment onCreatePane() {
        return new MapFragment();
    }

    @Override
    public void onRoomSelected(String roomId) {
        Bundle loadRoomDataArgs = new Bundle();
        loadRoomDataArgs.putString("room_id", roomId);
        // force load (don't use previously used data)
        getSupportLoaderManager().restartLoader(0, loadRoomDataArgs, this);
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle data) {
        return new CursorLoader(this,
                ScheduleContract.Rooms.buildRoomUri(data.getString("room_id")),
                RoomsQuery.PROJECTION,
                null, null, null);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
        try {
            if (!cursor.moveToFirst()) {
                return;
            }

            Intent roomIntent = new Intent(Intent.ACTION_VIEW,
                    ScheduleContract.Rooms.buildSessionsDirUri(
                            cursor.getString(RoomsQuery.ROOM_ID)));
            roomIntent.putExtra(Intent.EXTRA_TITLE, cursor.getString(RoomsQuery.ROOM_NAME));
            startActivity(roomIntent);

        } finally {
            cursor.close();
        }
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
    }

    private interface RoomsQuery {
        String[] PROJECTION = {
                ScheduleContract.Rooms.ROOM_ID,
                ScheduleContract.Rooms.ROOM_NAME,
                ScheduleContract.Rooms.ROOM_FLOOR,
        };

        int ROOM_ID = 0;
        int ROOM_NAME = 1;
        int ROOM_FLOOR = 2;
    }
} public class SessionDetailActivity extends SimpleSinglePaneActivity implements
        TrackInfoHelperFragment.Callbacks {

    private String mTrackId = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        if (BeamUtils.wasLaunchedThroughBeamFirstTime(this, getIntent())) {
            BeamUtils.setBeamUnlocked(this);
            showFirstBeamDialog();
        }

        BeamUtils.tryUpdateIntentFromBeam(this);
        super.onCreate(savedInstanceState);

        if (savedInstanceState == null) {
            Uri sessionUri = getIntent().getData();
            BeamUtils.setBeamSessionUri(this, sessionUri);
            trySetBeamCallback();
            getSupportFragmentManager().beginTransaction()
                    .add(TrackInfoHelperFragment.newFromSessionUri(sessionUri),
                            "track_info")
                    .commit();
        }
    }

    @Override
    protected Fragment onCreatePane() {
        return new SessionDetailFragment();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == android.R.id.home) {
            // Up to this session's track details, or Home if no track is available
            Intent parentIntent;
            if (mTrackId != null) {
                parentIntent = new Intent(Intent.ACTION_VIEW,
                        ScheduleContract.Tracks.buildTrackUri(mTrackId));
            } else {
                parentIntent = new Intent(this, HomeActivity.class);
            }

            NavUtils.navigateUpTo(this, parentIntent);
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onTrackInfoAvailable(String trackId, String trackName, int trackColor) {
        mTrackId = trackId;
        setTitle(trackName);
        // setActionBarColor(trackColor);
    }

    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    private void trySetBeamCallback() {
        if (UIUtils.hasICS()) {
            BeamUtils.setBeamCompleteCallback(this, new NfcAdapter.OnNdefPushCompleteCallback() {
                @Override
                public void onNdefPushComplete(NfcEvent event) {
                    // Beam has been sent
                    if (!BeamUtils.isBeamUnlocked(SessionDetailActivity.this)) {
                        BeamUtils.setBeamUnlocked(SessionDetailActivity.this);
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                showFirstBeamDialog();
                            }
                        });
                    }
                }
            });
        }
    }

    private void showFirstBeamDialog() {
        new AlertDialog.Builder(this)
                .setTitle(R.string.just_beamed)
                .setMessage(R.string.beam_unlocked_session)
                .setNegativeButton(R.string.close, null)
                .setPositiveButton(R.string.view_beam_session,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface di, int i) {
                                BeamUtils.launchBeamSession(SessionDetailActivity.this);
                                di.dismiss();
                            }
                        })
                .create()
                .show();
    }
} public class SessionsActivity extends SimpleSinglePaneActivity
        implements SessionsFragment.Callbacks {

    @Override
    protected Fragment onCreatePane() {
        return new SessionsFragment();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        getSupportMenuInflater().inflate(R.menu.search, menu);
        setupSearchMenuItem(menu);
        return true;
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private void setupSearchMenuItem(Menu menu) {
        MenuItem searchItem = menu.findItem(R.id.menu_search);
        if (searchItem != null && UIUtils.hasHoneycomb()) {
            SearchView searchView = (SearchView) searchItem.getActionView();
            if (searchView != null) {
                SearchManager searchManager = (SearchManager) getSystemService(SEARCH_SERVICE);
                searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
            }
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_search:
                if (!UIUtils.hasHoneycomb()) {
                    startSearch(null, false, Bundle.EMPTY, false);
                    return true;
                }
                break;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onSessionSelected(String sessionId) {
        startActivity(new Intent(Intent.ACTION_VIEW,
                ScheduleContract.Sessions.buildSessionUri(sessionId)));
        return false;
    }
} public class TrackDetailActivity extends BaseActivity implements
        ActionBar.TabListener,
        ViewPager.OnPageChangeListener,
        SessionsFragment.Callbacks,
        VendorsFragment.Callbacks,
        TrackInfoHelperFragment.Callbacks {

    private ViewPager mViewPager;
    private String mTrackId;
    private Uri mTrackUri;
    private boolean mShowVendors = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_track_detail);

        mTrackUri = getIntent().getData();
        mTrackId = ScheduleContract.Tracks.getTrackId(mTrackUri);

        mViewPager = (ViewPager) findViewById(R.id.pager);
        TrackDetailPagerAdapter trackDetailPagerAdapter = new TrackDetailPagerAdapter(getSupportFragmentManager());
        mViewPager.addOnPageChangeListener(this);
        mViewPager.setPageMarginDrawable(R.drawable.grey_border_inset_lr);
        mViewPager.setPageMargin(getResources().getDimensionPixelSize(R.dimen.page_margin_width));

        mShowVendors = false;//!ScheduleContract.Tracks.CODELABS_TRACK_ID.equals(mTrackId) && !ScheduleContract.Tracks.TECH_TALK_TRACK_ID.equals(mTrackId);
        trackDetailPagerAdapter.notifyDataSetChanged();
        mViewPager.setAdapter(trackDetailPagerAdapter);


        if (mShowVendors) {
            final ActionBar actionBar = getSupportActionBar();
            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
            actionBar.addTab(actionBar.newTab()
                    .setText(R.string.title_sessions)
                    .setTabListener(this));
            actionBar.addTab(actionBar.newTab()
                    .setText(R.string.title_vendors)
                    .setTabListener(this));
        }
        
        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction()
                    .add(TrackInfoHelperFragment.newFromTrackUri(mTrackUri), "track_info")
                    .commit();
        }
    }

    @Override
    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
        mViewPager.setCurrentItem(tab.getPosition());
    }

    @Override
    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
    }

    @Override
    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
    }

    @Override
    public void onPageScrolled(int i, float v, int i1) {
    }

    @Override
    public void onPageSelected(int position) {
        getSupportActionBar().setSelectedNavigationItem(position);
        
        int titleId = -1;
        switch (position) {
            case 0:
                titleId = R.string.title_sessions;
                break;
            case 1:
                titleId = R.string.title_vendors;
                break;
        }
        
        String title = getString(titleId);
        EasyTracker.getTracker().trackView(title + ": " + getTitle());
        LOGD("Tracker", title + ": " + getTitle());
    }

    @Override
    public void onPageScrollStateChanged(int i) {
    }

    private class TrackDetailPagerAdapter extends FragmentPagerAdapter {

        public TrackDetailPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            boolean allTracks = (ScheduleContract.Tracks.ALL_TRACK_ID.equals(mTrackId));
            if (position == 0) {
                Fragment fragment = new SessionsFragment();
                fragment.setArguments(BaseActivity.intentToFragmentArguments(new Intent(
                        Intent.ACTION_VIEW,
                        allTracks
                                ? ScheduleContract.Sessions.CONTENT_URI
                                : ScheduleContract.Tracks.buildSessionsUri(mTrackId))));
                return fragment;
            } else {
                Fragment fragment = new VendorsFragment();
                fragment.setArguments(BaseActivity.intentToFragmentArguments(new Intent(
                        Intent.ACTION_VIEW,
                        allTracks
                                ? ScheduleContract.Vendors.CONTENT_URI
                                : ScheduleContract.Tracks.buildVendorsUri(mTrackId))));
                return fragment;
            }
        }

        @Override
        public int getCount() {
            return mShowVendors ? 2 : 1;
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        getSupportMenuInflater().inflate(R.menu.track_detail, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_social_stream:
                //Intent intent = new Intent(this, SocialStreamActivity.class);
                //startActivity(intent);
                //break;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onTrackInfoAvailable(String trackId, String trackName, int trackColor) {
        setTitle(trackName);
        // setActionBarColor(trackColor);
        
        EasyTracker.getTracker().trackView(getString(R.string.title_sessions) + ": " + getTitle());
        LOGD("Tracker", getString(R.string.title_sessions) + ": " + getTitle());
    }

    @Override
    public boolean onSessionSelected(String sessionId) {
        startActivity(new Intent(Intent.ACTION_VIEW,
                ScheduleContract.Sessions.buildSessionUri(sessionId)));
        return false;
    }

    @Override
    public boolean onVendorSelected(String vendorId) {
        startActivity(new Intent(Intent.ACTION_VIEW,
                ScheduleContract.Vendors.buildVendorUri(vendorId)));
        return false;
    }
} public class VendorDetailActivity extends SimpleSinglePaneActivity implements
        VendorDetailFragment.Callbacks,
        TrackInfoHelperFragment.Callbacks {

    private String mTrackId = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    protected Fragment onCreatePane() {
        return new VendorDetailFragment();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == android.R.id.home) {
            // Up to this session's track details, or Home if no track is available
            Intent parentIntent;
            if (mTrackId != null) {
                parentIntent = new Intent(Intent.ACTION_VIEW,
                        ScheduleContract.Tracks.buildTrackUri(mTrackId));
            } else {
                parentIntent = new Intent(this, HomeActivity.class);
            }

            NavUtils.navigateUpTo(this, parentIntent);
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onTrackInfoAvailable(String trackId, String trackName, int trackColor) {
        mTrackId = trackId;
        setTitle(trackName);
        // setActionBarColor(trackColor);
    }

    @Override
    public void onTrackIdAvailable(final String trackId) {
        new Handler().post(new Runnable() {
            @Override
            public void run() {
                FragmentManager fm = getSupportFragmentManager();
                if (fm.findFragmentByTag("track_info") == null) {
                    fm.beginTransaction()
                            .add(TrackInfoHelperFragment.newFromTrackUri(
                                    ScheduleContract.Tracks.buildTrackUri(trackId)),
                                    "track_info")
                            .commit();
                }
            }
        });
    }
} @TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class MapMultiPaneActivity extends BaseActivity implements
        FragmentManager.OnBackStackChangedListener,
        MapFragment.Callbacks,
        SessionsFragment.Callbacks,
        LoaderManager.LoaderCallbacks<Cursor> {

    private boolean mPauseBackStackWatcher = false;

    private FragmentBreadCrumbs mFragmentBreadCrumbs;
    private String mSelectedRoomName;

    private MapFragment mMapFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_map);

        FragmentManager fm = getSupportFragmentManager();
        fm.addOnBackStackChangedListener(this);

        mFragmentBreadCrumbs = (FragmentBreadCrumbs) findViewById(R.id.breadcrumbs);
        mFragmentBreadCrumbs.setActivity(this);

        mMapFragment = (MapFragment) fm.findFragmentByTag("map");
        if (mMapFragment == null) {
            mMapFragment = new MapFragment();
            mMapFragment.setArguments(intentToFragmentArguments(getIntent()));

            fm.beginTransaction()
                    .add(R.id.fragment_container_map, mMapFragment, "map")
                    .commit();
        }

        findViewById(R.id.close_button).setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                clearBackStack(false);
            }
        });

        updateBreadCrumbs();
        onConfigurationChanged(getResources().getConfiguration());
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        boolean landscape = (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE);

        LinearLayout spacerView = (LinearLayout) findViewById(R.id.map_detail_spacer);
        spacerView.setOrientation(landscape ? LinearLayout.HORIZONTAL : LinearLayout.VERTICAL);
        spacerView.setGravity(landscape ? Gravity.RIGHT : Gravity.BOTTOM);

        View popupView = findViewById(R.id.map_detail_popup);
        LinearLayout.LayoutParams popupLayoutParams = (LinearLayout.LayoutParams)
                popupView.getLayoutParams();
        popupLayoutParams.width = landscape ? 0 : ViewGroup.LayoutParams.MATCH_PARENT;
        popupLayoutParams.height = landscape ? ViewGroup.LayoutParams.MATCH_PARENT : 0;
        popupView.setLayoutParams(popupLayoutParams);

        popupView.requestLayout();
    }

    private void clearBackStack(boolean pauseWatcher) {
        if (pauseWatcher) {
            mPauseBackStackWatcher = true;
        }

        FragmentManager fm = getSupportFragmentManager();
        while (fm.getBackStackEntryCount() > 0) {
            fm.popBackStackImmediate();
        }

        if (pauseWatcher) {
            mPauseBackStackWatcher = false;
        }
    }

    public void onBackStackChanged() {
        if (mPauseBackStackWatcher) {
            return;
        }

        if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
            showDetailPane(false);
        }

        updateBreadCrumbs();
    }

    private void showDetailPane(boolean show) {
        View detailPopup = findViewById(R.id.map_detail_spacer);
        if (show != (detailPopup.getVisibility() == View.VISIBLE)) {
            detailPopup.setVisibility(show ? View.VISIBLE : View.GONE);

            // Pan the map left or up depending on the orientation.
            boolean landscape = getResources().getConfiguration().orientation
                    == Configuration.ORIENTATION_LANDSCAPE;
            mMapFragment.panBy(
                    landscape ? (show ? 0.25f : -0.25f) : 0,
                    landscape ? 0 : (show ? 0.25f : -0.25f));
        }
    }

    public void updateBreadCrumbs() {
        final String title = (mSelectedRoomName != null)
                ? mSelectedRoomName
                : getString(R.string.title_sessions);
        final String detailTitle = getString(R.string.title_session_detail);

        if (getSupportFragmentManager().getBackStackEntryCount() >= 2) {
            mFragmentBreadCrumbs.setParentTitle(title, title, mFragmentBreadCrumbsClickListener);
            mFragmentBreadCrumbs.setTitle(detailTitle, detailTitle);
        } else {
            mFragmentBreadCrumbs.setParentTitle(null, null, null);
            mFragmentBreadCrumbs.setTitle(title, title);
        }
    }

    private View.OnClickListener mFragmentBreadCrumbsClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            getSupportFragmentManager().popBackStack();
        }
    };

    @Override
    public void onRoomSelected(String roomId) {
        // Load room details
        mSelectedRoomName = null;
        Bundle loadRoomDataArgs = new Bundle();
        loadRoomDataArgs.putString("room_id", roomId);
        getSupportLoaderManager().restartLoader(0, loadRoomDataArgs, this); // force load

        // Show the sessions in the room
        clearBackStack(true);
        showDetailPane(true);
        SessionsFragment fragment = new SessionsFragment();
        fragment.setArguments(BaseActivity.intentToFragmentArguments(
                new Intent(Intent.ACTION_VIEW,
                        ScheduleContract.Rooms.buildSessionsDirUri(roomId))));
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.fragment_container_detail, fragment)
                .addToBackStack(null)
                .commit();
        updateBreadCrumbs();
    }

    @Override
    public boolean onSessionSelected(String sessionId) {
        // Show the session details
        showDetailPane(true);
        SessionDetailFragment fragment = new SessionDetailFragment();
        Intent intent = new Intent(Intent.ACTION_VIEW,
                ScheduleContract.Sessions.buildSessionUri(sessionId));
        intent.putExtra(SessionDetailFragment.EXTRA_VARIABLE_HEIGHT_HEADER, true);
        fragment.setArguments(BaseActivity.intentToFragmentArguments(intent));
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.fragment_container_detail, fragment)
                .addToBackStack(null)
                .commit();
        updateBreadCrumbs();
        return false;
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle data) {
        return new CursorLoader(this,
                ScheduleContract.Rooms.buildRoomUri(data.getString("room_id")),
                RoomsQuery.PROJECTION,
                null, null, null);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
        try {
            if (!cursor.moveToFirst()) {
                return;
            }

            mSelectedRoomName = cursor.getString(RoomsQuery.ROOM_NAME);
            updateBreadCrumbs();

        } finally {
            cursor.close();
        }
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
    }

    private interface RoomsQuery {
        String[] PROJECTION = {
                ScheduleContract.Rooms.ROOM_ID,
                ScheduleContract.Rooms.ROOM_NAME,
                ScheduleContract.Rooms.ROOM_FLOOR,
        };

        int ROOM_ID = 0;
        int ROOM_NAME = 1;
        int ROOM_FLOOR = 2;
    }
} @TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class SessionsVendorsMultiPaneActivity extends BaseActivity implements
        ActionBar.TabListener,
        SessionsFragment.Callbacks,
        VendorsFragment.Callbacks,
        VendorDetailFragment.Callbacks,
        TracksDropdownFragment.Callbacks,
        TrackInfoHelperFragment.Callbacks {

    public static final String EXTRA_MASTER_URI =
            "com.google.android.apps.iosched.extra.MASTER_URI";

    private static final String STATE_VIEW_TYPE = "view_type";

    private TracksDropdownFragment mTracksDropdownFragment;
    private Fragment mDetailFragment;
    private boolean mFullUI = false;

    private ShowHideMasterLayout mShowHideMasterLayout;

    private String mViewType;

    private boolean mInitialTabSelect = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        if (BeamUtils.wasLaunchedThroughBeamFirstTime(this, getIntent())) {
            BeamUtils.setBeamUnlocked(this);
            showFirstBeamDialog();
        }

        BeamUtils.tryUpdateIntentFromBeam(this);

        super.onCreate(savedInstanceState);

        trySetBeamCallback();

        setContentView(R.layout.activity_sessions_vendors);

        final FragmentManager fm = getSupportFragmentManager();
        mTracksDropdownFragment = (TracksDropdownFragment) fm.findFragmentById(
                R.id.fragment_tracks_dropdown);

        mShowHideMasterLayout = (ShowHideMasterLayout) findViewById(R.id.show_hide_master_layout);
        if (mShowHideMasterLayout != null) {
            mShowHideMasterLayout.setFlingToExposeMasterEnabled(true);
        }

        routeIntent(getIntent(), savedInstanceState != null);

        if (savedInstanceState != null) {
            if (mFullUI) {
                getSupportActionBar().setSelectedNavigationItem(
                        TracksDropdownFragment.VIEW_TYPE_SESSIONS.equals(
                                savedInstanceState.getString(STATE_VIEW_TYPE)) ? 0 : 1);
            }

            mDetailFragment = fm.findFragmentById(R.id.fragment_container_detail);
            updateDetailBackground();
        }

        // This flag prevents onTabSelected from triggering extra master pane reloads
        // unless it's actually being triggered by the user (and not automatically by
        // the system)
        mInitialTabSelect = false;

        EasyTracker.getTracker().setContext(this);
    }

    private void routeIntent(Intent intent, boolean updateSurfaceOnly) {
        Uri uri = intent.getData();
        if (uri == null) {
            return;
        }

        if (intent.hasExtra(Intent.EXTRA_TITLE)) {
            setTitle(intent.getStringExtra(Intent.EXTRA_TITLE));
        }

        String mimeType = getContentResolver().getType(uri);

        if (ScheduleContract.Tracks.CONTENT_ITEM_TYPE.equals(mimeType)) {
            // Load track details
            showFullUI(true);
            if (!updateSurfaceOnly) {
                // TODO: don't assume the URI will contain the track ID
                String selectedTrackId = ScheduleContract.Tracks.getTrackId(uri);
                loadTrackList(TracksDropdownFragment.VIEW_TYPE_SESSIONS, selectedTrackId);
                onTrackSelected(selectedTrackId);
                if (mShowHideMasterLayout != null) {
                    mShowHideMasterLayout.showMaster(true, ShowHideMasterLayout.FLAG_IMMEDIATE);
                }
            }

        } else if (ScheduleContract.Sessions.CONTENT_TYPE.equals(mimeType)) {
            // Load a session list, hiding the tracks dropdown and the tabs
            mViewType = TracksDropdownFragment.VIEW_TYPE_SESSIONS;
            showFullUI(false);
            if (!updateSurfaceOnly) {
                loadSessionList(uri, null);
                if (mShowHideMasterLayout != null) {
                    mShowHideMasterLayout.showMaster(true, ShowHideMasterLayout.FLAG_IMMEDIATE);
                }
            }

        } else if (ScheduleContract.Sessions.CONTENT_ITEM_TYPE.equals(mimeType)) {
            // Load session details
            if (intent.hasExtra(EXTRA_MASTER_URI)) {
                mViewType = TracksDropdownFragment.VIEW_TYPE_SESSIONS;
                showFullUI(false);
                if (!updateSurfaceOnly) {
                    loadSessionList((Uri) intent.getParcelableExtra(EXTRA_MASTER_URI),
                            ScheduleContract.Sessions.getSessionId(uri));
                    loadSessionDetail(uri);
                }
            } else {
                mViewType = TracksDropdownFragment.VIEW_TYPE_SESSIONS; // prepare for onTrackInfo...
                showFullUI(true);
                if (!updateSurfaceOnly) {
                    loadSessionDetail(uri);
                    loadTrackInfoFromSessionUri(uri);
                }
            }

        } else if (ScheduleContract.Vendors.CONTENT_TYPE.equals(mimeType)) {
            // Load a vendor list
            mViewType = TracksDropdownFragment.VIEW_TYPE_VENDORS;
            showFullUI(false);
            if (!updateSurfaceOnly) {
                loadVendorList(uri, null);
                if (mShowHideMasterLayout != null) {
                    mShowHideMasterLayout.showMaster(true, ShowHideMasterLayout.FLAG_IMMEDIATE);
                }
            }

        } else if (ScheduleContract.Vendors.CONTENT_ITEM_TYPE.equals(mimeType)) {
            // Load vendor details
            mViewType = TracksDropdownFragment.VIEW_TYPE_VENDORS;
            showFullUI(false);
            if (!updateSurfaceOnly) {
                Uri masterUri = (Uri) intent.getParcelableExtra(EXTRA_MASTER_URI);
                if (masterUri == null) {
                    masterUri = ScheduleContract.Vendors.CONTENT_URI;
                }
                loadVendorList(masterUri, ScheduleContract.Vendors.getVendorId(uri));
                loadVendorDetail(uri);
            }
        }

        updateDetailBackground();
    }

    private void showFullUI(boolean fullUI) {
        mFullUI = fullUI;
        final ActionBar actionBar = getSupportActionBar();
        final FragmentManager fm = getSupportFragmentManager();

        if (fullUI) {
            actionBar.removeAllTabs();
            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
            actionBar.setDisplayShowTitleEnabled(false);
            actionBar.addTab(actionBar.newTab()
                    .setText(R.string.title_sessions)
                    .setTag(TracksDropdownFragment.VIEW_TYPE_SESSIONS)
                    .setTabListener(this));
            //actionBar.addTab(actionBar.newTab()
            //        .setText(R.string.title_vendors)
            //        .setTag(TracksDropdownFragment.VIEW_TYPE_VENDORS)
            //        .setTabListener(this));

            fm.beginTransaction()
                    .show(fm.findFragmentById(R.id.fragment_tracks_dropdown))
                    .commit();
        } else {
            actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
            actionBar.setDisplayShowTitleEnabled(true);

            fm.beginTransaction()
                    .hide(fm.findFragmentById(R.id.fragment_tracks_dropdown))
                    .commit();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        getSupportMenuInflater().inflate(R.menu.search, menu);
        MenuItem searchItem = menu.findItem(R.id.menu_search);
        if (searchItem != null && UIUtils.hasHoneycomb()) {
            SearchView searchView = (SearchView) searchItem.getActionView();
            if (searchView != null) {
                SearchManager searchManager = (SearchManager) getSystemService(SEARCH_SERVICE);
                searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
            }
        }
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                if (mShowHideMasterLayout != null && !mShowHideMasterLayout.isMasterVisible()) {
                    // If showing the detail view, pressing Up should show the master pane.
                    mShowHideMasterLayout.showMaster(true, 0);
                    return true;
                }
                break;

            case R.id.menu_search:
                if (!UIUtils.hasHoneycomb()) {
                    startSearch(null, false, Bundle.EMPTY, false);
                    return true;
                }
                break;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString(STATE_VIEW_TYPE, mViewType);
    }

    @Override
    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
        loadTrackList((String) tab.getTag());
        if (!mInitialTabSelect) {
            onTrackSelected(mTracksDropdownFragment.getSelectedTrackId());
            if (mShowHideMasterLayout != null) {
                mShowHideMasterLayout.showMaster(true, 0);
            }
        }
    }

    @Override
    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
    }

    @Override
    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
    }

    private void loadTrackList(String viewType) {
        loadTrackList(viewType, null);
    }

    private void loadTrackList(String viewType, String selectTrackId) {
        if (mDetailFragment != null && !mViewType.equals(viewType)) {
            getSupportFragmentManager().beginTransaction()
                    .remove(mDetailFragment)
                    .commit();
            mDetailFragment = null;
        }

        mViewType = viewType;
        if (selectTrackId != null) {
            mTracksDropdownFragment.loadTrackList(viewType, selectTrackId);
        } else {
            mTracksDropdownFragment.loadTrackList(viewType);
        }

        updateDetailBackground();
    }

    private void updateDetailBackground() {
        if (mDetailFragment == null) {
            if (TracksDropdownFragment.VIEW_TYPE_SESSIONS.equals(mViewType)) {
                findViewById(R.id.fragment_container_detail).setBackgroundResource(
                        R.drawable.grey_frame_on_white_empty_sessions);
            } else {
                findViewById(R.id.fragment_container_detail).setBackgroundResource(
                        R.drawable.grey_frame_on_white_empty_sandbox);
            }
        } else {
            findViewById(R.id.fragment_container_detail).setBackgroundResource(
                    R.drawable.grey_frame_on_white);
        }
    }

    private void loadSessionList(Uri sessionsUri, String selectSessionId) {
        SessionsFragment fragment = new SessionsFragment();
        fragment.setSelectedSessionId(selectSessionId);
        fragment.setArguments(BaseActivity.intentToFragmentArguments(
                new Intent(Intent.ACTION_VIEW, sessionsUri)));
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.fragment_container_master, fragment)
                .commit();
    }

    private void loadSessionDetail(Uri sessionUri) {
        BeamUtils.setBeamSessionUri(this, sessionUri);
        SessionDetailFragment fragment = new SessionDetailFragment();
        fragment.setArguments(BaseActivity.intentToFragmentArguments(
                new Intent(Intent.ACTION_VIEW, sessionUri)));
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.fragment_container_detail, fragment)
                .commit();
        mDetailFragment = fragment;
        updateDetailBackground();

        // If loading session details in portrait, hide the master pane
        if (mShowHideMasterLayout != null) {
            mShowHideMasterLayout.showMaster(false, 0);
        }
    }

    private void loadVendorList(Uri vendorsUri, String selectVendorId) {
        VendorsFragment fragment = new VendorsFragment();
        fragment.setSelectedVendorId(selectVendorId);
        fragment.setArguments(BaseActivity.intentToFragmentArguments(
                new Intent(Intent.ACTION_VIEW, vendorsUri)));
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.fragment_container_master, fragment)
                .commit();
    }

    private void loadVendorDetail(Uri vendorUri) {
        VendorDetailFragment fragment = new VendorDetailFragment();
        fragment.setArguments(BaseActivity.intentToFragmentArguments(
                new Intent(Intent.ACTION_VIEW, vendorUri)));
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.fragment_container_detail, fragment)
                .commit();
        mDetailFragment = fragment;
        updateDetailBackground();

        // If loading session details in portrait, hide the master pane
        if (mShowHideMasterLayout != null) {
            mShowHideMasterLayout.showMaster(false, 0);
        }
    }

    @Override
    public void onTrackNameAvailable(String trackId, String trackName) {
        String trackType;

        if (TracksDropdownFragment.VIEW_TYPE_SESSIONS.equals(mViewType)) {
            trackType = getString(R.string.title_sessions);
        } else {
            trackType = getString(R.string.title_vendors);
        }

        EasyTracker.getTracker().trackView(trackType + ": " + getTitle());
        LOGD("Tracker", trackType + ": " + mTracksDropdownFragment.getTrackName());
    }

    @Override
    public void onTrackSelected(String trackId) {
        boolean allTracks = (ScheduleContract.Tracks.ALL_TRACK_ID.equals(trackId));

        if (TracksDropdownFragment.VIEW_TYPE_SESSIONS.equals(mViewType)) {
            loadSessionList(allTracks
                    ? ScheduleContract.Sessions.CONTENT_URI
                    : ScheduleContract.Tracks.buildSessionsUri(trackId), null);

        } else {
            loadVendorList(allTracks
                    ? ScheduleContract.Vendors.CONTENT_URI
                    : ScheduleContract.Tracks.buildVendorsUri(trackId), null);

        }
    }

    @Override
    public boolean onSessionSelected(String sessionId) {
        loadSessionDetail(ScheduleContract.Sessions.buildSessionUri(sessionId));
        return true;
    }

    @Override
    public boolean onVendorSelected(String vendorId) {
        loadVendorDetail(ScheduleContract.Vendors.buildVendorUri(vendorId));
        return true;
    }

    private TrackInfoHelperFragment mTrackInfoHelperFragment;
    private String mTrackInfoLoadCookie;

    private void loadTrackInfoFromSessionUri(Uri sessionUri) {
        mTrackInfoLoadCookie = ScheduleContract.Sessions.getSessionId(sessionUri);
        Uri trackDirUri = ScheduleContract.Sessions.buildTracksDirUri(
                ScheduleContract.Sessions.getSessionId(sessionUri));
        android.support.v4.app.FragmentTransaction ft =
                getSupportFragmentManager().beginTransaction();
        if (mTrackInfoHelperFragment != null) {
            ft.remove(mTrackInfoHelperFragment);
        }
        mTrackInfoHelperFragment = TrackInfoHelperFragment.newFromTrackUri(trackDirUri);
        ft.add(mTrackInfoHelperFragment, "track_info").commit();
    }

    @Override
    public void onTrackInfoAvailable(String trackId, String trackName, int trackColor) {
        loadTrackList(mViewType, trackId);
        boolean allTracks = (ScheduleContract.Tracks.ALL_TRACK_ID.equals(trackId));

        if (TracksDropdownFragment.VIEW_TYPE_SESSIONS.equals(mViewType)) {
            loadSessionList(allTracks
                    ? ScheduleContract.Sessions.CONTENT_URI
                    : ScheduleContract.Tracks.buildSessionsUri(trackId),
                    mTrackInfoLoadCookie);
        } else {
            loadVendorList(allTracks
                    ? ScheduleContract.Vendors.CONTENT_URI
                    : ScheduleContract.Tracks.buildVendorsUri(trackId),
                    mTrackInfoLoadCookie);
        }
    }

    @Override
    public void onTrackIdAvailable(String trackId) {
    }

    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    private void trySetBeamCallback() {
        if (UIUtils.hasICS()) {
            BeamUtils.setBeamCompleteCallback(this, new NfcAdapter.OnNdefPushCompleteCallback() {
                @Override
                public void onNdefPushComplete(NfcEvent event) {
                    // Beam has been sent
                    if (!BeamUtils.isBeamUnlocked(SessionsVendorsMultiPaneActivity.this)) {
                        BeamUtils.setBeamUnlocked(SessionsVendorsMultiPaneActivity.this);
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                showFirstBeamDialog();
                            }
                        });
                    }
                }
            });
        }
    }

    private void showFirstBeamDialog() {
        new AlertDialog.Builder(this)
                .setTitle(R.string.just_beamed)
                .setMessage(R.string.beam_unlocked_session)
                .setNegativeButton(R.string.close, null)
                .setPositiveButton(R.string.view_beam_session,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface di, int i) {
                                BeamUtils.launchBeamSession(SessionsVendorsMultiPaneActivity.this);
                                di.dismiss();
                            }
                        })
                .create()
                .show();
    }
}
import android.annotation.TargetApi;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.Typeface;
import android.os.Build;
import android.preference.PreferenceManager;
import android.support.v4.app.FragmentActivity;
import android.text.Html;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.method.LinkMovementMethod;
import android.text.style.StyleSpan;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.apps.iosched.io.model.Constants;
import com.google.android.apps.iosched.provider.ScheduleContract.Blocks;
import com.google.android.apps.iosched.provider.ScheduleContract.Rooms;
import com.google.android.apps.iosched.ui.phone.MapActivity;
import com.google.android.apps.iosched.ui.phone.SessionDetailActivity;
import com.google.android.apps.iosched.ui.phone.SessionsActivity;
import com.google.android.apps.iosched.ui.phone.TrackDetailActivity;
import com.google.android.apps.iosched.ui.phone.VendorDetailActivity;
import com.google.android.apps.iosched.ui.tablet.MapMultiPaneActivity;
import com.google.android.apps.iosched.ui.tablet.SessionsVendorsMultiPaneActivity;
import java.util.Calendar;
import java.util.Formatter;
import java.util.Locale;
import java.util.TimeZone;
import no.java.schedule.BuildConfig;
import no.java.schedule.R;
                    sLivestreamAvailableText = Html.fromHtml(
                            context.getString(R.string.live_available_badge));
                }
                if (!empty) {
                    sb.append("  ");
                }
                sb.append(sLivestreamAvailableText);
            }

            subtitleView.setText(sb);
        }
    }

    /**
     * Given a snippet string with matching segments surrounded by curly
     * braces, turn those areas into bold spans, removing the curly braces.
     */
    public static Spannable buildStyledSnippet(String snippet) {
        final SpannableStringBuilder builder = new SpannableStringBuilder(snippet);

        // Walk through string, inserting bold snippet spans
        int startIndex = -1, endIndex = -1, delta = 0;
        while ((startIndex = snippet.indexOf('{', endIndex)) != -1) {
            endIndex = snippet.indexOf('}', startIndex);

            // Remove braces from both sides
            builder.delete(startIndex - delta, startIndex - delta + 1);
            builder.delete(endIndex - delta - 1, endIndex - delta);

            // Insert bold style
            builder.setSpan(sBoldSpan, startIndex - delta, endIndex - delta - 1,
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

            delta += 2;
        }

        return builder;
    }

    public static void preferPackageForIntent(Context context, Intent intent, String packageName) {
        PackageManager pm = context.getPackageManager();
        for (ResolveInfo resolveInfo : pm.queryIntentActivities(intent, 0)) {
            if (resolveInfo.activityInfo.packageName.equals(packageName)) {
                intent.setPackage(packageName);
                break;
            }
        }
    }

    public static ImageFetcher getImageFetcher(final FragmentActivity activity) {
        // The ImageFetcher takes care of loading remote images into our ImageView
        ImageFetcher fetcher = new ImageFetcher(activity);
        fetcher.setImageCache(ImageCache.findOrCreateCache(activity, "imageFetcher"));
        return fetcher;
    }

    public static String getSessionHashtagsString(String hashtags) {
        if (!TextUtils.isEmpty(hashtags)) {
            if (!hashtags.startsWith("#")) {
                hashtags = "#" + hashtags;
            }

            if (hashtags.contains(CONFERENCE_HASHTAG)) {
                return hashtags;
            }
            return CONFERENCE_HASHTAG + " " + hashtags;
        } else {
            return CONFERENCE_HASHTAG;
        }
    }

    private static final int BRIGHTNESS_THRESHOLD = 130;

    /**
     * Calculate whether a color is light or dark, based on a commonly known
     * brightness formula.
     *
     * @see {@literal http://en.wikipedia.org/wiki/HSV_color_space%23Lightness}
     */
    public static boolean isColorDark(int color) {
        return Color.alpha(color) != 0 && (((30 * Color.red(color) +
                59 * Color.green(color) +
                11 * Color.blue(color)) / 100) <= BRIGHTNESS_THRESHOLD);
    }

    // Shows whether a notification was fired for a particular session time block. In the
    // event that notification has not been fired yet, return false and set the bit.
    public static boolean isNotificationFiredForBlock(Context context, String blockId) {
        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
        final String key = String.format("notification_fired_%s", blockId);
        boolean fired = sp.getBoolean(key, false);
        sp.edit().putBoolean(key, true).commit();
        return fired;
    }

    private static final long sAppLoadTime = System.currentTimeMillis();

    public static long getCurrentTime(final Context context) {
        if (BuildConfig.DEBUG) {
            return context.getSharedPreferences("mock_data", Context.MODE_PRIVATE)
                    .getLong("mock_current_time", System.currentTimeMillis())
                    + System.currentTimeMillis() - sAppLoadTime;
        } else {
            return System.currentTimeMillis();
        }
    }

    public static void safeOpenLink(Context context, Intent linkIntent) {
        try {
            context.startActivity(linkIntent);
        } catch (ActivityNotFoundException e) {
            Toast.makeText(context, "Couldn't open link", Toast.LENGTH_SHORT).show();
        }
    }

    // TODO: use <meta-data> element instead
    private static final Class[] sPhoneActivities = new Class[]{
            MapActivity.class,
            SessionDetailActivity.class,
            SessionsActivity.class,
            TrackDetailActivity.class,