git.fiddlerwoaroof.com
fiddlerwoaroof authored on 05/04/2015 07:08:09
Showing 33 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1 @@
1
+/build
0 2
new file mode 100644
1 3
Binary files /dev/null and b/app/app-release.apk differ
2 4
new file mode 100644
... ...
@@ -0,0 +1,117 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="Marrow1" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
3
+  <component name="FacetManager">
4
+    <facet type="android-gradle" name="Android-Gradle">
5
+      <configuration>
6
+        <option name="GRADLE_PROJECT_PATH" value=":app" />
7
+      </configuration>
8
+    </facet>
9
+    <facet type="android" name="Android">
10
+      <configuration>
11
+        <option name="SELECTED_BUILD_VARIANT" value="debug" />
12
+        <option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
13
+        <option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
14
+        <option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
15
+        <option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugAndroidTest" />
16
+        <option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" />
17
+        <option name="TEST_SOURCE_GEN_TASK_NAME" value="generateDebugAndroidTestSources" />
18
+        <option name="ALLOW_USER_CONFIGURATION" value="false" />
19
+        <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
20
+        <option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
21
+        <option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
22
+        <option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
23
+      </configuration>
24
+    </facet>
25
+  </component>
26
+  <component name="NewModuleRootManager" inherit-compiler-output="false">
27
+    <output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
28
+    <output-test url="file://$MODULE_DIR$/build/intermediates/classes/androidTest/debug" />
29
+    <exclude-output />
30
+    <content url="file://$MODULE_DIR$">
31
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
32
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
33
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
34
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
35
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
36
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/debug" type="java-resource" />
37
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
38
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
39
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
40
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
41
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
42
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/androidTest/debug" type="java-test-resource" />
43
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
44
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
45
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
46
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
47
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
48
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
49
+      <sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
50
+      <sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
51
+      <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
52
+      <sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
53
+      <sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
54
+      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
55
+      <sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
56
+      <sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
57
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
58
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
59
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
60
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
61
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
62
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
63
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
64
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
65
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
66
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
67
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes" />
68
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
69
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" />
70
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex-cache" />
71
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
72
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/jacoco" />
73
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaResources" />
74
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/libs" />
75
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
76
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
77
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/ndk" />
78
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
79
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard" />
80
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
81
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
82
+      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
83
+      <excludeFolder url="file://$MODULE_DIR$/build/outputs" />
84
+      <excludeFolder url="file://$MODULE_DIR$/build/tmp" />
85
+    </content>
86
+    <orderEntry type="jdk" jdkName="Android API 19 Platform" jdkType="Android SDK" />
87
+    <orderEntry type="sourceFolder" forTests="false" />
88
+    <orderEntry type="library" exported="" name="play-services-drive-7.0.0" level="project" />
89
+    <orderEntry type="library" exported="" name="play-services-maps-7.0.0" level="project" />
90
+    <orderEntry type="library" exported="" name="play-services-appindexing-7.0.0" level="project" />
91
+    <orderEntry type="library" exported="" name="play-services-cast-7.0.0" level="project" />
92
+    <orderEntry type="library" exported="" name="play-services-wearable-7.0.0" level="project" />
93
+    <orderEntry type="library" exported="" name="play-services-panorama-7.0.0" level="project" />
94
+    <orderEntry type="library" exported="" name="jdeferred-core-1.2.3" level="project" />
95
+    <orderEntry type="library" exported="" name="support-annotations-22.0.0" level="project" />
96
+    <orderEntry type="library" exported="" name="play-services-plus-7.0.0" level="project" />
97
+    <orderEntry type="library" exported="" name="play-services-7.0.0" level="project" />
98
+    <orderEntry type="library" exported="" name="play-services-ads-7.0.0" level="project" />
99
+    <orderEntry type="library" exported="" name="play-services-base-7.0.0" level="project" />
100
+    <orderEntry type="library" exported="" name="play-services-location-7.0.0" level="project" />
101
+    <orderEntry type="library" exported="" name="slf4j-api-1.7.2" level="project" />
102
+    <orderEntry type="library" exported="" name="play-services-gcm-7.0.0" level="project" />
103
+    <orderEntry type="library" exported="" name="play-services-safetynet-7.0.0" level="project" />
104
+    <orderEntry type="library" exported="" name="play-services-nearby-7.0.0" level="project" />
105
+    <orderEntry type="library" exported="" name="play-services-fitness-7.0.0" level="project" />
106
+    <orderEntry type="library" exported="" name="support-v4-22.0.0" level="project" />
107
+    <orderEntry type="library" exported="" name="jdeferred-android-aar-1.2.3" level="project" />
108
+    <orderEntry type="library" exported="" name="play-services-analytics-7.0.0" level="project" />
109
+    <orderEntry type="library" exported="" name="javacc-4.1" level="project" />
110
+    <orderEntry type="library" exported="" name="play-services-appstate-7.0.0" level="project" />
111
+    <orderEntry type="library" exported="" name="resty-0.3.2" level="project" />
112
+    <orderEntry type="library" exported="" name="play-services-identity-7.0.0" level="project" />
113
+    <orderEntry type="library" exported="" name="play-services-games-7.0.0" level="project" />
114
+    <orderEntry type="library" exported="" name="play-services-wallet-7.0.0" level="project" />
115
+  </component>
116
+</module>
117
+
0 118
new file mode 100644
... ...
@@ -0,0 +1,33 @@
1
+apply plugin: 'com.android.application'
2
+
3
+android {
4
+    compileSdkVersion 19
5
+    buildToolsVersion "22.0.1"
6
+
7
+    defaultConfig {
8
+        applicationId "com.joinmarrow.marrow"
9
+        minSdkVersion 19
10
+        targetSdkVersion 19
11
+        versionCode 4
12
+        //converges on pi/3
13
+        versionName "1.047"
14
+    }
15
+    buildTypes {
16
+        release {
17
+            minifyEnabled false
18
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19
+        }
20
+    }
21
+    compileOptions {
22
+        sourceCompatibility JavaVersion.VERSION_1_7
23
+        targetCompatibility JavaVersion.VERSION_1_7
24
+    }
25
+}
26
+
27
+dependencies {
28
+    compile fileTree(include: ['*.jar'], dir: 'libs')
29
+    compile 'us.monoid.web:resty:0.3.2'
30
+    compile 'org.jdeferred:jdeferred-android-aar:1.2.3'
31
+    compile 'com.google.android.gms:play-services:7.0.0'
32
+    compile 'com.android.support:support-v4:19.0.0'
33
+}
0 34
new file mode 100644
... ...
@@ -0,0 +1,17 @@
1
+# Add project specific ProGuard rules here.
2
+# By default, the flags in this file are appended to flags specified
3
+# in /home/edwlan/adt-bundle-linux-x86_64-20130729/sdk/tools/proguard/proguard-android.txt
4
+# You can edit the include path and order by changing the proguardFiles
5
+# directive in build.gradle.
6
+#
7
+# For more details, see
8
+#   http://developer.android.com/guide/developing/tools/proguard.html
9
+
10
+# Add any project specific keep options here:
11
+
12
+# If your project uses WebView with JS, uncomment the following
13
+# and specify the fully qualified class name to the JavaScript interface
14
+# class:
15
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16
+#   public *;
17
+#}
0 18
new file mode 100644
... ...
@@ -0,0 +1,13 @@
1
+package com.joinmarrow.marrow;
2
+
3
+import android.app.Application;
4
+import android.test.ApplicationTestCase;
5
+
6
+/**
7
+ * <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
8
+ */
9
+public class ApplicationTest extends ApplicationTestCase<Application> {
10
+    public ApplicationTest() {
11
+        super(Application.class);
12
+    }
13
+}
0 14
\ No newline at end of file
1 15
new file mode 100644
... ...
@@ -0,0 +1,36 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3
+    package="com.joinmarrow.marrow" >
4
+
5
+    <uses-permission android:name="android.permission.INTERNET" />
6
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
7
+
8
+
9
+    <application
10
+        android:allowBackup="true"
11
+        android:icon="@mipmap/ic_launcher"
12
+        android:label="@string/app_name"
13
+        android:theme="@style/AppTheme" >
14
+
15
+        <activity
16
+            android:name=".MarrowActivity"
17
+            android:label="@string/app_name"
18
+            android:windowSoftInputMode="stateHidden" >
19
+            <intent-filter>
20
+                <action android:name="android.intent.action.MAIN" />
21
+
22
+                <category android:name="android.intent.category.LAUNCHER" />
23
+            </intent-filter>
24
+        </activity>
25
+        <activity android:name=".SettingsActivity" />
26
+        <activity
27
+            android:name=".LoginActivity"
28
+            android:configChanges="orientation|keyboardHidden|screenSize"
29
+            android:label="@string/title_activity_login"
30
+            android:theme="@style/FullscreenTheme" >
31
+        </activity>
32
+        <meta-data android:name="com.google.android.gms.version"
33
+            android:value="@integer/google_play_services_version" />
34
+    </application>
35
+
36
+</manifest>
0 37
new file mode 100644
1 38
Binary files /dev/null and b/app/src/main/ic_launcher-web.png differ
2 39
new file mode 100644
... ...
@@ -0,0 +1,178 @@
1
+package com.joinmarrow.marrow;
2
+
3
+import com.joinmarrow.marrow.util.SystemUiHider;
4
+
5
+import android.annotation.TargetApi;
6
+import android.app.Activity;
7
+import android.content.SharedPreferences;
8
+import android.os.Build;
9
+import android.os.Bundle;
10
+import android.os.Handler;
11
+import android.preference.PreferenceManager;
12
+import android.util.Log;
13
+import android.view.MotionEvent;
14
+import android.view.View;
15
+import android.widget.EditText;
16
+
17
+
18
+/**
19
+ * An example full-screen activity that shows and hides the system UI (i.e.
20
+ * status bar and navigation/system bar) with user interaction.
21
+ *
22
+ * @see SystemUiHider
23
+ */
24
+public class LoginActivity extends Activity {
25
+    /**
26
+     * Whether or not the system UI should be auto-hidden after
27
+     * {@link #AUTO_HIDE_DELAY_MILLIS} milliseconds.
28
+     */
29
+    private static final boolean AUTO_HIDE = true;
30
+
31
+    /**
32
+     * If {@link #AUTO_HIDE} is set, the number of milliseconds to wait after
33
+     * user interaction before hiding the system UI.
34
+     */
35
+    private static final int AUTO_HIDE_DELAY_MILLIS = 3000;
36
+
37
+    /**
38
+     * If set, will toggle the system UI visibility upon interaction. Otherwise,
39
+     * will show the system UI visibility upon interaction.
40
+     */
41
+    private static final boolean TOGGLE_ON_CLICK = true;
42
+
43
+    /**
44
+     * The flags to pass to {@link SystemUiHider#getInstance}.
45
+     */
46
+    private static final int HIDER_FLAGS = SystemUiHider.FLAG_HIDE_NAVIGATION;
47
+
48
+    /**
49
+     * The instance of the {@link SystemUiHider} for this activity.
50
+     */
51
+    private SystemUiHider mSystemUiHider;
52
+
53
+    @Override
54
+    protected void onCreate(Bundle savedInstanceState) {
55
+        super.onCreate(savedInstanceState);
56
+
57
+        setContentView(R.layout.activity_login);
58
+
59
+        //final View controlsView = findViewById(R.id.fullscreen_content_controls);
60
+        final View contentView = findViewById(R.id.fullscreen_content);
61
+
62
+        // Set up an instance of SystemUiHider to control the system UI for
63
+        // this activity.
64
+        mSystemUiHider = SystemUiHider.getInstance(this, contentView, HIDER_FLAGS);
65
+        mSystemUiHider.setup();
66
+        mSystemUiHider
67
+                .setOnVisibilityChangeListener(new SystemUiHider.OnVisibilityChangeListener() {
68
+                    // Cached values.
69
+                    int mControlsHeight;
70
+                    int mShortAnimTime;
71
+
72
+                    @Override
73
+                    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
74
+                    public void onVisibilityChange(boolean visible) {
75
+                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
76
+                            // If the ViewPropertyAnimator API is available
77
+                            // (Honeycomb MR2 and later), use it to animate the
78
+                            // in-layout UI controls at the bottom of the
79
+                            // screen.
80
+//                            if (mControlsHeight == 0) {
81
+//                                mControlsHeight = controlsView.getHeight();
82
+//                            }
83
+//                            if (mShortAnimTime == 0) {
84
+//                                mShortAnimTime = getResources().getInteger(
85
+//                                        android.R.integer.config_shortAnimTime);
86
+//                            }
87
+//                            controlsView.animate()
88
+//                                    .translationY(visible ? 0 : mControlsHeight)
89
+//                                    .setDuration(mShortAnimTime);
90
+                        } else {
91
+                            // If the ViewPropertyAnimator APIs aren't
92
+                            // available, simply show or hide the in-layout UI
93
+                            // controls.
94
+//                            controlsView.setVisibility(visible ? View.VISIBLE : View.GONE);
95
+                        }
96
+
97
+                        if (visible && AUTO_HIDE) {
98
+                            // Schedule a hide().
99
+                            delayedHide(AUTO_HIDE_DELAY_MILLIS);
100
+                        }
101
+                    }
102
+                });
103
+
104
+        // Set up the user interaction to manually show or hide the system UI.
105
+        contentView.setOnClickListener(new View.OnClickListener() {
106
+            @Override
107
+            public void onClick(View view) {
108
+                if (TOGGLE_ON_CLICK) {
109
+                    mSystemUiHider.toggle();
110
+                } else {
111
+                    mSystemUiHider.show();
112
+                }
113
+            }
114
+        });
115
+
116
+        // Upon interacting with UI controls, delay any scheduled hide()
117
+        // operations to prevent the jarring behavior of controls going away
118
+        // while interacting with the UI.
119
+//        findViewById(R.id.dummy_button).setOnTouchListener(mDelayHideTouchListener);
120
+}
121
+
122
+    @Override
123
+    protected void onPostCreate(Bundle savedInstanceState) {
124
+        super.onPostCreate(savedInstanceState);
125
+
126
+        // Trigger the initial hide() shortly after the activity has been
127
+        // created, to briefly hint to the user that UI controls
128
+        // are available.
129
+        delayedHide(100);
130
+    }
131
+
132
+
133
+    /**
134
+     * Touch listener to use for in-layout UI controls to delay hiding the
135
+     * system UI. This is to prevent the jarring behavior of controls going away
136
+     * while interacting with activity UI.
137
+     */
138
+    View.OnTouchListener mDelayHideTouchListener = new View.OnTouchListener() {
139
+        @Override
140
+        public boolean onTouch(View view, MotionEvent motionEvent) {
141
+            if (AUTO_HIDE) {
142
+                delayedHide(AUTO_HIDE_DELAY_MILLIS);
143
+            }
144
+            return false;
145
+        }
146
+    };
147
+
148
+    Handler mHideHandler = new Handler();
149
+    Runnable mHideRunnable = new Runnable() {
150
+        @Override
151
+        public void run() {
152
+            mSystemUiHider.hide();
153
+        }
154
+    };
155
+
156
+    /**
157
+     * Schedules a call to hide() in [delay] milliseconds, canceling any
158
+     * previously scheduled calls.
159
+     */
160
+    private void delayedHide(int delayMillis) {
161
+        mHideHandler.removeCallbacks(mHideRunnable);
162
+        mHideHandler.postDelayed(mHideRunnable, delayMillis);
163
+    }
164
+
165
+    public void loginClick(View ignored) {
166
+        Log.i("marrow", "Ouch Agaain!");
167
+        EditText username = (EditText)findViewById(R.id.userNameEntry);
168
+        EditText password = (EditText)findViewById(R.id.passwordEntry);
169
+
170
+        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
171
+        SharedPreferences.Editor ed = sp.edit();
172
+        ed.putString("username", username.getText().toString());
173
+        ed.putString("password", password.getText().toString());
174
+        ed.commit();
175
+        finish();
176
+    }
177
+}
178
+    
0 179
new file mode 100644
... ...
@@ -0,0 +1,276 @@
1
+package com.joinmarrow.marrow;
2
+
3
+import android.app.Activity;
4
+import android.content.Context;
5
+import android.content.Intent;
6
+import android.content.SharedPreferences;
7
+import android.net.Uri;
8
+import android.os.AsyncTask;
9
+import android.os.Bundle;
10
+import android.preference.PreferenceManager;
11
+import android.util.Log;
12
+import android.view.KeyEvent;
13
+import android.view.Menu;
14
+import android.view.MenuItem;
15
+import android.view.View;
16
+import android.view.inputmethod.InputMethodManager;
17
+import android.widget.AdapterView;
18
+import android.widget.ArrayAdapter;
19
+import android.widget.ListView;
20
+import android.widget.TextView;
21
+
22
+import com.joinmarrow.marrow.tasks.LogonTask;
23
+
24
+import org.jdeferred.Deferred;
25
+import org.jdeferred.DoneCallback;
26
+import org.jdeferred.FailCallback;
27
+import org.jdeferred.Promise;
28
+import org.jdeferred.impl.DeferredObject;
29
+
30
+import java.io.IOException;
31
+import java.util.ArrayList;
32
+import java.util.HashMap;
33
+import java.util.List;
34
+
35
+import us.monoid.json.JSONArray;
36
+import us.monoid.json.JSONException;
37
+import us.monoid.json.JSONObject;
38
+import us.monoid.web.Resty;
39
+
40
+
41
+public class MarrowActivity extends Activity {
42
+    private TextView userNameText;
43
+    private ListView linkList;
44
+    private String username;
45
+    private String password;
46
+    private String marrowSite;
47
+    public SharedPreferences sharedPref;
48
+
49
+    private class MarrowItem {
50
+        public String iTitle;
51
+        public String iUrl;
52
+
53
+        public MarrowItem(String title, String url) {
54
+            iTitle = title;
55
+            iUrl = url;
56
+        }
57
+
58
+        public String toString() {
59
+            return iTitle;
60
+        }
61
+    }
62
+
63
+    List<MarrowItem> linkData = new ArrayList<MarrowItem>();
64
+    private class GetSubscriptions extends AsyncTask<String, Void, JSONObject> {
65
+        protected JSONObject doInBackground(String... user) {
66
+            JSONObject result = new JSONObject();
67
+            if (null != user && password != "") {
68
+                try {
69
+                    result = new Resty()
70
+                            .json(marrowSite.concat("/api/bones/subscriptions"))
71
+                            .toObject();
72
+                } catch (IOException | JSONException e) {
73
+                    Log.e("marrow", e.getMessage());
74
+                } finally {
75
+                    Log.i("marrow", result.toString());
76
+                }
77
+            }
78
+            return result;
79
+        }
80
+
81
+        protected void onPostExecute(JSONObject result) {
82
+            ListView linkList = (ListView) findViewById(R.id.linkList);
83
+            JSONArray data = new JSONArray();
84
+            try {
85
+                data = result.getJSONArray("marrow");
86
+            } catch (JSONException e) {
87
+                Log.i("marrow", "unexpected JSONException");
88
+                e.printStackTrace();
89
+                Log.d("marrow", result.toString());
90
+            }
91
+            linkData.clear();
92
+            for (int x = 0; x < data.length(); x++) {
93
+                try {
94
+                    linkData.add(
95
+                            new MarrowItem(
96
+                                    data.getJSONObject(x).getString("title"),
97
+                                    data.getJSONObject(x).getString("url")
98
+                            )
99
+                    );
100
+                } catch (JSONException e) {
101
+                    e.printStackTrace();
102
+                }
103
+            }
104
+            ((ArrayAdapter<String>) linkList.getAdapter()).notifyDataSetChanged();
105
+
106
+        }
107
+    }
108
+
109
+    private class GetBoneTask extends AsyncTask<String, Void, JSONObject> {
110
+        protected JSONObject doInBackground(String... user) {
111
+            JSONObject result = new JSONObject();
112
+            if (null != user) {
113
+                try {
114
+                    result = new Resty()
115
+                            .json(marrowSite.concat("/api/bones/u/").concat(user[0]))
116
+                            .toObject();
117
+                } catch (IOException | JSONException e) {
118
+                    Log.e("marrow", e.getMessage());
119
+                } finally {
120
+                    Log.i("marrow", result.toString());
121
+                }
122
+            }
123
+        return result;
124
+        }
125
+
126
+        protected void onPostExecute(JSONObject result) {
127
+            ListView linkList = (ListView) findViewById(R.id.linkList);
128
+            JSONArray data = new JSONArray();
129
+            try {
130
+                data = result.getJSONArray("marrow");
131
+            } catch (JSONException e) {
132
+                Log.i("marrow", "unexpected JSONException");
133
+                e.printStackTrace();
134
+                Log.d("marrow", result.toString());
135
+            }
136
+            linkData.clear();
137
+            for (int x = 0; x < data.length(); x++) {
138
+                try {
139
+                    linkData.add(
140
+                        new MarrowItem(
141
+                            data.getJSONObject(x).getString("title"),
142
+                            data.getJSONObject(x).getString("url")
143
+                        )
144
+                    );
145
+                } catch (JSONException e) {
146
+                    e.printStackTrace();
147
+                }
148
+            }
149
+            ((ArrayAdapter<String>) linkList.getAdapter()).notifyDataSetChanged();
150
+
151
+        }
152
+    }
153
+
154
+    public void goButtonClicked(View view) {
155
+        String userName = userNameText.getText().toString().trim();
156
+        new GetBoneTask().execute(userName);
157
+        InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
158
+        imm.hideSoftInputFromWindow(userNameText.getWindowToken(), 0);
159
+    }
160
+    @Override
161
+    protected void onCreate(Bundle savedInstanceState) {
162
+        super.onCreate(savedInstanceState);
163
+        setContentView(R.layout.activity_marrow);
164
+        userNameText = (TextView) findViewById(R.id.userName);
165
+        userNameText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
166
+            @Override
167
+            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
168
+                boolean result = false;
169
+                if (v.getText() != "") {
170
+                    goButtonClicked(v);
171
+                    result = true;
172
+                }
173
+                return result;
174
+            }
175
+        });
176
+        linkList = (ListView) findViewById(R.id.linkList);
177
+        linkList.setAdapter(
178
+            new ArrayAdapter<MarrowItem>(
179
+                this,
180
+                android.R.layout.simple_list_item_1,
181
+                linkData
182
+            )
183
+        );
184
+        linkList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
185
+            @Override
186
+            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
187
+                MarrowItem item = linkData.get(position);
188
+                Log.i("Marrow", item.iUrl);
189
+                Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(item.iUrl));
190
+                startActivity(browserIntent);
191
+            }
192
+        });
193
+
194
+        final MarrowActivity self = this;
195
+        sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
196
+        username = sharedPref.getString("username", "test");
197
+        password = sharedPref.getString("password", "");
198
+        marrowSite  = sharedPref.getString("site", "https://joinmarrow.com");
199
+
200
+        if (! password.equals("")) {
201
+            Deferred<Boolean, Void, Void> waitForLogon = new DeferredObject();
202
+            Promise<Boolean, Void, Void> logonPromise = waitForLogon.promise();
203
+            new LogonTask(waitForLogon).execute(username, password, marrowSite);
204
+            logonPromise.done(new DoneCallback<Boolean>() {
205
+                @Override
206
+                public void onDone(Boolean success) {
207
+                    if (success) {
208
+                        new GetSubscriptions().execute();
209
+                    } else {
210
+                        startActivity(new Intent(self, LoginActivity.class));
211
+                    }
212
+                }
213
+            }).fail(new FailCallback<Void>() {
214
+                @Override
215
+                public void onFail(Void result) {
216
+                    new GetBoneTask().execute(username);
217
+                }
218
+            });
219
+        }
220
+
221
+        SharedPreferences.OnSharedPreferenceChangeListener spl =
222
+                new SharedPreferences.OnSharedPreferenceChangeListener() {
223
+                    @Override
224
+                    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
225
+                                                          String key) {
226
+                        Log.i("marrow", key);
227
+                        if (key.equals("username")) {
228
+                            username = sharedPreferences.getString("username", "");
229
+                        } else if (key.equals("password")) {
230
+                            Log.i("marrow", "changing Password");
231
+                            password = sharedPreferences.getString("password", "");
232
+                            Deferred<Boolean, Void, Void> waitForLogon = new DeferredObject<Boolean, Void, Void>();
233
+                            Promise<Boolean, Void, Void> logonPromise = waitForLogon.promise();
234
+                            new LogonTask(waitForLogon).execute();
235
+                            logonPromise.done(new DoneCallback<Boolean>() {
236
+                                @Override
237
+                                public void onDone(Boolean result) {
238
+                                    if (result) {
239
+                                        new GetSubscriptions().execute();
240
+                                    } else {
241
+                                        startActivity(new Intent(self, LoginActivity.class));
242
+                                    }
243
+                                }
244
+                            });
245
+                        } else if (key.equals("marrowSite")) {
246
+                            marrowSite =  sharedPreferences.getString("site", "https://joinmarrow.com");
247
+                        }
248
+                    }
249
+                };
250
+        sharedPref.registerOnSharedPreferenceChangeListener(spl);
251
+    }
252
+
253
+
254
+    @Override
255
+    public boolean onCreateOptionsMenu(Menu menu) {
256
+        // Inflate the menu; this adds items to the action bar if it is present.
257
+        getMenuInflater().inflate(R.menu.menu_marrow, menu);
258
+        return true;
259
+    }
260
+
261
+    @Override
262
+    public boolean onOptionsItemSelected(MenuItem item) {
263
+        // Handle action bar item clicks here. The action bar will
264
+        // automatically handle clicks on the Home/Up button, so long
265
+        // as you specify a parent activity in AndroidManifest.xml.
266
+        int id = item.getItemId();
267
+
268
+        //noinspection SimplifiableIfStatement
269
+        if (id == R.id.action_settings) {
270
+            startActivity(new Intent(this, SettingsActivity.class));
271
+            return true;
272
+        }
273
+
274
+        return super.onOptionsItemSelected(item);
275
+    }
276
+}
0 277
new file mode 100644
... ...
@@ -0,0 +1,42 @@
1
+package com.joinmarrow.marrow;
2
+
3
+import android.app.Application;
4
+
5
+import com.google.android.gms.analytics.GoogleAnalytics;
6
+import com.google.android.gms.analytics.Tracker;
7
+
8
+import java.util.HashMap;
9
+
10
+/**
11
+ * Created by edwlan on 4/4/15.
12
+ */
13
+public class MarrowApp extends Application {
14
+    /**
15
+     * Enum used to identify the tracker that needs to be used for tracking.
16
+     *
17
+     * A single tracker is usually enough for most purposes. In case you do need multiple trackers,
18
+     * storing them all in Application object helps ensure that they are created only once per
19
+     * application instance.
20
+     */
21
+    /*public enum TrackerName {
22
+        APP_TRACKER, // Tracker used only in this app.
23
+        GLOBAL_TRACKER, // Tracker used by all the apps from a company. eg: roll-up tracking.
24
+        ECOMMERCE_TRACKER, // Tracker used by all ecommerce transactions from a company.
25
+    }
26
+
27
+    HashMap<TrackerName, Tracker> mTrackers = new HashMap<TrackerName, Tracker>();
28
+*/
29
+    /*synchronized Tracker getTracker(TrackerName trackerId) {
30
+        if (!mTrackers.containsKey(trackerId)) {
31
+
32
+            GoogleAnalytics analytics = GoogleAnalytics.getInstance(this);
33
+            Tracker t = (trackerId == TrackerName.APP_TRACKER) ? analytics.newTracker()
34
+                    : (trackerId == TrackerName.GLOBAL_TRACKER) ? analytics.newTracker(R.xml.global_tracker)
35
+                    : analytics.newTracker(R.xml.ecommerce_tracker);
36
+            mTrackers.put(trackerId, t);
37
+
38
+        }
39
+        return mTrackers.get(trackerId);
40
+    }*/
41
+
42
+}
0 43
new file mode 100644
... ...
@@ -0,0 +1,35 @@
1
+package com.joinmarrow.marrow;
2
+
3
+import android.app.Activity;
4
+import android.content.SharedPreferences;
5
+import android.os.Bundle;
6
+import android.preference.PreferenceFragment;
7
+import android.preference.PreferenceManager;
8
+
9
+import org.jdeferred.Deferred;
10
+import org.jdeferred.DoneCallback;
11
+import org.jdeferred.Promise;
12
+import org.jdeferred.impl.DeferredObject;
13
+
14
+public class SettingsActivity extends Activity {
15
+    public static class SettingsFragment extends PreferenceFragment {
16
+        @Override
17
+        public void onCreate(Bundle savedInstanceState) {
18
+            super.onCreate(savedInstanceState);
19
+
20
+            // Load the preferences from an XML resource
21
+            addPreferencesFromResource(R.xml.preferences);
22
+        }
23
+    }
24
+
25
+    @Override
26
+    protected void onCreate(Bundle savedInstanceState) {
27
+        super.onCreate(savedInstanceState);
28
+
29
+        // Display the fragment as the main content.
30
+        getFragmentManager().beginTransaction()
31
+                .replace(android.R.id.content, new SettingsFragment())
32
+                .commit();
33
+
34
+    }
35
+}
0 36
new file mode 100644
... ...
@@ -0,0 +1,60 @@
1
+package com.joinmarrow.marrow.tasks;
2
+
3
+import android.os.AsyncTask;
4
+import android.util.Log;
5
+
6
+import org.jdeferred.Deferred;
7
+
8
+import java.util.HashMap;
9
+
10
+import us.monoid.json.JSONObject;
11
+import us.monoid.web.Resty;
12
+
13
+/**
14
+ * Created by edwlan on 4/5/15.
15
+ */
16
+public class LogonTask extends AsyncTask<String, Integer, JSONObject> {
17
+    Deferred taskDeferred;
18
+    private String endpoint;
19
+
20
+    public LogonTask(Deferred d, String url) {
21
+        super();
22
+        endpoint = url.concat("/api/user/login");
23
+        taskDeferred = d;
24
+    }
25
+
26
+    protected JSONObject doInBackground(String... info) {
27
+        String username = info[0];
28
+        String password = info[1];
29
+
30
+        JSONObject result = new JSONObject();
31
+        try {
32
+            Log.i("marrow", "getting");
33
+
34
+            HashMap<String, String> authInfo = new HashMap<>();
35
+            authInfo.put("username", username);
36
+            authInfo.put("password", password);
37
+            JSONObject postData = new JSONObject(authInfo);
38
+            //Log.i("marrow", postData.toString());
39
+
40
+            result = new Resty().json(endpoint, Resty.content(postData)).toObject();
41
+            Log.i("marrow", "gotten");
42
+        } catch (IOException | JSONException e) {
43
+            Log.i("marrow", "fail!");
44
+            Log.e("marrow", e.getLocalizedMessage());
45
+        }
46
+        return result;
47
+    }
48
+
49
+    protected void onPostExecute(JSONObject result) {
50
+        boolean success = false;
51
+        try {
52
+            success = result.getBoolean("status");
53
+            taskDeferred.resolve(success);
54
+        } catch (JSONException e) {
55
+            e.printStackTrace();
56
+            taskDeferred.reject(result);
57
+        }
58
+    }
59
+}
60
+
0 61
new file mode 100644
... ...
@@ -0,0 +1,172 @@
1
+package com.joinmarrow.marrow.util;
2
+
3
+import android.app.Activity;
4
+import android.os.Build;
5
+import android.view.View;
6
+
7
+/**
8
+ * A utility class that helps with showing and hiding system UI such as the
9
+ * status bar and navigation/system bar. This class uses backward-compatibility
10
+ * techniques described in <a href=
11
+ * "http://developer.android.com/training/backward-compatible-ui/index.html">
12
+ * Creating Backward-Compatible UIs</a> to ensure that devices running any
13
+ * version of ndroid OS are supported. More specifically, there are separate
14
+ * implementations of this abstract class: for newer devices,
15
+ * {@link #getInstance} will return a {@link SystemUiHiderHoneycomb} instance,
16
+ * while on older devices {@link #getInstance} will return a
17
+ * {@link SystemUiHiderBase} instance.
18
+ * <p/>
19
+ * For more on system bars, see <a href=
20
+ * "http://developer.android.com/design/get-started/ui-overview.html#system-bars"
21
+ * > System Bars</a>.
22
+ *
23
+ * @see android.view.View#setSystemUiVisibility(int)
24
+ * @see android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN
25
+ */
26
+public abstract class SystemUiHider {
27
+    /**
28
+     * When this flag is set, the
29
+     * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN}
30
+     * flag will be set on older devices, making the status bar "float" on top
31
+     * of the activity layout. This is most useful when there are no controls at
32
+     * the top of the activity layout.
33
+     * <p/>
34
+     * This flag isn't used on newer devices because the <a
35
+     * href="http://developer.android.com/design/patterns/actionbar.html">action
36
+     * bar</a>, the most important structural element of an Android app, should
37
+     * be visible and not obscured by the system UI.
38
+     */
39
+    public static final int FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES = 0x1;
40
+
41
+    /**
42
+     * When this flag is set, {@link #show()} and {@link #hide()} will toggle
43
+     * the visibility of the status bar. If there is a navigation bar, show and
44
+     * hide will toggle low profile mode.
45
+     */
46
+    public static final int FLAG_FULLSCREEN = 0x2;
47
+
48
+    /**
49
+     * When this flag is set, {@link #show()} and {@link #hide()} will toggle
50
+     * the visibility of the navigation bar, if it's present on the device and
51
+     * the device allows hiding it. In cases where the navigation bar is present
52
+     * but cannot be hidden, show and hide will toggle low profile mode.
53
+     */
54
+    public static final int FLAG_HIDE_NAVIGATION = FLAG_FULLSCREEN | 0x4;
55
+
56
+    /**
57
+     * The activity associated with this UI hider object.
58
+     */
59
+    protected Activity mActivity;
60
+
61
+    /**
62
+     * The view on which {@link View#setSystemUiVisibility(int)} will be called.
63
+     */
64
+    protected View mAnchorView;
65
+
66
+    /**
67
+     * The current UI hider flags.
68
+     *
69
+     * @see #FLAG_FULLSCREEN
70
+     * @see #FLAG_HIDE_NAVIGATION
71
+     * @see #FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES
72
+     */
73
+    protected int mFlags;
74
+
75
+    /**
76
+     * The current visibility callback.
77
+     */
78
+    protected OnVisibilityChangeListener mOnVisibilityChangeListener = sDummyListener;
79
+
80
+    /**
81
+     * Creates and returns an instance of {@link SystemUiHider} that is
82
+     * appropriate for this device. The object will be either a
83
+     * {@link SystemUiHiderBase} or {@link SystemUiHiderHoneycomb} depending on
84
+     * the device.
85
+     *
86
+     * @param activity   The activity whose window's system UI should be
87
+     *                   controlled by this class.
88
+     * @param anchorView The view on which
89
+     *                   {@link View#setSystemUiVisibility(int)} will be called.
90
+     * @param flags      Either 0 or any combination of {@link #FLAG_FULLSCREEN},
91
+     *                   {@link #FLAG_HIDE_NAVIGATION}, and
92
+     *                   {@link #FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES}.
93
+     */
94
+    public static SystemUiHider getInstance(Activity activity, View anchorView, int flags) {
95
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
96
+            return new SystemUiHiderHoneycomb(activity, anchorView, flags);
97
+        } else {
98
+            return new SystemUiHiderBase(activity, anchorView, flags);
99
+        }
100
+    }
101
+
102
+    protected SystemUiHider(Activity activity, View anchorView, int flags) {
103
+        mActivity = activity;
104
+        mAnchorView = anchorView;
105
+        mFlags = flags;
106
+    }
107
+
108
+    /**
109
+     * Sets up the system UI hider. Should be called from
110
+     * {@link Activity#onCreate}.
111
+     */
112
+    public abstract void setup();
113
+
114
+    /**
115
+     * Returns whether or not the system UI is visible.
116
+     */
117
+    public abstract boolean isVisible();
118
+
119
+    /**
120
+     * Hide the system UI.
121
+     */
122
+    public abstract void hide();
123
+
124
+    /**
125
+     * Show the system UI.
126
+     */
127
+    public abstract void show();
128
+
129
+    /**
130
+     * Toggle the visibility of the system UI.
131
+     */
132
+    public void toggle() {
133
+        if (isVisible()) {
134
+            hide();
135
+        } else {
136
+            show();
137
+        }
138
+    }
139
+
140
+    /**
141
+     * Registers a callback, to be triggered when the system UI visibility
142
+     * changes.
143
+     */
144
+    public void setOnVisibilityChangeListener(OnVisibilityChangeListener listener) {
145
+        if (listener == null) {
146
+            listener = sDummyListener;
147
+        }
148
+
149
+        mOnVisibilityChangeListener = listener;
150
+    }
151
+
152
+    /**
153
+     * A dummy no-op callback for use when there is no other listener set.
154
+     */
155
+    private static OnVisibilityChangeListener sDummyListener = new OnVisibilityChangeListener() {
156
+        @Override
157
+        public void onVisibilityChange(boolean visible) {
158
+        }
159
+    };
160
+
161
+    /**
162
+     * A callback interface used to listen for system UI visibility changes.
163
+     */
164
+    public interface OnVisibilityChangeListener {
165
+        /**
166
+         * Called when the system UI visibility has changed.
167
+         *
168
+         * @param visible True if the system UI is visible.
169
+         */
170
+        public void onVisibilityChange(boolean visible);
171
+    }
172
+}
0 173
new file mode 100644
... ...
@@ -0,0 +1,63 @@
1
+package com.joinmarrow.marrow.util;
2
+
3
+import android.app.Activity;
4
+import android.view.View;
5
+import android.view.WindowManager;
6
+
7
+/**
8
+ * A base implementation of {@link SystemUiHider}. Uses APIs available in all
9
+ * API levels to show and hide the status bar.
10
+ */
11
+public class SystemUiHiderBase extends SystemUiHider {
12
+    /**
13
+     * Whether or not the system UI is currently visible. This is a cached value
14
+     * from calls to {@link #hide()} and {@link #show()}.
15
+     */
16
+    private boolean mVisible = true;
17
+
18
+    /**
19
+     * Constructor not intended to be called by clients. Use
20
+     * {@link SystemUiHider#getInstance} to obtain an instance.
21
+     */
22
+    protected SystemUiHiderBase(Activity activity, View anchorView, int flags) {
23
+        super(activity, anchorView, flags);
24
+    }
25
+
26
+    @Override
27
+    public void setup() {
28
+        if ((mFlags & FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES) == 0) {
29
+            mActivity.getWindow().setFlags(
30
+                    WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
31
+                            | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
32
+                    WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
33
+                            | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
34
+        }
35
+    }
36
+
37
+    @Override
38
+    public boolean isVisible() {
39
+        return mVisible;
40
+    }
41
+
42
+    @Override
43
+    public void hide() {
44
+        if ((mFlags & FLAG_FULLSCREEN) != 0) {
45
+            mActivity.getWindow().setFlags(
46
+                    WindowManager.LayoutParams.FLAG_FULLSCREEN,
47
+                    WindowManager.LayoutParams.FLAG_FULLSCREEN);
48
+        }
49
+        mOnVisibilityChangeListener.onVisibilityChange(false);
50
+        mVisible = false;
51
+    }
52
+
53
+    @Override
54
+    public void show() {
55
+        if ((mFlags & FLAG_FULLSCREEN) != 0) {
56
+            mActivity.getWindow().setFlags(
57
+                    0,
58
+                    WindowManager.LayoutParams.FLAG_FULLSCREEN);
59
+        }
60
+        mOnVisibilityChangeListener.onVisibilityChange(true);
61
+        mVisible = true;
62
+    }
63
+}
0 64
new file mode 100644
... ...
@@ -0,0 +1,141 @@
1
+package com.joinmarrow.marrow.util;
2
+
3
+import android.annotation.TargetApi;
4
+import android.app.Activity;
5
+import android.os.Build;
6
+import android.view.View;
7
+import android.view.WindowManager;
8
+
9
+/**
10
+ * An API 11+ implementation of {@link SystemUiHider}. Uses APIs available in
11
+ * Honeycomb and later (specifically {@link View#setSystemUiVisibility(int)}) to
12
+ * show and hide the system UI.
13
+ */
14
+@TargetApi(Build.VERSION_CODES.HONEYCOMB)
15
+public class SystemUiHiderHoneycomb extends SystemUiHiderBase {
16
+    /**
17
+     * Flags for {@link View#setSystemUiVisibility(int)} to use when showing the
18
+     * system UI.
19
+     */
20
+    private int mShowFlags;
21
+
22
+    /**
23
+     * Flags for {@link View#setSystemUiVisibility(int)} to use when hiding the
24
+     * system UI.
25
+     */
26
+    private int mHideFlags;
27
+
28
+    /**
29
+     * Flags to test against the first parameter in
30
+     * {@link android.view.View.OnSystemUiVisibilityChangeListener#onSystemUiVisibilityChange(int)}
31
+     * to determine the system UI visibility state.
32
+     */
33
+    private int mTestFlags;
34
+
35
+    /**
36
+     * Whether or not the system UI is currently visible. This is cached from
37
+     * {@link android.view.View.OnSystemUiVisibilityChangeListener}.
38
+     */
39
+    private boolean mVisible = true;
40
+
41
+    /**
42
+     * Constructor not intended to be called by clients. Use
43
+     * {@link SystemUiHider#getInstance} to obtain an instance.
44
+     */
45
+    protected SystemUiHiderHoneycomb(Activity activity, View anchorView, int flags) {
46
+        super(activity, anchorView, flags);
47
+
48
+        mShowFlags = View.SYSTEM_UI_FLAG_VISIBLE;
49
+        mHideFlags = View.SYSTEM_UI_FLAG_LOW_PROFILE;
50
+        mTestFlags = View.SYSTEM_UI_FLAG_LOW_PROFILE;
51
+
52
+        if ((mFlags & FLAG_FULLSCREEN) != 0) {
53
+            // If the client requested fullscreen, add flags relevant to hiding
54
+            // the status bar. Note that some of these constants are new as of
55
+            // API 16 (Jelly Bean). It is safe to use them, as they are inlined
56
+            // at compile-time and do nothing on pre-Jelly Bean devices.
57
+            mShowFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
58
+            mHideFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
59
+                    | View.SYSTEM_UI_FLAG_FULLSCREEN;
60
+        }
61
+
62
+        if ((mFlags & FLAG_HIDE_NAVIGATION) != 0) {
63
+            // If the client requested hiding navigation, add relevant flags.
64
+            mShowFlags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
65
+            mHideFlags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
66
+                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
67
+            mTestFlags |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
68
+        }
69
+    }
70
+
71
+    /**
72
+     * {@inheritDoc}
73
+     */
74
+    @Override
75
+    public void setup() {
76
+        mAnchorView.setOnSystemUiVisibilityChangeListener(mSystemUiVisibilityChangeListener);
77
+    }
78
+
79
+    /**
80
+     * {@inheritDoc}
81
+     */
82
+    @Override
83
+    public void hide() {
84
+        mAnchorView.setSystemUiVisibility(mHideFlags);
85
+    }
86
+
87
+    /**
88
+     * {@inheritDoc}
89
+     */
90
+    @Override
91
+    public void show() {
92
+        mAnchorView.setSystemUiVisibility(mShowFlags);
93
+    }
94
+
95
+    /**
96
+     * {@inheritDoc}
97
+     */
98
+    @Override
99
+    public boolean isVisible() {
100
+        return mVisible;
101
+    }
102
+
103
+    private View.OnSystemUiVisibilityChangeListener mSystemUiVisibilityChangeListener
104
+            = new View.OnSystemUiVisibilityChangeListener() {
105
+        @Override
106
+        public void onSystemUiVisibilityChange(int vis) {
107
+            // Test against mTestFlags to see if the system UI is visible.
108
+            if ((vis & mTestFlags) != 0) {
109
+                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
110
+                    // Pre-Jelly Bean, we must manually hide the action bar
111
+                    // and use the old window flags API.
112
+                    mActivity.getActionBar().hide();
113
+                    mActivity.getWindow().setFlags(
114
+                            WindowManager.LayoutParams.FLAG_FULLSCREEN,
115
+                            WindowManager.LayoutParams.FLAG_FULLSCREEN);
116
+                }
117
+
118
+                // Trigger the registered listener and cache the visibility
119
+                // state.
120
+                mOnVisibilityChangeListener.onVisibilityChange(false);
121
+                mVisible = false;
122
+
123
+            } else {
124
+                mAnchorView.setSystemUiVisibility(mShowFlags);
125
+                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
126
+                    // Pre-Jelly Bean, we must manually show the action bar
127
+                    // and use the old window flags API.
128
+                    mActivity.getActionBar().show();
129
+                    mActivity.getWindow().setFlags(
130
+                            0,
131
+                            WindowManager.LayoutParams.FLAG_FULLSCREEN);
132
+                }
133
+
134
+                // Trigger the registered listener and cache the visibility
135
+                // state.
136
+                mOnVisibilityChangeListener.onVisibilityChange(true);
137
+                mVisible = true;
138
+            }
139
+        }
140
+    };
141
+}
0 142
new file mode 100644
... ...
@@ -0,0 +1,52 @@
1
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
2
+    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
3
+    android:layout_height="match_parent" android:background="#ffffff"
4
+    tools:context="com.joinmarrow.marrow.LoginActivity">
5
+
6
+    <!-- The primary full-screen view. This can be replaced with whatever view
7
+         is needed to present your content, e.g. VideoView, SurfaceView,
8
+         TextureView, etc. -->
9
+
10
+    <!-- This FrameLayout insets its children based on system windows using
11
+         android:fitsSystemWindows. -->
12
+
13
+    <RelativeLayout
14
+        android:layout_width="fill_parent"
15
+        android:layout_height="fill_parent"
16
+        android:layout_gravity="right|bottom"
17
+        android:id="@+id/fullscreen_content">
18
+
19
+        <EditText
20
+            android:layout_width="fill_parent"
21
+            android:layout_height="wrap_content"
22
+            android:id="@+id/userNameEntry"
23
+            android:singleLine="true"
24
+            android:hint="Username"
25
+            android:layout_alignParentTop="true"
26
+            android:layout_alignParentStart="true"
27
+            android:layout_marginTop="80dp" />
28
+
29
+        <EditText
30
+            android:layout_width="fill_parent"
31
+            android:layout_height="wrap_content"
32
+            android:inputType="textPassword"
33
+            android:ems="10"
34
+            android:id="@+id/passwordEntry"
35
+            android:singleLine="true"
36
+            android:hint="Password"
37
+            android:layout_below="@+id/userNameEntry"
38
+            android:layout_alignParentStart="true"
39
+            android:layout_marginTop="20dp" />
40
+
41
+        <Button
42
+            android:layout_width="wrap_content"
43
+            android:layout_height="wrap_content"
44
+            android:text="Login"
45
+            android:id="@+id/button"
46
+            android:onClick="loginClick"
47
+            android:layout_below="@+id/passwordEntry"
48
+            android:layout_centerHorizontal="true"
49
+            android:layout_marginTop="20dp" />
50
+
51
+    </RelativeLayout>
52
+</FrameLayout>
0 53
new file mode 100644
... ...
@@ -0,0 +1,49 @@
1
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
2
+    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
3
+    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
4
+    android:paddingRight="@dimen/activity_horizontal_margin"
5
+    android:paddingTop="@dimen/activity_vertical_margin"
6
+    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MarrowActivity">
7
+
8
+    <LinearLayout
9
+        android:orientation="vertical"
10
+        android:layout_width="fill_parent"
11
+        android:layout_height="fill_parent"
12
+        android:layout_alignParentTop="true"
13
+        android:layout_alignParentBottom="true"
14
+        android:layout_alignParentStart="true"
15
+        android:layout_alignParentEnd="true">
16
+
17
+        <LinearLayout
18
+            android:orientation="horizontal"
19
+            android:layout_width="match_parent"
20
+            android:layout_height="wrap_content"
21
+            android:layout_gravity="center_horizontal">
22
+
23
+            <EditText
24
+                android:layout_width="wrap_content"
25
+                android:layout_height="wrap_content"
26
+                android:id="@+id/userName"
27
+                android:maxLines="1"
28
+                android:layout_weight="1"
29
+                android:hint="Username" />
30
+
31
+            <Button
32
+                android:layout_width="wrap_content"
33
+                android:layout_height="fill_parent"
34
+                android:text="Get Links!"
35
+                android:id="@+id/getUser"
36
+                android:onClick="goButtonClicked" />
37
+        </LinearLayout>
38
+
39
+        <ListView
40
+            android:layout_width="wrap_content"
41
+            android:layout_height="match_parent"
42
+            android:id="@+id/linkList"
43
+            tools:listitem="@android:layout/simple_list_item_1"
44
+            android:choiceMode="none"
45
+            android:focusable="true"
46
+            android:focusableInTouchMode="true" />
47
+
48
+    </LinearLayout>
49
+</RelativeLayout>
0 50
new file mode 100644
... ...
@@ -0,0 +1,6 @@
1
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
2
+    xmlns:app="http://schemas.android.com/apk/res-auto"
3
+    xmlns:tools="http://schemas.android.com/tools" tools:context=".MarrowActivity">
4
+    <item android:id="@+id/action_settings" android:title="@string/action_settings"
5
+        android:orderInCategory="100" />
6
+</menu>
0 7
new file mode 100644
1 8
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
2 9
new file mode 100644
3 10
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
4 11
new file mode 100644
5 12
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
6 13
new file mode 100644
7 14
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
8 15
new file mode 100644
9 16
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
10 17
new file mode 100644
... ...
@@ -0,0 +1,15 @@
1
+<resources>
2
+
3
+    <style name="FullscreenTheme" parent="android:Theme.Holo">
4
+        <item name="android:actionBarStyle">@style/FullscreenActionBarStyle</item>
5
+        <item name="android:windowActionBarOverlay">true</item>
6
+        <item name="android:windowBackground">@null</item>
7
+        <item name="metaButtonBarStyle">?android:attr/buttonBarStyle</item>
8
+        <item name="metaButtonBarButtonStyle">?android:attr/buttonBarButtonStyle</item>
9
+    </style>
10
+
11
+    <style name="FullscreenActionBarStyle" parent="android:Widget.Holo.ActionBar">
12
+        <item name="android:background">@color/black_overlay</item>
13
+    </style>
14
+
15
+</resources>
0 16
new file mode 100644
... ...
@@ -0,0 +1,6 @@
1
+<resources>
2
+    <!-- Example customization of dimensions originally defined in res/values/dimens.xml
3
+         (such as screen margins) for screens with more than 820dp of available width. This
4
+         would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
5
+    <dimen name="activity_horizontal_margin">64dp</dimen>
6
+</resources>
0 7
new file mode 100644
... ...
@@ -0,0 +1,12 @@
1
+<resources>
2
+
3
+    <!-- Declare custom theme attributes that allow changing which styles are
4
+         used for button bars depending on the API level.
5
+         ?android:attr/buttonBarStyle is new as of API 11 so this is
6
+         necessary to support previous API levels. -->
7
+    <declare-styleable name="ButtonBarContainerTheme">
8
+        <attr name="metaButtonBarStyle" format="reference" />
9
+        <attr name="metaButtonBarButtonStyle" format="reference" />
10
+    </declare-styleable>
11
+
12
+</resources>
0 13
new file mode 100644
... ...
@@ -0,0 +1,5 @@
1
+<resources>
2
+
3
+    <color name="black_overlay">#66000000</color>
4
+
5
+</resources>
0 6
new file mode 100644
... ...
@@ -0,0 +1,5 @@
1
+<resources>
2
+    <!-- Default screen margins, per the Android Design guidelines. -->
3
+    <dimen name="activity_horizontal_margin">16dp</dimen>
4
+    <dimen name="activity_vertical_margin">16dp</dimen>
5
+</resources>
0 6
new file mode 100644
... ...
@@ -0,0 +1,12 @@
1
+<resources>
2
+    <string name="app_name">Marrow</string>
3
+
4
+    <string name="action_settings">Settings</string>
5
+    <string name="username">Username</string>
6
+    <string name="password">Password</string>
7
+    <string name="site">Site URL (do not change)</string>
8
+
9
+    <string name="title_activity_login">LoginActivity</string>
10
+    <string name="dummy_button">Dummy Button</string>
11
+    <string name="dummy_content">DUMMY\nCONTENT</string>
12
+</resources>
0 13
new file mode 100644
... ...
@@ -0,0 +1,27 @@
1
+<resources>
2
+
3
+    <!-- Base application theme. -->
4
+    <style name="AppTheme" parent="android:Theme.Holo.Light">
5
+        <!-- Customize your theme here. -->
6
+    </style>
7
+
8
+    <style name="FullscreenTheme" parent="android:Theme.NoTitleBar">
9
+        <item name="android:windowContentOverlay">@null</item>
10
+        <item name="android:windowBackground">@null</item>
11
+        <item name="metaButtonBarStyle">@style/ButtonBar</item>
12
+        <item name="metaButtonBarButtonStyle">@style/ButtonBarButton</item>
13
+    </style>
14
+
15
+    <!-- Backward-compatible version of ?android:attr/buttonBarStyle -->
16
+    <style name="ButtonBar">
17
+        <item name="android:paddingLeft">2dp</item>
18
+        <item name="android:paddingTop">5dp</item>
19
+        <item name="android:paddingRight">2dp</item>
20
+        <item name="android:paddingBottom">0dp</item>
21
+        <item name="android:background">@android:drawable/bottom_bar</item>
22
+    </style>
23
+
24
+    <!-- Backward-compatible version of ?android:attr/buttonBarButtonStyle -->
25
+    <style name="ButtonBarButton" />
26
+
27
+</resources>
0 28
new file mode 100644
... ...
@@ -0,0 +1,17 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<resources>
3
+    <integer name="ga_sessionTimeout">300</integer>
4
+
5
+    <!-- Enable automatic Activity measurement -->
6
+    <bool name="ga_autoActivityTracking">true</bool>
7
+
8
+    <!-- The screen names that will appear in reports -->
9
+    <screenName name="com.google.android.gms.analytics.samples.mobileplayground.ScreenviewFragment">
10
+        AnalyticsSampleApp ScreenViewSampleScreen
11
+    </screenName>
12
+    <screenName name="com.google.android.gms.analytics.samples.mobileplayground.EcommerceFragment">
13
+        AnalyticsSampleApp EcommerceSampleScreen
14
+    </screenName>
15
+    <!--  The following value should be replaced with correct property id. -->
16
+    <string name="ga_trackingId">UA-61547817-1</string>
17
+</resources>
0 18
new file mode 100644
... ...
@@ -0,0 +1,14 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
3
+    <EditTextPreference
4
+        android:key="username"
5
+        android:title="@string/username" />
6
+    <EditTextPreference
7
+        android:key="password"
8
+        android:title="@string/password" />
9
+    <EditTextPreference
10
+        android:key="site"
11
+        android:title="@string/site"
12
+        android:defaultValue="https://joinmarrow.com" />
13
+
14
+</PreferenceScreen>
0 15
\ No newline at end of file