Skip to content
This repository
Browse code

Add Imgur uploader sample.

  • Loading branch information...
commit 7dcd3c66a1e0ecc1a06c310b287cf2fcff6bd10c 1 parent 8e6dcd1
Jake Wharton authored September 28, 2012

Showing 36 changed files with 723 additions and 56 deletions. Show diff stats Hide diff stats

  1. 6  CHANGELOG.md
  2. 192  pom.xml
  3. 30  tape-sample/AndroidManifest.xml
  4. 56  tape-sample/pom.xml
  5. BIN  tape-sample/res/drawable-hdpi/icon.png
  6. BIN  tape-sample/res/drawable-mdpi/icon.png
  7. BIN  tape-sample/res/drawable-xhdpi/icon.png
  8. 30  tape-sample/res/layout/sample_activity.xml
  9. 9  tape-sample/res/layout/upload.xml
  10. 10  tape-sample/res/values/strings.xml
  11. 41  tape-sample/src/main/java/com/squareup/tape/sample/GsonConverter.java
  12. 10  tape-sample/src/main/java/com/squareup/tape/sample/ImageUploadQueueSizeEvent.java
  13. 10  tape-sample/src/main/java/com/squareup/tape/sample/ImageUploadSuccessEvent.java
  14. 75  tape-sample/src/main/java/com/squareup/tape/sample/ImageUploadTask.java
  15. 65  tape-sample/src/main/java/com/squareup/tape/sample/ImageUploadTaskQueue.java
  16. 58  tape-sample/src/main/java/com/squareup/tape/sample/ImageUploadTaskService.java
  17. 92  tape-sample/src/main/java/com/squareup/tape/sample/SampleActivity.java
  18. 53  tape-sample/src/main/java/com/squareup/tape/sample/SampleApplication.java
  19. 34  tape/pom.xml
  20. 0  { → tape}/src/main/java/com/squareup/tape/FileException.java
  21. 0  { → tape}/src/main/java/com/squareup/tape/FileObjectQueue.java
  22. 0  { → tape}/src/main/java/com/squareup/tape/InMemoryObjectQueue.java
  23. 0  { → tape}/src/main/java/com/squareup/tape/ObjectQueue.java
  24. 0  { → tape}/src/main/java/com/squareup/tape/QueueFile.java
  25. 0  { → tape}/src/main/java/com/squareup/tape/SerializedConverter.java
  26. 0  { → tape}/src/main/java/com/squareup/tape/Task.java
  27. 0  { → tape}/src/main/java/com/squareup/tape/TaskInjector.java
  28. 6  { → tape}/src/main/java/com/squareup/tape/TaskQueue.java
  29. 0  { → tape}/src/test/java/com/squareup/tape/QueueFileTest.java
  30. 0  { → tape}/src/test/java/com/squareup/tape/QueueTestUtils.java
  31. 0  { → tape}/src/test/java/com/squareup/tape/SerializedConverterTest.java
  32. 0  { → tape}/src/test/resources/empty-serialized-queue
  33. 0  { → tape}/src/test/resources/one-entry-serialized-queue
  34. 0  { → tape}/src/test/resources/truncated-empty-serialized-queue
  35. 0  { → tape}/src/test/resources/truncated-one-entry-serialized-queue
  36. 2  website/index.html
6  CHANGELOG.md
Source Rendered
... ...
@@ -1,6 +1,12 @@
1 1
 Change Log
2 2
 ==========
3 3
 
  4
+Version 1.0.1 *(In Development)*
  5
+--------------------------------
  6
+
  7
+ * Allow a `TaskQueue`'s `TaskInject` to be `null`.
  8
+
  9
+
4 10
 Version 1.0.0 *(2012-09-25)*
5 11
 ----------------------------
6 12
 
192  pom.xml
... ...
@@ -1,6 +1,21 @@
1 1
 <?xml version="1.0" encoding="UTF-8"?>
  2
+<!--
  3
+ Copyright (C) 2012 Square, Inc.
2 4
 
3  
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  5
+  Licensed under the Apache License, Version 2.0 (the "License");
  6
+  you may not use this file except in compliance with the License.
  7
+  You may obtain a copy of the License at
  8
+
  9
+       http://www.apache.org/licenses/LICENSE-2.0
  10
+
  11
+  Unless required by applicable law or agreed to in writing, software
  12
+  distributed under the License is distributed on an "AS IS" BASIS,
  13
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14
+  See the License for the specific language governing permissions and
  15
+  limitations under the License.
  16
+-->
  17
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  18
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4 19
   <modelVersion>4.0.0</modelVersion>
5 20
 
6 21
   <parent>
@@ -10,12 +25,32 @@
10 25
   </parent>
11 26
 
12 27
   <groupId>com.squareup</groupId>
13  
-  <artifactId>tape</artifactId>
14  
-  <packaging>jar</packaging>
  28
+  <artifactId>tape-parent</artifactId>
15 29
   <version>1.0.1-SNAPSHOT</version>
  30
+  <packaging>pom</packaging>
16 31
 
17  
-  <name>Tape</name>
  32
+  <name>Tape (Parent)</name>
18 33
   <description>A lightning fast, transactional, file-based FIFO for Android and Java.</description>
  34
