Java tutorial
/* * Copyright (C) 2011 The Stanford MobiSocial Laboratory * * This file is part of Musubi, a mobile social network. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package edu.stanford.mobisocial.dungbeetle.feed.objects; import java.util.List; import mobisocial.socialkit.Obj; import mobisocial.socialkit.SignedObj; import mobisocial.socialkit.musubi.DbObj; import mobisocial.socialkit.musubi.multiplayer.Multiplayer; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.app.Activity; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.view.Gravity; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import edu.stanford.mobisocial.dungbeetle.App; import edu.stanford.mobisocial.dungbeetle.DBHelper; import edu.stanford.mobisocial.dungbeetle.feed.iface.Activator; import edu.stanford.mobisocial.dungbeetle.feed.iface.DbEntryHandler; import edu.stanford.mobisocial.dungbeetle.feed.iface.FeedRenderer; import edu.stanford.mobisocial.dungbeetle.model.AppState; import edu.stanford.mobisocial.dungbeetle.model.Contact; import edu.stanford.mobisocial.dungbeetle.model.DbObject; import edu.stanford.mobisocial.dungbeetle.model.Feed; import edu.stanford.mobisocial.dungbeetle.model.Group; import edu.stanford.mobisocial.dungbeetle.model.PresenceAwareNotify; import edu.stanford.mobisocial.dungbeetle.util.Maybe; /** * A pointer to an application instance feed. * {@see LaunchApplicationAction} */ @Deprecated public class AppReferenceObj extends DbEntryHandler implements FeedRenderer, Activator { private static final String TAG = "AppReferenceObj"; private static final boolean DBG = false; public static final String TYPE = "invite_app_session"; public static final String ARG = "arg"; public static final String PACKAGE_NAME = "packageName"; public static final String OBJ_INTENT_ACTION = "intentAction"; public static final String OBJ_INTENT_CAT = "intentCat"; public static final String GROUP_URI = "groupuri"; public static final String CREATOR_ID = "creator_id"; private final AppStateObj mAppStateObj = new AppStateObj(); @Override public String getType() { return TYPE; } public static DbObject from(String packageName, String arg, String feedName, String groupUri, long creatorId) { return new DbObject(TYPE, json(packageName, arg, feedName, groupUri, creatorId)); } // TODO: Bundle <=> Json public static DbObject forFixedMembership(Bundle params, String[] membership, String feedName, String groupUri) { JSONObject json = new JSONObject(); try { JSONArray mship = new JSONArray(); for (String m : membership) { mship.put(m); } json.put(PACKAGE_NAME, params.getString(PACKAGE_NAME)); json.put(OBJ_INTENT_ACTION, params.getString(OBJ_INTENT_ACTION)); // todo: pendingIntent? parcelable? json.put(Multiplayer.OBJ_MEMBERSHIP, mship); json.put(DbObject.CHILD_FEED_NAME, feedName); json.put(GROUP_URI, groupUri); } catch (JSONException e) { } return new DbObject(TYPE, json); } public static JSONObject json(String packageName, String arg, String appFeedName, String appGroupUri, long creatorId) { JSONObject obj = new JSONObject(); try { obj.put(PACKAGE_NAME, packageName); obj.put(ARG, arg); obj.put(DbObject.CHILD_FEED_NAME, appFeedName); obj.put(GROUP_URI, appGroupUri); obj.put(CREATOR_ID, creatorId); } catch (JSONException e) { } return obj; } @Override public void handleDirectMessage(Context context, Contact from, JSONObject obj) { String packageName = obj.optString(PACKAGE_NAME); String arg = obj.optString(ARG); Intent launch = new Intent(); launch.setAction(Intent.ACTION_MAIN); launch.addCategory(Intent.CATEGORY_LAUNCHER); launch.putExtra(AppState.EXTRA_APPLICATION_ARGUMENT, arg); launch.putExtra("creator", false); launch.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); launch.setPackage(packageName); final PackageManager mgr = context.getPackageManager(); List<ResolveInfo> resolved = mgr.queryIntentActivities(launch, 0); if (resolved == null || resolved.size() == 0) { Toast.makeText(context, "Could not find application to handle invite", Toast.LENGTH_SHORT).show(); return; } ActivityInfo info = resolved.get(0).activityInfo; launch.setComponent(new ComponentName(info.packageName, info.name)); PendingIntent contentIntent = PendingIntent.getActivity(context, 0, launch, PendingIntent.FLAG_CANCEL_CURRENT); (new PresenceAwareNotify(context)).notify("New Invitation", "Invitation received from " + from.name, "Click to launch application.", contentIntent); } public void render(final Context context, final ViewGroup frame, Obj obj, boolean allowInteractions) { JSONObject content = obj.getJson(); // TODO: hack to show object history in app feeds SignedObj appState = getAppStateForChildFeed(context, obj); if (appState != null) { mAppStateObj.render(context, frame, obj, allowInteractions); return; } else { String appName = content.optString(PACKAGE_NAME); if (appName.contains(".")) { // TODO: look up label. appName = appName.substring(appName.lastIndexOf(".") + 1); } String text = "Welcome to " + appName + "!"; TextView valueTV = new TextView(context); valueTV.setText(text); valueTV.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)); valueTV.setGravity(Gravity.TOP | Gravity.LEFT); frame.addView(valueTV); } } @Override public void activate(Context context, SignedObj obj) { JSONObject content = obj.getJson(); if (DBG) Log.d(TAG, "activating from appReferenceObj: " + content); if (!content.has(DbObject.CHILD_FEED_NAME)) { Log.wtf(TAG, "Bad app reference found."); Toast.makeText(context, "Could not launch application.", Toast.LENGTH_SHORT).show(); return; } Log.w(TAG, "Using old-school app launch"); SignedObj appContent = getAppStateForChildFeed(context, obj); if (appContent == null) { Intent launch = AppStateObj.getLaunchIntent(context, obj); if (!(context instanceof Activity)) { launch.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } context.startActivity(launch); } else { if (DBG) Log.d(TAG, "pulled app state " + appContent); try { appContent.getJson().put(PACKAGE_NAME, content.get(PACKAGE_NAME)); appContent.getJson().put(OBJ_INTENT_ACTION, content.get(OBJ_INTENT_ACTION)); appContent.getJson().put(DbObject.CHILD_FEED_NAME, content.get(DbObject.CHILD_FEED_NAME)); } catch (JSONException e) { } //mAppStateObj.activate(context, appContent); Log.wtf(TAG, "dead code exception"); } } private SignedObj getAppStateForChildFeed(Context context, Obj appReferenceObj) { JSONObject appReference = appReferenceObj.getJson(); if (DBG) Log.w(TAG, "returning app state for " + appReference.toString()); if (appReference.has(DbObject.CHILD_FEED_NAME)) { String feedName = appReference.optString(DbObject.CHILD_FEED_NAME); Uri feedUri = Feed.uriForName(feedName); String selection = "type in ('" + AppStateObj.TYPE + "')"; String[] projection = null; String order = "_id desc LIMIT 1"; Cursor c = context.getContentResolver().query(feedUri, projection, selection, null, order); if (c.moveToFirst()) { return App.instance().getMusubi().objForCursor(c); } } else if (appReference.has("state")) { return (SignedObj) appReferenceObj; } return null; } /** * Subscribe to the application feed automatically. * TODO, work out observers vs. players. */ @Override public void afterDbInsertion(Context context, DbObj obj) { JSONObject content = obj.getJson(); if (content.has(DbObject.CHILD_FEED_NAME)) { String feedName = content.optString(DbObject.CHILD_FEED_NAME); DBHelper helper = DBHelper.getGlobal(context); Maybe<Group> mg = helper.groupByFeedName(feedName); helper.close(); if (!mg.isKnown() && content.has(GROUP_URI)) { Uri gUri = Uri.parse(content.optString(GROUP_URI)); Group.join(context, gUri); } } } }