From 8a43b8dd3648905af3d5acbdc88cf44b6d21da1e Mon Sep 17 00:00:00 2001 From: David Hu Date: Tue, 1 Apr 2014 19:35:09 -0400 Subject: [PATCH 01/14] Add Google Play Services SDK to allow use of GCM --- AndroidManifest.xml | 2 ++ README.md | 1 + build.gradle | 1 + proguard-project.txt | 19 +++++++++++++++++++ 4 files changed, 23 insertions(+) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 982344e..cd3ecc2 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -49,6 +49,8 @@ android:screenOrientation="portrait"/> + diff --git a/README.md b/README.md index 1188f7e..11987c1 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ The following instructions are tested for Intellij on Mac OS X and Windows: 1. Ensure you have [the latest Android SDKs and build tools installed](https://developer.android.com/sdk/index.html). +1. Install the [Google Play Services SDK](http://developer.android.com/google/play-services/setup.html#Install). 1. Create a file in the project root directory called `local.properties` and add the line `sdk.dir=/path/to/your/sdk`. 1. Download [Gradle](http://www.gradle.org/downloads) (tested with version 1.10). 1. Open Intellij (or Android Studio). Ensure you have the Gradle Intellij plugin. diff --git a/build.gradle b/build.gradle index f80ef7c..03612f0 100644 --- a/build.gradle +++ b/build.gradle @@ -42,6 +42,7 @@ dependencies { compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.1' compile "com.mixpanel.android:mixpanel-android:4.0.0@aar" compile 'com.crashlytics.android:crashlytics:1.+' + compile 'com.google.android.gms:play-services:4.0.30' } android { diff --git a/proguard-project.txt b/proguard-project.txt index 492ca2c..c7f9bf7 100644 --- a/proguard-project.txt +++ b/proguard-project.txt @@ -42,3 +42,22 @@ # We're open-sourced anyway... let's make life easier :) -dontobfuscate + +# Don't strip away required classes from Google Play Services SDK. +# From http://developer.android.com/google/play-services/setup.html +-keep class * extends java.util.ListResourceBundle { + protected Object[][] getContents(); +} + +-keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable { + public static final *** NULL; +} + +-keepnames @com.google.android.gms.common.annotation.KeepName class * +-keepclassmembernames class * { + @com.google.android.gms.common.annotation.KeepName *; +} + +-keepnames class * implements android.os.Parcelable { + public static final ** CREATOR; +} From 35bcf859aa829c8ca3d0f6ca5c53c624b12ed81d Mon Sep 17 00:00:00 2001 From: David Hu Date: Wed, 2 Apr 2014 02:15:16 -0400 Subject: [PATCH 02/14] Get a registration ID from GCM on main app start --- AndroidManifest.xml | 14 ++ .../uwflow/flow_android/MainFlowActivity.java | 3 + .../flow_android/constant/Constants.java | 2 + .../flow_android/util/RegistrationIdUtil.java | 131 ++++++++++++++++++ 4 files changed, 150 insertions(+) create mode 100644 src/com/uwflow/flow_android/util/RegistrationIdUtil.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index cd3ecc2..4e94feb 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -14,6 +14,12 @@ + + + + + + + + + + + + + Date: Thu, 3 Apr 2014 00:11:28 -0400 Subject: [PATCH 03/14] Alert and start app on course page on push notification --- AndroidManifest.xml | 5 +- res/drawable-xhdpi/ic_notification.png | Bin 0 -> 4611 bytes .../uwflow/flow_android/MainFlowActivity.java | 27 +++-- .../GcmBroadcastReceiver.java | 23 +++++ .../services/GcmIntentService.java | 93 ++++++++++++++++++ 5 files changed, 139 insertions(+), 9 deletions(-) create mode 100644 res/drawable-xhdpi/ic_notification.png create mode 100644 src/com/uwflow/flow_android/broadcast_receiver/GcmBroadcastReceiver.java create mode 100644 src/com/uwflow/flow_android/services/GcmIntentService.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 4e94feb..d757b6d 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -17,6 +17,7 @@ + @@ -53,14 +54,14 @@ - - + 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 literal 0 HcmV?d00001 diff --git a/src/com/uwflow/flow_android/MainFlowActivity.java b/src/com/uwflow/flow_android/MainFlowActivity.java index b6bed67..41cafec 100644 --- a/src/com/uwflow/flow_android/MainFlowActivity.java +++ b/src/com/uwflow/flow_android/MainFlowActivity.java @@ -35,6 +35,7 @@ import com.uwflow.flow_android.nfc.SharableURL; import com.uwflow.flow_android.util.FacebookUtilities; import com.uwflow.flow_android.util.RegistrationIdUtil; +import org.apache.commons.lang3.StringUtils; import org.json.JSONException; import org.json.JSONObject; @@ -155,8 +156,12 @@ public void onDrawerOpened(View view) { mDrawerList.setOnItemClickListener(new DrawerItemClickListener()); if (savedInstanceState == null) { - Fragment initialFragment; - if (isUserLoggedIn) { + Bundle bundle = getIntent().getExtras(); + String courseId = (bundle == null ? null : bundle.getString(Constants.COURSE_ID_KEY)); + + if (StringUtils.isNotEmpty(courseId)) { + replaceWithFragment(CourseFragment.newInstance(courseId), false); + } else if (isUserLoggedIn) { selectItem(Constants.NAV_DRAWER_PROFILE_INDEX, false); } else { selectItem(Constants.NAV_DRAWER_EXPLORE_INDEX, false); @@ -342,6 +347,18 @@ private void selectItem(int itemID, boolean addToBackStack) { return; } + replaceWithFragment(fragment, addToBackStack); + int selectedPosition = mNavDrawerAdapter.getPositionFromId(itemID); + if (selectedPosition >= 0) { + mDrawerList.setItemChecked(selectedPosition, true); + } + mDrawerLayout.closeDrawer(mDrawerContainer); + } + + /** + * Adds the given fragment to the back stack and replaces the current one with it. + */ + private void replaceWithFragment(Fragment fragment, boolean addToBackStack) { FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction transaction = fragmentManager.beginTransaction() .replace(R.id.content_frame, fragment); @@ -349,13 +366,9 @@ private void selectItem(int itemID, boolean addToBackStack) { transaction.addToBackStack(null); } transaction.commit(); - int selectedPosition = mNavDrawerAdapter.getPositionFromId(itemID); - if (selectedPosition >= 0) { - mDrawerList.setItemChecked(selectedPosition, true); - } - mDrawerLayout.closeDrawer(mDrawerContainer); } + private void handleNfcIntent(Intent intent) { if (intent == null) return; diff --git a/src/com/uwflow/flow_android/broadcast_receiver/GcmBroadcastReceiver.java b/src/com/uwflow/flow_android/broadcast_receiver/GcmBroadcastReceiver.java new file mode 100644 index 0000000..53f74b6 --- /dev/null +++ b/src/com/uwflow/flow_android/broadcast_receiver/GcmBroadcastReceiver.java @@ -0,0 +1,23 @@ +package com.uwflow.flow_android.broadcast_receiver; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.support.v4.content.WakefulBroadcastReceiver; +import com.uwflow.flow_android.services.GcmIntentService; + +/** + * Receives push notifications from GCM. + */ +public class GcmBroadcastReceiver extends WakefulBroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + // Explicitly specify that GcmIntentService will handle the intent. + ComponentName componentName = new ComponentName(context.getPackageName(), GcmIntentService.class.getName()); + + // Start the handling service, keeping the device awake while it is launching. + startWakefulService(context, intent.setComponent(componentName)); + setResultCode(Activity.RESULT_OK); + } +} diff --git a/src/com/uwflow/flow_android/services/GcmIntentService.java b/src/com/uwflow/flow_android/services/GcmIntentService.java new file mode 100644 index 0000000..288f5d4 --- /dev/null +++ b/src/com/uwflow/flow_android/services/GcmIntentService.java @@ -0,0 +1,93 @@ +package com.uwflow.flow_android.services; + +import android.app.IntentService; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.NotificationCompat; +import android.support.v4.app.TaskStackBuilder; +import android.util.Log; +import com.crashlytics.android.Crashlytics; +import com.google.android.gms.gcm.GoogleCloudMessaging; +import com.uwflow.flow_android.MainFlowActivity; +import com.uwflow.flow_android.R; +import com.uwflow.flow_android.broadcast_receiver.GcmBroadcastReceiver; +import com.uwflow.flow_android.constant.Constants; + +/** + * Service that handles push notifications from GCM. + */ +public class GcmIntentService extends IntentService { + private static final String TAG = GcmIntentService.class.getSimpleName(); + + private static final int NOTIFICATION_ID = 1; + + public GcmIntentService() { + super("GcmIntentService"); + } + + @Override + protected void onHandleIntent(Intent intent) { + Bundle extras = intent.getExtras(); + GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this); + String messageType = gcm.getMessageType(intent); + + if (!extras.isEmpty()) { + if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) { + String errorMessage = "Push notification send error: " + extras.toString(); + Crashlytics.log(Log.ERROR, TAG, errorMessage); + Log.e(TAG, errorMessage); + } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) { + String errorMessage = "Deleted push notifications on server: " + extras.toString(); + Crashlytics.log(Log.ERROR, TAG, errorMessage); + Log.e(TAG, errorMessage); + } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) { + // Actually a regular message. Handle it. + Log.i(TAG, "Received push notification " + extras.toString()); + displayNotification(extras); + } + } + + // Release the wake lock provided by the WakefulBroadcastReceiver. + GcmBroadcastReceiver.completeWakefulIntent(intent); + } + + /** + * Notify a push notification received from GCM. + * This is currently only configured to receive course class seat opening alerts. + * @param data + */ + private void displayNotification(Bundle data) { + Intent resultIntent = new Intent(this, MainFlowActivity.class); + resultIntent.putExtra(Constants.COURSE_ID_KEY, "cs241"); // FIXME(david): Don't hardcode + + // The stack builder object will contain an artificial back stack for the started Activity. + // This ensures that navigating backward from the Activity leads out of the app to the Home screen. + TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); + // Adds the back stack for the Intent (but not the Intent itself) + stackBuilder.addParentStack(MainFlowActivity.class); + // Adds the Intent that starts the Activity to the top of the stack + stackBuilder.addNextIntent(resultIntent); + + PendingIntent contentIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); + + // TODO(david): Hook up text with data format from server + Notification notification = new NotificationCompat.Builder(this) + .setSmallIcon(R.drawable.ic_notification) + .setContentTitle("Content title is here") + .setContentText("This is the content text") + .setContentIntent(contentIntent) + .setAutoCancel(true) + .setPriority(Notification.PRIORITY_HIGH) + .setDefaults(Notification.DEFAULT_ALL) + .build(); + + NotificationManager notificationManager = (NotificationManager) this.getSystemService( + Context.NOTIFICATION_SERVICE); + notificationManager.notify(NOTIFICATION_ID, notification); + } + +} From 5cb1bcb37ec8cbd0d104e67684cb25384a60436e Mon Sep 17 00:00:00 2001 From: David Hu Date: Thu, 3 Apr 2014 00:21:22 -0400 Subject: [PATCH 04/14] Don't use a WakefulBroadcastReceiver and remove WAKE_LOCK permission --- AndroidManifest.xml | 2 - .../GcmBroadcastReceiver.java | 84 +++++++++++++++-- .../services/GcmIntentService.java | 93 ------------------- 3 files changed, 76 insertions(+), 103 deletions(-) delete mode 100644 src/com/uwflow/flow_android/services/GcmIntentService.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index d757b6d..5328d2e 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -17,7 +17,6 @@ - @@ -61,7 +60,6 @@ - Date: Thu, 3 Apr 2014 02:21:59 -0400 Subject: [PATCH 05/14] Revert "Remove checkbox for push notification on class schedule for now" This reverts commit ae4e14489b6ff8eae61470ab20fe9f298b205f24. Conflicts: res/layout/course_schedule.xml --- res/layout/course_class_row_item.xml | 1 + res/layout/course_schedule.xml | 12 +++++++- .../adapters/CourseClassListAdapter.java | 30 +++++++++++++++---- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/res/layout/course_class_row_item.xml b/res/layout/course_class_row_item.xml index 73039ab..31d2316 100644 --- a/res/layout/course_class_row_item.xml +++ b/res/layout/course_class_row_item.xml @@ -3,4 +3,5 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> + diff --git a/res/layout/course_schedule.xml b/res/layout/course_schedule.xml index 5e9f1ae..96c525b 100644 --- a/res/layout/course_schedule.xml +++ b/res/layout/course_schedule.xml @@ -38,7 +38,12 @@ android:textStyle="bold" android:layout_weight="1" android:textColor="@color/white"/> - + @@ -54,5 +59,10 @@ android:padding="7dp" android:layout_width="match_parent" android:layout_height="wrap_content"/> + \ No newline at end of file diff --git a/src/com/uwflow/flow_android/adapters/CourseClassListAdapter.java b/src/com/uwflow/flow_android/adapters/CourseClassListAdapter.java index 9f96824..c78a25e 100644 --- a/src/com/uwflow/flow_android/adapters/CourseClassListAdapter.java +++ b/src/com/uwflow/flow_android/adapters/CourseClassListAdapter.java @@ -1,20 +1,19 @@ package com.uwflow.flow_android.adapters; +import java.util.ArrayList; +import java.util.List; + import android.content.Context; import android.text.Html; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.TextView; +import android.widget.*; import com.uwflow.flow_android.R; import com.uwflow.flow_android.db_object.Meeting; import com.uwflow.flow_android.db_object.Section; import com.uwflow.flow_android.util.StringHelper; -import java.util.ArrayList; -import java.util.List; - /** * Created by jasperfung on 2/22/14. */ @@ -52,9 +51,11 @@ public View getView(int position, View convertView, ViewGroup parent) { // Fill view with appropriate data TextView column1, column2; + CheckBox checkbox; column1 = (TextView) convertView.findViewById(R.id.col1); column2 = (TextView) convertView.findViewById(R.id.col2); + checkbox = (CheckBox) convertView.findViewById(R.id.checkbox); Section currClass = mClasses.get(position); @@ -116,6 +117,25 @@ public View getView(int position, View convertView, ViewGroup parent) { } column2.setText(Html.fromHtml(string2)); + + // Enable notification subscription checkbox for at-capacity classes + if (enrollmentTotal >= enrollmentCapacity) { + // TODO: we need some way of checking the reminder state of this class + checkbox.setChecked(true); + checkbox.setVisibility(View.VISIBLE); + } else { + checkbox.setVisibility(View.INVISIBLE); + } + + convertView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + CheckBox cb = (CheckBox)v.findViewById(R.id.checkbox); + cb.setChecked(!cb.isChecked()); + // TODO: subscribe for notifications of open seats in this class + } + }); + return convertView; } From 9ba958c5bc84596757e644587a5811231a061c4b Mon Sep 17 00:00:00 2001 From: David Hu Date: Thu, 3 Apr 2014 02:56:56 -0400 Subject: [PATCH 06/14] Use button instead of checkbox for course alerts ... so that we don't have to keep track of what already has an alert. --- res/drawable-xhdpi/ic_add_alert.png | Bin 0 -> 2254 bytes res/layout/course_class_row_item.xml | 10 +++++- res/layout/course_schedule.xml | 5 --- .../adapters/CourseClassListAdapter.java | 31 +++++++++--------- 4 files changed, 25 insertions(+), 21 deletions(-) create mode 100644 res/drawable-xhdpi/ic_add_alert.png diff --git a/res/drawable-xhdpi/ic_add_alert.png b/res/drawable-xhdpi/ic_add_alert.png new file mode 100644 index 0000000000000000000000000000000000000000..a0a526f4ded0cb693d9fc7a9837e84f3fd0178d0 GIT binary patch literal 2254 zcmbVO3se(V8crY}AOV7{fKV9XB3ei?Nq~^ZBQK(%1QAjRf|!sDWQ1hGWMYCV@(?X3 zT5a(G_@G#;)q>)yYXt;fJam=Sc9n;3ELugux+>ISCn)Zov!3obJLk;Y```P2-~YV# zOj$zw9J13iCjx;$md+I?;v?VsI@sgieQ@p#eDK0z6j&0HiJ4U>L=b3@3V2?kgo6J&ra29rf&a(HYO4+Md? z4;8nDYBG6=V#!-uxD-j%Vwi!)V3^Hjx|vN!&@2X%%jH@*SS%W@K{Mv*F_nd;H%^~m z5JN^a3L7vO(F0aSRR&_hBB{8iZ$i)+WU_a}dgI$f;VENSR0al<4l;B)Yh2^nMl2Ef zw;S)(Hp=r15F-&XA|_Og*CTWK1Q^fVpBu6&;@1+3=3y6!@+R2L?{jo7fZN;a3Obs<9%3xKqO?xgouS~JoC&LHaAQV z6D|>nMJ!HCj8GIdftBiwm`bmPChWqv-M3hr;7_nT5elg=1eGI5&O`?!Xb}uCY7qk< zN(u#JDmARP%GUC{iB=4u@KQ)4K@lA=o?jmP9{c}0?l)M?|C2KY?hM1)9RJZQ6H9mp zTBq+?9~a&o9!QU$7!*GmGp2n+CJ;ztQn5g8>3LL@k`piZpzVn~d-9Sxh5DvlKm)_k zabu|mm3qv>-M=BqBD^DwC?&bBdD>!|;V2E*5djE9kL2nt+Mg0X`Skk3=s~Z_9T)qa ztnGciV&}#7121kIH=n!kdIvWv^KoD?FjR$h4pmuDn{eVbLOda`a7v5gEs|kel(8Yn z%)d^;&Mr9==P*neK=>4ki*HfJkgxm@YV-94cez;Ma#GUmd%y8PI@cl+vB#n8>Va{d33PG7894ix9v96ZuY$V@%o~>^0oq6%VPg_R!OGU=dFSb zu2CD1p=rI*;xe0*zDJ^IjM;m5er_vU^%X%ax%HbFmtzWd*2J2sc!ADH6j=7v$eP^n zNb>VSmvuB@g+Dl1v-0N}_We1}?0y$y&nR*5^8IB;xu-W@#dA=`(gbrrhd9#VR#F#L z8tuQzLjGsb;RjUywKI~@GO3cX)%AzeQ-ATe?VWO}6>A_oZk5%Rlg_uGT>%>HkNtM( zc4PW;BhB{P1+m1jjSGOJ)yGJehJRDH!fr2LCg<<1UZQ_FHqU2)M5`9oDq3cBO2M`<?~AOQ1^zd% zy#YXnX-@swS}JAtkg;y#H|LUzdzDQwrOv$P_FIb2JaD=%zeyF(dPV)ZA#KBKrQ?Y6 zmj&&_fnexgjgfdf{P^;$dn=nakM`d<1@#(gUim5G^VhiT9;yaL`m;0oCS9SKI&UXv z8%U=7$=J7y$)$&;z7)JVRyX!+ZVjzu^?XugTWv{=tRl4LgLzKp)24d_%T|?jk*c0A zwXtp00_x@FZh6tZl+#CBlA40)XGffRfZK;Vk17u=r761igzt1rKkH@BrL`yz63;E0 z-Qhn>jANI>4}vc#UX^xUTjM|G<)q5fo9kKIql z%lS!n$3nuqVtr2y+pIbg(L=stlW$+$9lO!2-F=KFzgK_xvk#+ACJbDGQ|X(*nOA?= zNfw=O4*uTxv!nj&2R#&8&xNT%pZm65Y!^S!cKMG#KaNWET9Ls_H|_oCZ?N~(6}S9O z`>!nn?J819GhHhea`w6^$USPUeb3epd$wNuCM)9Dz-v37%L8qrV2d*v;ljOeVeNhO z{*Kp2h@v|~#Jj;siz3NadAs)5RK2K9^aCsIZGvq`_Ba2*a3NL&G)O9qM{G)tTf91N)J~sg+ETtRtw400p^NwVHr2<*$G-XA zI){Zb{C0B-A5>ATebUl$I3|M0(zD - + diff --git a/res/layout/course_schedule.xml b/res/layout/course_schedule.xml index 96c525b..4c6bcd5 100644 --- a/res/layout/course_schedule.xml +++ b/res/layout/course_schedule.xml @@ -59,10 +59,5 @@ android:padding="7dp" android:layout_width="match_parent" android:layout_height="wrap_content"/> - \ No newline at end of file diff --git a/src/com/uwflow/flow_android/adapters/CourseClassListAdapter.java b/src/com/uwflow/flow_android/adapters/CourseClassListAdapter.java index c78a25e..81a742e 100644 --- a/src/com/uwflow/flow_android/adapters/CourseClassListAdapter.java +++ b/src/com/uwflow/flow_android/adapters/CourseClassListAdapter.java @@ -1,23 +1,28 @@ package com.uwflow.flow_android.adapters; -import java.util.ArrayList; -import java.util.List; - import android.content.Context; import android.text.Html; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.*; +import android.widget.BaseAdapter; +import android.widget.ImageButton; +import android.widget.TextView; import com.uwflow.flow_android.R; import com.uwflow.flow_android.db_object.Meeting; import com.uwflow.flow_android.db_object.Section; import com.uwflow.flow_android.util.StringHelper; +import java.util.ArrayList; +import java.util.List; + /** * Created by jasperfung on 2/22/14. */ public class CourseClassListAdapter extends BaseAdapter { + private static final String TAG = CourseClassListAdapter.class.getSimpleName(); + private List
mClasses; private Context mContext; @@ -51,11 +56,10 @@ public View getView(int position, View convertView, ViewGroup parent) { // Fill view with appropriate data TextView column1, column2; - CheckBox checkbox; column1 = (TextView) convertView.findViewById(R.id.col1); column2 = (TextView) convertView.findViewById(R.id.col2); - checkbox = (CheckBox) convertView.findViewById(R.id.checkbox); + ImageButton addAlertButton = (ImageButton) convertView.findViewById(R.id.add_alert_button); Section currClass = mClasses.get(position); @@ -117,22 +121,19 @@ public View getView(int position, View convertView, ViewGroup parent) { } column2.setText(Html.fromHtml(string2)); - - // Enable notification subscription checkbox for at-capacity classes + // Enable notification subscription button for at-capacity classes + // TODO(david): Would be good to change button styling if alert already added if (enrollmentTotal >= enrollmentCapacity) { - // TODO: we need some way of checking the reminder state of this class - checkbox.setChecked(true); - checkbox.setVisibility(View.VISIBLE); + addAlertButton.setVisibility(View.VISIBLE); } else { - checkbox.setVisibility(View.INVISIBLE); + addAlertButton.setVisibility(View.INVISIBLE); } - convertView.setOnClickListener(new View.OnClickListener() { + addAlertButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - CheckBox cb = (CheckBox)v.findViewById(R.id.checkbox); - cb.setChecked(!cb.isChecked()); // TODO: subscribe for notifications of open seats in this class + Log.d(TAG, "Subscribe to class opening alert button clicked!"); } }); From 2a8563d664b1d1492e4fd64018063a6b41a9477f Mon Sep 17 00:00:00 2001 From: David Hu Date: Thu, 3 Apr 2014 03:47:43 -0400 Subject: [PATCH 07/14] Use random ID for push notification notification; add TODO comment --- .../adapters/CourseClassListAdapter.java | 1 + .../adapters/ProfileScheduleAdapter.java | 13 ++++++------- .../broadcast_receiver/GcmBroadcastReceiver.java | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/com/uwflow/flow_android/adapters/CourseClassListAdapter.java b/src/com/uwflow/flow_android/adapters/CourseClassListAdapter.java index 81a742e..258e900 100644 --- a/src/com/uwflow/flow_android/adapters/CourseClassListAdapter.java +++ b/src/com/uwflow/flow_android/adapters/CourseClassListAdapter.java @@ -123,6 +123,7 @@ public View getView(int position, View convertView, ViewGroup parent) { // Enable notification subscription button for at-capacity classes // TODO(david): Would be good to change button styling if alert already added + // TODO(david): Change back to checkbox (and style it properly) if above is done. if (enrollmentTotal >= enrollmentCapacity) { addAlertButton.setVisibility(View.VISIBLE); } else { diff --git a/src/com/uwflow/flow_android/adapters/ProfileScheduleAdapter.java b/src/com/uwflow/flow_android/adapters/ProfileScheduleAdapter.java index 0eefc8d..eebf8ab 100644 --- a/src/com/uwflow/flow_android/adapters/ProfileScheduleAdapter.java +++ b/src/com/uwflow/flow_android/adapters/ProfileScheduleAdapter.java @@ -5,17 +5,17 @@ import android.content.Context; import android.graphics.Typeface; import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentTransaction; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.*; import com.uwflow.flow_android.FlowApplication; +import android.widget.BaseExpandableListAdapter; +import android.widget.ImageButton; +import android.widget.TableLayout; +import android.widget.TextView; import com.uwflow.flow_android.R; -import com.uwflow.flow_android.constant.Constants; -import com.uwflow.flow_android.db_object.*; -import com.uwflow.flow_android.fragment.CourseFragment; +import com.uwflow.flow_android.db_object.ScheduleCourse; +import com.uwflow.flow_android.db_object.ScheduleCourses; import com.uwflow.flow_android.util.CalendarHelper; import com.uwflow.flow_android.util.CourseUtil; @@ -155,7 +155,6 @@ public View getChildView(final int groupPosition, final int childPosition, addAlarmButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - // TODO: Add an alarm for the current course mContext.startActivity(CalendarHelper.getAddAlarmIntent(title, location, startDate)); } }); diff --git a/src/com/uwflow/flow_android/broadcast_receiver/GcmBroadcastReceiver.java b/src/com/uwflow/flow_android/broadcast_receiver/GcmBroadcastReceiver.java index 653eaf6..1ae99c6 100644 --- a/src/com/uwflow/flow_android/broadcast_receiver/GcmBroadcastReceiver.java +++ b/src/com/uwflow/flow_android/broadcast_receiver/GcmBroadcastReceiver.java @@ -17,6 +17,8 @@ import com.uwflow.flow_android.R; import com.uwflow.flow_android.constant.Constants; +import java.util.Random; + /** * Receives push notifications from GCM. * @@ -26,8 +28,6 @@ public class GcmBroadcastReceiver extends BroadcastReceiver { private final String TAG = GcmBroadcastReceiver.class.getSimpleName(); - private static final int NOTIFICATION_ID = 1; - @Override public void onReceive(Context context, Intent intent) { Bundle extras = intent.getExtras(); @@ -85,7 +85,7 @@ private void displayNotification(Context context, Bundle data) { NotificationManager notificationManager = (NotificationManager) context.getSystemService( Context.NOTIFICATION_SERVICE); - notificationManager.notify(NOTIFICATION_ID, notification); + notificationManager.notify(new Random().nextInt(), notification); } } From 9d206cc19934b0e2a1a98f6a5d3800d73fa93cd4 Mon Sep 17 00:00:00 2001 From: David Hu Date: Thu, 3 Apr 2014 10:52:59 -0400 Subject: [PATCH 08/14] Properly display notification contents from server --- .../GcmBroadcastReceiver.java | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/com/uwflow/flow_android/broadcast_receiver/GcmBroadcastReceiver.java b/src/com/uwflow/flow_android/broadcast_receiver/GcmBroadcastReceiver.java index 1ae99c6..274bac6 100644 --- a/src/com/uwflow/flow_android/broadcast_receiver/GcmBroadcastReceiver.java +++ b/src/com/uwflow/flow_android/broadcast_receiver/GcmBroadcastReceiver.java @@ -16,6 +16,9 @@ import com.uwflow.flow_android.MainFlowActivity; import com.uwflow.flow_android.R; import com.uwflow.flow_android.constant.Constants; +import com.uwflow.flow_android.util.CourseUtil; +import org.json.JSONException; +import org.json.JSONObject; import java.util.Random; @@ -59,8 +62,22 @@ public void onReceive(Context context, Intent intent) { * @param data */ private void displayNotification(Context context, Bundle data) { + String courseId = data.getString("course_id"); + String humanizedCourseId = CourseUtil.humanizeCourseId(courseId); + String courseName = ""; + try { + JSONObject course = new JSONObject(data.getString("course")); + courseName = course.getString("name"); + } catch (JSONException e) { + e.printStackTrace(); + Crashlytics.logException(e); + } + + String title = String.format("%s: spots open!", humanizedCourseId); + String text = String.format("Enroll now for %s: %s", humanizedCourseId, courseName); + Intent resultIntent = new Intent(context, MainFlowActivity.class); - resultIntent.putExtra(Constants.COURSE_ID_KEY, "cs241"); // FIXME(david): Don't hardcode + resultIntent.putExtra(Constants.COURSE_ID_KEY, courseId); // The stack builder object will contain an artificial back stack for the started Activity. // This ensures that navigating backward from the Activity leads out of the app to the Home screen. @@ -75,8 +92,8 @@ private void displayNotification(Context context, Bundle data) { // TODO(david): Hook up text with data format from server Notification notification = new NotificationCompat.Builder(context) .setSmallIcon(R.drawable.ic_notification) - .setContentTitle("Content title is here") - .setContentText("This is the content text") + .setContentTitle(title) + .setContentText(text) .setContentIntent(contentIntent) .setAutoCancel(true) .setPriority(Notification.PRIORITY_HIGH) From a3c4293fa3bf43e1df9c80ad1ae2fb6ee15d6c3d Mon Sep 17 00:00:00 2001 From: David Hu Date: Sat, 5 Apr 2014 17:15:10 -0400 Subject: [PATCH 09/14] Update receiver to match server response format --- .../broadcast_receiver/GcmBroadcastReceiver.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/com/uwflow/flow_android/broadcast_receiver/GcmBroadcastReceiver.java b/src/com/uwflow/flow_android/broadcast_receiver/GcmBroadcastReceiver.java index 274bac6..778d364 100644 --- a/src/com/uwflow/flow_android/broadcast_receiver/GcmBroadcastReceiver.java +++ b/src/com/uwflow/flow_android/broadcast_receiver/GcmBroadcastReceiver.java @@ -16,7 +16,6 @@ import com.uwflow.flow_android.MainFlowActivity; import com.uwflow.flow_android.R; import com.uwflow.flow_android.constant.Constants; -import com.uwflow.flow_android.util.CourseUtil; import org.json.JSONException; import org.json.JSONObject; @@ -62,20 +61,21 @@ public void onReceive(Context context, Intent intent) { * @param data */ private void displayNotification(Context context, Bundle data) { - String courseId = data.getString("course_id"); - String humanizedCourseId = CourseUtil.humanizeCourseId(courseId); String courseName = ""; + String courseId = ""; + String courseCode = ""; + try { JSONObject course = new JSONObject(data.getString("course")); courseName = course.getString("name"); + courseId = course.getString("id"); + courseCode = course.getString("code"); } catch (JSONException e) { e.printStackTrace(); Crashlytics.logException(e); } - String title = String.format("%s: spots open!", humanizedCourseId); - String text = String.format("Enroll now for %s: %s", humanizedCourseId, courseName); - + // TODO(david): Look into why this doesn't go to the right course if Flow is already started Intent resultIntent = new Intent(context, MainFlowActivity.class); resultIntent.putExtra(Constants.COURSE_ID_KEY, courseId); @@ -89,7 +89,9 @@ private void displayNotification(Context context, Bundle data) { PendingIntent contentIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); - // TODO(david): Hook up text with data format from server + String title = String.format("%s: spots open!", courseCode); + String text = String.format("%s: %s has seats open now.", courseCode, courseName); + Notification notification = new NotificationCompat.Builder(context) .setSmallIcon(R.drawable.ic_notification) .setContentTitle(title) From e24d0b7acff178c5edb2905df992f32f5a74e93e Mon Sep 17 00:00:00 2001 From: David Hu Date: Sat, 5 Apr 2014 18:15:06 -0400 Subject: [PATCH 10/14] Actually send a POST request to add alert --- .../adapters/CourseClassListAdapter.java | 61 ++++++++++++++++--- .../flow_android/constant/Constants.java | 1 + .../flow_android/network/FlowApiRequests.java | 54 ++++++++++++++++ .../flow_android/util/RegistrationIdUtil.java | 6 +- 4 files changed, 114 insertions(+), 8 deletions(-) diff --git a/src/com/uwflow/flow_android/adapters/CourseClassListAdapter.java b/src/com/uwflow/flow_android/adapters/CourseClassListAdapter.java index 258e900..6f44c71 100644 --- a/src/com/uwflow/flow_android/adapters/CourseClassListAdapter.java +++ b/src/com/uwflow/flow_android/adapters/CourseClassListAdapter.java @@ -9,10 +9,18 @@ import android.widget.BaseAdapter; import android.widget.ImageButton; import android.widget.TextView; +import android.widget.Toast; +import com.crashlytics.android.Crashlytics; import com.uwflow.flow_android.R; import com.uwflow.flow_android.db_object.Meeting; import com.uwflow.flow_android.db_object.Section; +import com.uwflow.flow_android.network.FlowApiRequestCallback; +import com.uwflow.flow_android.network.FlowApiRequests; +import com.uwflow.flow_android.util.CourseUtil; +import com.uwflow.flow_android.util.RegistrationIdUtil; import com.uwflow.flow_android.util.StringHelper; +import org.apache.commons.lang3.StringUtils; +import org.json.JSONObject; import java.util.ArrayList; import java.util.List; @@ -59,10 +67,9 @@ public View getView(int position, View convertView, ViewGroup parent) { column1 = (TextView) convertView.findViewById(R.id.col1); column2 = (TextView) convertView.findViewById(R.id.col2); - ImageButton addAlertButton = (ImageButton) convertView.findViewById(R.id.add_alert_button); - - Section currClass = mClasses.get(position); + final ImageButton addAlertButton = (ImageButton) convertView.findViewById(R.id.add_alert_button); + final Section currClass = mClasses.get(position); // Populate first column (class info) String sectionType = currClass.getSectionType(); @@ -88,7 +95,6 @@ public View getView(int position, View convertView, ViewGroup parent) { enrollmentCapacity); column1.setText(string1); - // Populate second column (time and location) String string2; String building = meeting.getBuilding(); @@ -124,17 +130,58 @@ public View getView(int position, View convertView, ViewGroup parent) { // Enable notification subscription button for at-capacity classes // TODO(david): Would be good to change button styling if alert already added // TODO(david): Change back to checkbox (and style it properly) if above is done. - if (enrollmentTotal >= enrollmentCapacity) { + final String registrationId = RegistrationIdUtil.getRegistrationId(mContext); + if (RegistrationIdUtil.supportsGcm(mContext) && StringUtils.isNotEmpty(registrationId) && + enrollmentTotal >= enrollmentCapacity) { addAlertButton.setVisibility(View.VISIBLE); } else { addAlertButton.setVisibility(View.INVISIBLE); } + final String finalSectionType = sectionType; + final String finalSectionNumber = sectionNumber; + final String userId = null; // TODO(david): Get the user ID + addAlertButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - // TODO: subscribe for notifications of open seats in this class - Log.d(TAG, "Subscribe to class opening alert button clicked!"); + final String courseId = currClass.getCourseId(); + final String humanizedCourseId = CourseUtil.humanizeCourseId(courseId); + final String termId = currClass.getTermId(); + String registrationId = RegistrationIdUtil.getRegistrationId(mContext); + + addAlertButton.setEnabled(false); + + FlowApiRequests.addCourseAlert(registrationId, courseId, termId, finalSectionType, finalSectionNumber, + userId, new FlowApiRequestCallback() { + @Override + public void onSuccess(JSONObject response) { + String message = String.format( + "You will be notified when a seat opens up for %s: %s %s.", + humanizedCourseId, finalSectionType, finalSectionNumber); + Toast.makeText(mContext, message, Toast.LENGTH_LONG).show(); + addAlertButton.setEnabled(true); + } + + @Override + public void onFailure(String error) { + String message; + + // TODO(david): Server should return error code instead + if (StringUtils.containsIgnoreCase(error, "already exists")) { + message = String.format("You've already added an alert for %s: %s %s", + humanizedCourseId, finalSectionType, finalSectionNumber); + } else { + message = String.format("Uh oh, could not add a course alert for %s. Error: %s", + humanizedCourseId, error); + Log.d(TAG, message); + Crashlytics.log(Log.ERROR, TAG, message); + } + + Toast.makeText(mContext, message, Toast.LENGTH_LONG).show(); + addAlertButton.setEnabled(true); + } + }); } }); diff --git a/src/com/uwflow/flow_android/constant/Constants.java b/src/com/uwflow/flow_android/constant/Constants.java index 43fbdc5..4be2cc2 100644 --- a/src/com/uwflow/flow_android/constant/Constants.java +++ b/src/com/uwflow/flow_android/constant/Constants.java @@ -28,6 +28,7 @@ public class Constants { public static final String API_USERS_FRIENDS = "api/v1/users/%s/friends"; public static final String API_USER_SHORTLIST_COURSE = "api/v1/user/shortlist/%s"; public static final String API_SEARCH_COURSES = "api/v1/search/courses?%s"; + public static final String API_GCM_COURSE_ALERTS = "api/v1/alerts/course/gcm"; public static class DatabaseColumnName{ public static final String USER_ID = "user_id"; diff --git a/src/com/uwflow/flow_android/network/FlowApiRequests.java b/src/com/uwflow/flow_android/network/FlowApiRequests.java index b71e19b..56b8be8 100644 --- a/src/com/uwflow/flow_android/network/FlowApiRequests.java +++ b/src/com/uwflow/flow_android/network/FlowApiRequests.java @@ -17,6 +17,7 @@ import com.uwflow.flow_android.constant.Constants; import com.uwflow.flow_android.db_object.*; import com.uwflow.flow_android.util.JsonToDbUtil; +import com.uwflow.flow_android.util.RegistrationIdUtil; import org.apache.commons.lang3.StringUtils; import org.apache.http.Header; import org.json.JSONException; @@ -77,6 +78,59 @@ public void onFailure(Throwable e, JSONObject errorResponse) { }); } + public static void addCourseAlert(String registrationId, final String courseId, String termId, String sectionType, + String sectionNum, String userId, final FlowApiRequestCallback callback) { + RequestParams params = new RequestParams(); + params.put("registration_id", registrationId); + params.put("course_id", courseId); + + if (StringUtils.isNotEmpty(termId)) { + params.put("term_id", termId); + } + if (StringUtils.isNotEmpty(sectionType)) { + params.put("section_type", sectionType); + } + if (StringUtils.isNotEmpty(sectionNum)) { + params.put("section_num", sectionNum); + } + if (StringUtils.isNotEmpty(userId)) { + params.put("user_id", userId); + } + + FlowAsyncClient.post(Constants.API_GCM_COURSE_ALERTS, params, new JsonHttpResponseHandler() { + @Override + public void onSuccess(JSONObject response) { + Log.d(TAG, "Add alert for course " + courseId + " success."); + callback.onSuccess(response); + } + + @Override + public void onFailure(String responseBody, Throwable error) { + Log.d(TAG, "Add alert for course " + courseId + " failed."); + callback.onFailure(responseBody); + } + + @Override + public void onFailure(Throwable e, JSONObject errorResponse) { + Log.d(TAG, "Add alert for course " + courseId + " failed."); + + if (errorResponse == null) { + callback.onFailure(null); + return; + } + + String errorMessage = ""; + try { + errorMessage = errorResponse.getString("error"); + } catch (JSONException e1) { + // Ignore could not parse error message + } + + callback.onFailure(errorMessage); + } + }); + } + public static void searchCourses(String keywords, String sortMode, Boolean excludeTakenCourses, Integer count, Integer offset, final FlowApiRequestCallback callback) { // Build the search query string diff --git a/src/com/uwflow/flow_android/util/RegistrationIdUtil.java b/src/com/uwflow/flow_android/util/RegistrationIdUtil.java index a1cba69..f8222e3 100644 --- a/src/com/uwflow/flow_android/util/RegistrationIdUtil.java +++ b/src/com/uwflow/flow_android/util/RegistrationIdUtil.java @@ -37,7 +37,7 @@ public class RegistrationIdUtil { * @param context */ public static void init(Context context) { - if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS) { + if (supportsGcm(context)) { mGcm = GoogleCloudMessaging.getInstance(context); mRegistrationId = getRegistrationId(context); @@ -50,6 +50,10 @@ public static void init(Context context) { } } + public static boolean supportsGcm(Context context) { + return GooglePlayServicesUtil.isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS; + } + /** * Get the current registration ID from shared preferences. * From 98b041a2bc1bb1d3fc1472482df92cdde28d5572 Mon Sep 17 00:00:00 2001 From: David Hu Date: Sun, 6 Apr 2014 12:45:57 -0400 Subject: [PATCH 11/14] Send user ID in POST /api/v1/alerts/course/gcm --- .../adapters/CourseClassListAdapter.java | 3 ++- .../network/FlowApiRequestCallback.java | 2 -- .../flow_android/network/FlowApiRequests.java | 3 ++- .../network/FlowDatabaseLoader.java | 27 +++++++++---------- .../uwflow/flow_android/util/UserUtil.java | 25 +++++++++++++++++ 5 files changed, 41 insertions(+), 19 deletions(-) create mode 100644 src/com/uwflow/flow_android/util/UserUtil.java diff --git a/src/com/uwflow/flow_android/adapters/CourseClassListAdapter.java b/src/com/uwflow/flow_android/adapters/CourseClassListAdapter.java index 6f44c71..d4898ce 100644 --- a/src/com/uwflow/flow_android/adapters/CourseClassListAdapter.java +++ b/src/com/uwflow/flow_android/adapters/CourseClassListAdapter.java @@ -19,6 +19,7 @@ import com.uwflow.flow_android.util.CourseUtil; import com.uwflow.flow_android.util.RegistrationIdUtil; import com.uwflow.flow_android.util.StringHelper; +import com.uwflow.flow_android.util.UserUtil; import org.apache.commons.lang3.StringUtils; import org.json.JSONObject; @@ -140,7 +141,7 @@ public View getView(int position, View convertView, ViewGroup parent) { final String finalSectionType = sectionType; final String finalSectionNumber = sectionNumber; - final String userId = null; // TODO(david): Get the user ID + final String userId = UserUtil.getLoggedInUserId(mContext); addAlertButton.setOnClickListener(new View.OnClickListener() { @Override diff --git a/src/com/uwflow/flow_android/network/FlowApiRequestCallback.java b/src/com/uwflow/flow_android/network/FlowApiRequestCallback.java index 284d01c..8a8616a 100644 --- a/src/com/uwflow/flow_android/network/FlowApiRequestCallback.java +++ b/src/com/uwflow/flow_android/network/FlowApiRequestCallback.java @@ -3,8 +3,6 @@ import com.uwflow.flow_android.db_object.*; import org.json.JSONObject; -import java.util.ArrayList; - public abstract class FlowApiRequestCallback { abstract public void onSuccess(JSONObject response); abstract public void onFailure(String error); diff --git a/src/com/uwflow/flow_android/network/FlowApiRequests.java b/src/com/uwflow/flow_android/network/FlowApiRequests.java index 56b8be8..0077f21 100644 --- a/src/com/uwflow/flow_android/network/FlowApiRequests.java +++ b/src/com/uwflow/flow_android/network/FlowApiRequests.java @@ -97,7 +97,8 @@ public static void addCourseAlert(String registrationId, final String courseId, params.put("user_id", userId); } - FlowAsyncClient.post(Constants.API_GCM_COURSE_ALERTS, params, new JsonHttpResponseHandler() { + //FlowAsyncClient.post(Constants.API_GCM_COURSE_ALERTS, params, new JsonHttpResponseHandler() { + FlowAsyncClient.client.post("https://divad12.fwd.wf/" + Constants.API_GCM_COURSE_ALERTS, params, new JsonHttpResponseHandler() { @Override public void onSuccess(JSONObject response) { Log.d(TAG, "Add alert for course " + courseId + " success."); diff --git a/src/com/uwflow/flow_android/network/FlowDatabaseLoader.java b/src/com/uwflow/flow_android/network/FlowDatabaseLoader.java index 9ea6b56..b82063a 100644 --- a/src/com/uwflow/flow_android/network/FlowDatabaseLoader.java +++ b/src/com/uwflow/flow_android/network/FlowDatabaseLoader.java @@ -1,23 +1,23 @@ package com.uwflow.flow_android.network; import android.content.Context; -import android.content.SharedPreferences; import android.os.AsyncTask; -import android.preference.PreferenceManager; import com.crashlytics.android.Crashlytics; import com.j256.ormlite.dao.Dao; import com.j256.ormlite.stmt.QueryBuilder; -import com.uwflow.flow_android.adapters.ProfileScheduleAdapter; import com.uwflow.flow_android.broadcast_receiver.BroadcastFactory; -import com.uwflow.flow_android.constant.Constants; import com.uwflow.flow_android.dao.FlowDatabaseHelper; import com.uwflow.flow_android.db_object.*; import com.uwflow.flow_android.util.CalendarHelper; import com.uwflow.flow_android.util.JsonToDbUtil; +import com.uwflow.flow_android.util.UserUtil; import org.json.JSONObject; import java.sql.SQLException; -import java.util.*; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.List; import java.util.concurrent.Callable; /** @@ -29,13 +29,11 @@ public class FlowDatabaseLoader { protected FlowDatabaseHelper flowDatabaseHelper; protected Context context; protected FlowImageLoader flowImageLoader; - protected SharedPreferences sp; public FlowDatabaseLoader(Context context, FlowDatabaseHelper flowDatabaseHelper) { this.context = context; this.flowDatabaseHelper = flowDatabaseHelper; this.flowImageLoader = new FlowImageLoader(context); - sp = PreferenceManager.getDefaultSharedPreferences(context); } /** @@ -88,9 +86,7 @@ protected Void doInBackground(JSONObject... jsonObjects) { if (user != null && user.getProfilePicUrls() != null) flowImageLoader.preloadImage(user.getProfilePicUrls().getLarge()); if (user != null) { - SharedPreferences.Editor editor = sp.edit(); - editor.putString(Constants.PROFILE_ID_KEY, user.getId()); - editor.commit(); + UserUtil.saveLoggedInUserId(context, user.getId()); userDao.createOrUpdate(user); } } catch (SQLException e) { @@ -127,11 +123,12 @@ public void updateOrCreateUserScheduleImage(ScheduleImage scheduleImage) { return; } if (scheduleImage.getId() == null) { - String id = sp.getString(Constants.PROFILE_ID_KEY, null); - if (id == null) + String id = UserUtil.getLoggedInUserId(context); + if (id == null) { return; - else - scheduleImage.setId(id); + } + + scheduleImage.setId(id); } new AsyncTask() { @Override @@ -390,7 +387,7 @@ protected ScheduleImage doInBackground(String... strings) { try { String arg = strings[0]; if (arg == null) { - arg = sp.getString(Constants.PROFILE_ID_KEY, null); + arg = UserUtil.getLoggedInUserId(context); if (arg == null) return null; } Dao scheduleImageStringDao = flowDatabaseHelper.getUserSchduleImageDao(); diff --git a/src/com/uwflow/flow_android/util/UserUtil.java b/src/com/uwflow/flow_android/util/UserUtil.java new file mode 100644 index 0000000..4d3f5d8 --- /dev/null +++ b/src/com/uwflow/flow_android/util/UserUtil.java @@ -0,0 +1,25 @@ +package com.uwflow.flow_android.util; + +import android.content.Context; +import android.preference.PreferenceManager; +import com.uwflow.flow_android.constant.Constants; + +public class UserUtil { + + /** + * Save the logged in user's ID in shared preferences. + */ + public static void saveLoggedInUserId(Context context, String userId) { + PreferenceManager.getDefaultSharedPreferences(context).edit() + .putString(Constants.PROFILE_ID_KEY, userId) + .commit(); + } + + /** + * Get the logged in user's ID from shared preferences. + */ + public static String getLoggedInUserId(Context context) { + return PreferenceManager.getDefaultSharedPreferences(context).getString(Constants.PROFILE_ID_KEY, null); + } + +} From 68731a8f51580cea49fd8c0829ed0dca19532d22 Mon Sep 17 00:00:00 2001 From: David Hu Date: Mon, 7 Apr 2014 13:17:42 -0400 Subject: [PATCH 12/14] Redesign course sections screen to make alert on seats clearer --- res/drawable-xhdpi/ic_add_alert.png | Bin 2254 -> 2030 bytes res/layout/course_class_row_item.xml | 55 +++++++--- res/layout/course_schedule.xml | 25 ----- .../adapters/CourseClassListAdapter.java | 95 ++++++++---------- .../fragment/CourseScheduleFragment.java | 5 +- 5 files changed, 90 insertions(+), 90 deletions(-) diff --git a/res/drawable-xhdpi/ic_add_alert.png b/res/drawable-xhdpi/ic_add_alert.png index a0a526f4ded0cb693d9fc7a9837e84f3fd0178d0..e1ea09367fb66e692a038ed9ab72815bab3ba955 100644 GIT binary patch delta 1359 zcmZ|HeLT|%0LStDHf@u~$V@qT$y2D;nAtoen{DOc5RD@-8Id^WSx?)@Q);jE8k(8X zaG}ne!!fl7}))$-^u1u)2#;?*8ch?EClo^L@5!S&!`lSp4p518@|81?Mb~ z#1VlHaxQ@Pnxj$9C=!ZHB)Fi-j*cWW!NnVcb9E)V5}XJmG?v8i1e^YkNZ&-3i* zAQw$Hs@0mhdD%7KC9T%z?gU4MV97Wv++zX4`(>Ptwe7zgO+o6{P9y1FCfpS}B^;Wb zetSv14C|b+E1jt*lm2=cER?JivSD>ho2&&lu)z3gUfcGVw4Md1>Q?mDrxZn+I+UFvJ*Uj z4s1%esLx99oJhrtSNsO`guO6+;?!u2g!y{Kb2lFXdSd5Q1b^;I2{Zun;3+2c28^N< z|HMuq=sRc_bzsXsUit#LulI&qZ)zwS{j;aFTVmOwP4nvy1lP796p9d6rn*mQ<(g82 zP)wa2g7m45J-gSsK|8`&Gl$eM>9JIF!`l-g_Xeo9_+U`u2*@|#s@0d!lWa&9W0vK$ zZqS<-O||ULTuR^lVBADwbFG|R|A;C~YFn=scDhqMhYqtk{D)!xOsLxTd;*QHZ`)kt zS5KpFp4yQsGQ9KdeEj)4O?&P`!ucjqFp9!G66%LPX=qlWv*U~fu2ZB*cUe>BupoN4 zXw+%v31xZZK&a=$fc!T2l*MPLy}x74&Dua#UBknnw7Q3V9{K}__vKcy3=?Rt%6sRi zuYrMeFb(O2KY-5%f?4)52CfH7d2BP&>7?CqrN?Is8KT|d%zsceqqfA5PPO`%0HO%S zE=TjI5POt0-1@Aum|pB*9^OzHv$KNHj+HQ2ktU;p2~J`jP+cH+q>WDl?T_#xUn!Di zRtl#Wrq^@5jD<6R5ITIA+bn0$T<}#uF0W7u$Y(x+tD(cOt0%5Q+jf5?AtJPE=CJ+? zZ41`Od{#=4{G+V8AK*mMh zd8z!stEHplgHAkt{RYI{02(w#@|&77$x#9FPwR(Tj6BL>#2LD%4b#LCqAX`1Z_H@8 z8;%u+2SrRW1TOND5kZlIyrrx!s6stj3ShgsM)WAT4f+@~Z~QK0UnqR?Ip@}#*^f1J z<+|uqv+o*{F4=9_%bF$X}k79GL!iFS3%h9dP6#NSlY8mgf hX|hwzjYS~{0+J}sJgw@_jsyKS9~dcs*i4}2{R?JAS{48R delta 1607 zcmaFIe@<|MCu7=1FLlPrvlvq*XEAEl7x?;G`4?rTXXYj5xa237=BDPAc)HjsRpb`v zrDUd9xtW{085)|K7?>Lwm{}MaS{PUuyE(a-TDZ7bI$AhcDk%U}0?ojt*U{10$=KDz z#mU&nz|hdu*wW0=)xyo$#o5T*)z!(_45)XqE|a7JR2@(;c6F0~F&a)@%%mSf*fGT= zL8)n0DP(wLvL3Tjy_%FPF9QS1KTj9OkcwMxW<}=sIf@*AACk?TwKgL8KC9|ReNN7a z9pXw#+r)(wH`-M=J@T~aVBzojbbvXD(^GYxje?`|n~>z`8CQe6L+`$}e=9k2-nl#P zyKjH1n}6=a`tSF4mLEIwf1YJ}+B@|og%7iePJNhFQN(1yIETTHLA|~~_yFevmI5%} z*ErQpqnf?sXx1hlj*o)R^Bn{$_~aUsKFEb^Dq>o4MkvH3f^WauO}Q6)UdCBgcsj)} zUO&(qvZXn65G(THl{KEYU>tDxgwH6LZxmWXgB%~b@tvC|A zbRFFdIDA+(A7r_p*@zlmWA!EM`E&VT%!d@xhs$B*#Z6|=MQ ze*E*733JOxc3Kp1K=XoF&7zsHf@}G^GGuPAabD{f*7!Dsx6J#)p7jZw7WWmx1RVDY z9iF|Kf&ZZ328I%oh^9Qj$Bv5kN>3w)=TE)enOIvt}duH)OK;hgz<8|6`lRAVMjzvz%$GXnBmQ)px)CM6 zPa$i0?*B^m4T5`om4fat@8v1&Q*F$7Dwny>;fQK|gQvh=!^M+&KK@K`jA@A#(+lzi957B;mq}Ut}1c4{AN#JVZ-sjwLY2> z!r>B66!m9c_&kMudUX11hsH#Chss}qTSC@t&21}j%G=+0i}mWx9*5w^|4hszz2pvk zWNO`FbBp&;JyR{)?3-Q_%QKd4vkG~-?ozv`-Tr{*mouaFrWt5le>I=ic{h*FcAoaF zihXazBQhkSqMc-3Fkdj{lQ&?lx$^9tU9@Cfl3`rw3fUc*(%0)A$RAeh?lfSX63wE) zKQqdF1%CwZt>g^0TQfv&%{aF#-DcbK|Ew~Xo*(~ZaDb=ChOgf8%$e>N$*WKP-@@qp z=mXV9L{}nM^Ef_b=-6G0sxm=&5z1c-6;Cf^p_Qm5VZV zu95rM`8TrT0rMk)2aYGU+e{7jiEpd?#hO=HI=yFAOuh46{ainpmC-UxGHm;v_Hsn2 z$uG5RcsVoaaKC!UDZ?q1_3E#mtPcP6>5d&A;}gBNey59ealOxzuDvTbtx&ssl6FL; zqyMSYGVQSE<&pVwJ44Q<&aQv!GG+dW6Xv^_d8?eF?-XgyY0S1X`L;MwUDw$q_Vn8? zLPoz&?f>pldc5}S>&-$Rq^F)tnr$%C;fF+T`WS@E# a2?p&ur;lvn`uvFj2s~Z=T-G@yGywonC!m!8 diff --git a/res/layout/course_class_row_item.xml b/res/layout/course_class_row_item.xml index 982a7a0..55a57ca 100644 --- a/res/layout/course_class_row_item.xml +++ b/res/layout/course_class_row_item.xml @@ -1,15 +1,46 @@ - - - + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="3dp" + android:paddingBottom="3dp" + android:paddingLeft="10dp" + android:paddingRight="10dp"> + + + + + + diff --git a/res/layout/course_schedule.xml b/res/layout/course_schedule.xml index 4c6bcd5..eecdda9 100644 --- a/res/layout/course_schedule.xml +++ b/res/layout/course_schedule.xml @@ -24,31 +24,6 @@ android:layout_weight="1" android:layout_width="match_parent" android:layout_height="0dp" > - - - - - - - - - - 1 meeting - String professor = meeting.getProfId(); - if (professor != null) { - professor = StringHelper.capitalize(professor.replaceAll("_", " ")); - } - int enrollmentTotal = currClass.getEnrollmentTotal(); - int enrollmentCapacity = currClass.getEnrollmentCapacity(); + Meeting meeting = currClass.getMeetings().get(0); // TODO: Handle more than 1 meeting // Make sure we don't have nulls - if (sectionType == null) sectionType = "---"; - if (sectionNumber == null) sectionNumber = "---"; - if (professor == null) professor = "---"; - - String string1 = String.format("%s %s\n%s\nSeats: %d/%d", - sectionType, - sectionNumber, - professor, - enrollmentTotal, - enrollmentCapacity); - column1.setText(string1); - - // Populate second column (time and location) - String string2; + if (sectionType == null) sectionType = ""; + if (sectionNumber == null) sectionNumber = ""; + + column1.setText(String.format("%s\n%s", sectionType, sectionNumber)); + + // Populate second column (class details) + List detailsList = new LinkedList(); String building = meeting.getBuilding(); String room = meeting.getRoom(); String campus = currClass.getCampus(); + if (campus == null) campus = ""; + String professor = meeting.getProfId(); - String time; long startSeconds = meeting.getStartSeconds(); long endSeconds = meeting.getEndSeconds(); - if (startSeconds == 0 || endSeconds == 0) { - time = "N/A"; - } else { - time = String.format("%s - %s", + if (startSeconds != 0 && endSeconds != 0) { + detailsList.add(String.format("%s - %s", getTimeFromSeconds(startSeconds), - getTimeFromSeconds(endSeconds)); + getTimeFromSeconds(endSeconds))); } - if (campus == null) campus = ""; - if (building == null || room == null) { - string2= String.format("%s
%s
%s", - time, - getFormattedDays(meeting.getDays()), - campus); - } else { - string2= String.format("%s
%s
%s %s - %s", - time, - getFormattedDays(meeting.getDays()), - building, - room, - campus); + if (meeting.getDays() != null && !meeting.getDays().isEmpty()) { + detailsList.add(getFormattedDays(meeting.getDays())); + } + if (StringUtils.isNotEmpty(building) || StringUtils.isNotEmpty(room)) { + detailsList.add(String.format("%s %s - %s", building, room, campus)); + } else if (StringUtils.isNotEmpty(campus)) { + detailsList.add(campus); + } + if (StringUtils.isNotEmpty(professor)) { + professor = StringHelper.capitalize(professor.replaceAll("_", " ")); + detailsList.add(professor); } - column2.setText(Html.fromHtml(string2)); + column2.setText(Html.fromHtml(StringUtils.join(detailsList, "
"))); + + // Populate seats available column + int enrollmentTotal = currClass.getEnrollmentTotal(); + int enrollmentCapacity = currClass.getEnrollmentCapacity(); + String fractionHtml = String.format("%s/%s
seats", enrollmentTotal, enrollmentCapacity); + seatsAvailableTextView.setText(Html.fromHtml(fractionHtml)); // Enable notification subscription button for at-capacity classes // TODO(david): Would be good to change button styling if alert already added // TODO(david): Change back to checkbox (and style it properly) if above is done. final String registrationId = RegistrationIdUtil.getRegistrationId(mContext); - if (RegistrationIdUtil.supportsGcm(mContext) && StringUtils.isNotEmpty(registrationId) && - enrollmentTotal >= enrollmentCapacity) { + //if (RegistrationIdUtil.supportsGcm(mContext) && StringUtils.isNotEmpty(registrationId) && + // enrollmentTotal >= enrollmentCapacity) { + if (enrollmentTotal >= enrollmentCapacity) { addAlertButton.setVisibility(View.VISIBLE); } else { addAlertButton.setVisibility(View.INVISIBLE); @@ -161,7 +156,6 @@ public void onSuccess(JSONObject response) { "You will be notified when a seat opens up for %s: %s %s.", humanizedCourseId, finalSectionType, finalSectionNumber); Toast.makeText(mContext, message, Toast.LENGTH_LONG).show(); - addAlertButton.setEnabled(true); } @Override @@ -192,12 +186,11 @@ public void onFailure(String error) { private String getTimeFromSeconds(long seconds) { int hours = (int)(seconds / 3600); int minutes = (int)(seconds % 3600) / 60; - if (hours >= 12 && minutes >= 0) { - if (hours > 12) hours -= 12; - return String.format("%d:%dpm", hours, minutes); - } else { - return String.format("%d:%dam", hours, minutes); - } + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.HOUR_OF_DAY, hours); + cal.set(Calendar.MINUTE, minutes); + + return new SimpleDateFormat("h:mma").format(cal.getTime()); } private String getFormattedDays(ArrayList days) { diff --git a/src/com/uwflow/flow_android/fragment/CourseScheduleFragment.java b/src/com/uwflow/flow_android/fragment/CourseScheduleFragment.java index 4cad7b9..90c9d31 100644 --- a/src/com/uwflow/flow_android/fragment/CourseScheduleFragment.java +++ b/src/com/uwflow/flow_android/fragment/CourseScheduleFragment.java @@ -127,13 +127,14 @@ private View createScheduleTermHeader(String heading) { TextView textView = new TextView(getActivity()); textView.setText(heading); textView.setTypeface(null, Typeface.BOLD); + textView.setTextColor(getResources().getColor(R.color.white)); textView.setLayoutParams(new TableLayout.LayoutParams( TableLayout.LayoutParams.MATCH_PARENT, TableLayout.LayoutParams.WRAP_CONTENT, 1f)); float scale = getResources().getDisplayMetrics().density; // scale for converting dp to px - textView.setPadding((int)(10 * scale + 0.5f), 0, 0, 0); - textView.setBackgroundResource(R.color.flow_light_blue); + textView.setPadding((int)(10 * scale + 0.5f), 8, 0, 8); + textView.setBackgroundResource(R.color.flow_blue); return textView; } From ff990ba6ec49c178601a3ecae77ad1b22aff7db8 Mon Sep 17 00:00:00 2001 From: David Hu Date: Mon, 7 Apr 2014 13:34:16 -0400 Subject: [PATCH 13/14] Reorder profile tabs to have courses as 1st tab, since no class schedule this month --- res/layout/profile_schedule_layout.xml | 2 +- src/com/uwflow/flow_android/adapters/ProfilePagerAdapter.java | 2 +- src/com/uwflow/flow_android/constant/Constants.java | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/res/layout/profile_schedule_layout.xml b/res/layout/profile_schedule_layout.xml index cd08031..56513ab 100644 --- a/res/layout/profile_schedule_layout.xml +++ b/res/layout/profile_schedule_layout.xml @@ -84,7 +84,7 @@ android:layout_height="match_parent" android:gravity="center" android:textColor="@color/grey_dark" - android:text="No schedule uploaded" + android:text="No class schedule available" android:textSize="18dp" android:visibility="gone"/> diff --git a/src/com/uwflow/flow_android/adapters/ProfilePagerAdapter.java b/src/com/uwflow/flow_android/adapters/ProfilePagerAdapter.java index c8eff1d..2bc5bdf 100644 --- a/src/com/uwflow/flow_android/adapters/ProfilePagerAdapter.java +++ b/src/com/uwflow/flow_android/adapters/ProfilePagerAdapter.java @@ -17,8 +17,8 @@ public class ProfilePagerAdapter extends FragmentStatePagerAdapter { private static final int USER_FRIEND_PROFILE_TAB_NUMBER = 3; private static final String[] TITLES = new String[]{ - "Schedule", "Courses", + "Schedule", "Exams", "Friends", }; diff --git a/src/com/uwflow/flow_android/constant/Constants.java b/src/com/uwflow/flow_android/constant/Constants.java index 4be2cc2..c9aa6a2 100644 --- a/src/com/uwflow/flow_android/constant/Constants.java +++ b/src/com/uwflow/flow_android/constant/Constants.java @@ -85,8 +85,8 @@ public static class BroadcastActionId { public static final int COURSE_ABOUT_PAGE_INDEX = 1; public static final int COURSE_REVIEWS_PAGE_INDEX = 2; - public static final int PROFILE_SCHEDULE_PAGE_INDEX = 0; - public static final int PROFILE_COURSES_PAGE_INDEX = 1; + public static final int PROFILE_COURSES_PAGE_INDEX = 0; + public static final int PROFILE_SCHEDULE_PAGE_INDEX = 1; public static final int PROFILE_EXAMS_PAGE_INDEX = 2; public static final int PROFILE_FRIENDS_PAGE_INDEX = 3; From 1526d60fedb67b8ccb95e480c42f5b19fcc8df3c Mon Sep 17 00:00:00 2001 From: David Hu Date: Mon, 7 Apr 2014 13:47:16 -0400 Subject: [PATCH 14/14] Remove local testing code --- .../uwflow/flow_android/adapters/CourseClassListAdapter.java | 5 ++--- src/com/uwflow/flow_android/network/FlowApiRequests.java | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/com/uwflow/flow_android/adapters/CourseClassListAdapter.java b/src/com/uwflow/flow_android/adapters/CourseClassListAdapter.java index 9d905cc..53bd44c 100644 --- a/src/com/uwflow/flow_android/adapters/CourseClassListAdapter.java +++ b/src/com/uwflow/flow_android/adapters/CourseClassListAdapter.java @@ -126,9 +126,8 @@ public View getView(int position, View convertView, ViewGroup parent) { // TODO(david): Would be good to change button styling if alert already added // TODO(david): Change back to checkbox (and style it properly) if above is done. final String registrationId = RegistrationIdUtil.getRegistrationId(mContext); - //if (RegistrationIdUtil.supportsGcm(mContext) && StringUtils.isNotEmpty(registrationId) && - // enrollmentTotal >= enrollmentCapacity) { - if (enrollmentTotal >= enrollmentCapacity) { + if (RegistrationIdUtil.supportsGcm(mContext) && StringUtils.isNotEmpty(registrationId) && + enrollmentTotal >= enrollmentCapacity) { addAlertButton.setVisibility(View.VISIBLE); } else { addAlertButton.setVisibility(View.INVISIBLE); diff --git a/src/com/uwflow/flow_android/network/FlowApiRequests.java b/src/com/uwflow/flow_android/network/FlowApiRequests.java index 0077f21..56b8be8 100644 --- a/src/com/uwflow/flow_android/network/FlowApiRequests.java +++ b/src/com/uwflow/flow_android/network/FlowApiRequests.java @@ -97,8 +97,7 @@ public static void addCourseAlert(String registrationId, final String courseId, params.put("user_id", userId); } - //FlowAsyncClient.post(Constants.API_GCM_COURSE_ALERTS, params, new JsonHttpResponseHandler() { - FlowAsyncClient.client.post("https://divad12.fwd.wf/" + Constants.API_GCM_COURSE_ALERTS, params, new JsonHttpResponseHandler() { + FlowAsyncClient.post(Constants.API_GCM_COURSE_ALERTS, params, new JsonHttpResponseHandler() { @Override public void onSuccess(JSONObject response) { Log.d(TAG, "Add alert for course " + courseId + " success.");