+  <url>http://github.com/square/tape/</url>
  35
+
  36
+  <modules>
  37
+    <module>tape</module>
  38
+    <module>tape-sample</module>
  39
+  </modules>
  40
+
  41
+  <properties>
  42
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  43
+
  44
+    <android.version>4.1.1.4</android.version>
  45
+    <android.platform>16</android.platform>
  46
+    <http-request.version>2.2</http-request.version>
  47
+    <dagger.version>1.0-SNAPSHOT</dagger.version>
  48
+    <otto.version>1.3.1</otto.version>
  49
+    <gson.version>2.2</gson.version>
  50
+    <junit.version>4.10</junit.version>
  51
+    <fest.version>1.4</fest.version>
  52
+    <commons-io.version>2.4</commons-io.version>
  53
+  </properties>
19 54
 
20 55
   <scm>
21 56
     <url>http://github.com/square/tape</url>
@@ -41,65 +76,114 @@
41 76
     </license>
42 77
   </licenses>
43 78
 
44  
-  <properties>
45  
-    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  79
+  <dependencyManagement>
  80
+    <dependencies>
  81
+      <dependency>
  82
+        <groupId>com.google.android</groupId>
  83
+        <artifactId>android</artifactId>
  84
+        <version>${android.version}</version>
  85
+      </dependency>
  86
+      <dependency>
  87
+        <groupId>com.squareup</groupId>
  88
+        <artifactId>dagger</artifactId>
  89
+        <version>${dagger.version}</version>
  90
+      </dependency>
  91
+      <dependency>
  92
+        <groupId>com.squareup</groupId>
  93
+        <artifactId>otto</artifactId>
  94
+        <version>${otto.version}</version>
  95
+      </dependency>
  96
+      <dependency>
  97
+        <groupId>com.github.kevinsawicki</groupId>
  98
+        <artifactId>http-request</artifactId>
  99
+        <version>${http-request.version}</version>
  100
+      </dependency>
  101
+      <dependency>
  102
+        <groupId>com.google.code.gson</groupId>
  103
+        <artifactId>gson</artifactId>
  104
+        <version>${gson.version}</version>
  105
+      </dependency>
  106
+      <dependency>
  107
+        <groupId>junit</groupId>
  108
+        <artifactId>junit</artifactId>
  109
+        <version>${junit.version}</version>
  110
+      </dependency>
  111
+      <dependency>
  112
+        <groupId>org.easytesting</groupId>
  113
+        <artifactId>fest-assert</artifactId>
  114
+        <version>${fest.version}</version>
  115
+      </dependency>
  116
+      <dependency>
  117
+        <groupId>commons-io</groupId>
  118
+        <artifactId>commons-io</artifactId>
  119
+        <version>${commons-io.version}</version>
  120
+      </dependency>
  121
+    </dependencies>
  122
+  </dependencyManagement>
46 123
 
47  
-    <java.version>1.6</java.version>
48  
-    <junit.version>4.10</junit.version>
49  
-    <fest.version>1.4</fest.version>
50  
-    <commons-io.version>2.4</commons-io.version>
51  
-  </properties>
  124
+  <build>
  125
+    <pluginManagement>
  126
+      <plugins>
  127
+        <plugin>
  128
+          <groupId>org.apache.maven.plugins</groupId>
  129
+          <artifactId>maven-compiler-plugin</artifactId>
  130
+          <version>2.5</version>
  131
+          <configuration>
  132
+            <source>1.6</source>
  133
+            <target>1.6</target>
  134
+          </configuration>
  135
+        </plugin>
52 136
 
53  
-  <dependencies>
54  
-    <dependency>
55  
-      <groupId>junit</groupId>
56  
-      <artifactId>junit</artifactId>
57  
-      <version>${junit.version}</version>
58  
-      <scope>test</scope>
59  
-    </dependency>
60  
-    <dependency>
61  
-      <groupId>org.easytesting</groupId>
62  
-      <artifactId>fest-assert</artifactId>
63  
-      <version>${fest.version}</version>
64  
-      <scope>test</scope>
65  
-    </dependency>
66  
-    <dependency>
67  
-      <groupId>commons-io</groupId>
68  
-      <artifactId>commons-io</artifactId>
69  
-      <version>${commons-io.version}</version>
70  
-      <scope>test</scope>
71  
-    </dependency>
72  
-  </dependencies>
  137
+        <plugin>
  138
+          <groupId>org.apache.maven.plugins</groupId>
  139
+          <artifactId>maven-checkstyle-plugin</artifactId>
  140
+          <version>2.9.1</version>
  141
+          <configuration>
  142
+            <failsOnError>true</failsOnError>
  143
+            <configLocation>../checkstyle.xml</configLocation>
  144
+          </configuration>
  145
+          <executions>
  146
+            <execution>
  147
+              <phase>verify</phase>
  148
+              <goals>
  149
+                <goal>checkstyle</goal>
  150
+              </goals>
  151
+            </execution>
  152
+          </executions>
  153
+        </plugin>
73 154
 
