/*
* 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.webapp;
import mobisocial.musubi.App;
import mobisocial.musubi.BJDNotImplementedException;
import mobisocial.musubi.Helpers;
import mobisocial.musubi.PickContactsActivity;
import mobisocial.musubi.R;
import mobisocial.musubi.objects.AppObj;
import mobisocial.musubi.provider.MusubiContentProvider;
import mobisocial.musubi.ui.MusubiBaseActivity;
import mobisocial.musubi.util.ActivityCallout;
import mobisocial.socialkit.Obj;
import mobisocial.socialkit.musubi.DbFeed;
import mobisocial.socialkit.musubi.Musubi;
import mobisocial.socialkit.musubi.multiplayer.Multiplayer;
import mobisocial.socialkit.obj.MemObj;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.webkit.WebView;
import android.webkit.WebViewClient;
/**
* A web-based 'app store' for finding new Musubi apps. Also
* contains a partial implementaion of the SocialKit-JS library.
*/
public class AppCorralActivity extends MusubiBaseActivity {
private static final String EXTRA_CURRENT_PAGE = "page";
private String mCurrentPage;
private SocialKitJavascript mSocialKitJavascript;
private Uri mFeedUri;
private Musubi mMusubi;
WebView mWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mFeedUri = (Uri)getIntent().getParcelableExtra(Musubi.EXTRA_FEED_URI);
setContentView(R.layout.appcorral);
if (savedInstanceState != null) {
mCurrentPage = savedInstanceState.getString(EXTRA_CURRENT_PAGE);
} else if (getIntent().getData() != null) {
mCurrentPage = getIntent().getDataString();
} else {
mCurrentPage = "http://musubi.us/apps";
}
WebViewClient webViewClient = new AppStoreWebViewClient();
mWebView = (WebView) findViewById(R.id.webview);
mWebView.getSettings().setJavaScriptEnabled(true);
//mWebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
mWebView.setWebViewClient(webViewClient);
mSocialKitJavascript = SocialKitJavascript.bindAccess(this, MusubiContentProvider.SUPER_APP_ID, 0);
mWebView.addJavascriptInterface(mSocialKitJavascript, SocialKitJavascript.MUSUBI_JS_VAR);
mWebView.loadUrl(mCurrentPage);
mMusubi = App.getMusubi(this);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// Check if the key event was the BACK key and if there's history
if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
// If it wasn't the BACK key or there's no web page history, bubble up to the default
// system behavior (probably exit the activity)
return super.onKeyDown(keyCode, event);
}
class AppStoreWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Uri uri = Uri.parse(url);
String scheme = uri.getScheme();
if (scheme.startsWith("http")) {
if (!uri.getPath().endsWith(".apk")) {
return false;
}
}
// TODO: Launch in WebAppActivity
if (scheme.startsWith("socialkit")) {
String appUrl = uri.buildUpon().scheme("http").build().toString();
Intent app = new Intent(Intent.ACTION_VIEW);
app.setClass(AppCorralActivity.this, WebAppActivity.class);
app.putExtra(Musubi.EXTRA_FEED_URI, mFeedUri);
app.putExtra(WebAppActivity.EXTRA_APP_URI, Uri.parse(appUrl));
startActivity(app);
return true;
}
// Otherwise, the link is not for a page on my site, so launch another Activity that handles URLs
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
return true;
}
@Override
public void onPageFinished(WebView view, String url) {
if (DBG) Log.d(TAG, "Page loaded, injecting musubi SocialKit bridge for " + url);
mCurrentPage = url;
// Launch musubi app
DbFeed dbFeed = mMusubi.getFeed(mFeedUri);
SocialKitJavascript.SKFeed feed = mSocialKitJavascript.new SKFeed(dbFeed);
SocialKitJavascript.SKUser user = mSocialKitJavascript.new SKUser(
mMusubi.userForLocalDevice(dbFeed.getUri()));
String initSocialKit = new StringBuilder("javascript:")
.append("Musubi._launch(").append(
user.toJson() + ", " + feed.toJson() + ",'someappid', false)").toString();
Log.d(TAG, "Android calling " + initSocialKit);
mWebView.loadUrl(initSocialKit);
}
@Override
public void onReceivedError(WebView view, int errorCode, String description,
String failingUrl) {
if (DBG) {
Log.d(TAG, "socialkit.js error: " + errorCode + ", " + description);
}
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(EXTRA_CURRENT_PAGE, mCurrentPage);
}
/**
* When a webapp is launched, we create an Obj of type "app"
* representing the app session. The obj's json has a field
* web_url identifying the webapp code, and a "membership"
* list of participants. This class manages the picker for
* selecting contacts. Once the user has selected participants,
* the obj is created and sent to the current feed, and the app is
* launched.
*/
private class MembersSelectedCallout implements ActivityCallout {
private final Context mContext;
private final Uri mFeedUri;
private final String mAppUrl;
private int mMaxPlayers = -1;
public MembersSelectedCallout(Context context, Uri feedUri, String appUrl) {
mFeedUri = feedUri;
mContext = context;
mAppUrl = appUrl;
}
public void setMaxAdditionalMembers(int p) {
mMaxPlayers = p;
}
@Override
public Intent getStartIntent() {
Intent i = new Intent(mContext, PickContactsActivity.class);
i.putExtra(PickContactsActivity.INTENT_EXTRA_PARENT_FEED, mFeedUri);
i.putExtra(PickContactsActivity.INTENT_EXTRA_MEMBERS_MAX, mMaxPlayers);
return i;
}
@Override
public void handleResult(int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK) {
// Create and share new application instance
Obj obj = objForPickerResult(mAppUrl, data);
/*SignedObjFuture future =*/ Helpers.sendToFeed(mContext, obj, mFeedUri);
//new AppObj().activate(mContext, future.get());
} else {
Log.i(TAG, "No members selected.");
}
}
public Obj objForPickerResult(String appUrl, Intent data) {
long[] contactIds = data.getLongArrayExtra("contacts");
JSONArray participantIds = new JSONArray();
BJDNotImplementedException.except(BJDNotImplementedException.MSG_LOCAL_PERSON_ID);
String personId = null;
participantIds.put(personId);
for (long id : contactIds) {
Log.d(TAG, "objForPicker is broken");
// TODO: Add to participantIds array
}
JSONObject json = new JSONObject();
try {
json.put(Multiplayer.OBJ_MEMBERSHIP, participantIds);
json.put(AppObj.WEB_URL, appUrl);
} catch (JSONException e) {
Log.e(TAG, "Error setting up json");
}
return new MemObj(AppObj.TYPE, json);
}
}
}