mobisocial.musubi.ui.fragments.AppSelectDialog.java Source code

Java tutorial

Introduction

Here is the source code for mobisocial.musubi.ui.fragments.AppSelectDialog.java

Source

/*
 * Copyright 2012 The Stanford MobiSocial Laboratory
 *
 * 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 mobisocial.musubi.ui.fragments;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import mobisocial.musubi.App;
import mobisocial.musubi.R;
import mobisocial.musubi.feed.iface.FeedAction;
import mobisocial.musubi.model.MApp;
import mobisocial.musubi.model.helpers.AppManager;
import mobisocial.musubi.model.helpers.FeedManager;
import mobisocial.musubi.objects.WebAppObj;
import mobisocial.musubi.provider.MusubiContentProvider;
import mobisocial.musubi.provider.MusubiContentProvider.Provided;
import mobisocial.musubi.ui.MusubiBaseActivity;
import mobisocial.musubi.util.InstrumentedActivity;
import mobisocial.musubi.webapp.AppCorralActivity;
import mobisocial.musubi.webapp.WebAppActivity;
import mobisocial.socialkit.Obj;
import mobisocial.socialkit.musubi.Musubi;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.ContentUris;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.LabeledIntent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.app.SupportActivity;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.text.TextUtils.TruncateAt;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class AppSelectDialog extends DialogFragment implements LoaderCallbacks<List<AppSelectDialog.IMusubiApp>> {
    private static final String TAG = "LaunchAppDialog";
    private static final boolean DBG = MusubiBaseActivity.DBG;
    private Uri mFeedUri;
    private MusubiAppAdapter mAppAdapter;
    private boolean mHomeScreen;
    private IMusubiApp mSelectedApp;
    private IMusubiApp mMusubiFeedApp;

    private Activity mActivity;

    private static final String ARG_FEED_URI = "feedUri";
    private static final String ARG_HOME_SCREEN = "homeScreen";

    static final String CATEGORY_MUSUBI_MENU = "musubi.intent.category.MENU";

    public static final String SKETCH_APP_ID = "musubi.sketch";
    public static final String SHOUT_APP_ID = "musubi.shout";

    public static AppSelectDialog newInstance(boolean forHomeScreen, Uri feedUri) {
        if (DBG)
            Log.d(TAG, "New AppSelectDialog.");

        AppSelectDialog frag = new AppSelectDialog();
        Bundle args = new Bundle();
        args.putParcelable(ARG_FEED_URI, feedUri);
        args.putBoolean(ARG_HOME_SCREEN, forHomeScreen);
        frag.setArguments(args);
        return frag;
    }

    @Override
    public void onAttach(SupportActivity activity) {
        super.onAttach(activity);
        mActivity = activity.asActivity();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setStyle(STYLE_NO_TITLE, R.style.Theme_D1dialog);

        mFeedUri = getArguments().getParcelable(ARG_FEED_URI);
        mHomeScreen = getArguments().getBoolean(ARG_HOME_SCREEN);
        if (getTargetFragment() != null) {
            setRetainInstance(true);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.applaunch_dialog, container, false);
        final Activity context = mActivity;
        if (mHomeScreen) {
            view.findViewById(R.id.appbar).setVisibility(View.GONE);
            mMusubiFeedApp = new MusubiFeed(context);
            mSelectedApp = mMusubiFeedApp;
        } else {
            setActionItems((ViewGroup) view.findViewById(R.id.appbar));
        }

        ListView listView = (ListView) view.findViewById(android.R.id.list);
        mAppAdapter = new MusubiAppAdapter(context);
        listView.setAdapter(mAppAdapter);
        listView.setOnItemClickListener(mAppAdapter);
        listView.setOnItemLongClickListener(mAppAdapter);
        view.findViewById(R.id.content).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent webStore = new Intent(context, AppCorralActivity.class);
                webStore.putExtra(Musubi.EXTRA_FEED_URI, mFeedUri);
                startActivity(webStore);
                getDialog().dismiss();
            }
        });
        getLoaderManager().initLoader(0, null, this);
        return view;
    }

    private void setActionItems(ViewGroup view) {
        final Context context = mActivity;
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        List<FeedAction> actions = FeedAction.getFeedActions();
        for (final FeedAction a : actions) {
            if (a.isActive(context)) {
                ft.add(a, a.getName());
                ImageButton b = new ImageButton(context);
                b.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
                b.setImageDrawable(a.getIcon(mActivity));
                b.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        a.onClick(context, mFeedUri);
                        Dialog d = getDialog();
                        if (d != null)
                            d.dismiss();
                    }
                });
                view.addView(b);
            }
        }
        ft.commit();
    }

    private class MusubiAppAdapter extends ArrayAdapter<IMusubiApp>
            implements OnItemClickListener, OnItemLongClickListener {
        private final Context mContext;

        public MusubiAppAdapter(Context context) {
            super(context, 0, 0);
            mContext = context;
        }

        public MusubiAppAdapter(Context context, List<IMusubiApp> objects) {
            super(context, 0, 0, objects);
            mContext = context;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if (convertView == null) {
                convertView = newView(parent);
            }

            IMusubiApp app = getItem(position);
            ((TextView) convertView.findViewById(R.id.text)).setText(app.getName());
            ((ImageView) convertView.findViewById(R.id.icon)).setImageDrawable(app.getIcon());
            return convertView;
        }

        private View newView(ViewGroup parent) {
            LinearLayout frame = new LinearLayout(mContext);
            AbsListView.LayoutParams lp = new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT,
                    AbsListView.LayoutParams.MATCH_PARENT);
            frame.setLayoutParams(lp);
            frame.setOrientation(LinearLayout.HORIZONTAL);
            frame.setGravity(Gravity.CENTER_HORIZONTAL);

            ImageView icon = new ImageView(mContext);
            icon.setId(R.id.icon);
            icon.setLayoutParams(new LayoutParams(80, 80));
            icon.setPadding(6, 6, 6, 6);
            frame.addView(icon);

            TextView label = new TextView(mContext);
            label.setId(R.id.text);
            label.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.MATCH_PARENT));
            label.setTextSize(24);
            label.setEllipsize(TruncateAt.END);
            label.setGravity(Gravity.CENTER_VERTICAL);
            frame.addView(label);

            return frame;
        }

        @Override
        public void onItemClick(AdapterView<?> adapterView, View view, int item, long itemId) {
            mSelectedApp = getItem(item);
            Fragment target = getTargetFragment();
            if (target != null) {
                int requestCode = getTargetRequestCode();
                getTargetFragment().onActivityResult(requestCode, Activity.RESULT_OK, null);
            } else {
                Intent launch = new Intent(mSelectedApp.getLaunchIntent(mActivity, mFeedUri));
                String appIdStr = mSelectedApp.getAppId();
                long feedId = ContentUris.parseId(mFeedUri);

                SQLiteOpenHelper db = App.getDatabaseSource(getActivity());
                MApp app = new AppManager(db).ensureApp(appIdStr);
                new FeedManager(db).ensureFeedApp(feedId, app.id_);
                mActivity.startActivity(launch);
            }
            dismiss();
        }

        @Override
        public boolean onItemLongClick(AdapterView<?> adapterView, View view, int item, long itemId) {
            IMusubiApp app = getItem(item);
            if (!(app instanceof MusubiWebApp)) {
                return false;
            }
            MusubiWebApp web = (MusubiWebApp) app;
            String appId = web.getAppId();
            String name = web.getName();

            if (SKETCH_APP_ID.equals(appId) || SHOUT_APP_ID.equals(appId)) {
                return false;
            }

            //TODO: add an internal flag or something that we can consult when deciding if the 
            //delete option should be available
            ((InstrumentedActivity) getActivity()).showDialog(WebAppContextMenu.newInstance(appId, name));
            return true;
        }
    }

    /**
     * Gets the app the user currently has selected.
     */
    public IMusubiApp getSelectedApp() {
        return mSelectedApp;
    }

    public interface IMusubiApp {
        public String getAppId();

        public String getName();

        public Drawable getIcon();

        public LabeledIntent getLaunchIntent(Context context, Uri feedUri);
    }

    /**
     * An "app" that is just a Musubi feed.
     */
    static class MusubiFeed implements IMusubiApp {
        final Context mContext;

        public MusubiFeed(Context c) {
            mContext = c;
        }

        @Override
        public String getName() {
            return "New Conversation...";
        }

        @Override
        public Drawable getIcon() {
            return mContext.getResources().getDrawable(R.drawable.ic_text_holo_light);
        }

        @Override
        public LabeledIntent getLaunchIntent(Context context, Uri feedUri) {
            Intent i = new Intent(Intent.ACTION_VIEW);
            i.setDataAndType(feedUri, MusubiContentProvider.getType(Provided.FEEDS_ID));
            i.setPackage(context.getPackageName());
            LabeledIntent l = new LabeledIntent(i, context.getPackageName(), getName(),
                    R.drawable.ic_text_holo_light);
            return l;
        }

        @Override
        public String getAppId() {
            return MusubiContentProvider.SUPER_APP_ID;
        }
    }

    public static class MusubiWebApp implements IMusubiApp {
        final String mName;
        final String mWebAppUrl;
        final String mAppId;
        final Context mContext;
        final int mIconResource;

        public MusubiWebApp(Context context, String name, String appId, String webAppUrl, int iconResource) {
            mContext = context;
            mName = name;
            mAppId = appId;
            mWebAppUrl = webAppUrl;
            mIconResource = iconResource;
        }

        @Override
        public String getName() {
            return mName;
        }

        public Drawable getIcon() {
            return mContext.getResources().getDrawable(mIconResource);
        }

        public Uri getUri() {
            return Uri.parse(mWebAppUrl);
        }

        @Override
        public LabeledIntent getLaunchIntent(Context context, Uri feedUri) {
            Intent appIntent = new Intent(Intent.ACTION_VIEW);
            appIntent.setClass(context, WebAppActivity.class);
            appIntent.putExtra(Musubi.EXTRA_FEED_URI, feedUri);
            appIntent.putExtra(WebAppActivity.EXTRA_APP_NAME, mName);
            appIntent.putExtra(WebAppActivity.EXTRA_APP_URI, getUri());
            appIntent.putExtra(WebAppActivity.EXTRA_APP_ID, mAppId);
            LabeledIntent labeled = new LabeledIntent(appIntent, context.getPackageName(), mName, mIconResource);
            return labeled;
        }

        @Override
        public String getAppId() {
            return mAppId;
        }
    }

    static class MusubiInstalledApp implements IMusubiApp {
        private final PackageManager mPackageManager;
        private final ResolveInfo mInfo;
        private final String mLabel;

        public MusubiInstalledApp(PackageManager pm, ResolveInfo info) {
            mPackageManager = pm;
            mInfo = info;
            mLabel = info.loadLabel(pm).toString();
        }

        public ResolveInfo getAppInfo() {
            return mInfo;
        }

        @Override
        public String getName() {
            return mLabel;
        }

        @Override
        public Drawable getIcon() {
            return getAppInfo().loadIcon(mPackageManager);
        }

        @Override
        public LabeledIntent getLaunchIntent(Context context, Uri feedUri) {
            String sourcePkg = getAppInfo().activityInfo.packageName;
            int labelRes = getAppInfo().activityInfo.labelRes;
            int iconRes = getAppInfo().activityInfo.icon;

            Intent intent = new Intent(Intent.ACTION_MAIN);
            intent.addCategory(CATEGORY_MUSUBI_MENU);
            intent.setClassName(sourcePkg, getAppInfo().activityInfo.name);
            intent.putExtra(Musubi.EXTRA_FEED_URI, feedUri);
            LabeledIntent labeled = new LabeledIntent(intent, sourcePkg, labelRes, iconRes);
            return labeled;
        }

        @Override
        public String getAppId() {
            return getAppInfo().activityInfo.packageName;
        }
    }

    public interface OnAppSelectedListener {
        public void onAppSelected(AppSelectDialog dialog, IMusubiApp app);
    }

    static class WebAppContextMenu extends DialogFragment {
        static final String APP_ID = "app_id";
        static final String NAME = "name";

        public static WebAppContextMenu newInstance(String appId, String name) {
            WebAppContextMenu d = new WebAppContextMenu();
            Bundle b = new Bundle();
            b.putString(APP_ID, appId);
            b.putString(NAME, name);
            d.setArguments(b);
            return d;
        }

        public WebAppContextMenu() {
        }

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            final String name = getArguments().getString(NAME);
            final String appId = getArguments().getString(APP_ID);

            return new AlertDialog.Builder(getActivity()).setTitle(name).setItems(
                    new String[] { "Remove", "Copy to clipboard" }, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            if (which == 0) {
                                AppManager am = new AppManager(App.getDatabaseSource(getActivity()));
                                am.deleteAppWithId(appId);
                                getActivity().getContentResolver()
                                        .notifyChange(MusubiContentProvider.uriForDir(Provided.OBJECTS), null);
                                Toast.makeText(getActivity(), "Removed app " + name + ".", Toast.LENGTH_SHORT)
                                        .show();
                            } else if (which == 1) {
                                AppManager am = new AppManager(App.getDatabaseSource(getActivity()));
                                MApp app = am.lookupAppByAppId(appId);
                                if (app == null) {
                                    Toast.makeText(getActivity(), "Error getting app.", Toast.LENGTH_SHORT).show();
                                    return;
                                }
                                if (app.webAppUrl_ == null) {
                                    Toast.makeText(getActivity(), "Not a copyable app.", Toast.LENGTH_SHORT).show();
                                    return;
                                }
                                Obj obj = WebAppObj.forUri(Uri.parse(app.webAppUrl_));
                                new ClipboardKeeper(getActivity()).store(obj);
                                Toast.makeText(getActivity(),
                                        "Put content on your clipboard. Use the pin menu to paste it.",
                                        Toast.LENGTH_SHORT).show();
                            }
                        }
                    }).create();
        }
    }

    @Override
    public Loader<List<IMusubiApp>> onCreateLoader(int id, Bundle args) {
        return new MusubiAppLoader(getActivity());
    }

    @Override
    public void onLoadFinished(Loader<List<IMusubiApp>> loader, List<IMusubiApp> data) {
        mAppAdapter.clear();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            mAppAdapter.addAll(data);
        } else {
            for (IMusubiApp app : data) {
                mAppAdapter.add(app);
            }
        }
    }

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

    static class MusubiAppLoader extends AsyncTaskLoader<List<IMusubiApp>> {
        private List<IMusubiApp> mData;

        public MusubiAppLoader(Context context) {
            super(context);
        }

        @Override
        protected void onStartLoading() {
            if (mData != null) {
                deliverResult(mData);
            } else {
                forceLoad();
            }
        }

        @Override
        public List<IMusubiApp> loadInBackground() {
            mData = getAvailableApps(getContext());
            return mData;
        }

        private List<IMusubiApp> getAvailableApps(Context context) {
            final PackageManager mgr = context.getPackageManager();
            final List<IMusubiApp> apps = new LinkedList<IMusubiApp>();

            // Web Apps
            apps.addAll(getWebApps(context));

            // User installed apps
            Intent i = new Intent();
            List<ResolveInfo> infos;
            i.setAction(Intent.ACTION_MAIN);
            i.addCategory(CATEGORY_MUSUBI_MENU);
            infos = mgr.queryIntentActivities(i, 0);
            if (DBG)
                Log.d(TAG, "Queried " + infos.size() + " feed apps.");
            for (int j = 0; j < infos.size(); j++) {
                apps.add(new MusubiInstalledApp(mgr, infos.get(j)));
            }

            return apps;
        }

        List<MusubiWebApp> getWebApps(Context context) {
            SQLiteDatabase db = App.getDatabaseSource(context).getReadableDatabase();
            String table = MApp.TABLE;
            String[] columns = new String[] { MApp.COL_ID, MApp.COL_APP_ID, MApp.COL_NAME, MApp.COL_WEB_APP_URL };
            String selection = MApp.COL_WEB_APP_URL + " is not null AND " + MApp.COL_DELETED + "=0";
            String[] selectionArgs = null;
            String groupBy = null, having = null, orderBy = null;
            Cursor c = db.query(table, columns, selection, selectionArgs, groupBy, having, orderBy);

            List<MusubiWebApp> apps = new ArrayList<MusubiWebApp>();
            try {
                while (c.moveToNext()) {
                    String appId = c.getString(1);
                    String name = c.getString(2);
                    String webUrl = c.getString(3);

                    int iconResource;
                    if (SKETCH_APP_ID.equals(appId)) {
                        iconResource = R.drawable.sketch;
                    } else if (SHOUT_APP_ID.equals(appId)) {
                        iconResource = R.drawable.shout;
                    } else {
                        iconResource = R.drawable.ic_menu_globe;
                    }
                    apps.add(new MusubiWebApp(context, name, appId, webUrl, iconResource));
                }
                return apps;
            } finally {
                c.close();
            }
        }
    }
}