74  
-  <build>
75  
-    <plugins>
76  
-      <plugin>
77  
-        <groupId>org.apache.maven.plugins</groupId>
78  
-        <artifactId>maven-compiler-plugin</artifactId>
79  
-        <version>2.5</version>
80  
-        <configuration>
81  
-          <source>${java.version}</source>
82  
-          <target>${java.version}</target>
83  
-        </configuration>
84  
-      </plugin>
  155
+        <plugin>
  156
+          <groupId>com.jayway.maven.plugins.android.generation2</groupId>
  157
+          <artifactId>android-maven-plugin</artifactId>
  158
+          <version>3.3.2</version>
  159
+          <configuration>
  160
+            <sdk>
  161
+              <platform>${android.platform}</platform>
  162
+            </sdk>
  163
+          </configuration>
  164
+        </plugin>
  165
+      </plugins>
  166
+    </pluginManagement>
85 167
 
  168
+    <plugins>
86 169
       <plugin>
87 170
         <groupId>org.apache.maven.plugins</groupId>
88  
-        <artifactId>maven-checkstyle-plugin</artifactId>
89  
-        <version>2.9.1</version>
  171
+        <artifactId>maven-release-plugin</artifactId>
  172
+        <version>2.3.2</version>
90 173
         <configuration>
91  
-          <failsOnError>true</failsOnError>
92  
-          <configLocation>checkstyle.xml</configLocation>
  174
+          <autoVersionSubmodules>true</autoVersionSubmodules>
93 175
         </configuration>
94  
-        <executions>
95  
-          <execution>
96  
-            <phase>verify</phase>
97  
-            <goals>
98  
-              <goal>checkstyle</goal>
99  
-            </goals>
100  
-          </execution>
101  
-        </executions>
102 176
       </plugin>
103 177
     </plugins>
104 178
   </build>
  179
+
  180
+  <repositories>
  181
+    <repository>
  182
+      <id>oss-sonatype-snapshots</id>
  183
+      <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
  184
+      <snapshots>
  185
+        <enabled>true</enabled>
  186
+      </snapshots>
  187
+    </repository>
  188
+  </repositories>
105 189
 </project>
30  tape-sample/AndroidManifest.xml
... ...
@@ -0,0 +1,30 @@
  1
+<?xml version="1.0" encoding="utf-8"?>
  2
+
  3
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  4
+          package="com.squareup.tape.sample"
  5
+          android:versionCode="1"
  6
+          android:versionName="1.0">
  7
+
  8
+  <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="16"/>
  9
+
  10
+  <uses-permission android:name="android.permission.INTERNET"/>
  11
+
  12
+  <uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
  13
+
  14
+  <application android:icon="@drawable/icon"
  15
+               android:label="@string/application_name"
  16
+               android:name=".SampleApplication">
  17
+
  18
+    <activity android:label="@string/activity_name"
  19
+              android:name=".SampleActivity">
  20
+      <intent-filter>
  21
+        <action android:name="android.intent.action.MAIN"/>
  22
+        <category android:name="android.intent.category.DEFAULT"/>
  23
+        <category android:name="android.intent.category.LAUNCHER"/>
  24
+      </intent-filter>
  25
+    </activity>
  26
+
  27
+    <service android:name=".ImageUploadTaskService"/>
  28
+
  29
+  </application>
  30
+</manifest>
56  tape-sample/pom.xml
... ...
@@ -0,0 +1,56 @@
  1
+<?xml version="1.0" encoding="UTF-8"?>
  2
+
  3
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  5
+  <modelVersion>4.0.0</modelVersion>
  6
+
  7
+  <parent>
  8
+    <groupId>com.squareup</groupId>
  9
+    <artifactId>tape-parent</artifactId>
  10
+    <version>1.0.1-SNAPSHOT</version>
  11
+    <relativePath>../pom.xml</relativePath>
  12
+  </parent>
  13
+
  14
+  <name>Tape Android Sample</name>
  15
+  <artifactId>tape-sample</artifactId>
  16
+  <packaging>apk</packaging>
  17
+
  18
+  <dependencies>
  19
+    <dependency>
  20
+      <groupId>com.google.android</groupId>
  21
+      <artifactId>android</artifactId>
  22
+      <scope>provided</scope>
  23
+    </dependency>
  24
+    <dependency>
  25
+      <groupId>com.squareup</groupId>
  26
+      <artifactId>tape</artifactId>
  27
+      <version>${project.version}</version>
  28
+    </dependency>
  29
+    <dependency>
  30
+      <groupId>com.squareup</groupId>
  31
+      <artifactId>dagger</artifactId>
  32
+    </dependency>
  33
+    <dependency>
  34
+      <groupId>com.squareup</groupId>
  35
+      <artifactId>otto</artifactId>
  36
+    </dependency>
  37
+    <dependency>
  38
+      <groupId>com.github.kevinsawicki</groupId>
  39
+      <artifactId>http-request</artifactId>
  40
+    </dependency>
  41
+    <dependency>
  42
+      <groupId>com.google.code.gson</groupId>
  43
+      <artifactId>gson</artifactId>
  44
+    </dependency>
  45
+  </dependencies>
  46
+
  47
+  <build>
  48
+    <plugins>
  49
