aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Doan <andy.doan@linaro.org>2011-10-27 00:37:39 -0500
committerAndy Doan <andy.doan@linaro.org>2011-10-27 01:50:33 -0500
commit46c60edce5506e0b78a0ccb48d9408ea40c7676f (patch)
tree4b35b30fbc2bc4a7a4a03ff6d060e3e688b7701a
parentbf6f99338f5815c405d78079541c2de1ec63c612 (diff)
downloadLinaroConnect-46c60edce5506e0b78a0ccb48d9408ea40c7676f.tar.gz
add support for showing personal schedule
This creates a class that can automate the logic of logging into summit.linaro.org and getting the user's key which is used in the url to download their iCal schedule
-rw-r--r--AndroidManifest.xml9
-rw-r--r--res/layout/my_schedule_unconfigured.xml84
-rw-r--r--res/values/strings.xml13
-rw-r--r--src/org/linaro/connect/MyScheduleActivity.java118
-rw-r--r--src/org/linaro/connect/OpenIDLogin.java134
-rw-r--r--src/org/linaro/connect/ScheduleActivity.java6
6 files changed, 364 insertions, 0 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 92392a9..2c3c1e9 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -49,6 +49,15 @@
<activity android:name=".ScheduleItemActivity"
android:label="@string/schedule_item">
</activity>
+ <activity android:name=".MyScheduleActivity"
+ android:label="@string/schedule_mine"
+ android:configChanges="orientation|keyboardHidden" >
+ <intent-filter>
+ <action android:name="org.linaro.connect.MY_SCHEDULE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="http"/>
+ </intent-filter>
+ </activity>
</application>
</manifest> \ No newline at end of file
diff --git a/res/layout/my_schedule_unconfigured.xml b/res/layout/my_schedule_unconfigured.xml
new file mode 100644
index 0000000..6d9ef82
--- /dev/null
+++ b/res/layout/my_schedule_unconfigured.xml
@@ -0,0 +1,84 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical"
+ android:background="@color/main_bg"
+ android:paddingLeft="5px"
+>
+
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
+ android:textSize="14sp"
+ android:textStyle="bold"
+ android:gravity="center"
+ android:text="@string/my_schedule_lp"
+ />
+
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
+ android:text="@string/my_schedule_user"
+ />
+ <EditText
+ android:id="@+id/my_schedule_user"
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
+ />
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
+ android:text="@string/my_schedule_pass"
+ />
+ <EditText
+ android:id="@+id/my_schedule_pass"
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
+ android:inputType="textPassword"
+ />
+
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ >
+ <TextView
+ android:id="@+id/my_schedule_status"
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
+ android:layout_weight="2"
+ android:layout_gravity="center"
+ />
+ <Button
+ android:id="@+id/my_schedule_login"
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
+ android:layout_weight="3"
+ android:layout_gravity="right"
+ android:text="@string/my_schedule_login"
+ />
+ </LinearLayout>
+
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
+ android:textSize="14sp"
+ android:textStyle="bold"
+ android:text="@string/my_schedule_login_about"
+ />
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
+ android:background="@drawable/rounded"
+ android:paddingLeft="5px"
+ android:textColor="@color/linaro_green"
+ android:text="@string/my_schedule_info"
+ />
+
+ <WebView
+ android:id="@+id/my_schedule_webview"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ />
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d3fb3b3..78057a8 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -3,4 +3,17 @@
<string name="app_name">Linaro Connect</string>
<string name="posting_refresh">Refresh</string>
<string name="schedule_item">Linaro Connect - Session</string>
+
+ <string name="schedule_mine">Linaro Connect - My Schedule</string>
+ <string name="my_schedule_lp">Launchpad Login</string>
+ <string name="my_schedule_user">Email:</string>
+ <string name="my_schedule_pass">Password:</string>
+ <string name="my_schedule_info">In order to access your schedule we\'ll need
+ to log into Launchpad one time. This will give the app a key that it can
+ retrieve your schedule with. No personal information will be saved.
+ </string>
+ <string name="my_schedule_login_about">About</string>
+ <string name="my_schedule_login">Log In</string>
+ <string name="my_schedule_login_busy">Authorizing...</string>
+ <string name="my_schedule_login_failed">Login failed! Try Again.</string>
</resources>
diff --git a/src/org/linaro/connect/MyScheduleActivity.java b/src/org/linaro/connect/MyScheduleActivity.java
new file mode 100644
index 0000000..8de22dd
--- /dev/null
+++ b/src/org/linaro/connect/MyScheduleActivity.java
@@ -0,0 +1,118 @@
+package org.linaro.connect;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.SharedPreferences.Editor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.view.View;
+import android.view.Window;
+import android.webkit.WebView;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+
+/**
+ * This is a dual-purpose activity. If the user has never used it or logged
+ * into summit, then it prompts them for authentication information.
+ *
+ * Once we have the secret key we need, its just a pass-through that launches
+ * the ScheduleActivty with the proper URL.
+ */
+public class MyScheduleActivity extends Activity{
+
+ private Button mLoginBtn;
+ private TextView mStatus;
+ private OpenIDLogin mOil;
+
+ private String mKeyName;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+ super.onCreate(savedInstanceState);
+
+ //we use the url of the event as keyname, so uds-p, uds-o will each
+ //have their own key
+ mKeyName = getIntent().getDataString();
+
+ String secret = getPreferences(MODE_PRIVATE).getString(mKeyName, null);
+ if( secret != null )
+ launchRealCalendar(secret);
+ else
+ onCreateUnconfigured(savedInstanceState);
+ }
+
+ protected void onCreateUnconfigured(Bundle savedInstanceState) {
+ setContentView(R.layout.my_schedule_unconfigured);
+
+ final WebView wv = (WebView)findViewById(R.id.my_schedule_webview);
+ wv.setVisibility(View.GONE);
+ mOil = new OpenIDLogin(getIntent().getDataString(), wv);
+
+ mStatus = (TextView)findViewById(R.id.my_schedule_status);
+
+ mLoginBtn = (Button)findViewById(R.id.my_schedule_login);
+ mLoginBtn.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ String user = getInput(R.id.my_schedule_user);
+ String pass = getInput(R.id.my_schedule_pass);
+
+ setProgressBarIndeterminateVisibility(true);
+ mLoginBtn.setEnabled(false);
+ mLoginBtn.setText(R.string.my_schedule_login_busy);
+
+ mOil.login(user, pass, mHandler);
+ }
+ });
+ }
+
+ private String getInput(int id) {
+ EditText t = (EditText)findViewById(id);
+ return t.getText().toString();
+ }
+
+ private Uri getICalUri(String key) {
+ String url = getIntent().getDataString()+"participant/my_schedule_"+key+".ical";
+ return Uri.parse(url);
+ }
+
+ private void launchRealCalendar(String key) {
+ Intent cal = new Intent("org.linaro.connect.SCHEDULE", getICalUri(key));
+ cal.putExtra(JSONLayoutItem.INTENT_LABEL, "My Schedule");
+ cal.putExtra(ScheduleActivity.INTENT_CACHENAME, "my-schedule");
+ startActivity(cal);
+ finish();
+ }
+
+ Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ int percent = msg.getData().getInt(OpenIDLogin.STATUS, -1);
+ if( percent != -1 ) {
+ mStatus.setText("" + percent + "% ...");
+ return;
+ }
+
+ //the login has succeeded or failed
+ setProgressBarIndeterminateVisibility(false);
+ mLoginBtn.setText(R.string.my_schedule_login);
+
+ String token = msg.getData().getString(OpenIDLogin.SECRET_KEY);
+ if( token == null ) {
+ mStatus.setText(R.string.my_schedule_login_failed);
+ mLoginBtn.setEnabled(true);
+ return;
+ }
+
+ //the login succeed
+ Editor ed = getPreferences(MODE_PRIVATE).edit();
+ ed.putString(mKeyName, token);
+ ed.commit();
+ launchRealCalendar(token);
+ }
+ };
+}
diff --git a/src/org/linaro/connect/OpenIDLogin.java b/src/org/linaro/connect/OpenIDLogin.java
new file mode 100644
index 0000000..7326625
--- /dev/null
+++ b/src/org/linaro/connect/OpenIDLogin.java
@@ -0,0 +1,134 @@
+package org.linaro.connect;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+/**
+ * This class uses some JavaScript trickery via the android webview in order
+ * to perform an openid login to summit.linaro.org. We need to get the key
+ * that is used for a users personal ical schedule.
+ */
+public class OpenIDLogin {
+
+ public final static String SECRET_KEY = "SECRET";
+ public final static String STATUS = "STATUS";
+
+ private final WebView mWebView;
+ private String mOnSetUserPassJS;
+ private Handler mHandler;
+
+ private boolean mLoginHit = false;
+
+ public OpenIDLogin(final String destinationURL, WebView v) {
+ mWebView = v;
+
+ v.getSettings().setJavaScriptEnabled(true);
+ v.getSettings().setDatabaseEnabled(false);
+ v.getSettings().setSaveFormData(false);
+ v.getSettings().setSavePassword(false);
+
+ v.addJavascriptInterface(new JavaScriptInterface(), "ANDROID");
+ v.setWebViewClient(new WebViewClient() {
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ // inject the proper js script into what we are loading
+ if(url.equals(destinationURL)) {
+ mWebView.loadUrl(onSummitLoggedIn);
+ sendStatus(90);
+ }
+ else if( url.equals("http://summit.linaro.org/openid/login/?next=") ) {
+ mWebView.loadUrl(onOpenidRedirect);
+ sendStatus(30);
+ }
+ else if( url.startsWith("https://login.launchpad.net/") ) {
+ if(mLoginHit) {
+ //this is the second time we hit this page. this means
+ //the login failed
+ sendStatus(90);
+ sendToken(null);
+ return;
+ }
+
+ mLoginHit = true;
+ mWebView.loadUrl(mOnSetUserPassJS);
+ sendStatus(60);
+ }
+ else {
+ Log.w(LinaroConnect.TAG, "unknown URL: " + url);
+ sendToken(null); //tell the caller to stop waiting
+ }
+ }
+ });
+ }
+
+ //launches a login in a background thread
+ public void login(String user, String pass, Handler h) {
+ mOnSetUserPassJS = String.format(SETUSERPASS_JS, new Object[]{user, pass});
+ mHandler = h;
+ mLoginHit = false;
+ sendStatus(0);
+ mWebView.loadUrl("http://summit.linaro.org/openid/login?next=");
+ }
+
+ private void sendToken(String token) {
+ Bundle b = new Bundle();
+ b.putString(SECRET_KEY, token);
+
+ Message m = mHandler.obtainMessage();
+ m.setData(b);
+ m.sendToTarget();
+ }
+
+ private void sendStatus(int percent) {
+ Bundle b = new Bundle();
+ b.putInt(STATUS, percent);
+
+ Message m = mHandler.obtainMessage();
+ m.setData(b);
+ m.sendToTarget();
+ }
+
+ class JavaScriptInterface {
+ final static String NEEDLE = "participant/my_schedule_";
+
+ public void onOpenidRedirect() {
+ }
+
+ /**
+ * Called when we are actually logged into summit with the content of
+ * the page. We search the page for the key used to download the
+ * user's ical schedule
+ */
+ public void onSummitLoggedIn(String html) {
+ int idx = html.indexOf(NEEDLE);
+ String token = null;
+ if(idx > 0) {
+ idx+= NEEDLE.length();
+ int idx2 = html.indexOf(".ical", idx);
+ if( idx2 > 0 )
+ token = html.substring(idx, idx2);
+ }
+ sendToken(token);
+ }
+ }
+
+ /**
+ * This is the JavaScript that we use to automatically fill in the login
+ * form on login.launchpad.net
+ */
+ private final static String SETUSERPASS_JS = "javascript:(function() { " +
+ "document.forms[0].elements[1].value = '%s'; " +
+ "document.forms[0].elements[2].value = '%s'; " +
+ "document.forms[0].submit(); " +
+ "})()";
+
+ /** not currently used */
+ private static String onOpenidRedirect = "javascript:window.ANDROID.onOpenidRedirect()";
+ /** used to get the HTML of the page we are actually looking for*/
+ private static String onSummitLoggedIn = "javascript:window.ANDROID.onSummitLoggedIn(document.getElementsByTagName('body')[0].innerHTML)";
+
+}
diff --git a/src/org/linaro/connect/ScheduleActivity.java b/src/org/linaro/connect/ScheduleActivity.java
index ac68232..7a229e3 100644
--- a/src/org/linaro/connect/ScheduleActivity.java
+++ b/src/org/linaro/connect/ScheduleActivity.java
@@ -20,6 +20,9 @@ import android.widget.TextView;
public class ScheduleActivity extends Activity {
+ /** used to specify an alternate name for the cache in the intent*/
+ public static final String INTENT_CACHENAME = "org.linaro.connect.CACHENAME";
+
private static final int REFRESH_ID = Menu.FIRST + 1;
private ScheduleAdapter mAdapter;
@@ -89,6 +92,9 @@ public class ScheduleActivity extends Activity {
if(idx > 0)
url = url.substring(0, idx);
+ String cacheName = getIntent().getStringExtra(INTENT_CACHENAME);
+ if( cacheName != null )
+ setCacheFileName(cacheName);
setUrl(url);
}