/*
* 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.objects;
import java.util.List;
import mobisocial.musubi.App;
import mobisocial.musubi.R;
import mobisocial.musubi.feed.iface.Activator;
import mobisocial.musubi.feed.iface.DbEntryHandler;
import mobisocial.musubi.feed.iface.FeedRenderer;
import mobisocial.musubi.model.MApp;
import mobisocial.musubi.model.helpers.AppManager;
import mobisocial.musubi.provider.MusubiContentProvider;
import mobisocial.musubi.provider.MusubiContentProvider.Provided;
import mobisocial.musubi.service.MusubiService;
import mobisocial.musubi.ui.fragments.FeedListFragment.FeedSummary;
import mobisocial.musubi.ui.widget.DbObjCursorAdapter.DbObjCursor;
import mobisocial.musubi.util.CommonLayouts;
import mobisocial.musubi.util.InstrumentedActivity;
import mobisocial.musubi.webapp.WebAppActivity;
import mobisocial.socialkit.Obj;
import mobisocial.socialkit.musubi.DbObj;
import mobisocial.socialkit.musubi.Musubi;
import mobisocial.socialkit.obj.MemObj;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
public class WebAppObj extends DbEntryHandler implements FeedRenderer, Activator {
static final String TYPE = "webapp";
static final String OBJ_URL = "url";
@Override
public String getType() {
return TYPE;
}
public static Obj forUri(Uri uri) {
try {
JSONObject json = new JSONObject();
json.put(OBJ_URL, uri.toString());
return new MemObj(TYPE, json);
} catch (JSONException e) {
throw new IllegalStateException("bad json library", e);
}
}
@Override
public View createView(Context context, ViewGroup parent) {
LinearLayout frame = new LinearLayout(context);
frame.setLayoutParams(CommonLayouts.FULL_WIDTH);
frame.setOrientation(LinearLayout.VERTICAL);
LinearLayout appBar = new LinearLayout(context);
appBar.setLayoutParams(CommonLayouts.FULL_WIDTH);
appBar.setOrientation(LinearLayout.HORIZONTAL);
frame.addView(appBar);
Drawable icon = context.getResources().getDrawable(R.drawable.ic_menu_globe);
ImageView iv = new ImageView(context);
iv.setImageDrawable(icon);
iv.setAdjustViewBounds(true);
iv.setMaxWidth(60);
iv.setMaxHeight(60);
iv.setLayoutParams(CommonLayouts.WRAPPED);
appBar.addView(iv);
TextView tv = new TextView(context);
tv.setLayoutParams(CommonLayouts.WRAPPED);
tv.setGravity(Gravity.CENTER_VERTICAL);
appBar.addView(tv);
LinearLayout actionBar = new LinearLayout(context);
actionBar.setLayoutParams(CommonLayouts.WRAPPED);
actionBar.setOrientation(LinearLayout.HORIZONTAL);
frame.addView(actionBar);
Button b = new Button(context);
// required for listview long-press
b.setLayoutParams(CommonLayouts.WRAPPED);
b.setFocusable(false);
b.setText("Run");
b.setOnClickListener(getRunListener());
actionBar.addView(b);
b = new Button(context);
// required for listview long-press
b.setLayoutParams(CommonLayouts.WRAPPED);
b.setFocusable(false);
b.setOnClickListener(getAddListener());
actionBar.addView(b);
return frame;
}
@Override
public void activate(Context context, DbObj obj) {
// we have BUTTONS
}
@Override
public void render(Context context, View view, DbObjCursor obj, boolean allowInteractions)
throws Exception {
LinearLayout frame = (LinearLayout)view;
TextView tv = (TextView)((ViewGroup)frame.getChildAt(0)).getChildAt(1);
tv.setText("Webapp " + getAppName(obj));
if (allowInteractions) {
Button b = (Button)((ViewGroup)frame.getChildAt(1)).getChildAt(0);
long objId = obj.objId;
b.setTag(objId);
b = (Button)((ViewGroup)((ViewGroup)view).getChildAt(1)).getChildAt(1);
b.setTag(objId);
AppManager am = new AppManager(App.getDatabaseSource(context));
MApp lookup = am.lookupAppByAppId(getAppId(obj));
//deleted ones can be readded
//ensure app may have put it in the table without a url;
if (lookup == null || lookup.deleted_ == true || lookup.webAppUrl_ == null) {
b.setText("Add");
b.setEnabled(true);
} else {
b.setText("Added");
b.setEnabled(false);
}
}
}
OnClickListener mAddListener;
private OnClickListener getAddListener() {
if (mAddListener == null) {
mAddListener = new OnClickListener() {
@Override
public void onClick(View v) {
Context context = v.getContext();
if (context instanceof InstrumentedActivity) {
InstrumentedActivity a = (InstrumentedActivity) context;
try {
DbObj obj = App.getMusubi(context).objForId((Long)v.getTag());
String name = getAppName(obj);
Uri uri = Uri.parse(obj.getJson().optString(OBJ_URL));
String appId = getAppId(obj);
a.showDialog(AddWebAppDialog.newInstance(obj.getLocalId(), appId, name, uri));
} catch (Throwable t) {
Toast.makeText(context, "Failed to load webapp", Toast.LENGTH_SHORT).show();
}
}
}
};
}
return mAddListener;
}
OnClickListener mRunListener;
private OnClickListener getRunListener() {
if (mRunListener == null) {
mRunListener = new OnClickListener() {
@Override
public void onClick(View v) {
Context context = v.getContext();
DbObj obj = App.getMusubi(context).objForId((Long)v.getTag());
Intent appIntent = new Intent(Intent.ACTION_VIEW);
appIntent.setClass(context, WebAppActivity.class);
appIntent.putExtra(Musubi.EXTRA_FEED_URI, obj.getContainingFeed().getUri());
appIntent.putExtra(WebAppActivity.EXTRA_APP_NAME, getAppName(obj));
appIntent.putExtra(WebAppActivity.EXTRA_APP_URI, Uri.parse(obj.getJson().optString(OBJ_URL)));
appIntent.putExtra(WebAppActivity.EXTRA_APP_ID, getAppId(obj));
context.startActivity(appIntent);
}
};
}
return mRunListener;
}
String getAppName(Obj obj) {
Uri appUri = Uri.parse(obj.getJson().optString(OBJ_URL));
String given = appUri.getQueryParameter("n");
if (given == null) {
given = appUri.getLastPathSegment();
if (given == null || given.length() <= 1 || given.startsWith("index")) {
List<String> segs = appUri.getPathSegments();
if (segs.size() > 1) {
given = segs.get(segs.size() - 2);
} else {
given = appUri.getAuthority();
}
}
}
return given;
}
String getAppId(Obj obj) {
Uri appUri = Uri.parse(obj.getJson().optString(OBJ_URL));
return appUri.getAuthority() + "/" + getAppName(obj);
}
static class AddWebAppDialog extends DialogFragment {
public static AddWebAppDialog newInstance(long objId, String appId, String name, Uri uri) {
Bundle b = new Bundle();
b.putString("name", name);
b.putParcelable("uri", uri);
b.putString("appid", appId);
b.putLong("objId", objId);
AddWebAppDialog d = new AddWebAppDialog();
d.setArguments(b);
return d;
}
public AddWebAppDialog() {
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Uri appUri = getArguments().getParcelable("uri");
final String name = getArguments().getString("name");
final String appId = getArguments().getString("appid");
final long objId = getArguments().getLong("objId");
return new AlertDialog.Builder(getActivity()).setTitle("Add to app list?")
.setMessage("Add " + name + " to your list of applications?")
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
SQLiteOpenHelper databaseSource = App.getDatabaseSource(getActivity());
AppManager am = new AppManager(databaseSource);
SQLiteDatabase db = databaseSource.getWritableDatabase();
db.beginTransaction();
MApp app = null;
try {
MApp lookup = am.lookupAppByAppId(appId);
//could be re-adding
//could have had this app discovered p2p
if (lookup != null && lookup.deleted_ == false && lookup.webAppUrl_ != null) {
Toast.makeText(getActivity(), "App already installed.",
Toast.LENGTH_SHORT).show();
return;
}
app = lookup;
if(app == null)
app = new MApp();
app.appId_ = appId;
app.name_ = name;
app.webAppUrl_ = appUri.toString();
app.deleted_ = false;
if(lookup != null) {
am.updateApp(app);
} else {
am.insertApp(app);
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
if (app == null || app.id_ == -1) {
Toast.makeText(getActivity(), "Error installing webapp.",
Toast.LENGTH_SHORT).show();
} else {
//load the app manifest
//TODO: just load this one...
getActivity().getContentResolver().notifyChange(MusubiService.UPDATE_APP_MANIFESTS, null);
Toast.makeText(getActivity(),
"Installed " + name + " to pin menu.", Toast.LENGTH_SHORT)
.show();
getActivity().getContentResolver().notifyChange(
MusubiContentProvider.uriForItem(Provided.OBJS_ID, objId), null);
}
}
}).setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// no harm no foul
}
}).create();
}
}
@Override
public void getSummaryText(Context context, TextView view, FeedSummary summary) {
JSONObject obj = summary.getJson();
view.setTypeface(null, Typeface.ITALIC);
view.setText(summary.getSender()
+ " posted a new web app: "
+ obj.optString(OBJ_URL));
}
}