+      <plugin>
  50
+        <groupId>com.jayway.maven.plugins.android.generation2</groupId>
  51
+        <artifactId>android-maven-plugin</artifactId>
  52
+        <extensions>true</extensions>
  53
+      </plugin>
  54
+    </plugins>
  55
+  </build>
  56
+</project>
BIN  tape-sample/res/drawable-hdpi/icon.png
BIN  tape-sample/res/drawable-mdpi/icon.png
BIN  tape-sample/res/drawable-xhdpi/icon.png
30  tape-sample/res/layout/sample_activity.xml
... ...
@@ -0,0 +1,30 @@
  1
+<?xml version="1.0" encoding="utf-8"?>
  2
+
  3
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  4
+              android:orientation="vertical"
  5
+              android:layout_width="match_parent"
  6
+              android:layout_height="match_parent"
  7
+              android:padding="8dp"
  8
+              android:gravity="center_horizontal">
  9
+  <Button
  10
+      android:id="@+id/upload"
  11
+      android:layout_width="wrap_content"
  12
+      android:layout_height="wrap_content"
  13
+      android:textSize="24sp"
  14
+      android:text="@string/upload"
  15
+      />
  16
+  <TextView
  17
+      android:id="@+id/status"
  18
+      android:layout_width="wrap_content"
  19
+      android:layout_height="wrap_content"
  20
+      android:layout_marginTop="20dp"
  21
+      android:textSize="16sp"
  22
+      />
  23
+  <ListView
  24
+      android:id="@+id/uploads"
  25
+      android:layout_width="match_parent"
  26
+      android:layout_height="0dp"
  27
+      android:layout_weight="1"
  28
+      android:layout_marginTop="20dp"
  29
+      />
  30
+</LinearLayout>
9  tape-sample/res/layout/upload.xml
... ...
@@ -0,0 +1,9 @@
  1
+<?xml version="1.0" encoding="utf-8"?>
  2
+
  3
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
  4
+          android:id="@android:id/text1"
  5
+          android:layout_width="match_parent"
  6
+          android:layout_height="match_parent"
  7
+          android:padding="10dp"
  8
+          android:textSize="16sp"
  9
+          android:autoLink="web"/>
10  tape-sample/res/values/strings.xml
... ...
@@ -0,0 +1,10 @@
  1
+<?xml version="1.0" encoding="utf-8"?>
  2
+
  3
+<resources>
  4
+  <string name="activity_name">Tape</string>
  5
+  <string name="application_name">Tape Sample</string>
  6
+  <string name="upload">Upload Image</string>
  7
+  <string name="status">%s uploads pending.</string>
  8
+  <string name="task_added">Added new upload task.</string>
  9
+  <string name="task_completed">An upload task completed.</string>
  10
+</resources>
41  tape-sample/src/main/java/com/squareup/tape/sample/GsonConverter.java
... ...
@@ -0,0 +1,41 @@
  1
+// Copyright 2012 Square, Inc.
  2
+package com.squareup.tape.sample;
  3
+
  4
+import com.google.gson.Gson;
  5
+import com.squareup.tape.FileObjectQueue;
  6
+
  7
+import java.io.ByteArrayInputStream;
  8
+import java.io.IOException;
  9
+import java.io.InputStreamReader;
  10
+import java.io.OutputStream;
  11
+import java.io.OutputStreamWriter;
  12
+import java.io.Reader;
  13
+import java.io.Writer;
  14
+
  15
+/**
  16
+ * Use GSON to serialize classes to a bytes.
  17
+ * <p/>
  18
+ * Note: This will only work when concrete classes are specified for {@code T}. If you want to specify an interface for
  19
+ * {@code T} then you need to also include the concrete class name in the serialized byte array so that you can
  20
+ * deserialize to the appropriate type.
  21
+ */
  22
+public class GsonConverter<T> implements FileObjectQueue.Converter<T> {
  23
+  private final Gson gson;
  24
+  private final Class<T> type;
  25
+
  26
+  public GsonConverter(Gson gson, Class<T> type) {
  27
+    this.gson = gson;
  28
+    this.type = type;
  29
+  }
  30
+
  31
+  @Override public T from(byte[] bytes) {
  32
+    Reader reader = new InputStreamReader(new ByteArrayInputStream(bytes));
  33
+    return gson.fromJson(reader, type);
  34
+  }
  35
+
  36
+  @Override public void toStream(T object, OutputStream bytes) throws IOException {
  37
+    Writer writer = new OutputStreamWriter(bytes);
  38
+    gson.toJson(object, writer);
  39
+    writer.close();
  40
+  }
  41
+}
10  tape-sample/src/main/java/com/squareup/tape/sample/ImageUploadQueueSizeEvent.java
... ...
@@ -0,0 +1,10 @@
  1
+// Copyright 2012 Square, Inc.
  2
+package com.squareup.tape.sample;
  3
+
  4
+public class ImageUploadQueueSizeEvent {
  5
+  public final int size;
  6
+
  7
+  public ImageUploadQueueSizeEvent(int size) {
  8
+    this.size = size;
  9
+  }
  10
+}
10  tape-sample/src/main/java/com/squareup/tape/sample/ImageUploadSuccessEvent.java
... ...
@@ -0,0 +1,10 @@
  1
+// Copyright 2012 Square, Inc.
  2
+package com.squareup.tape.sample;
  3
+
  4
+public class ImageUploadSuccessEvent {
  5
+  public final String url;
  6
+
  7
+  public ImageUploadSuccessEvent(String url) {
  8
+    this.url = url;
  9
+  }
  10
+}
75  tape-sample/src/main/java/com/squareup/tape/sample/ImageUploadTask.java
... ...
@@ -0,0 +1,75 @@
  1
+// Copyright 2012 Square, Inc.
  2
+package com.squareup.tape.sample;
  3
+
  4
+import android.os.Handler;
  5
+import android.os.Looper;
  6
+import android.util.Log;
  7
+import com.github.kevinsawicki.http.HttpRequest;
  8
+import com.squareup.tape.Task;
  9
+
  10
+import java.io.File;
  11
+import java.util.regex.Matcher;
  12
+import java.util.regex.Pattern;
  13
+
  14
+import static com.github.kevinsawicki.http.HttpRequest.post;
  15
+
  16
+/** Uploads the specified file to imgur.com. */
  17
+public class ImageUploadTask implements Task<ImageUploadTask.Callback> {
  18
+  private static final long serialVersionUID = 126142781146165256L;
  19
+
  20
+  private static final String TAG = "Tape:ImageUploadTask";
  21
+  private static final String IMGUR_API_KEY = "74e20e836f0307a90683c4643a2b656e";
  22
+  private static final String IMGUR_UPLOAD_URL = "http://api.imgur.com/2/upload";
  23
+  private static final Pattern IMGUR_URL_REGEX = Pattern.compile("<imgur_page>(.+?)</imgur_page>");
  24
+  private static final Handler MAIN_THREAD = new Handler(Looper.getMainLooper());
  25
+
  26
+  public interface Callback {
  27
+    void onSuccess(String url);
  28
+    void onFailure();
  29
+  }
  30
+
  31
+  private final File file;
  32
+
  33
+  public ImageUploadTask(File file) {
  34
+    this.file = file;
  35
+  }
  36
+
  37
+  @Override public void execute(final Callback callback) {
  38
+    // Image uploading is slow. Execute HTTP POST on a background thread.
  39
+    new Thread(new Runnable() {
  40
+      @Override public void run() {
  41
+        try {
  42
+          HttpRequest request = post(IMGUR_UPLOAD_URL)
  43
+              .part("key", IMGUR_API_KEY)
  44
+              .part("image", file);
  45
+
  46
+          if (request.ok()) {
  47
+            Matcher m = IMGUR_URL_REGEX.matcher(request.body());
  48
+            m.find();
  49
+            final String url = m.group(1);
  50
+            Log.i(TAG, "Upload success! " + url);
  51
+
  52
+            // Get back to the main thread before invoking a callback.
  53
+            MAIN_THREAD.post(new Runnable() {
  54
+              @Override public void run() {
  55
+                callback.onSuccess(url);
  56
+              }
  57
+            });
  58
+          } else {
  59
+            Log.i(TAG, "Upload failed :(  Will retry.");
  60
+
  61
+            // Get back to the main thread before invoking a callback.
  62
+            MAIN_THREAD.post(new Runnable() {
  63
+              @Override public void run() {
  64
+                callback.onFailure();
  65
+              }
  66
+            });
  67
+          }
  68
+        } catch (RuntimeException e) {
  69
+          e.printStackTrace();
  70
+          throw e;
  71
+        }
  72
+      }
  73
+    }).start();
  74
+  }
  75
+}
65  tape-sample/src/main/java/com/squareup/tape/sample/ImageUploadTaskQueue.java
... ...
@@ -0,0 +1,65 @@
  1
+// Copyright 2012 Square, Inc.
  2
+package com.squareup.tape.sample;
  3
+
  4
+import android.content.Context;
  5
+import android.content.Intent;
  6
+import com.google.gson.Gson;
  7
+import com.squareup.otto.Bus;
  8
+import com.squareup.otto.Produce;
  9
+import com.squareup.tape.FileObjectQueue;
  10
+import com.squareup.tape.FileObjectQueue.Converter;
  11
+import com.squareup.tape.ObjectQueue;
  12
+import com.squareup.tape.TaskQueue;
  13
+
  14
+import java.io.File;
  15
+import java.io.IOException;
  16
+
  17
+public class ImageUploadTaskQueue extends TaskQueue<ImageUploadTask> {
  18
+  private static final String FILENAME = "image_upload_task_queue";
  19
+
  20
+  private final Context context;
  21
+  private final Bus bus;
  22
+
  23
+  private ImageUploadTaskQueue(ObjectQueue<ImageUploadTask> delegate, Context context, Bus bus) {
  24
+    super(delegate);
  25
+    this.context = context;
  26
+    this.bus = bus;
  27
+    bus.register(this);
  28
+
  29
+    if (size() > 0) {
  30
+      startService();
  31
+    }
  32
+  }
  33
+
  34
+  private void startService() {
  35
+    context.startService(new Intent(context, ImageUploadTaskService.class));
  36
+  }
  37
+
  38
+  @Override public void add(ImageUploadTask entry) {
  39
+    super.add(entry);
  40
+    bus.post(produceSizeChanged());
  41
+    startService();
  42
+  }
  43
+
  44
+  @Override public void remove() {
  45
+    super.remove();
  46
+    bus.post(produceSizeChanged());
  47
+  }
  48
+
  49
+  @SuppressWarnings("UnusedDeclaration") // Used by event bus.
  50
+  @Produce public ImageUploadQueueSizeEvent produceSizeChanged() {
  51
+    return new ImageUploadQueueSizeEvent(size());
  52
+  }
  53
+
  54
+  public static ImageUploadTaskQueue create(Context context, Gson gson, Bus bus) {
  55
+    Converter<ImageUploadTask> converter = new GsonConverter<ImageUploadTask>(gson, ImageUploadTask.class);
  56
+    File queueFile = new File(context.getFilesDir(), FILENAME);
  57
+    FileObjectQueue<ImageUploadTask> delegate;
  58
+    try {
  59
+      delegate = new FileObjectQueue<ImageUploadTask>(queueFile, converter);
  60
+    } catch (IOException e) {
  61
+      throw new RuntimeException("Unable to create file queue.", e);
  62
+    }
  63
+    return new ImageUploadTaskQueue(delegate, context, bus);
  64
+  }
  65
+}
58  tape-sample/src/main/java/com/squareup/tape/sample/ImageUploadTaskService.java
... ...
@@ -0,0 +1,58 @@
  1
+// Copyright 2012 Square, Inc.
  2
+package com.squareup.tape.sample;
  3
+
  4
+import android.app.Service;
  5
+import android.content.Intent;
  6
+import android.os.IBinder;
  7
+import android.util.Log;
  8
+import com.squareup.otto.Bus;
  9
+import com.squareup.tape.sample.ImageUploadTask.Callback;
  10
+
  11
+import javax.inject.Inject;
  12
+
  13
+public class ImageUploadTaskService extends Service implements Callback {
  14
+  private static final String TAG = "Tape:ImageUploadTaskService";
  15
+
  16
+  @Inject ImageUploadTaskQueue queue;
  17
+  @Inject Bus bus;
  18
+
  19
+  private boolean running;
  20
+
  21
+  @Override public void onCreate() {
  22
+    super.onCreate();
  23
+    ((SampleApplication) getApplication()).inject(this);
  24
+    Log.i(TAG, "Service starting!");
  25
+  }
  26
+
  27
+  @Override public int onStartCommand(Intent intent, int flags, int startId) {
  28
+    executeNext();
  29
+    return START_STICKY;
  30
+  }
  31
+
  32
+  private void executeNext() {
  33
+    if (running) return; // Only one task at a time.
  34
+
  35
+    ImageUploadTask task = queue.peek();
  36
+    if (task != null) {
  37
+      running = true;
  38
+      task.execute(this);
  39
+    } else {
  40
+      Log.i(TAG, "Service starting!");
  41
+      stopSelf(); // No more tasks are present. Stop.
  42
+    }
  43
+  }
  44
+
  45
+  @Override public void onSuccess(final String url) {
  46
+    running = false;
  47
+    queue.remove();
  48
+    bus.post(new ImageUploadSuccessEvent(url));
  49
+    executeNext();
  50
+  }
  51
+
  52
+  @Override public void onFailure() {
  53
+  }
  54
+
  55
+  @Override public IBinder onBind(Intent intent) {
  56
+    return null;
  57
+  }
  58
+}
92  tape-sample/src/main/java/com/squareup/tape/sample/SampleActivity.java
... ...
@@ -0,0 +1,92 @@
  1
+// Copyright 2012 Square, Inc.
  2
+package com.squareup.tape.sample;
  3
+
  4
+import android.app.Activity;
  5
+import android.content.Intent;
  6
+import android.database.Cursor;
  7
+import android.os.Bundle;
  8
+import android.view.View;
  9
+import android.view.View.OnClickListener;
  10
+import android.widget.ArrayAdapter;
  11
+import android.widget.ListView;
  12
+import android.widget.TextView;
  13
+import android.widget.Toast;
  14
+import com.squareup.otto.Bus;
  15
+import com.squareup.otto.Subscribe;
  16
+
  17
+import javax.inject.Inject;
  18
+import java.io.File;
  19
+
  20
+import static android.content.Intent.ACTION_PICK;
  21
+import static android.provider.MediaStore.MediaColumns.DATA;
  22
+import static android.widget.Toast.LENGTH_SHORT;
  23
+
  24
+public class SampleActivity extends Activity {
  25
+  private static final int PICK_IMAGE = 4 + 8 + 15 + 16 + 23 + 42;
  26
+
  27
+  @Inject ImageUploadTaskQueue queue; // NOTE: Injection starts queue processing!
  28
+  @Inject Bus bus;
  29
+
  30
+  private TextView status;
  31
+  private ArrayAdapter<String> uploads;
  32
+
  33
+  @Override protected void onCreate(Bundle savedInstanceState) {
  34
+    super.onCreate(savedInstanceState);
  35
+
  36
+    ((SampleApplication) getApplication()).inject(this);
  37
+
  38
+    setContentView(R.layout.sample_activity);
  39
+
  40
+    // Status text reports number of pending uploads in the queue.
  41
+    status = (TextView) findViewById(R.id.status);
  42
+
  43
+    // Hook up adapter to list of uploaded images.
  44
+    uploads = new ArrayAdapter<String>(this, R.layout.upload, android.R.id.text1);
  45
+    ListView uploadList = (ListView) findViewById(R.id.uploads);
  46
+    uploadList.setAdapter(uploads);
  47
+
  48
+    // Upload button delegates to the gallery for selecting an image.
  49
+    findViewById(R.id.upload).setOnClickListener(new OnClickListener() {
  50
+      @Override public void onClick(View view) {
  51
+        Intent pickImageIntent = new Intent(ACTION_PICK);
  52
+        pickImageIntent.setType("image/*");
  53
+        startActivityForResult(pickImageIntent, PICK_IMAGE);
  54
+      }
  55
+    });
  56
+  }
  57
+
  58
+  @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  59
+    if (requestCode == PICK_IMAGE && resultCode == RESULT_OK) {
  60
+      // Fetch the path to the selected image.
  61
+      Cursor cursor = getContentResolver().query(data.getData(), new String[] { DATA }, null, null, null);
  62
+      cursor.moveToFirst();
  63
+      File image = new File(cursor.getString(cursor.getColumnIndex(DATA)));
  64
+      cursor.close();
  65
+
  66
+      // Add the image upload task to the queue.
  67
+      queue.add(new ImageUploadTask(image));
  68
+      Toast.makeText(this, R.string.task_added, LENGTH_SHORT).show();
  69
+    }
  70
+  }
  71
+
  72
+  @SuppressWarnings("UnusedDeclaration") // Used by event bus.
  73
+  @Subscribe public void onQueueSizeChanged(ImageUploadQueueSizeEvent event) {
  74
+    status.setText(getString(R.string.status, event.size));
  75
+  }
  76
+
  77
+  @SuppressWarnings("UnusedDeclaration") // Used by event bus.
  78
+  @Subscribe public void onUploadSuccess(ImageUploadSuccessEvent event) {
  79
+    Toast.makeText(this, R.string.task_completed, LENGTH_SHORT).show();
  80
+    uploads.add(event.url);
  81
+  }
  82
+
  83
+  @Override protected void onResume() {
  84
+    super.onResume();
  85
+    bus.register(this); // Register for events when we are becoming the active activity.
  86
+  }
  87
+
  88
+  @Override protected void onPause() {
  89
+    super.onPause();
  90
+    bus.unregister(this); // Unregister from events when we are no longer active.
  91
+  }
  92
+}
53  tape-sample/src/main/java/com/squareup/tape/sample/SampleApplication.java
... ...
@@ -0,0 +1,53 @@
  1
+// Copyright 2012 Square, Inc.
  2
+package com.squareup.tape.sample;
  3
+
  4
+import android.app.Application;
  5
+import android.content.Context;
  6
+import com.google.gson.Gson;
  7
+import com.google.gson.GsonBuilder;
  8
+import com.squareup.otto.Bus;
  9
+import dagger.Module;
  10
+import dagger.ObjectGraph;
  11
+import dagger.Provides;
  12
+
  13
+import javax.inject.Singleton;
  14
+
  15
+public class SampleApplication extends Application {
  16
+  private ObjectGraph objectGraph;
  17
+
  18
+  @Override public void onCreate() {
  19
+    super.onCreate();
  20
+    objectGraph = ObjectGraph.get(new SampleModule(this));
  21
+  }
  22
+
  23
+  public void inject(Object object) {
  24
+    objectGraph.inject(object);
  25
+  }
  26
+
  27
+  @Module(
  28
+      entryPoints = {
  29
+          SampleActivity.class, //
  30
+          ImageUploadTaskQueue.class, //
  31
+          ImageUploadTaskService.class //
  32
+      }
  33
+  )
  34
+  static class SampleModule {
  35
+    private final Context appContext;
  36
+
  37
+    SampleModule(Context appContext) {
  38
+      this.appContext = appContext;
  39
+    }
  40
+
  41
+    @Provides @Singleton ImageUploadTaskQueue provideTaskQueue(Gson gson, Bus bus) {
  42
+      return ImageUploadTaskQueue.create(appContext, gson, bus);
  43
+    }
  44
+
  45
+    @Provides @Singleton Bus provideBus() {
  46
+      return new Bus();
  47
+    }
  48
+
  49
+    @Provides @Singleton Gson provideGson() {
  50
+      return new GsonBuilder().create();
  51
+    }
  52
+  }
  53
+}
34  tape/pom.xml
... ...
@@ -0,0 +1,34 @@
  1
+<?xml version="1.0" encoding="UTF-8"?>
  2
+
  3
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  5
+  <modelVersion>4.0.0</modelVersion>
  6
+
  7
+  <parent>
  8
+    <groupId>com.squareup</groupId>
  9
+    <artifactId>tape-parent</artifactId>
  10
+    <version>1.0.1-SNAPSHOT</version>
  11
+    <relativePath>../pom.xml</relativePath>
  12
+  </parent>
  13
+
  14
+  <name>Tape</name>
  15
+  <artifactId>tape</artifactId>
  16
+
  17
+  <dependencies>
  18
+    <dependency>
  19
+      <groupId>junit</groupId>
  20
+      <artifactId>junit</artifactId>
  21
+      <scope>test</scope>
  22
+    </dependency>
  23
+    <dependency>
  24
+      <groupId>org.easytesting</groupId>
  25
+      <artifactId>fest-assert</artifactId>
  26
+      <scope>test</scope>
  27
+    </dependency>
  28
+    <dependency>
  29
+      <groupId>commons-io</groupId>
  30
+      <artifactId>commons-io</artifactId>
  31
+      <scope>test</scope>
  32
+    </dependency>
  33
+  </dependencies>
  34
+</project>
0  src/main/java/com/squareup/tape/FileException.java → ...rc/main/java/com/squareup/tape/FileException.java
File renamed without changes
0  src/main/java/com/squareup/tape/FileObjectQueue.java → .../main/java/com/squareup/tape/FileObjectQueue.java
File renamed without changes
0  ...n/java/com/squareup/tape/InMemoryObjectQueue.java → ...n/java/com/squareup/tape/InMemoryObjectQueue.java
File renamed without changes
0  src/main/java/com/squareup/tape/ObjectQueue.java → .../src/main/java/com/squareup/tape/ObjectQueue.java
File renamed without changes
0  src/main/java/com/squareup/tape/QueueFile.java → tape/src/main/java/com/squareup/tape/QueueFile.java
File renamed without changes
0  ...n/java/com/squareup/tape/SerializedConverter.java → ...n/java/com/squareup/tape/SerializedConverter.java
File renamed without changes
0  src/main/java/com/squareup/tape/Task.java → tape/src/main/java/com/squareup/tape/Task.java
File renamed without changes
0  src/main/java/com/squareup/tape/TaskInjector.java → ...src/main/java/com/squareup/tape/TaskInjector.java
File renamed without changes
6  src/main/java/com/squareup/tape/TaskQueue.java → tape/src/main/java/com/squareup/tape/TaskQueue.java
@@ -11,6 +11,10 @@
11 11
   private final TaskInjector<T> taskInjector;
12 12
   private final ObjectQueue<T> delegate;
13 13
 
  14
+  public TaskQueue(ObjectQueue<T> delegate) {
  15
+    this(delegate, null);
  16
+  }
  17
+
14 18
   public TaskQueue(ObjectQueue<T> delegate, TaskInjector<T> taskInjector) {
15 19
     this.delegate = delegate;
16 20
     this.taskInjector = taskInjector;
@@ -23,7 +27,7 @@ public TaskQueue(ObjectQueue<T> delegate, TaskInjector<T> taskInjector) {
23 27
    */
24 28
   @Override public T peek() {
25 29
     T task = delegate.peek();
26  
-    if (task != null) {
  30
+    if (task != null && taskInjector != null) {
27 31
       taskInjector.injectMembers(task);
28 32
     }
29 33
     return task;
0  src/test/java/com/squareup/tape/QueueFileTest.java → ...rc/test/java/com/squareup/tape/QueueFileTest.java
File renamed without changes
0  src/test/java/com/squareup/tape/QueueTestUtils.java → ...c/test/java/com/squareup/tape/QueueTestUtils.java
File renamed without changes
0  ...va/com/squareup/tape/SerializedConverterTest.java → ...va/com/squareup/tape/SerializedConverterTest.java
File renamed without changes
0  src/test/resources/empty-serialized-queue → tape/src/test/resources/empty-serialized-queue
File renamed without changes
0  src/test/resources/one-entry-serialized-queue → tape/src/test/resources/one-entry-serialized-queue
File renamed without changes
0  src/test/resources/truncated-empty-serialized-queue → ...c/test/resources/truncated-empty-serialized-queue
File renamed without changes
0  ...st/resources/truncated-one-entry-serialized-queue → ...st/resources/truncated-one-entry-serialized-queue
File renamed without changes
2  website/index.html
@@ -42,7 +42,7 @@ <h2 id="download">Download</h2>
42 42
       <div class="row">
43 43
         <div class="span12">
44 44
           <h2 id="examples">Examples</h2>
45  
-          <p></p>
  45
+          <p>For a more complete example of a background image uploader which expands on both of the following examples see the <a href="https://github.com/square/tape/tree/master/tape-sample">sample Android application</a> in the repository.</p>
46 46
           <h3 id="example-image-queue">Android Task Queue Service</h3>
47 47
           <p>When used on Android, a service is the perfect companion to a <code>TaskQueue</code> since it allows actions to be completed in the background. If the user is uploading new photos to their favorite sharing site, the service will iterate through the queue until all of the upload tasks completes successfully.</p>
48 48
           <pre class="prettyprint">/** Listener for starting the upload service when the queue has tasks. */

0 notes on commit 7dcd3c6

Please sign in to comment.
Something went wrong with that request. Please try again.