(), PremiumMvp.Presenter
val map = it.getValue(gti)
exists = map?.contains(promo)
}
- Logger.e(it.children, it.childrenCount, exists)
return@flatMap Observable.just(exists)
}
.doOnComplete { sendToView { it.hideProgress() } }
.subscribe({
when (it) {
- true -> sendToView { it.onSuccessfullyActivated() }
+ true -> sendToView {
+ if (promo.contains("student")) {
+ PrefGetter.setProItems()
+ } else {
+ PrefGetter.setProItems()
+ PrefGetter.setEnterpriseItem()
+ }
+ it.onSuccessfullyActivated()
+ }
else -> sendToView { it.onNoMatch() }
}
}, ::println))
diff --git a/app/src/main/res/raw/changelog.html b/app/src/main/res/raw/changelog.html
index 5bf6dd1f2..14695aae0 100644
--- a/app/src/main/res/raw/changelog.html
+++ b/app/src/main/res/raw/changelog.html
@@ -8,28 +8,22 @@
FastHub changelog
- Version 4.3.0 (Project Columns and Cards)
+ Version 4.4.0 (Org Project Columns and Cards)
- Reporting Issues or Feature Requests in Google Play review section, will be ignored or might even get your account to be blocked from
- FastHub. You are using an app for GitHub, which provides a proper way to report issues.
-
- Please report the issues in FastHub repo instead, by opening the Drawer Menu and clicking on “Report an Issue”
- PLEASE USE IT.
+ Please report the issues in FastHub repo instead, by opening the Drawer Menu and clicking on “Report an Issue”
+ PLEASE USE IT.
- Bugs , Enhancements & new Features (4.3.0)
+ Bugs , Enhancements & new Features (4.4.0)
- - Project Columns & Cards (Edit, Create & Delete)
- - (New) Repo Collaborators now can Edit, delete & create files.
- - (New) Repo Collaborators now can Edit, delete & Comments.
- - (New) Long press in Feeds to navigate directly to Repo.
- - (Enhancement) Made Search to have minimum 2 chars.
- - (Enhancement) Adding blockable progress when adding new comment.
- - (Fix) Crash in PRs & Issues comments due to Table rendering!.
- - (Fix) ReadMe scrolling when Device Animation is turned off.
- - (Fix) Closed/Opened Issue pagination where most of the issues in the page are PRs (GitHub API!!!!).
+ - (New) Org Project Columns & Cards (Edit, Create & Delete)
+ - (New) Displaying Labels under Issue/Pr description.
+ - (Enhancement) Removal of PR review limit.
+ - (Enhancement) Selected text will be taken in consideration when adding Image/Link.
+ - (Enhancement) Removed Loading background.
+ - (Enhancement) More markdown enhancement.
- (Fix) Lots of bug fixes.
- There are more stuff are not mentioned, find them out :stuck_out_tongue:
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 012dd54ce..1a5c453ff 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -592,6 +592,19 @@
• I\'m having this issue or I want this & that!!
Head to https://github.com/k0shk0sh/FastHub/issues/new and create new issue for bugs or feature requests, I really do encourage you to
search before opening a ticket. Any duplicate request will result in it being closed immediately.
+
+ • How do I get PROMO CODE?
+ If you are a student, you\'ll have to provide me via Email that you are student, you will need below documents:
+
+ - Your university identity card & your identity card (that shows your name & your face to compare it!)
+ - Your university start & end date
+ - Rate FastHub in the Play Store
+
+ If you aren\'t a student and you can\'t afford to pay for PRO, you\'ll need:
+
+ - Write an article about FastHub in social media such as (Medium)
+ - Rate FastHub in the Play Store
+
]]>
FAQ
Comments added successfully
diff --git a/jobdispatcher/build.gradle b/jobdispatcher/build.gradle
deleted file mode 100644
index d326ddf27..000000000
--- a/jobdispatcher/build.gradle
+++ /dev/null
@@ -1,79 +0,0 @@
-apply plugin: "com.android.library"
-
-android {
- compileSdkVersion 26
- buildToolsVersion "26.0.1"
-
- defaultConfig {
- minSdkVersion 16
- targetSdkVersion 26
- versionCode 1
- versionName "0.8.0"
- testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner'
- }
-
- defaultPublishConfig "release"
- publishNonDefault true
-
- buildTypes {
- debug {
- testCoverageEnabled true
- }
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt')
- }
- }
-
- sourceSets {
- // A set of testing helpers that are shared across test types
- testLib { java.srcDir("src/main") }
- test { java.srcDir("src/testLib") } // Robolectric tests
- androidTest { java.srcDir("src/testLib") } // Android (e2e) tests
- }
-}
-
-dependencies {
- // The main library only depends on the Android support lib
- compile "com.android.support:support-v4:26.0.1"
-
- def junit = 'junit:junit:4.12'
- def robolectric = 'org.robolectric:robolectric:3.3.2'
-
- // The common test library uses JUnit
- testLibCompile junit
-
- // The unit tests are written using JUnit, Robolectric, and Mockito
- testCompile junit
- testCompile robolectric
- testCompile 'org.mockito:mockito-core:2.2.5'
-
- // The Android (e2e) tests are written using JUnit and the test support lib
- androidTestCompile junit
- androidTestCompile 'com.android.support.test:runner:0.5'
-}
-
-task javadocs(type: Javadoc) {
- description "Generate Javadocs"
- source = android.sourceSets.main.java.sourceFiles
- classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
- classpath += configurations.compile
- failOnError false
-}
-
-task javadocsJar(type: Jar, dependsOn: javadocs) {
- description "Package Javadocs into a jar"
- classifier = "javadoc"
- from javadocs.destinationDir
-}
-
-task sourcesJar(type: Jar) {
- description "Package sources into a jar"
- classifier = "sources"
- from android.sourceSets.main.java.sourceFiles
-}
-
-task aar(dependsOn: "assembleRelease") {
- group "artifact"
- description "Builds the library AARs"
-}
diff --git a/jobdispatcher/coverage.gradle b/jobdispatcher/coverage.gradle
deleted file mode 100644
index 204f2dc22..000000000
--- a/jobdispatcher/coverage.gradle
+++ /dev/null
@@ -1,40 +0,0 @@
-apply plugin: "jacoco"
-
-jacoco {
- // see https://github.com/jacoco/jacoco/pull/288 and the top build.gradle
- toolVersion "0.7.6.201602180812"
-}
-
-android {
- testOptions {
- unitTests.all {
- systemProperty "robolectric.logging.enabled", true
- systemProperty "robolectric.logging", "stdout"
-
- jacoco {
- includeNoLocationClasses = true
- }
- }
- }
-}
-
-// ignore these when generating coverage
-def ignoredPrefixes = ['R$', 'R.class', 'BuildConfig.class']
-
-task coverage(type: JacocoReport, dependsOn: ["testDebugUnitTest"]) {
- group = "Reports"
- description = "Generate a coverage report"
-
- classDirectories = fileTree(
- dir: "${project.buildDir}/intermediates/classes/debug/com/firebase/",
- exclude: { d -> ignoredPrefixes.any { p -> d.file.name.startsWith(p) } }
- )
- sourceDirectories = files(["src/main/java/com/firebase/"])
- executionData = files("${project.buildDir}/jacoco/testDebugUnitTest.exec")
-
- reports {
- xml.enabled = true
- html.enabled = true
- html.destination "${buildDir}/coverage_html"
- }
-}
diff --git a/jobdispatcher/src/androidTest/AndroidManifest.xml b/jobdispatcher/src/androidTest/AndroidManifest.xml
deleted file mode 100644
index c87f27fcf..000000000
--- a/jobdispatcher/src/androidTest/AndroidManifest.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/jobdispatcher/src/androidTest/java/com/firebase/jobdispatcher/EndToEndTest.java b/jobdispatcher/src/androidTest/java/com/firebase/jobdispatcher/EndToEndTest.java
deleted file mode 100644
index 48b1048bc..000000000
--- a/jobdispatcher/src/androidTest/java/com/firebase/jobdispatcher/EndToEndTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2017 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Basic end to end test for the JobDispatcher. Requires Google Play services be installed and
- * available.
- */
-@RunWith(AndroidJUnit4.class)
-public final class EndToEndTest {
- private Context appContext;
- private FirebaseJobDispatcher dispatcher;
-
- @Before public void setUp() {
- appContext = InstrumentationRegistry.getTargetContext();
- dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(appContext));
- TestJobService.reset();
- }
-
- @Test public void basicImmediateJob() throws InterruptedException {
- final CountDownLatch latch = new CountDownLatch(1);
- TestJobService.setProxy(new TestJobService.JobServiceProxy() {
- @Override
- public boolean onStartJob(JobParameters params) {
- latch.countDown();
- return false;
- }
-
- @Override
- public boolean onStopJob(JobParameters params) {
- return false;
- }
- });
-
- dispatcher.mustSchedule(
- dispatcher.newJobBuilder()
- .setService(TestJobService.class)
- .setTrigger(Trigger.NOW)
- .setTag("basic-immediate-job")
- .build());
-
- assertTrue("Latch wasn't counted down as expected", latch.await(120, TimeUnit.SECONDS));
- }
-}
diff --git a/jobdispatcher/src/main/AndroidManifest.xml b/jobdispatcher/src/main/AndroidManifest.xml
deleted file mode 100644
index 71205bd86..000000000
--- a/jobdispatcher/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/BundleProtocol.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/BundleProtocol.java
deleted file mode 100644
index 774a83401..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/BundleProtocol.java
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-final class BundleProtocol {
- static final String PACKED_PARAM_BUNDLE_PREFIX = "com.firebase.jobdispatcher.";
-
- // PACKED_PARAM values are only read on the client side, so as long as the
- // extraction process gets the same changes then it's fine.
- static final String PACKED_PARAM_CONSTRAINTS = "constraints";
- static final String PACKED_PARAM_LIFETIME = "persistent";
- static final String PACKED_PARAM_RECURRING = "recurring";
- static final String PACKED_PARAM_SERVICE = "service";
- static final String PACKED_PARAM_TAG = "tag";
- static final String PACKED_PARAM_EXTRAS = "extras";
- static final String PACKED_PARAM_TRIGGER_TYPE = "trigger_type";
- static final String PACKED_PARAM_TRIGGER_WINDOW_END = "window_end";
- static final String PACKED_PARAM_TRIGGER_WINDOW_START = "window_start";
- static final int TRIGGER_TYPE_EXECUTION_WINDOW = 1;
- static final int TRIGGER_TYPE_IMMEDIATE = 2;
- static final int TRIGGER_TYPE_CONTENT_URI = 3;
- static final String PACKED_PARAM_RETRY_STRATEGY_INITIAL_BACKOFF_SECONDS =
- "initial_backoff_seconds";
- static final String PACKED_PARAM_RETRY_STRATEGY_MAXIMUM_BACKOFF_SECONDS =
- "maximum_backoff_seconds";
- static final String PACKED_PARAM_RETRY_STRATEGY_POLICY = "retry_policy";
- static final String PACKED_PARAM_REPLACE_CURRENT = "replace_current";
- static final String PACKED_PARAM_CONTENT_URI_FLAGS_ARRAY = "content_uri_flags_array";
- static final String PACKED_PARAM_CONTENT_URI_ARRAY = "content_uri_array";
- static final String PACKED_PARAM_TRIGGERED_URIS = "triggered_uris";
- static final String PACKED_PARAM_OBSERVED_URI = "observed_uris";
-
- BundleProtocol() {
- }
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/Constraint.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/Constraint.java
deleted file mode 100644
index ff413fb20..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/Constraint.java
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import android.support.annotation.IntDef;
-import android.support.annotation.VisibleForTesting;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * A Constraint is a runtime requirement for a job. A job only becomes eligible to run once its
- * trigger has been activated and all constraints are satisfied.
- */
-public final class Constraint {
- /**
- * Only run the job when an unmetered network is available.
- */
- public static final int ON_UNMETERED_NETWORK = 1;
-
- /**
- * Only run the job when a network connection is available. If both this and
- * {@link #ON_UNMETERED_NETWORK} is provided, {@link #ON_UNMETERED_NETWORK} will take
- * precedence.
- */
- public static final int ON_ANY_NETWORK = 1 << 1;
-
- /**
- * Only run the job when the device is currently charging.
- */
- public static final int DEVICE_CHARGING = 1 << 2;
-
- /**
- * Only run the job when the device is idle. This is ignored for devices that don't expose the
- * concept of an idle state.
- */
- public static final int DEVICE_IDLE = 1 << 3;
-
- @VisibleForTesting
- static final int[] ALL_CONSTRAINTS = {
- ON_ANY_NETWORK, ON_UNMETERED_NETWORK, DEVICE_CHARGING, DEVICE_IDLE};
-
- /** Constraint shouldn't ever be instantiated. */
- private Constraint() {}
-
- /**
- * A tooling type-hint for any of the valid constraint values.
- */
- @IntDef(flag = true, value = {
- ON_ANY_NETWORK,
- ON_UNMETERED_NETWORK,
- DEVICE_CHARGING,
- DEVICE_IDLE,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface JobConstraint {}
-
- /**
- * Compact a provided array of constraints into a single int.
- *
- * @see #uncompact(int)
- */
- static int compact(@JobConstraint int[] constraints) {
- int result = 0;
- if (constraints == null) {
- return result;
- }
- for (int c : constraints) {
- result |= c;
- }
- return result;
- }
-
- /**
- * Unpack a single int into an array of constraints.
- *
- * @see #compact(int[])
- */
- static int[] uncompact(int compactConstraints) {
- int length = 0;
- for (int c : ALL_CONSTRAINTS) {
- length += (compactConstraints & c) == c ? 1 : 0;
- }
- int[] list = new int[length];
-
- int i = 0;
- for (int c : ALL_CONSTRAINTS) {
- if ((compactConstraints & c) == c) {
- list[i++] = c;
- }
- }
-
- return list;
- }
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/DefaultJobValidator.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/DefaultJobValidator.java
deleted file mode 100644
index 4804804e5..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/DefaultJobValidator.java
+++ /dev/null
@@ -1,288 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static com.firebase.jobdispatcher.RetryStrategy.RETRY_POLICY_EXPONENTIAL;
-import static com.firebase.jobdispatcher.RetryStrategy.RETRY_POLICY_LINEAR;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.support.annotation.CallSuper;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Locale;
-
-/**
- * Validates Jobs according to some safe standards.
- *
- * Custom JobValidators should typically extend from this.
- */
-public class DefaultJobValidator implements JobValidator {
-
- /**
- * The maximum length of a tag, in characters (i.e. String.length()). Strings longer than this
- * will cause validation to fail.
- */
- public static final int MAX_TAG_LENGTH = 100;
-
- /**
- * The maximum size, in bytes, that the provided extras bundle can be. Corresponds to
- * {@link Parcel#dataSize()}.
- */
- public final static int MAX_EXTRAS_SIZE_BYTES = 10 * 1024;
-
- /** Private ref to the Context. Necessary to check that the manifest is configured correctly. */
- private final Context context;
-
- public DefaultJobValidator(Context context) {
- this.context = context;
- }
-
- /** @see {@link #MAX_EXTRAS_SIZE_BYTES}. */
- private static int measureBundleSize(Bundle extras) {
- Parcel p = Parcel.obtain();
- extras.writeToParcel(p, 0);
- int sizeInBytes = p.dataSize();
- p.recycle();
-
- return sizeInBytes;
- }
-
- /** Combines two {@literal Lists} together. */
- @Nullable
- private static List mergeErrorLists(@Nullable List errors,
- @Nullable List newErrors) {
- if (errors == null) {
- return newErrors;
- }
- if (newErrors == null) {
- return errors;
- }
-
- errors.addAll(newErrors);
- return errors;
- }
-
- @Nullable
- private static List addError(@Nullable List errors, String newError) {
- if (newError == null) {
- return errors;
- }
- if (errors == null) {
- return getMutableSingletonList(newError);
- }
-
- Collections.addAll(errors, newError);
-
- return errors;
- }
-
- @Nullable
- private static List addErrorsIf(boolean condition, List errors, String newErr) {
- if (condition) {
- return addError(errors, newErr);
- }
-
- return errors;
- }
-
- /**
- * Attempts to validate the provided {@code JobParameters}. If the JobParameters is valid, null will be
- * returned. If the JobParameters has errors, a list of those errors will be returned.
- */
- @Nullable
- @Override
- @CallSuper
- public List validate(JobParameters job) {
- List errors = null;
-
- errors = mergeErrorLists(errors, validate(job.getTrigger()));
- errors = mergeErrorLists(errors, validate(job.getRetryStrategy()));
-
- if (job.isRecurring() && job.getTrigger() == Trigger.NOW) {
- errors = addError(errors, "ImmediateTriggers can't be used with recurring jobs");
- }
-
- errors = mergeErrorLists(errors, validateForTransport(job.getExtras()));
- if (job.getLifetime() > Lifetime.UNTIL_NEXT_BOOT) {
- //noinspection ConstantConditions
- errors = mergeErrorLists(errors, validateForPersistence(job.getExtras()));
- }
-
- errors = mergeErrorLists(errors, validateTag(job.getTag()));
- errors = mergeErrorLists(errors, validateService(job.getService()));
-
- return errors;
- }
-
- /**
- * Attempts to validate the provided Trigger. If valid, null is returned. Otherwise a list of
- * errors will be returned.
- *
- * Note that a Trigger that passes validation here is not necessarily valid in all permutations
- * of a JobParameters. For example, an Immediate is never valid for a recurring job.
- * @param trigger
- */
- @Nullable
- @Override
- @CallSuper
- public List validate(JobTrigger trigger) {
- if (trigger != Trigger.NOW
- && !(trigger instanceof JobTrigger.ExecutionWindowTrigger)
- && !(trigger instanceof JobTrigger.ContentUriTrigger)) {
- return getMutableSingletonList("Unknown trigger provided");
- }
-
- return null;
- }
-
- /**
- * Attempts to validate the provided RetryStrategy. If valid, null is returned. Otherwise a list
- * of errors will be returned.
- */
- @Nullable
- @Override
- @CallSuper
- public List validate(RetryStrategy retryStrategy) {
- List errors = null;
-
- int policy = retryStrategy.getPolicy();
- int initial = retryStrategy.getInitialBackoff();
- int maximum = retryStrategy.getMaximumBackoff();
-
- errors = addErrorsIf(policy != RETRY_POLICY_EXPONENTIAL && policy != RETRY_POLICY_LINEAR,
- errors, "Unknown retry policy provided");
- errors = addErrorsIf(maximum < initial,
- errors, "Maximum backoff must be greater than or equal to initial backoff");
- errors = addErrorsIf(300 > maximum,
- errors, "Maximum backoff must be greater than 300s (5 minutes)");
- errors = addErrorsIf(initial < 30,
- errors, "Initial backoff must be at least 30s");
-
- return errors;
- }
-
- @Nullable
- private List validateForPersistence(Bundle extras) {
- List errors = null;
-
- if (extras != null) {
- // check the types to make sure they're persistable
- for (String k : extras.keySet()) {
- errors = addError(errors, validateExtrasType(extras, k));
- }
- }
-
- return errors;
- }
-
- @Nullable
- private List validateForTransport(Bundle extras) {
- if (extras == null) {
- return null;
- }
-
- int bundleSizeInBytes = measureBundleSize(extras);
- if (bundleSizeInBytes > MAX_EXTRAS_SIZE_BYTES) {
- return getMutableSingletonList(String.format(Locale.US,
- "Extras too large: %d bytes is > the max (%d bytes)",
- bundleSizeInBytes, MAX_EXTRAS_SIZE_BYTES));
- }
-
- return null;
- }
-
- @Nullable
- private String validateExtrasType(Bundle extras, String key) {
- Object o = extras.get(key);
-
- if (o == null
- || o instanceof Integer
- || o instanceof Long
- || o instanceof Double
- || o instanceof String
- || o instanceof Boolean) {
- return null;
- }
-
- return String.format(Locale.US,
- "Received value of type '%s' for key '%s', but only the"
- + " following extra parameter types are supported:"
- + " Integer, Long, Double, String, and Boolean",
- o == null ? null : o.getClass(), key);
- }
-
- private List validateService(String service) {
- if (service == null || service.isEmpty()) {
- return getMutableSingletonList("Service can't be empty");
- }
-
- if (context == null) {
- return getMutableSingletonList("Context is null, can't query PackageManager");
- }
-
- PackageManager pm = context.getPackageManager();
- if (pm == null) {
- return getMutableSingletonList("PackageManager is null, can't validate service");
- }
-
- final String msg = "Couldn't find a registered service with the name " + service
- + ". Is it declared in the manifest with the right intent-filter?";
-
- Intent executeIntent = new Intent(JobService.ACTION_EXECUTE);
- executeIntent.setClassName(context, service);
- List intentServices = pm.queryIntentServices(executeIntent, 0);
- if (intentServices == null || intentServices.isEmpty()) {
- return getMutableSingletonList(msg);
- }
-
- for (ResolveInfo info : intentServices) {
- if (info.serviceInfo != null && info.serviceInfo.enabled) {
- // found a match!
- return null;
- }
- }
-
- return getMutableSingletonList(msg);
- }
-
- private List validateTag(String tag) {
- if (tag == null) {
- return getMutableSingletonList("Tag can't be null");
- }
-
- if (tag.length() > MAX_TAG_LENGTH) {
- return getMutableSingletonList("Tag must be shorter than " + MAX_TAG_LENGTH);
- }
-
- return null;
- }
-
- @NonNull
- private static List getMutableSingletonList(String msg) {
- ArrayList strings = new ArrayList<>();
- strings.add(msg);
- return strings;
- }
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/Driver.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/Driver.java
deleted file mode 100644
index fe832721c..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/Driver.java
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import android.support.annotation.NonNull;
-import com.firebase.jobdispatcher.FirebaseJobDispatcher.CancelResult;
-import com.firebase.jobdispatcher.FirebaseJobDispatcher.ScheduleResult;
-
-/**
- * Driver represents a component that understands how to schedule, validate, and execute jobs.
- */
-public interface Driver {
-
- /**
- * Schedules the provided Job.
- *
- * @return one of the SCHEDULE_RESULT_ constants
- */
- @ScheduleResult
- int schedule(@NonNull Job job);
-
- /**
- * Cancels the job with the provided tag and class.
- *
- * @return one of the CANCEL_RESULT_ constants.
- */
- @CancelResult
- int cancel(@NonNull String tag);
-
- /**
- * Cancels all jobs registered with this Driver.
- *
- * @return one of the CANCEL_RESULT_ constants.
- */
- @CancelResult
- int cancelAll();
-
- /**
- * Returns a JobValidator configured for this backend.
- */
- @NonNull
- JobValidator getValidator();
-
- /**
- * Indicates whether the backend is available.
- */
- boolean isAvailable();
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/ExecutionDelegator.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/ExecutionDelegator.java
deleted file mode 100644
index 1dbacb3cb..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/ExecutionDelegator.java
+++ /dev/null
@@ -1,160 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static android.content.Context.BIND_AUTO_CREATE;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.support.annotation.NonNull;
-import android.support.annotation.VisibleForTesting;
-import android.support.v4.util.SimpleArrayMap;
-import android.util.Log;
-import com.firebase.jobdispatcher.JobService.JobResult;
-import java.lang.ref.WeakReference;
-
-/**
- * ExecutionDelegator tracks local Binder connections to client JobServices and handles
- * communication with those services.
- */
-/* package */ class ExecutionDelegator {
- @VisibleForTesting
- static final int JOB_FINISHED = 1;
-
- static final String TAG = "FJD.ExternalReceiver";
-
- interface JobFinishedCallback {
- void onJobFinished(@NonNull JobInvocation jobInvocation, @JobResult int result);
- }
-
- /**
- * A mapping of {@link JobInvocation} to (local) binder connections.
- * Synchronized by itself.
- */
- private final SimpleArrayMap serviceConnections =
- new SimpleArrayMap<>();
- private final ResponseHandler responseHandler =
- new ResponseHandler(Looper.getMainLooper(), new WeakReference<>(this));
- private final Context context;
- private final JobFinishedCallback jobFinishedCallback;
-
- ExecutionDelegator(Context context, JobFinishedCallback jobFinishedCallback) {
- this.context = context;
- this.jobFinishedCallback = jobFinishedCallback;
- }
-
- /**
- * Executes the provided {@code jobInvocation} by kicking off the creation of a new Binder
- * connection to the Service.
- *
- * @return true if the service was bound successfully.
- */
- boolean executeJob(JobInvocation jobInvocation) {
- if (jobInvocation == null) {
- return false;
- }
-
- JobServiceConnection conn = new JobServiceConnection(jobInvocation,
- responseHandler.obtainMessage(JOB_FINISHED));
-
- synchronized (serviceConnections) {
- JobServiceConnection oldConnection = serviceConnections.put(jobInvocation, conn);
- if (oldConnection != null) {
- Log.e(TAG, "Received execution request for already running job");
- }
- return context.bindService(createBindIntent(jobInvocation), conn, BIND_AUTO_CREATE);
- }
- }
-
- @NonNull
- private Intent createBindIntent(JobParameters jobParameters) {
- Intent execReq = new Intent(JobService.ACTION_EXECUTE);
- execReq.setClassName(context, jobParameters.getService());
- return execReq;
- }
-
- void stopJob(JobInvocation job) {
- synchronized (serviceConnections) {
- JobServiceConnection jobServiceConnection = serviceConnections.remove(job);
- if (jobServiceConnection != null) {
- jobServiceConnection.onStop();
- safeUnbindService(jobServiceConnection);
- }
- }
- }
-
- private void safeUnbindService(JobServiceConnection connection) {
- if (connection != null && connection.isBound()) {
- try {
- context.unbindService(connection);
- } catch (IllegalArgumentException e) {
- Log.w(TAG, "Error unbinding service: " + e.getMessage());
- }
- }
- }
-
- private void onJobFinishedMessage(JobInvocation jobInvocation, int result) {
- synchronized (serviceConnections) {
- JobServiceConnection connection = serviceConnections.remove(jobInvocation);
- safeUnbindService(connection);
- }
-
- jobFinishedCallback.onJobFinished(jobInvocation, result);
- }
-
- private static class ResponseHandler extends Handler {
-
- /**
- * We hold a WeakReference to the ExecutionDelegator because it holds a reference to a
- * Service Context and Handlers are often kept in memory longer than you'd expect because
- * any pending Messages can maintain references to them.
- */
- private final WeakReference executionDelegatorReference;
-
- ResponseHandler(Looper looper, WeakReference executionDelegator) {
- super(looper);
- this.executionDelegatorReference = executionDelegator;
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case JOB_FINISHED:
- if (msg.obj instanceof JobInvocation) {
- ExecutionDelegator delegator = this.executionDelegatorReference.get();
- if (delegator == null) {
- Log.wtf(TAG, "handleMessage: service was unexpectedly GC'd"
- + ", can't send job result");
- return;
- }
-
- delegator.onJobFinishedMessage((JobInvocation) msg.obj, msg.arg1);
- return;
- }
-
- Log.wtf(TAG, "handleMessage: unknown obj returned");
- return;
-
- default:
- Log.wtf(TAG, "handleMessage: unknown message type received: " + msg.what);
- }
- }
- }
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/FirebaseJobDispatcher.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/FirebaseJobDispatcher.java
deleted file mode 100644
index 1a76093f8..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/FirebaseJobDispatcher.java
+++ /dev/null
@@ -1,211 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import android.support.annotation.IntDef;
-import android.support.annotation.NonNull;
-import com.firebase.jobdispatcher.RetryStrategy.RetryPolicy;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * The FirebaseJobDispatcher provides a driver-agnostic API for scheduling and cancelling Jobs.
- *
- * @see #FirebaseJobDispatcher(Driver)
- * @see Driver
- * @see JobParameters
- */
-public final class FirebaseJobDispatcher {
- /**
- * Indicates the schedule request seems to have been successful.
- */
- public final static int SCHEDULE_RESULT_SUCCESS = 0;
-
- /**
- * Indicates the schedule request encountered an unknown error.
- */
- public final static int SCHEDULE_RESULT_UNKNOWN_ERROR = 1;
-
- /**
- * Indicates the schedule request failed because the driver was unavailable.
- */
- public final static int SCHEDULE_RESULT_NO_DRIVER_AVAILABLE = 2;
-
- /**
- * Indicates the schedule request failed because the Trigger was unsupported.
- */
- public final static int SCHEDULE_RESULT_UNSUPPORTED_TRIGGER = 3;
-
- /**
- * Indicates the schedule request failed because the service is not exposed or configured
- * correctly.
- */
- public final static int SCHEDULE_RESULT_BAD_SERVICE = 4;
-
- /**
- * Indicates the cancel request seems to have been successful.
- */
- public final static int CANCEL_RESULT_SUCCESS = 0;
- /**
- * Indicates the cancel request encountered an unknown error.
- */
- public final static int CANCEL_RESULT_UNKNOWN_ERROR = 1;
- /**
- * Indicates the cancel request failed because the driver was unavailable.
- */
- public final static int CANCEL_RESULT_NO_DRIVER_AVAILABLE = 2;
- /**
- * The backing Driver for this instance.
- */
- private final Driver mDriver;
- /**
- * The ValidationEnforcer configured for the current Driver.
- */
- private final ValidationEnforcer mValidator;
- /**
- * Single instance of a RetryStrategy.Builder, configured with the current driver's validation
- * settings. We can do this because the RetryStrategy.Builder is stateless.
- */
- private RetryStrategy.Builder mRetryStrategyBuilder;
-
- /**
- * Instantiates a new FirebaseJobDispatcher using the provided Driver.
- */
- public FirebaseJobDispatcher(Driver driver) {
- mDriver = driver;
- mValidator = new ValidationEnforcer(mDriver.getValidator());
- mRetryStrategyBuilder = new RetryStrategy.Builder(mValidator);
- }
-
- /**
- * Attempts to schedule the provided Job.
- *
- * Returns one of the SCHEDULE_RESULT_ constants.
- */
- @ScheduleResult
- public int schedule(@NonNull Job job) {
- if (!mDriver.isAvailable()) {
- return SCHEDULE_RESULT_NO_DRIVER_AVAILABLE;
- }
-
- return mDriver.schedule(job);
- }
-
- /**
- * Attempts to cancel the Job that matches the provided tag and endpoint.
- *
- * Returns one of the CANCEL_RESULT_ constants.
- */
- @CancelResult
- public int cancel(@NonNull String tag) {
- if (!mDriver.isAvailable()) {
- return CANCEL_RESULT_NO_DRIVER_AVAILABLE;
- }
-
- return mDriver.cancel(tag);
- }
-
- /**
- * Attempts to cancel all Jobs registered for this package.
- *
- * Returns one of the CANCEL_RESULT_ constants.
- */
- @CancelResult
- public int cancelAll() {
- if (!mDriver.isAvailable()) {
- return CANCEL_RESULT_NO_DRIVER_AVAILABLE;
- }
-
- return mDriver.cancelAll();
- }
-
- /**
- * Attempts to schedule the provided Job, throwing an exception if it fails.
- *
- * @throws ScheduleFailedException
- */
- public void mustSchedule(Job job) {
- if (schedule(job) != SCHEDULE_RESULT_SUCCESS) {
- throw new ScheduleFailedException();
- }
- }
-
- /**
- * Returns a ValidationEnforcer configured for the current Driver.
- */
- public ValidationEnforcer getValidator() {
- return mValidator;
- }
-
- /**
- * Creates a new Job.Builder, configured with the current driver's validation settings.
- */
- @NonNull
- public Job.Builder newJobBuilder() {
- return new Job.Builder(mValidator);
- }
-
- /**
- * Creates a new RetryStrategy from the provided parameters, validated with the current driver's
- * {@link JobValidator}.
- *
- * @param policy the backoff policy to use. One of the {@link RetryPolicy} constants.
- * @param initialBackoff the initial backoff, in seconds.
- * @param maximumBackoff the maximum backoff, in seconds.
- * @throws ValidationEnforcer.ValidationException
- * @see RetryStrategy
- */
- public RetryStrategy newRetryStrategy(@RetryPolicy int policy, int initialBackoff,
- int maximumBackoff) {
-
- return mRetryStrategyBuilder.build(policy, initialBackoff, maximumBackoff);
- }
-
- /**
- * Results that can legally be returned from {@link #schedule(Job)} calls.
- */
- @IntDef({
- SCHEDULE_RESULT_SUCCESS,
- SCHEDULE_RESULT_UNKNOWN_ERROR,
- SCHEDULE_RESULT_NO_DRIVER_AVAILABLE,
- SCHEDULE_RESULT_UNSUPPORTED_TRIGGER,
- SCHEDULE_RESULT_BAD_SERVICE,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface ScheduleResult {
- }
-
- /**
- * Results that can legally be returned from {@link #cancel(String)} or {@link #cancelAll()}
- * calls.
- */
- @IntDef({
- CANCEL_RESULT_SUCCESS,
- CANCEL_RESULT_UNKNOWN_ERROR,
- CANCEL_RESULT_NO_DRIVER_AVAILABLE,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface CancelResult {
- }
-
- /**
- * Thrown when a {@link FirebaseJobDispatcher#schedule(com.firebase.jobdispatcher.Job)} call
- * fails.
- */
- public final static class ScheduleFailedException extends RuntimeException {
- }
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/GooglePlayCallbackExtractor.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/GooglePlayCallbackExtractor.java
deleted file mode 100644
index 03fca073d..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/GooglePlayCallbackExtractor.java
+++ /dev/null
@@ -1,247 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import android.annotation.SuppressLint;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.support.annotation.Nullable;
-import android.util.Log;
-import android.util.Pair;
-import java.util.ArrayList;
-
-/**
- * Responsible for extracting a JobCallback from a given Bundle.
- *
- *
Google Play services will send the Binder packed inside a simple strong Binder wrapper ({@link
- * #PENDING_CALLBACK_CLASS}) under the key {@link #BUNDLE_KEY_CALLBACK "callback"}.
- */
-/* package */ final class GooglePlayCallbackExtractor {
-
- private static final String TAG = GooglePlayReceiver.TAG;
- private static final String ERROR_NULL_CALLBACK = "No callback received, terminating";
- private static final String ERROR_INVALID_CALLBACK = "Bad callback received, terminating";
-
- /** The Parcelable class that wraps the Binder we need to access. */
- private static final String PENDING_CALLBACK_CLASS =
- "com.google.android.gms.gcm.PendingCallback";
- /** The key for the wrapped Binder. */
- private static final String BUNDLE_KEY_CALLBACK = "callback";
- /** A magic number that indicates the following bytes belong to a Bundle. */
- private static final int BUNDLE_MAGIC = 0x4C444E42;
- /** A magic number that indicates the following value is a Parcelable. */
- private static final int VAL_PARCELABLE = 4;
-
- // GuardedBy("GooglePlayCallbackExtractor.class")
- private static Boolean shouldReadKeysAsStringsCached = null;
-
- public Pair extractCallback(@Nullable Bundle data) {
- if (data == null) {
- Log.e(TAG, ERROR_NULL_CALLBACK);
- return null;
- }
-
- return extractWrappedBinderFromParcel(data);
- }
-
- /**
- * Bundles are written out in the following format:
- * A header, which consists of:
- *
- * - length (int)
- * - magic number ({@link #BUNDLE_MAGIC}) (int)
- * - number of entries (int)
- *
- *
- * Then the map values, each of which looks like this:
- *
- * - string key
- * - int type marker
- * - (any) parceled value
- *
- *
- * We're just going to iterate over the map looking for the right key (BUNDLE_KEY_CALLBACK)
- * and try and read the IBinder straight from the parcelled data. This is entirely dependent
- * on the implementation of Parcel, but these specific parts of Parcel / Bundle haven't
- * changed since 2008 and newer versions of Android will ship with newer versions of Google
- * Play services which embed the IBinder directly into the Bundle (no need to deal with the
- * Parcelable issues).
- */
- @Nullable
- @SuppressLint("ParcelClassLoader")
- private Pair extractWrappedBinderFromParcel(Bundle data) {
- Bundle cleanBundle = new Bundle();
- Parcel serialized = toParcel(data);
- JobCallback callback = null;
-
- try {
- int length = serialized.readInt();
- if (length <= 0) {
- // Empty Bundle
- Log.w(TAG, ERROR_NULL_CALLBACK);
- return null;
- }
-
- int magic = serialized.readInt();
- if (magic != BUNDLE_MAGIC) {
- // Not a Bundle
- Log.w(TAG, ERROR_NULL_CALLBACK);
- return null;
- }
-
- int numEntries = serialized.readInt();
- for (int i = 0; i < numEntries; i++) {
- String entryKey = readKey(serialized);
- if (entryKey == null) {
- continue;
- }
-
- if (!(callback == null && BUNDLE_KEY_CALLBACK.equals(entryKey))) {
- // If it's not the 'callback' key, we can just read it using the standard
- // mechanisms because we're not afraid of rogue BadParcelableExceptions.
- Object value = serialized.readValue(null /* class loader */);
- if (value instanceof String) {
- cleanBundle.putString(entryKey, (String) value);
- } else if (value instanceof Boolean) {
- cleanBundle.putBoolean(entryKey, (boolean) value);
- } else if (value instanceof Integer) {
- cleanBundle.putInt(entryKey, (int) value);
- } else if (value instanceof ArrayList) {
- // The only acceptable ArrayList in a Bundle is one that consists entirely
- // of Parcelables, so this cast is safe.
- @SuppressWarnings("unchecked") // safe by specification
- ArrayList arrayList = (ArrayList) value;
- cleanBundle.putParcelableArrayList(entryKey, arrayList);
- } else if (value instanceof Bundle) {
- cleanBundle.putBundle(entryKey, (Bundle) value);
- } else if (value instanceof Parcelable) {
- cleanBundle.putParcelable(entryKey, (Parcelable) value);
- }
-
- // Move to the next key
- continue;
- }
-
- int typeTag = serialized.readInt();
- if (typeTag != VAL_PARCELABLE) {
- // If the key is correct ("callback"), but it's not a Parcelable then something
- // went wrong and we should bail.
- Log.w(TAG, ERROR_INVALID_CALLBACK);
- return null;
- }
-
- String clsname = serialized.readString();
- if (!PENDING_CALLBACK_CLASS.equals(clsname)) {
- // If it's a Parcelable, but not one we recognize then we should not try and
- // unpack it.
- Log.w(TAG, ERROR_INVALID_CALLBACK);
- return null;
- }
-
- // Instead of trying to instantiate clsname, we'll just read its single member.
- IBinder remote = serialized.readStrongBinder();
- callback = new GooglePlayJobCallback(remote);
- }
-
- if (callback == null) {
- Log.w(TAG, ERROR_NULL_CALLBACK);
- return null;
- }
- return Pair.create(callback, cleanBundle);
- } finally {
- serialized.recycle();
- }
- }
-
- private static Parcel toParcel(Bundle data) {
- Parcel serialized = Parcel.obtain();
- data.writeToParcel(serialized, 0);
- serialized.setDataPosition(0);
- return serialized;
- }
-
- /**
- * Reads the next key (String) from the provided {@code serialized} Parcel.
- *
- * Naively using {@link Parcel#readString()} fails on versions of Android older than L,
- * whereas {@link Parcel#readValue(ClassLoader)} works on older versions but fails on anything L
- * or newer.
- */
- private String readKey(Parcel serialized) {
- if (shouldReadKeysAsStrings()) {
- return serialized.readString();
- }
-
- // Older platforms require readValue
- Object entryKeyObj = serialized.readValue(null /* Use the system ClassLoader */);
- if (!(entryKeyObj instanceof String)) {
- // Should never happen (Bundle keys are always Strings)
- Log.w(TAG, ERROR_INVALID_CALLBACK);
- return null;
- }
-
- return (String) entryKeyObj;
- }
-
- /**
- * Checks whether {@link Parcel#readString()} or {@link Parcel#readValue()} should be used to
- * access Bundle keys from a serialized Parcel. Commit {@link
- * https://android.googlesource.com/platform/frameworks/base/+/9c3e74f
- * I57bda9eb79ceaaa9c1b94ad49d9e462b52102149} (which only officially landed in Lollipop) changed
- * from using writeValue to writeString for Bundle keys. Some OEMs have pulled this change into
- * their KitKat fork, so we can't trust the SDK version check. Instead, we'll write a dummy
- * Bundle to a Parcel and figure it out using that.
- *
- * The check is cached because the result can't change during runtime.
- */
- private static synchronized boolean shouldReadKeysAsStrings() {
- // We're pretty sure that readString() should always be used on L+, but if we shortcircuit
- // this check then we have no evidence that this code is functioning correctly on KitKat
- // devices that have the corresponding writeString() change.
- if (shouldReadKeysAsStringsCached == null) {
- final String expectedKey = "key";
- Bundle testBundle = new Bundle();
- testBundle.putString(expectedKey, "value");
- Parcel testParcel = toParcel(testBundle);
- try {
- // length
- checkCondition(testParcel.readInt() > 0);
- // magic
- checkCondition(testParcel.readInt() == BUNDLE_MAGIC);
- // num entries
- checkCondition(testParcel.readInt() == 1);
-
- shouldReadKeysAsStringsCached = expectedKey.equals(testParcel.readString());
- } catch (RuntimeException e) {
- shouldReadKeysAsStringsCached = Boolean.FALSE;
- } finally {
- testParcel.recycle();
- }
- }
-
- return shouldReadKeysAsStringsCached;
- }
-
- /** Throws an {@code IllegalStateException} if {@code condition} is false. */
- private static void checkCondition(boolean condition) {
- if (!condition) {
- throw new IllegalStateException();
- }
- }
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/GooglePlayDriver.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/GooglePlayDriver.java
deleted file mode 100644
index 58314821a..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/GooglePlayDriver.java
+++ /dev/null
@@ -1,162 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import android.app.PendingIntent;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.support.annotation.NonNull;
-
-import com.firebase.jobdispatcher.FirebaseJobDispatcher.ScheduleResult;
-
-/**
- * GooglePlayDriver provides an implementation of Driver for devices with Google Play
- * services installed. This backend does not do any availability checks and any uses should be
- * guarded with a call to {@code GoogleApiAvailability#isGooglePlayServicesAvailable(android.content.Context)}
- *
- * @see
- * GoogleApiAvailability
- */
-public final class GooglePlayDriver implements Driver {
- static final String BACKEND_PACKAGE = "com.google.android.gms";
- private final static String ACTION_SCHEDULE = "com.google.android.gms.gcm.ACTION_SCHEDULE";
-
- private final static String BUNDLE_PARAM_SCHEDULER_ACTION = "scheduler_action";
- private final static String BUNDLE_PARAM_TAG = "tag";
- private final static String BUNDLE_PARAM_TOKEN = "app";
- private final static String BUNDLE_PARAM_COMPONENT = "component";
-
- private final static String SCHEDULER_ACTION_SCHEDULE_TASK = "SCHEDULE_TASK";
- private final static String SCHEDULER_ACTION_CANCEL_TASK = "CANCEL_TASK";
- private final static String SCHEDULER_ACTION_CANCEL_ALL = "CANCEL_ALL";
- private static final String INTENT_PARAM_SOURCE = "source";
- private static final String INTENT_PARAM_SOURCE_VERSION = "source_version";
-
- private static final int JOB_DISPATCHER_SOURCE_CODE = 1 << 3;
- private static final int JOB_DISPATCHER_SOURCE_VERSION_CODE = 1;
-
- private final JobValidator mValidator;
- /**
- * The application Context. Used to send broadcasts.
- */
- private final Context mContext;
- /**
- * A PendingIntent from this package. Passed inside the broadcast so the receiver can verify the
- * sender's package.
- */
- private final PendingIntent mToken;
- /**
- * Turns Jobs into Bundles.
- */
- private final GooglePlayJobWriter mWriter;
-
- /**
- * Instantiates a new GooglePlayDriver.
- */
- public GooglePlayDriver(Context context) {
- mContext = context;
- mToken = PendingIntent.getBroadcast(context, 0, new Intent(), 0);
- mWriter = new GooglePlayJobWriter();
- mValidator = new DefaultJobValidator(context);
- }
-
- @Override
- public boolean isAvailable() {
- ApplicationInfo applicationInfo = null;
- try {
- applicationInfo = mContext.getPackageManager().getApplicationInfo(BACKEND_PACKAGE, 0);
- } catch (PackageManager.NameNotFoundException e) {
- e.printStackTrace();
- }
- return applicationInfo != null && applicationInfo.enabled;
- }
-
-
- /**
- * Schedules the provided Job.
- */
- @Override
- @ScheduleResult
- public int schedule(@NonNull Job job) {
- mContext.sendBroadcast(createScheduleRequest(job));
-
- return FirebaseJobDispatcher.SCHEDULE_RESULT_SUCCESS;
- }
-
- @Override
- public int cancel(@NonNull String tag) {
- mContext.sendBroadcast(createCancelRequest(tag));
-
- return FirebaseJobDispatcher.CANCEL_RESULT_SUCCESS;
- }
-
- @Override
- public int cancelAll() {
- mContext.sendBroadcast(createBatchCancelRequest());
-
- return FirebaseJobDispatcher.CANCEL_RESULT_SUCCESS;
- }
-
- @NonNull
- protected Intent createCancelRequest(@NonNull String tag) {
- Intent cancelReq = createSchedulerIntent(SCHEDULER_ACTION_CANCEL_TASK);
- cancelReq.putExtra(BUNDLE_PARAM_TAG, tag);
- cancelReq.putExtra(BUNDLE_PARAM_COMPONENT, new ComponentName(mContext, getReceiverClass()));
- return cancelReq;
- }
-
- @NonNull
- protected Intent createBatchCancelRequest() {
- Intent cancelReq = createSchedulerIntent(SCHEDULER_ACTION_CANCEL_ALL);
- cancelReq.putExtra(BUNDLE_PARAM_COMPONENT, new ComponentName(mContext, getReceiverClass()));
- return cancelReq;
- }
-
- @NonNull
- protected Class getReceiverClass() {
- return GooglePlayReceiver.class;
- }
-
- @NonNull
- @Override
- public JobValidator getValidator() {
- return mValidator;
- }
-
- @NonNull
- private Intent createScheduleRequest(JobParameters job) {
- Intent scheduleReq = createSchedulerIntent(SCHEDULER_ACTION_SCHEDULE_TASK);
- scheduleReq.putExtras(mWriter.writeToBundle(job, scheduleReq.getExtras()));
- return scheduleReq;
- }
-
- @NonNull
- private Intent createSchedulerIntent(String schedulerAction) {
- Intent scheduleReq = new Intent(ACTION_SCHEDULE);
-
- scheduleReq.setPackage(BACKEND_PACKAGE);
- scheduleReq.putExtra(BUNDLE_PARAM_SCHEDULER_ACTION, schedulerAction);
- scheduleReq.putExtra(BUNDLE_PARAM_TOKEN, mToken);
- scheduleReq.putExtra(INTENT_PARAM_SOURCE, JOB_DISPATCHER_SOURCE_CODE);
- scheduleReq.putExtra(INTENT_PARAM_SOURCE_VERSION, JOB_DISPATCHER_SOURCE_VERSION_CODE);
-
- return scheduleReq;
- }
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/GooglePlayJobCallback.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/GooglePlayJobCallback.java
deleted file mode 100644
index 7f47fe598..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/GooglePlayJobCallback.java
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.RemoteException;
-
-/**
- * Wraps the GooglePlay-specific callback class in a JobCallback-compatible interface.
- */
-/* package */ final class GooglePlayJobCallback implements JobCallback {
-
- private static final String DESCRIPTOR = "com.google.android.gms.gcm.INetworkTaskCallback";
- /** The only supported transaction ID. */
- private static final int TRANSACTION_TASK_FINISHED = IBinder.FIRST_CALL_TRANSACTION + 1;
-
- private final IBinder mRemote;
-
- public GooglePlayJobCallback(IBinder binder) {
- mRemote = binder;
- }
-
- @Override
- public void jobFinished(@JobService.JobResult int status) {
- Parcel request = Parcel.obtain();
- Parcel response = Parcel.obtain();
- try {
- request.writeInterfaceToken(DESCRIPTOR);
- request.writeInt(status);
-
- mRemote.transact(TRANSACTION_TASK_FINISHED, request, response, 0);
-
- response.readException();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- } finally {
- request.recycle();
- response.recycle();
- }
- }
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/GooglePlayJobWriter.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/GooglePlayJobWriter.java
deleted file mode 100644
index 0389f90f7..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/GooglePlayJobWriter.java
+++ /dev/null
@@ -1,198 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import android.net.Uri;
-import android.os.Bundle;
-import android.support.annotation.IntDef;
-import android.support.annotation.VisibleForTesting;
-import com.firebase.jobdispatcher.JobTrigger.ContentUriTrigger;
-import com.firebase.jobdispatcher.RetryStrategy.RetryPolicy;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/* package */ final class GooglePlayJobWriter {
-
- static final String REQUEST_PARAM_UPDATE_CURRENT = "update_current";
- static final String REQUEST_PARAM_EXTRAS = "extras";
- static final String REQUEST_PARAM_PERSISTED = "persisted";
- static final String REQUEST_PARAM_REQUIRED_NETWORK = "requiredNetwork";
- static final String REQUEST_PARAM_REQUIRES_CHARGING = "requiresCharging";
- static final String REQUEST_PARAM_REQUIRES_IDLE = "requiresIdle";
- static final String REQUEST_PARAM_RETRY_STRATEGY = "retryStrategy";
- static final String REQUEST_PARAM_SERVICE = "service";
- static final String REQUEST_PARAM_TAG = "tag";
-
- static final String REQUEST_PARAM_RETRY_STRATEGY_INITIAL_BACKOFF_SECONDS =
- "initial_backoff_seconds";
- static final String REQUEST_PARAM_RETRY_STRATEGY_MAXIMUM_BACKOFF_SECONDS =
- "maximum_backoff_seconds";
- static final String REQUEST_PARAM_RETRY_STRATEGY_POLICY = "retry_policy";
-
- static final String REQUEST_PARAM_TRIGGER_TYPE = "trigger_type";
- static final String REQUEST_PARAM_TRIGGER_WINDOW_END = "window_end";
- static final String REQUEST_PARAM_TRIGGER_WINDOW_FLEX = "period_flex";
- static final String REQUEST_PARAM_TRIGGER_WINDOW_PERIOD = "period";
- static final String REQUEST_PARAM_TRIGGER_WINDOW_START = "window_start";
-
- @VisibleForTesting
- /* package */ static final int LEGACY_RETRY_POLICY_EXPONENTIAL = 0;
- @VisibleForTesting
- /* package */ static final int LEGACY_RETRY_POLICY_LINEAR = 1;
- @VisibleForTesting
- /* package */ final static int LEGACY_NETWORK_UNMETERED = 1;
- @VisibleForTesting
- /* package */ final static int LEGACY_NETWORK_CONNECTED = 0;
- @VisibleForTesting
- /* package */ final static int LEGACY_NETWORK_ANY = 2;
-
- private JobCoder jobCoder = new JobCoder(BundleProtocol.PACKED_PARAM_BUNDLE_PREFIX, false);
-
- private static void writeExecutionWindowTriggerToBundle(JobParameters job, Bundle b,
- JobTrigger.ExecutionWindowTrigger trigger) {
-
- b.putInt(REQUEST_PARAM_TRIGGER_TYPE, BundleProtocol.TRIGGER_TYPE_EXECUTION_WINDOW);
-
- if (job.isRecurring()) {
- b.putLong(REQUEST_PARAM_TRIGGER_WINDOW_PERIOD,
- trigger.getWindowEnd());
- b.putLong(REQUEST_PARAM_TRIGGER_WINDOW_FLEX,
- trigger.getWindowEnd() - trigger.getWindowStart());
- } else {
- b.putLong(REQUEST_PARAM_TRIGGER_WINDOW_START,
- trigger.getWindowStart());
- b.putLong(REQUEST_PARAM_TRIGGER_WINDOW_END,
- trigger.getWindowEnd());
- }
- }
-
- private static void writeImmediateTriggerToBundle(Bundle b) {
- b.putInt(REQUEST_PARAM_TRIGGER_TYPE, BundleProtocol.TRIGGER_TYPE_IMMEDIATE);
- b.putLong(REQUEST_PARAM_TRIGGER_WINDOW_START, 0);
- b.putLong(REQUEST_PARAM_TRIGGER_WINDOW_END, 30);
- }
-
- private void writeContentUriTriggerToBundle(Bundle data, ContentUriTrigger uriTrigger) {
- data.putInt(BundleProtocol.PACKED_PARAM_TRIGGER_TYPE,
- BundleProtocol.TRIGGER_TYPE_CONTENT_URI);
-
- int size = uriTrigger.getUris().size();
- int[] flagsArray = new int[size];
- Uri[] uriArray = new Uri[size];
- for (int i = 0; i < size; i++) {
- ObservedUri uri = uriTrigger.getUris().get(i);
- flagsArray[i] = uri.getFlags();
- uriArray[i] = uri.getUri();
- }
- data.putIntArray(BundleProtocol.PACKED_PARAM_CONTENT_URI_FLAGS_ARRAY, flagsArray);
- data.putParcelableArray(BundleProtocol.PACKED_PARAM_CONTENT_URI_ARRAY, uriArray);
- }
-
- public Bundle writeToBundle(JobParameters job, Bundle b) {
- b.putString(REQUEST_PARAM_TAG, job.getTag());
- b.putBoolean(REQUEST_PARAM_UPDATE_CURRENT, job.shouldReplaceCurrent());
-
- boolean persisted = job.getLifetime() == Lifetime.FOREVER;
- b.putBoolean(REQUEST_PARAM_PERSISTED, persisted);
- b.putString(REQUEST_PARAM_SERVICE, GooglePlayReceiver.class.getName());
-
- writeTriggerToBundle(job, b);
- writeConstraintsToBundle(job, b);
- writeRetryStrategyToBundle(job, b);
-
- // Embed the job spec (minus extras) into the extras (under a prefix)
- Bundle extras = job.getExtras();
- if (extras == null) {
- extras = new Bundle();
- }
- b.putBundle(REQUEST_PARAM_EXTRAS, jobCoder.encode(job, extras));
-
- return b;
- }
-
- private void writeRetryStrategyToBundle(JobParameters job, Bundle b) {
- RetryStrategy strategy = job.getRetryStrategy();
-
- Bundle rb = new Bundle();
- rb.putInt(REQUEST_PARAM_RETRY_STRATEGY_POLICY,
- convertRetryPolicyToLegacyVersion(strategy.getPolicy()));
- rb.putInt(REQUEST_PARAM_RETRY_STRATEGY_INITIAL_BACKOFF_SECONDS,
- strategy.getInitialBackoff());
- rb.putInt(REQUEST_PARAM_RETRY_STRATEGY_MAXIMUM_BACKOFF_SECONDS,
- strategy.getMaximumBackoff());
-
- b.putBundle(REQUEST_PARAM_RETRY_STRATEGY, rb);
- }
-
- private int convertRetryPolicyToLegacyVersion(@RetryPolicy int policy) {
- switch (policy) {
- case RetryStrategy.RETRY_POLICY_LINEAR:
- return LEGACY_RETRY_POLICY_LINEAR;
-
- case RetryStrategy.RETRY_POLICY_EXPONENTIAL:
- // fallthrough
- default:
- return LEGACY_RETRY_POLICY_EXPONENTIAL;
- }
- }
-
- private void writeTriggerToBundle(JobParameters job, Bundle b) {
- final JobTrigger trigger = job.getTrigger();
-
- if (trigger == Trigger.NOW) {
- writeImmediateTriggerToBundle(b);
- } else if (trigger instanceof JobTrigger.ExecutionWindowTrigger) {
- writeExecutionWindowTriggerToBundle(job, b, (JobTrigger.ExecutionWindowTrigger) trigger);
- } else if (trigger instanceof JobTrigger.ContentUriTrigger) {
- writeContentUriTriggerToBundle(b, (JobTrigger.ContentUriTrigger) trigger);
- } else {
- throw new IllegalArgumentException("Unknown trigger: " + trigger.getClass());
- }
- }
-
- private void writeConstraintsToBundle(JobParameters job, Bundle b) {
- int c = Constraint.compact(job.getConstraints());
-
- b.putBoolean(REQUEST_PARAM_REQUIRES_CHARGING,
- (c & Constraint.DEVICE_CHARGING) == Constraint.DEVICE_CHARGING);
- b.putBoolean(REQUEST_PARAM_REQUIRES_IDLE,
- (c & Constraint.DEVICE_IDLE) == Constraint.DEVICE_IDLE);
- b.putInt(REQUEST_PARAM_REQUIRED_NETWORK, convertConstraintsToLegacyNetConstant(c));
- }
-
- /**
- * Converts a bitmap of Constraint values into a LegacyNetworkConstraint constant (int).
- */
- @LegacyNetworkConstant
- private int convertConstraintsToLegacyNetConstant(int constraintMap) {
- int reqNet = LEGACY_NETWORK_ANY;
-
- reqNet = (constraintMap & Constraint.ON_ANY_NETWORK) == Constraint.ON_ANY_NETWORK
- ? LEGACY_NETWORK_CONNECTED
- : reqNet;
-
- reqNet = (constraintMap & Constraint.ON_UNMETERED_NETWORK) == Constraint.ON_UNMETERED_NETWORK
- ? LEGACY_NETWORK_UNMETERED
- : reqNet;
-
- return reqNet;
- }
-
- @IntDef({LEGACY_NETWORK_ANY, LEGACY_NETWORK_CONNECTED, LEGACY_NETWORK_UNMETERED})
- @Retention(RetentionPolicy.SOURCE)
- private @interface LegacyNetworkConstant {}
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/GooglePlayMessageHandler.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/GooglePlayMessageHandler.java
deleted file mode 100644
index 664805f67..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/GooglePlayMessageHandler.java
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static com.firebase.jobdispatcher.GooglePlayJobWriter.REQUEST_PARAM_TAG;
-import static com.firebase.jobdispatcher.GooglePlayReceiver.TAG;
-
-import android.annotation.TargetApi;
-import android.app.AppOpsManager;
-import android.content.Context;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
-import android.util.Log;
-import com.firebase.jobdispatcher.JobInvocation.Builder;
-
-/**
- * A messenger for communication with GCM Network Scheduler.
- */
-@TargetApi(Build.VERSION_CODES.LOLLIPOP)
-class GooglePlayMessageHandler extends Handler {
-
- static final int MSG_START_EXEC = 1;
- static final int MSG_STOP_EXEC = 2;
- static final int MSG_RESULT = 3;
- private static final int MSG_INIT = 4;
- private final GooglePlayReceiver googlePlayReceiver;
-
- public GooglePlayMessageHandler(Looper mainLooper, GooglePlayReceiver googlePlayReceiver) {
- super(mainLooper);
- this.googlePlayReceiver = googlePlayReceiver;
- }
-
- @Override
- public void handleMessage(Message message) {
- if (message == null) {
- return;
- }
-
- AppOpsManager appOpsManager = (AppOpsManager) googlePlayReceiver.getApplicationContext()
- .getSystemService(Context.APP_OPS_SERVICE);
- try {
- appOpsManager.checkPackage(message.sendingUid, GooglePlayDriver.BACKEND_PACKAGE);
- } catch (SecurityException e) {
- Log.e(TAG, "Message was not sent from GCM.");
- return;
- }
-
- switch (message.what) {
- case MSG_START_EXEC:
- handleStartMessage(message);
- break;
-
- case MSG_STOP_EXEC:
- handleStopMessage(message);
- break;
-
- case MSG_INIT:
- // Not implemented.
- break;
-
- default:
- Log.e(TAG, "Unrecognized message received: " + message);
- break;
- }
- }
-
- private void handleStartMessage(Message message) {
- final Bundle data = message.getData();
-
- final Messenger replyTo = message.replyTo;
- String tag = data.getString(REQUEST_PARAM_TAG);
- if (replyTo == null || tag == null) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Invalid start execution message.");
- }
- return;
- }
-
- GooglePlayMessengerCallback messengerCallback =
- new GooglePlayMessengerCallback(replyTo, tag);
- JobInvocation jobInvocation = googlePlayReceiver.prepareJob(messengerCallback, data);
- googlePlayReceiver.getExecutionDelegator().executeJob(jobInvocation);
- }
-
- private void handleStopMessage(Message message) {
- Builder builder = GooglePlayReceiver.getJobCoder().decode(message.getData());
- if (builder == null) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Invalid stop execution message.");
- }
- return;
- }
- JobInvocation job = builder.build();
- googlePlayReceiver.getExecutionDelegator().stopJob(job);
- }
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/GooglePlayMessengerCallback.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/GooglePlayMessengerCallback.java
deleted file mode 100644
index 06fb153f3..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/GooglePlayMessengerCallback.java
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static com.firebase.jobdispatcher.GooglePlayJobWriter.REQUEST_PARAM_TAG;
-
-import android.os.Bundle;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.support.annotation.NonNull;
-import com.firebase.jobdispatcher.JobService.JobResult;
-
-/**
- * Wraps the GooglePlay messenger in a JobCallback-compatible interface.
- */
-class GooglePlayMessengerCallback implements JobCallback {
-
- private final Messenger messenger;
- private final String tag;
-
- GooglePlayMessengerCallback(Messenger messenger, String tag) {
- this.messenger = messenger;
- this.tag = tag;
- }
-
- @Override
- public void jobFinished(@JobResult int status) {
- try {
- messenger.send(createResultMessage(status));
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- @NonNull
- private Message createResultMessage(int result) {
- final Message msg = Message.obtain();
- msg.what = GooglePlayMessageHandler.MSG_RESULT;
- msg.arg1 = result;
-
- Bundle b = new Bundle();
- b.putString(REQUEST_PARAM_TAG, tag);
- msg.setData(b);
- return msg;
- }
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/GooglePlayReceiver.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/GooglePlayReceiver.java
deleted file mode 100644
index e8dc60609..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/GooglePlayReceiver.java
+++ /dev/null
@@ -1,274 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Messenger;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
-import android.support.v4.util.SimpleArrayMap;
-import android.util.Log;
-import android.util.Pair;
-import com.firebase.jobdispatcher.Job.Builder;
-import com.firebase.jobdispatcher.JobService.JobResult;
-import com.firebase.jobdispatcher.JobTrigger.ContentUriTrigger;
-
-/**
- * Handles incoming execute requests from the GooglePlay driver and forwards them to your Service.
- */
-public class GooglePlayReceiver extends Service implements ExecutionDelegator.JobFinishedCallback {
- /**
- * Logging tag.
- */
- /* package */ static final String TAG = "FJD.GooglePlayReceiver";
- /**
- * The action sent by Google Play services that triggers job execution.
- */
- @VisibleForTesting
- static final String ACTION_EXECUTE = "com.google.android.gms.gcm.ACTION_TASK_READY";
-
- /** Action sent by Google Play services when your app has been updated. */
- @VisibleForTesting
- static final String ACTION_INITIALIZE = "com.google.android.gms.gcm.SERVICE_ACTION_INITIALIZE";
-
- private static final String ERROR_NULL_INTENT = "Null Intent passed, terminating";
- private static final String ERROR_UNKNOWN_ACTION = "Unknown action received, terminating";
- private static final String ERROR_NO_DATA = "No data provided, terminating";
-
- private static final JobCoder prefixedCoder =
- new JobCoder(BundleProtocol.PACKED_PARAM_BUNDLE_PREFIX, true);
-
- private final GooglePlayCallbackExtractor callbackExtractor = new GooglePlayCallbackExtractor();
-
- /**
- * The single Messenger that's returned from valid onBind requests. Guarded by intrinsic lock.
- */
- @VisibleForTesting
- Messenger serviceMessenger;
-
- /**
- * Driver for rescheduling jobs. Guarded by intrinsic lock.
- */
- @VisibleForTesting
- Driver driver;
-
- /**
- * Guarded by intrinsic lock.
- */
- @VisibleForTesting
- ValidationEnforcer validationEnforcer;
-
- /**
- * The ExecutionDelegator used to communicate with client JobServices.
- * Guarded by intrinsic lock.
- */
- private ExecutionDelegator executionDelegator;
-
- /**
- * The most recent startId passed to onStartCommand.
- * Guarded by intrinsic lock.
- */
- private int latestStartId;
-
- /**
- * Endpoint (String) -> Tag (String) -> JobCallback
- */
- private SimpleArrayMap> callbacks =
- new SimpleArrayMap<>(1);
-
- private static void sendResultSafely(JobCallback callback, int result) {
- try {
- callback.jobFinished(result);
- } catch (Throwable e) {
- Log.e(TAG, "Encountered error running callback", e.getCause());
- }
- }
-
- @Override
- public final int onStartCommand(Intent intent, int flags, int startId) {
- try {
- super.onStartCommand(intent, flags, startId);
-
- if (intent == null) {
- Log.w(TAG, ERROR_NULL_INTENT);
- return START_NOT_STICKY;
- }
-
- String action = intent.getAction();
- if (ACTION_EXECUTE.equals(action)) {
- getExecutionDelegator().executeJob(prepareJob(intent));
- return START_NOT_STICKY;
- } else if (ACTION_INITIALIZE.equals(action)) {
- return START_NOT_STICKY;
- }
-
- Log.e(TAG, ERROR_UNKNOWN_ACTION);
- return START_NOT_STICKY;
- } finally {
- synchronized (this) {
- latestStartId = startId;
- if (callbacks.isEmpty()) {
- stopSelf(latestStartId);
- }
- }
- }
- }
-
- @Nullable
- @Override
- public IBinder onBind(Intent intent) {
- // Only Lollipop+ supports UID checking messages, so we can't trust this system on older
- // platforms.
- if (intent == null
- || Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP
- || !ACTION_EXECUTE.equals(intent.getAction())) {
- return null;
- }
- return getServiceMessenger().getBinder();
- }
-
- private synchronized Messenger getServiceMessenger() {
- if (serviceMessenger == null) {
- serviceMessenger =
- new Messenger(new GooglePlayMessageHandler(Looper.getMainLooper(), this));
- }
- return serviceMessenger;
- }
-
- /* package */ synchronized ExecutionDelegator getExecutionDelegator() {
- if (executionDelegator == null) {
- executionDelegator = new ExecutionDelegator(this, this);
- }
- return executionDelegator;
- }
-
- @NonNull
- private synchronized Driver getGooglePlayDriver() {
- if (driver == null) {
- driver = new GooglePlayDriver(getApplicationContext());
- }
- return driver;
- }
-
- @NonNull
- private synchronized ValidationEnforcer getValidationEnforcer() {
- if (validationEnforcer == null) {
- validationEnforcer = new ValidationEnforcer(getGooglePlayDriver().getValidator());
- }
- return validationEnforcer;
- }
-
- @Nullable
- @VisibleForTesting
- JobInvocation prepareJob(Intent intent) {
- Bundle intentExtras = intent.getExtras();
- if (intentExtras == null) {
- Log.e(TAG, ERROR_NO_DATA);
- return null;
- }
-
- // get the callback first. If we don't have this we can't talk back to the backend.
- Pair extraction = callbackExtractor.extractCallback(intentExtras);
- if (extraction == null) {
- Log.i(TAG, "no callback found");
- return null;
- }
- return prepareJob(extraction.first, extraction.second);
- }
-
- @Nullable
- synchronized JobInvocation prepareJob(JobCallback callback, Bundle bundle) {
- JobInvocation job = prefixedCoder.decodeIntentBundle(bundle);
- if (job == null) {
- Log.e(TAG, "unable to decode job");
- sendResultSafely(callback, JobService.RESULT_FAIL_NORETRY);
- return null;
- }
- SimpleArrayMap map = callbacks.get(job.getService());
- if (map == null) {
- map = new SimpleArrayMap<>(1);
- callbacks.put(job.getService(), map);
- }
-
- map.put(job.getTag(), callback);
-
- return job;
- }
-
- @Override
- public synchronized void onJobFinished(@NonNull JobInvocation js, @JobResult int result) {
- try {
- SimpleArrayMap map = callbacks.get(js.getService());
- if (map == null) {
- return;
- }
- JobCallback callback = map.remove(js.getTag());
- if (callback == null) {
- return;
- }
- if (map.isEmpty()) {
- callbacks.remove(js.getService());
- }
-
- if (needsToBeRescheduled(js, result)) {
- reschedule(js);
- } else {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "sending jobFinished for " + js.getTag() + " = " + result);
- }
- sendResultSafely(callback, result);
- }
- } finally {
- if (callbacks.isEmpty()) {
- // Safe to call stopSelf, even if we're being bound to
- stopSelf(latestStartId);
- }
- }
- }
-
- private void reschedule(JobInvocation jobInvocation) {
- Job job = new Builder(getValidationEnforcer(), jobInvocation)
- .setReplaceCurrent(true)
- .build();
-
- getGooglePlayDriver().schedule(job);
- }
-
- /**
- * Recurring content URI triggered jobs need to be rescheduled when execution is finished.
- *
- * GooglePlay does not support recurring content URI triggered jobs.
- *
- *
{@link JobService#RESULT_FAIL_RETRY} needs to be sent or current triggered URIs will be
- * lost.
- */
- private static boolean needsToBeRescheduled(JobParameters job, int result) {
- return job.isRecurring()
- && job.getTrigger() instanceof ContentUriTrigger
- && result != JobService.RESULT_FAIL_RETRY;
- }
-
- static JobCoder getJobCoder() {
- return prefixedCoder;
- }
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/Job.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/Job.java
deleted file mode 100644
index 692404fe9..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/Job.java
+++ /dev/null
@@ -1,378 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import com.firebase.jobdispatcher.Constraint.JobConstraint;
-
-/**
- * Job is the embodiment of a unit of work and an associated set of triggers, settings, and runtime
- * constraints.
- */
-public final class Job implements JobParameters {
- private final String mService;
- private final String mTag;
- private final JobTrigger mTrigger;
- private final RetryStrategy mRetryStrategy;
- private final int mLifetime;
- private final boolean mRecurring;
- private final int[] mConstraints;
- private final boolean mReplaceCurrent;
- private Bundle mExtras;
-
- private Job(Builder builder) {
- mService = builder.mServiceClassName;
- mExtras = builder.mExtras;
- mTag = builder.mTag;
- mTrigger = builder.mTrigger;
- mRetryStrategy = builder.mRetryStrategy;
- mLifetime = builder.mLifetime;
- mRecurring = builder.mRecurring;
- mConstraints = builder.mConstraints != null ? builder.mConstraints : new int[0];
- mReplaceCurrent = builder.mReplaceCurrent;
- }
-
- /**
- * {@inheritDoc}
- */
- @NonNull
- @Override
- public int[] getConstraints() {
- return mConstraints;
- }
-
- /**
- * {@inheritDoc}
- */
- @Nullable
- @Override
- public Bundle getExtras() {
- return mExtras;
- }
-
- /**
- * {@inheritDoc}
- */
- @NonNull
- @Override
- public RetryStrategy getRetryStrategy() {
- return mRetryStrategy;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean shouldReplaceCurrent() {
- return mReplaceCurrent;
- }
-
- @Nullable
- @Override
- public TriggerReason getTriggerReason() {
- return null;
- }
-
- /**
- * {@inheritDoc}
- */
- @NonNull
- @Override
- public String getTag() {
- return mTag;
- }
-
- /**
- * {@inheritDoc}
- */
- @NonNull
- @Override
- public JobTrigger getTrigger() {
- return mTrigger;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int getLifetime() {
- return mLifetime;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean isRecurring() {
- return mRecurring;
- }
-
- /**
- * {@inheritDoc}
- */
- @NonNull
- @Override
- public String getService() {
- return mService;
- }
-
- /**
- * A class that understands how to build a {@link Job}. Retrieved by calling
- * {@link FirebaseJobDispatcher#newJobBuilder()}.
- */
- public final static class Builder implements JobParameters {
- private final ValidationEnforcer mValidator;
-
- private String mServiceClassName;
- private Bundle mExtras;
- private String mTag;
- private JobTrigger mTrigger = Trigger.NOW;
- private int mLifetime = Lifetime.UNTIL_NEXT_BOOT;
- private int[] mConstraints;
-
- private RetryStrategy mRetryStrategy = RetryStrategy.DEFAULT_EXPONENTIAL;
- private boolean mReplaceCurrent = false;
- private boolean mRecurring = false;
-
- Builder(ValidationEnforcer validator) {
- mValidator = validator;
- }
-
- Builder(ValidationEnforcer validator, JobParameters job) {
- mValidator = validator;
-
- mTag = job.getTag();
- mServiceClassName = job.getService();
- mTrigger = job.getTrigger();
- mRecurring = job.isRecurring();
- mLifetime = job.getLifetime();
- mConstraints = job.getConstraints();
- mExtras = job.getExtras();
- mRetryStrategy = job.getRetryStrategy();
- }
-
- /**
- * Adds the provided constraint to the current list of runtime constraints.
- */
- public Builder addConstraint(@JobConstraint int constraint) {
- // Create a new, longer constraints array
- int[] newConstraints = new int[mConstraints == null ? 1 : mConstraints.length + 1];
-
- if (mConstraints != null && mConstraints.length != 0) {
- // Copy all the old values over
- System.arraycopy(mConstraints, 0, newConstraints, 0, mConstraints.length);
- }
-
- // add the new value
- newConstraints[newConstraints.length - 1] = constraint;
- // update the pointer
- mConstraints = newConstraints;
-
- return this;
- }
-
- /**
- * Sets whether this Job should replace pre-existing Jobs with the same tag.
- */
- public Builder setReplaceCurrent(boolean replaceCurrent) {
- mReplaceCurrent = replaceCurrent;
-
- return this;
- }
-
- /**
- * Builds the Job, using the settings provided so far.
- *
- * @throws ValidationEnforcer.ValidationException
- */
- public Job build() {
- mValidator.ensureValid(this);
-
- return new Job(this);
- }
-
- /**
- * {@inheritDoc}
- */
- @NonNull
- @Override
- public String getService() {
- return mServiceClassName;
- }
-
- /**
- * Sets the backing JobService class for the Job. See {@link #getService()}.
- */
- public Builder setService(Class extends JobService> serviceClass) {
- mServiceClassName = serviceClass == null ? null : serviceClass.getName();
-
- return this;
- }
-
- /**
- * Sets the backing JobService class name for the Job. See {@link #getService()}.
- *
- *
Should not be exposed, for internal use only.
- */
- Builder setServiceName(String serviceClassName) {
- mServiceClassName = serviceClassName;
-
- return this;
- }
-
- /**
- * {@inheritDoc}
- */
- @NonNull
- @Override
- public String getTag() {
- return mTag;
- }
-
- /**
- * Sets the unique String tag used to identify the Job. See {@link #getTag()}.
- */
- public Builder setTag(String tag) {
- mTag = tag;
-
- return this;
- }
-
- /**
- * {@inheritDoc}
- */
- @NonNull
- @Override
- public JobTrigger getTrigger() {
- return mTrigger;
- }
-
- /**
- * Sets the Trigger used for the Job. See {@link #getTrigger()}.
- */
- public Builder setTrigger(JobTrigger trigger) {
- mTrigger = trigger;
-
- return this;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- @Lifetime.LifetimeConstant
- public int getLifetime() {
- return mLifetime;
- }
-
- /**
- * Sets the Job's lifetime, or how long it should persist. See {@link #getLifetime()}.
- */
- public Builder setLifetime(@Lifetime.LifetimeConstant int lifetime) {
- mLifetime = lifetime;
-
- return this;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean isRecurring() {
- return mRecurring;
- }
-
- /**
- * Sets whether the job should recur. The default is false.
- */
- public Builder setRecurring(boolean recurring) {
- mRecurring = recurring;
-
- return this;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- @JobConstraint
- public int[] getConstraints() {
- return mConstraints == null ? new int[]{} : mConstraints;
- }
-
- /**
- * Sets the Job's runtime constraints. See {@link #getConstraints()}.
- */
- public Builder setConstraints(@JobConstraint int... constraints) {
- mConstraints = constraints;
-
- return this;
- }
-
- /**
- * {@inheritDoc}
- */
- @Nullable
- @Override
- public Bundle getExtras() {
- return mExtras;
- }
-
- /**
- * Sets the user-defined extras associated with the Job. See {@link #getExtras()}.
- */
- public Builder setExtras(Bundle extras) {
- mExtras = extras;
-
- return this;
- }
-
- /**
- * {@inheritDoc}
- */
- @NonNull
- @Override
- public RetryStrategy getRetryStrategy() {
- return mRetryStrategy;
- }
-
- /**
- * Set the RetryStrategy used for the Job. See {@link #getRetryStrategy()}.
- */
- public Builder setRetryStrategy(RetryStrategy retryStrategy) {
- mRetryStrategy = retryStrategy;
-
- return this;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean shouldReplaceCurrent() {
- return mReplaceCurrent;
- }
-
- @Nullable
- @Override
- public TriggerReason getTriggerReason() {
- return null;
- }
- }
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/JobCallback.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/JobCallback.java
deleted file mode 100644
index adeb82eaf..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/JobCallback.java
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-/**
- * JobCallback describes an object that knows how to send a JobResult back to the underlying
- * execution driver.
- */
-public interface JobCallback {
- /**
- * @throws RuntimeException
- */
- void jobFinished(@JobService.JobResult int status);
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/JobCoder.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/JobCoder.java
deleted file mode 100644
index e5523587e..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/JobCoder.java
+++ /dev/null
@@ -1,253 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static com.firebase.jobdispatcher.Constraint.compact;
-import static com.firebase.jobdispatcher.Constraint.uncompact;
-import static com.firebase.jobdispatcher.ExecutionDelegator.TAG;
-
-import android.net.Uri;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.util.Log;
-import com.firebase.jobdispatcher.JobTrigger.ContentUriTrigger;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-/**
- * JobCoder is a tool to encode and decode JobSpecs from Bundles.
- */
-/* package */ final class JobCoder {
- private final boolean includeExtras;
- private final String prefix;
-
- private static final String JSON_URI_FLAGS = "uri_flags";
- private static final String JSON_URIS = "uris";
-
- JobCoder(String prefix, boolean includeExtras) {
- this.includeExtras = includeExtras;
- this.prefix = prefix;
- }
-
- @NonNull
- Bundle encode(@NonNull JobParameters jobParameters, @NonNull Bundle data) {
- if (data == null) {
- throw new IllegalArgumentException("Unexpected null Bundle provided");
- }
-
- data.putInt(prefix + BundleProtocol.PACKED_PARAM_LIFETIME,
- jobParameters.getLifetime());
- data.putBoolean(prefix + BundleProtocol.PACKED_PARAM_RECURRING,
- jobParameters.isRecurring());
- data.putBoolean(prefix + BundleProtocol.PACKED_PARAM_REPLACE_CURRENT,
- jobParameters.shouldReplaceCurrent());
- data.putString(prefix + BundleProtocol.PACKED_PARAM_TAG,
- jobParameters.getTag());
- data.putString(prefix + BundleProtocol.PACKED_PARAM_SERVICE,
- jobParameters.getService());
- data.putInt(prefix + BundleProtocol.PACKED_PARAM_CONSTRAINTS,
- compact(jobParameters.getConstraints()));
-
- if (includeExtras) {
- data.putBundle(prefix + BundleProtocol.PACKED_PARAM_EXTRAS,
- jobParameters.getExtras());
- }
-
- encodeTrigger(jobParameters.getTrigger(), data);
- encodeRetryStrategy(jobParameters.getRetryStrategy(), data);
-
- return data;
- }
-
- JobInvocation decodeIntentBundle(@NonNull Bundle bundle) {
- if (bundle == null) {
- Log.e(TAG, "Unexpected null Bundle provided");
- return null;
- }
-
- Bundle taskExtras = bundle.getBundle(GooglePlayJobWriter.REQUEST_PARAM_EXTRAS);
- if (taskExtras == null) {
- return null;
- }
-
- JobInvocation.Builder builder = decode(taskExtras);
-
- List triggeredContentUris =
- bundle.getParcelableArrayList(BundleProtocol.PACKED_PARAM_TRIGGERED_URIS);
- if (triggeredContentUris != null) {
- builder.setTriggerReason(new TriggerReason(triggeredContentUris));
- }
- return builder.build();
- }
-
- @Nullable
- public JobInvocation.Builder decode(@NonNull Bundle data) {
- if (data == null) {
- throw new IllegalArgumentException("Unexpected null Bundle provided");
- }
-
- boolean recur = data.getBoolean(prefix + BundleProtocol.PACKED_PARAM_RECURRING);
- boolean replaceCur = data.getBoolean(prefix + BundleProtocol.PACKED_PARAM_REPLACE_CURRENT);
- int lifetime = data.getInt(prefix + BundleProtocol.PACKED_PARAM_LIFETIME);
- int[] constraints = uncompact(data.getInt(prefix + BundleProtocol.PACKED_PARAM_CONSTRAINTS));
-
- JobTrigger trigger = decodeTrigger(data);
- RetryStrategy retryStrategy = decodeRetryStrategy(data);
-
- String tag = data.getString(prefix + BundleProtocol.PACKED_PARAM_TAG);
- String service = data.getString(prefix + BundleProtocol.PACKED_PARAM_SERVICE);
-
- if (tag == null || service == null || trigger == null || retryStrategy == null) {
- return null;
- }
-
- JobInvocation.Builder builder = new JobInvocation.Builder();
- builder.setTag(tag);
- builder.setService(service);
- builder.setTrigger(trigger);
- builder.setRetryStrategy(retryStrategy);
- builder.setRecurring(recur);
- //noinspection WrongConstant
- builder.setLifetime(lifetime);
- //noinspection WrongConstant
- builder.setConstraints(constraints);
- builder.setReplaceCurrent(replaceCur);
-
- // repack the taskExtras
- builder.addExtras(data);
- return builder;
- }
-
- @NonNull
- private JobTrigger decodeTrigger(Bundle data) {
- switch (data.getInt(prefix + BundleProtocol.PACKED_PARAM_TRIGGER_TYPE)) {
- case BundleProtocol.TRIGGER_TYPE_IMMEDIATE:
- return Trigger.NOW;
-
- case BundleProtocol.TRIGGER_TYPE_EXECUTION_WINDOW:
- return Trigger.executionWindow(
- data.getInt(prefix + BundleProtocol.PACKED_PARAM_TRIGGER_WINDOW_START),
- data.getInt(prefix + BundleProtocol.PACKED_PARAM_TRIGGER_WINDOW_END));
-
- case BundleProtocol.TRIGGER_TYPE_CONTENT_URI:
- String uris = data.getString(prefix + BundleProtocol.PACKED_PARAM_OBSERVED_URI);
- List observedUris = convertJsonToObservedUris(uris);
- return Trigger.contentUriTrigger(Collections.unmodifiableList(observedUris));
-
- default:
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Unsupported trigger.");
- }
- return null;
- }
- }
-
- private void encodeTrigger(JobTrigger trigger, Bundle data) {
- if (trigger == Trigger.NOW) {
- data.putInt(prefix + BundleProtocol.PACKED_PARAM_TRIGGER_TYPE,
- BundleProtocol.TRIGGER_TYPE_IMMEDIATE);
- } else if (trigger instanceof JobTrigger.ExecutionWindowTrigger) {
- JobTrigger.ExecutionWindowTrigger t = (JobTrigger.ExecutionWindowTrigger) trigger;
-
- data.putInt(prefix + BundleProtocol.PACKED_PARAM_TRIGGER_TYPE,
- BundleProtocol.TRIGGER_TYPE_EXECUTION_WINDOW);
- data.putInt(prefix + BundleProtocol.PACKED_PARAM_TRIGGER_WINDOW_START,
- t.getWindowStart());
- data.putInt(prefix + BundleProtocol.PACKED_PARAM_TRIGGER_WINDOW_END,
- t.getWindowEnd());
- } else if (trigger instanceof JobTrigger.ContentUriTrigger) {
- data.putInt(prefix + BundleProtocol.PACKED_PARAM_TRIGGER_TYPE,
- BundleProtocol.TRIGGER_TYPE_CONTENT_URI);
- ContentUriTrigger uriTrigger = (ContentUriTrigger) trigger;
- String jsonTrigger = convertObservedUrisToJsonString(uriTrigger.getUris());
- data.putString(prefix + BundleProtocol.PACKED_PARAM_OBSERVED_URI, jsonTrigger);
- } else {
- throw new IllegalArgumentException("Unsupported trigger.");
- }
- }
-
- private RetryStrategy decodeRetryStrategy(Bundle data) {
- int policy = data.getInt(prefix + BundleProtocol.PACKED_PARAM_RETRY_STRATEGY_POLICY);
- if (policy != RetryStrategy.RETRY_POLICY_EXPONENTIAL
- && policy != RetryStrategy.RETRY_POLICY_LINEAR) {
-
- return RetryStrategy.DEFAULT_EXPONENTIAL;
- }
-
- //noinspection WrongConstant
- return new RetryStrategy(
- policy,
- data.getInt(prefix + BundleProtocol.PACKED_PARAM_RETRY_STRATEGY_INITIAL_BACKOFF_SECONDS),
- data.getInt(prefix + BundleProtocol.PACKED_PARAM_RETRY_STRATEGY_MAXIMUM_BACKOFF_SECONDS));
- }
-
- private void encodeRetryStrategy(RetryStrategy retryStrategy, Bundle data) {
- if (retryStrategy == null) {
- retryStrategy = RetryStrategy.DEFAULT_EXPONENTIAL;
- }
-
- data.putInt(prefix + BundleProtocol.PACKED_PARAM_RETRY_STRATEGY_POLICY,
- retryStrategy.getPolicy());
- data.putInt(prefix + BundleProtocol.PACKED_PARAM_RETRY_STRATEGY_INITIAL_BACKOFF_SECONDS,
- retryStrategy.getInitialBackoff());
- data.putInt(prefix + BundleProtocol.PACKED_PARAM_RETRY_STRATEGY_MAXIMUM_BACKOFF_SECONDS,
- retryStrategy.getMaximumBackoff());
- }
-
- @NonNull
- private String convertObservedUrisToJsonString(@NonNull List uris) {
- JSONObject contentUris = new JSONObject();
- JSONArray jsonFlags = new JSONArray();
- JSONArray jsonUris = new JSONArray();
- for (ObservedUri uri : uris) {
- jsonFlags.put(uri.getFlags());
- jsonUris.put(uri.getUri());
- }
- try {
- contentUris.put(JSON_URI_FLAGS, jsonFlags);
- contentUris.put(JSON_URIS, jsonUris);
- } catch (JSONException e) {
- throw new RuntimeException(e);
- }
- return contentUris.toString();
- }
-
- @NonNull
- private List convertJsonToObservedUris(@NonNull String contentUrisJson) {
- List uris = new ArrayList<>();
- try {
- JSONObject json = new JSONObject(contentUrisJson);
- JSONArray jsonFlags = json.getJSONArray(JSON_URI_FLAGS);
- JSONArray jsonUris = json.getJSONArray(JSON_URIS);
- int length = jsonFlags.length();
-
- for (int i = 0; i < length; i++) {
- int flags = jsonFlags.getInt(i);
- String uri = jsonUris.getString(i);
- uris.add(new ObservedUri(Uri.parse(uri), flags));
- }
- } catch (JSONException e) {
- throw new RuntimeException(e);
- }
- return uris;
- }
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/JobInvocation.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/JobInvocation.java
deleted file mode 100644
index 08263e845..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/JobInvocation.java
+++ /dev/null
@@ -1,236 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import com.firebase.jobdispatcher.Constraint.JobConstraint;
-
-/**
- * An internal non-Job implementation of JobParameters. Passed to JobService invocations.
- */
-/* package */ final class JobInvocation implements JobParameters {
-
- @NonNull
- private final String mTag;
-
- @NonNull
- private final String mService;
-
- @NonNull
- private final JobTrigger mTrigger;
-
- private final boolean mRecurring;
-
- private final int mLifetime;
-
- @NonNull
- @JobConstraint
- private final int[] mConstraints;
-
- @NonNull
- private final Bundle mExtras;
-
- private final RetryStrategy mRetryStrategy;
-
- private final boolean mReplaceCurrent;
-
- private final TriggerReason mTriggerReason;
-
- private JobInvocation(Builder builder) {
- mTag = builder.mTag;
- mService = builder.mService;
- mTrigger = builder.mTrigger;
- mRetryStrategy = builder.mRetryStrategy;
- mRecurring = builder.mRecurring;
- mLifetime = builder.mLifetime;
- mConstraints = builder.mConstraints;
- mExtras = builder.mExtras;
- mReplaceCurrent = builder.mReplaceCurrent;
- mTriggerReason = builder.mTriggerReason;
- }
-
- @NonNull
- @Override
- public String getService() {
- return mService;
- }
-
- @NonNull
- @Override
- public String getTag() {
- return mTag;
- }
-
- @NonNull
- @Override
- public JobTrigger getTrigger() {
- return mTrigger;
- }
-
- @Override
- public int getLifetime() {
- return mLifetime;
- }
-
- @Override
- public boolean isRecurring() {
- return mRecurring;
- }
-
- @NonNull
- @Override
- public int[] getConstraints() {
- return mConstraints;
- }
-
- @NonNull
- @Override
- public Bundle getExtras() {
- return mExtras;
- }
-
- @NonNull
- @Override
- public RetryStrategy getRetryStrategy() {
- return mRetryStrategy;
- }
-
- @Override
- public boolean shouldReplaceCurrent() {
- return mReplaceCurrent;
- }
-
- @Override
- public TriggerReason getTriggerReason() {
- return mTriggerReason;
- }
-
- static final class Builder {
-
- @NonNull
- private String mTag;
-
- @NonNull
- private String mService;
-
- @NonNull
- private JobTrigger mTrigger;
-
- private boolean mRecurring;
-
- private int mLifetime;
-
- @NonNull
- @JobConstraint
- private int[] mConstraints;
-
- @NonNull
- private final Bundle mExtras = new Bundle();
-
- private RetryStrategy mRetryStrategy;
-
- private boolean mReplaceCurrent;
-
- private TriggerReason mTriggerReason;
-
- JobInvocation build() {
- if (mTag == null || mService == null || mTrigger == null) {
- throw new IllegalArgumentException("Required fields were not populated.");
- }
- return new JobInvocation(this);
- }
-
- public Builder setTag(@NonNull String mTag) {
- this.mTag = mTag;
- return this;
- }
-
- public Builder setService(@NonNull String mService) {
- this.mService = mService;
- return this;
- }
-
- public Builder setTrigger(@NonNull JobTrigger mTrigger) {
- this.mTrigger = mTrigger;
- return this;
- }
-
- public Builder setRecurring(boolean mRecurring) {
- this.mRecurring = mRecurring;
- return this;
- }
-
- public Builder setLifetime(@Lifetime.LifetimeConstant int mLifetime) {
- this.mLifetime = mLifetime;
- return this;
- }
-
- public Builder setConstraints(@JobConstraint @NonNull int[] mConstraints) {
- this.mConstraints = mConstraints;
- return this;
- }
-
- public Builder addExtras(@NonNull Bundle bundle) {
- if (bundle != null) {
- mExtras.putAll(bundle);
- }
- return this;
- }
-
- public Builder setRetryStrategy(RetryStrategy mRetryStrategy) {
- this.mRetryStrategy = mRetryStrategy;
- return this;
- }
-
- public Builder setReplaceCurrent(boolean mReplaceCurrent) {
- this.mReplaceCurrent = mReplaceCurrent;
- return this;
- }
-
- public Builder setTriggerReason(TriggerReason triggerReason) {
- this.mTriggerReason = triggerReason;
- return this;
- }
- }
-
- /**
- * @return true if the tag and the service of provided {@link JobInvocation} have the same
- * values.
- */
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || !getClass().equals(o.getClass())) {
- return false;
- }
-
- JobInvocation jobInvocation = (JobInvocation) o;
-
- return mTag.equals(jobInvocation.mTag)
- && mService.equals(jobInvocation.mService);
- }
-
- @Override
- public int hashCode() {
- int result = mTag.hashCode();
- result = 31 * result + mService.hashCode();
- return result;
- }
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/JobParameters.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/JobParameters.java
deleted file mode 100644
index 24f0844e1..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/JobParameters.java
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import com.firebase.jobdispatcher.Constraint.JobConstraint;
-
-/**
- * JobParameters represents anything that can describe itself in terms of Job components.
- */
-public interface JobParameters {
-
- /**
- * Returns the name of the backing JobService class.
- */
- @NonNull
- String getService();
-
- /**
- * Returns a string identifier for the Job. Used when cancelling Jobs and displaying debug
- * messages.
- */
- @NonNull
- String getTag();
-
- /**
- * The Job's Trigger, which decides when the Job is ready to run.
- */
- @NonNull
- JobTrigger getTrigger();
-
- /**
- * The Job's lifetime; how long it should persist for.
- */
- @Lifetime.LifetimeConstant
- int getLifetime();
-
- /**
- * Whether the Job should repeat.
- */
- boolean isRecurring();
-
- /**
- * The runtime constraints applied to this Job. A Job is not run until the trigger is activated
- * and all the runtime constraints are satisfied.
- */
- @JobConstraint
- int[] getConstraints();
-
- /**
- * The optional set of user-supplied extras associated with this Job.
- */
- @Nullable
- Bundle getExtras();
-
- /**
- * The RetryStrategy for the Job. Used to determine how to handle failures.
- */
- @NonNull
- RetryStrategy getRetryStrategy();
-
- /**
- * Whether the Job should replace a pre-existing Job with the same tag.
- */
- boolean shouldReplaceCurrent();
-
- /** @return A {@link TriggerReason} that - if non null - describes why the job was triggered. */
- @Nullable
- TriggerReason getTriggerReason();
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/JobService.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/JobService.java
deleted file mode 100644
index 41076e767..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/JobService.java
+++ /dev/null
@@ -1,259 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import android.app.Service;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.Message;
-import android.support.annotation.IntDef;
-import android.support.annotation.MainThread;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
-import android.support.v4.util.SimpleArrayMap;
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Locale;
-
-/**
- * JobService is the fundamental unit of work used in the JobDispatcher.
- *
- * Users will need to override {@link #onStartJob(JobParameters)}, which is where any asynchronous
- * execution should start. This method, like most lifecycle methods, runs on the main thread; you
- * must offload execution to another thread (or {@link android.os.AsyncTask}, or
- * {@link android.os.Handler}, or your favorite flavor of concurrency).
- *
- * Once any asynchronous work is complete {@link #jobFinished(JobParameters, boolean)} should be
- * called to inform the backing driver of the result.
- *
- * Implementations should also override {@link #onStopJob(JobParameters)}, which will be called if
- * the scheduling engine wishes to interrupt your work (most likely because the runtime constraints
- * that are associated with the job in question are no longer met).
- */
-public abstract class JobService extends Service {
- /**
- * Returned to indicate the job was executed successfully. If the job is not recurring (i.e. a
- * one-off) it will be dequeued and forgotten. If it is recurring the trigger will be reset and
- * the job will be requeued.
- */
- public static final int RESULT_SUCCESS = 0;
-
- /**
- * Returned to indicate the job encountered an error during execution and should be retried after
- * a backoff period.
- */
- public static final int RESULT_FAIL_RETRY = 1;
-
- /**
- * Returned to indicate the job encountered an error during execution but should not be retried.
- * If the job is not recurring (i.e. a one-off) it will be dequeued and forgotten. If it is
- * recurring the trigger will be reset and the job will be requeued.
- */
- public static final int RESULT_FAIL_NORETRY = 2;
-
- static final String TAG = "FJD.JobService";
-
- @VisibleForTesting
- static final String ACTION_EXECUTE = "com.firebase.jobdispatcher.ACTION_EXECUTE";
-
- /**
- * Correlates job tags (unique strings) with Messages, which are used to signal the completion
- * of a job.
- */
- private final SimpleArrayMap runningJobs = new SimpleArrayMap<>(1);
- private LocalBinder binder = new LocalBinder();
-
- /**
- * The entry point to your Job. Implementations should offload work to another thread of
- * execution as soon as possible because this runs on the main thread. If work was offloaded,
- * call {@link JobService#jobFinished(JobParameters, boolean)} to notify the scheduling service
- * that the work is completed.
- *
- * In order to reschedule use {@link JobService#jobFinished(JobParameters, boolean)}.
- *
- * @return {@code true} if there is more work remaining in the worker thread, {@code false} if the job was completed.
- */
- @MainThread
- public abstract boolean onStartJob(JobParameters job);
-
- /**
- * Called when the scheduling engine has decided to interrupt the execution of a running job,
- * most likely because the runtime constraints associated with the job are no longer satisfied.
- * The job must stop execution.
- *
- * @return true if the job should be retried
- * @see com.firebase.jobdispatcher.JobInvocation.Builder#setRetryStrategy(RetryStrategy)
- * @see RetryStrategy
- */
- @MainThread
- public abstract boolean onStopJob(JobParameters job);
-
- @MainThread
- void start(JobParameters job, Message msg) {
- synchronized (runningJobs) {
- if (runningJobs.containsKey(job.getTag())) {
- Log.w(TAG, String
- .format(Locale.US, "Job with tag = %s was already running.", job.getTag()));
- return;
- }
- runningJobs.put(job.getTag(), new JobCallback(msg));
-
- boolean moreWork = onStartJob(job);
- if (!moreWork) {
- JobCallback callback = runningJobs.remove(job.getTag());
- if (callback != null) {
- callback.sendResult(RESULT_SUCCESS);
- }
- }
- }
- }
-
- @MainThread
- void stop(JobInvocation job) {
- synchronized (runningJobs) {
- JobCallback jobCallback = runningJobs.remove(job.getTag());
-
- if (jobCallback == null) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Provided job has already been executed.");
- }
- return;
- }
- boolean shouldRetry = onStopJob(job);
- jobCallback.sendResult(shouldRetry ? RESULT_FAIL_RETRY : RESULT_SUCCESS);
- }
- }
-
- /**
- * Callback to inform the scheduling driver that you've finished executing. Can be called from
- * any thread. When the system receives this message, it will release the wakelock being held.
- *
- * @param job
- * @param needsReschedule
- * whether the job should be rescheduled
- * @see com.firebase.jobdispatcher.JobInvocation.Builder#setRetryStrategy(RetryStrategy)
- */
- public final void jobFinished(@NonNull JobParameters job, boolean needsReschedule) {
- if (job == null) {
- Log.e(TAG, "jobFinished called with a null JobParameters");
- return;
- }
-
- synchronized (runningJobs) {
- JobCallback jobCallback = runningJobs.remove(job.getTag());
-
- if (jobCallback != null) {
- jobCallback.sendResult(needsReschedule ? RESULT_FAIL_RETRY : RESULT_SUCCESS);
- }
- }
- }
-
- @Override
- public final int onStartCommand(Intent intent, int flags, int startId) {
- stopSelf(startId);
-
- return START_NOT_STICKY;
- }
-
- @Nullable
- @Override
- public final IBinder onBind(Intent intent) {
- return binder;
- }
-
- @Override
- public final boolean onUnbind(Intent intent) {
- synchronized (runningJobs) {
- for (int i = runningJobs.size() - 1; i >= 0; i--) {
- JobCallback callback = runningJobs.get(runningJobs.keyAt(i));
- if (callback != null && callback.message != null) {
- if (callback.message.obj instanceof JobParameters) {
- callback.sendResult(onStopJob((JobParameters) callback.message.obj)
- // returned true, would like to be rescheduled
- ? RESULT_FAIL_RETRY
- // returned false, but was interrupted so consider it a fail
- : RESULT_FAIL_NORETRY);
- }
- }
- }
- }
-
- return super.onUnbind(intent);
- }
-
- @Override
- public final void onRebind(Intent intent) {
- super.onRebind(intent);
- }
-
- @Override
- public final void onStart(Intent intent, int startId) {
- }
-
- @Override
- protected final void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
- super.dump(fd, writer, args);
- }
-
- @Override
- public final void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- }
-
- @Override
- public final void onTaskRemoved(Intent rootIntent) {
- super.onTaskRemoved(rootIntent);
- }
-
- /**
- * The result returned from a job execution.
- */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({RESULT_SUCCESS, RESULT_FAIL_RETRY, RESULT_FAIL_NORETRY})
- public @interface JobResult {
- }
-
- private final static class JobCallback {
- public final Message message;
-
- private JobCallback(Message message) {
- this.message = message;
- }
-
- void sendResult(@JobResult int result) {
- try {
- if (message != null) {
- message.arg1 = result;
- message.sendToTarget();
- }
- } catch (Exception ignored) {}//catch this freaking crash!!!!
- }
- }
-
- class LocalBinder extends Binder {
- JobService getService() {
- return JobService.this;
- }
- }
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/JobServiceConnection.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/JobServiceConnection.java
deleted file mode 100644
index c96e9f687..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/JobServiceConnection.java
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static com.firebase.jobdispatcher.ExecutionDelegator.TAG;
-
-import android.content.ComponentName;
-import android.content.ServiceConnection;
-import android.os.IBinder;
-import android.os.Message;
-import android.support.annotation.VisibleForTesting;
-import android.util.Log;
-
-/**
- * ServiceConnection for job execution.
- */
-@VisibleForTesting
-class JobServiceConnection implements ServiceConnection {
-
- private final JobInvocation jobInvocation;
- // Should be sent only once. Can't be reused.
- private final Message jobFinishedMessage;
- private boolean wasMessageUsed = false;
-
- //Guarded by "this". Can be updated from main and binder threads.
- private JobService.LocalBinder binder;
-
- JobServiceConnection(JobInvocation jobInvocation, Message jobFinishedMessage) {
- this.jobFinishedMessage = jobFinishedMessage;
- this.jobInvocation = jobInvocation;
- this.jobFinishedMessage.obj = this.jobInvocation;
- }
-
- @Override
- public synchronized void onServiceConnected(ComponentName name, IBinder service) {
- if (!(service instanceof JobService.LocalBinder)) {
- Log.w(TAG, "Unknown service connected");
- return;
- }
- if (wasMessageUsed) {
- Log.w(TAG, "onServiceConnected Duplicate calls. Ignored.");
- return;
- } else {
- wasMessageUsed = true;
- }
-
- binder = (JobService.LocalBinder) service;
-
- JobService jobService = binder.getService();
-
- jobService.start(jobInvocation, jobFinishedMessage);
- }
-
- @Override
- public synchronized void onServiceDisconnected(ComponentName name) {
- binder = null;
- }
-
- synchronized boolean isBound() {
- return binder != null;
- }
-
- synchronized void onStop() {
- if (isBound()) {
- binder.getService().stop(jobInvocation);
- }
- }
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/JobTrigger.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/JobTrigger.java
deleted file mode 100644
index b1c510c7f..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/JobTrigger.java
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import java.util.List;
-
-/**
- * Contains all supported triggers.
- */
-public class JobTrigger {
-
- /**
- * ImmediateTrigger is a Trigger that's immediately available. The Job will be run as soon as
- * the runtime constraints are satisfied.
- */
- public static final class ImmediateTrigger extends JobTrigger {
- /* package */ ImmediateTrigger() {}
- }
-
- /**
- * ExecutionWindow represents a Job trigger that becomes eligible once
- * the current elapsed time exceeds the scheduled time + the {@code windowStart}
- * value. The scheduler backend is encouraged to use the windowEnd value as a
- * signal that the job should be run, but this is not an enforced behavior.
- */
- public static final class ExecutionWindowTrigger extends JobTrigger {
- private final int mWindowStart;
- private final int mWindowEnd;
-
- /* package */ ExecutionWindowTrigger(int windowStart, int windowEnd) {
- this.mWindowStart = windowStart;
- this.mWindowEnd = windowEnd;
- }
-
- public int getWindowStart() {
- return mWindowStart;
- }
-
- public int getWindowEnd() {
- return mWindowEnd;
- }
- }
-
- /** A trigger that will be triggered on content update for any of provided uris. */
- public static final class ContentUriTrigger extends JobTrigger {
- private final List uris;
-
- /* package */ ContentUriTrigger(List uris) {
- this.uris = uris;
- }
-
- public List getUris() {
- return uris;
- }
- }
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/JobValidator.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/JobValidator.java
deleted file mode 100644
index c97198f49..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/JobValidator.java
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import android.support.annotation.Nullable;
-import java.util.List;
-
-/**
- * A JobValidator is an object that knows how to validate Jobs and some of their composite
- * components.
- */
-public interface JobValidator {
- /**
- * Returns a List of error messages, or null if the JobParameters is
- * valid.
- */
- @Nullable
- List validate(JobParameters job);
-
- /**
- * Returns a List of error messages, or null if the Trigger is
- * valid.
- * @param trigger
- */
- @Nullable
- List validate(JobTrigger trigger);
-
- /**
- * Returns a List of error messages, or null if the RetryStrategy
- * is valid.
- */
- @Nullable
- List validate(RetryStrategy retryStrategy);
-
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/Lifetime.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/Lifetime.java
deleted file mode 100644
index 456bc221c..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/Lifetime.java
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import android.support.annotation.IntDef;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Lifetime represents how long a Job should last.
- */
-public final class Lifetime {
- /**
- * The Job should be preserved until the next boot. This is the default.
- */
- public final static int UNTIL_NEXT_BOOT = 1;
-
- /**
- * The Job should be preserved "forever."
- */
- public final static int FOREVER = 2;
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({FOREVER, UNTIL_NEXT_BOOT})
- @interface LifetimeConstant {}
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/ObservedUri.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/ObservedUri.java
deleted file mode 100644
index b22c15e01..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/ObservedUri.java
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import android.net.Uri;
-import android.support.annotation.IntDef;
-import android.support.annotation.NonNull;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/** Represents a single observed URI and any associated flags. */
-public final class ObservedUri {
-
- private final Uri uri;
-
- private final int flags;
-
- /** Flag enforcement. */
- @IntDef(flag = true, value = Flags.FLAG_NOTIFY_FOR_DESCENDANTS)
- @Retention(RetentionPolicy.SOURCE)
- public @interface Flags {
-
- /**
- * Triggers if any descendants of the given URI change. Corresponds to the {@code
- * notifyForDescendants} of {@link android.content.ContentResolver#registerContentObserver}.
- */
- int FLAG_NOTIFY_FOR_DESCENDANTS = 1 << 0;
- }
-
- /**
- * Create a new ObservedUri.
- *
- * @param uri The URI to observe.
- * @param flags Any {@link Flags} associated with the URI.
- */
- public ObservedUri(@NonNull Uri uri, @Flags int flags) {
- if (uri == null) {
- throw new IllegalArgumentException("URI must not be null.");
- }
- this.uri = uri;
- this.flags = flags;
- }
-
- public Uri getUri() {
- return uri;
- }
-
- public int getFlags() {
- return flags;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (!(o instanceof ObservedUri)) {
- return false;
- }
-
- ObservedUri otherUri = (ObservedUri) o;
- return flags == otherUri.flags && uri.equals(otherUri.uri);
- }
-
- @Override
- public int hashCode() {
- return uri.hashCode() ^ flags;
- }
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/RetryStrategy.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/RetryStrategy.java
deleted file mode 100644
index 7d9b31901..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/RetryStrategy.java
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import android.support.annotation.IntDef;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * RetryStrategy represents an approach to handling job execution failures. Jobs will have a
- * time-based backoff enforced, based on the chosen policy (one of {@code RETRY_POLICY_EXPONENTIAL}
- * or {@code RETRY_POLICY_LINEAR}.
- */
-public final class RetryStrategy {
- /**
- * Increase the backoff time exponentially.
- *
- * Calculated using {@code initial_backoff * 2 ^ (num_failures - 1)}.
- */
- public final static int RETRY_POLICY_EXPONENTIAL = 1;
-
- /**
- * Increase the backoff time linearly.
- *
- * Calculated using {@code initial_backoff * num_failures}.
- */
- public final static int RETRY_POLICY_LINEAR = 2;
-
- /**
- * Expected schedule is: [30s, 60s, 120s, 240s, ..., 3600s]
- */
- public final static RetryStrategy DEFAULT_EXPONENTIAL =
- new RetryStrategy(RETRY_POLICY_EXPONENTIAL, 30, 3600);
-
- /**
- * Expected schedule is: [30s, 60s, 90s, 120s, ..., 3600s]
- */
- public final static RetryStrategy DEFAULT_LINEAR =
- new RetryStrategy(RETRY_POLICY_LINEAR, 30, 3600);
-
- @RetryPolicy
- private final int mPolicy;
- private final int mInitialBackoff;
- private final int mMaximumBackoff;
-
- /* package */ RetryStrategy(@RetryPolicy int policy, int initialBackoff, int maximumBackoff) {
- mPolicy = policy;
- mInitialBackoff = initialBackoff;
- mMaximumBackoff = maximumBackoff;
- }
-
- /**
- * Returns the backoff policy in place.
- */
- @RetryPolicy
- public int getPolicy() {
- return mPolicy;
- }
-
- /**
- * Returns the initial backoff (i.e. when # of failures == 1), in seconds.
- */
- public int getInitialBackoff() {
- return mInitialBackoff;
- }
-
- /**
- * Returns the maximum backoff duration in seconds.
- */
- public int getMaximumBackoff() {
- return mMaximumBackoff;
- }
-
- @IntDef({RETRY_POLICY_LINEAR, RETRY_POLICY_EXPONENTIAL})
- @Retention(RetentionPolicy.SOURCE)
- public @interface RetryPolicy {
- }
-
- /* package */ final static class Builder {
- private final ValidationEnforcer mValidator;
-
- Builder(ValidationEnforcer validator) {
- mValidator = validator;
- }
-
- public RetryStrategy build(@RetryPolicy int policy, int initialBackoff, int maxBackoff) {
- RetryStrategy rs = new RetryStrategy(policy, initialBackoff, maxBackoff);
- mValidator.ensureValid(rs);
- return rs;
- }
- }
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/SimpleJobService.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/SimpleJobService.java
deleted file mode 100644
index 8cfbe5f4c..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/SimpleJobService.java
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import android.os.AsyncTask;
-import android.support.annotation.CallSuper;
-import android.support.v4.util.SimpleArrayMap;
-
-/**
- * SimpleJobService provides a simple way of doing background work in a JobService.
- *
- * Users should override onRunJob and return one of the {@link JobResult} ints.
- */
-public abstract class SimpleJobService extends JobService {
- private final SimpleArrayMap runningJobs =
- new SimpleArrayMap<>();
-
- @CallSuper
- @Override
- public boolean onStartJob(JobParameters job) {
- AsyncJobTask async = new AsyncJobTask(this, job);
-
- synchronized (runningJobs) {
- runningJobs.put(job, async);
- }
-
- async.execute();
-
- return true; // more work to do
- }
-
- @CallSuper
- @Override
- public boolean onStopJob(JobParameters job) {
- synchronized (runningJobs) {
- AsyncJobTask async = runningJobs.remove(job);
- if (async != null) {
- async.cancel(true);
- return true;
- }
- }
-
- return false;
- }
-
- private void onJobFinished(JobParameters jobParameters, boolean b) {
- synchronized (runningJobs) {
- runningJobs.remove(jobParameters);
- }
-
- jobFinished(jobParameters, b);
- }
-
- @JobResult
- public abstract int onRunJob(JobParameters job);
-
- private static class AsyncJobTask extends AsyncTask {
- private final SimpleJobService jobService;
- private final JobParameters jobParameters;
-
- private AsyncJobTask(SimpleJobService jobService, JobParameters jobParameters) {
- this.jobService = jobService;
- this.jobParameters = jobParameters;
- }
-
- @Override
- protected Integer doInBackground(Void... params) {
- return jobService.onRunJob(jobParameters);
- }
-
- @Override
- protected void onPostExecute(Integer integer) {
- jobService.onJobFinished(jobParameters, integer == JobService.RESULT_FAIL_RETRY);
- }
- }
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/Trigger.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/Trigger.java
deleted file mode 100644
index 3e01ae9c5..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/Trigger.java
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import android.support.annotation.NonNull;
-import java.util.List;
-
-/**
- * Generally, a Trigger is an object that can answer the question, "is this job ready to run?"
- *
- * More specifically, a Trigger is an opaque, abstract class used to root the type hierarchy.
- */
-public final class Trigger {
-
- /**
- * Immediate is a Trigger that's immediately available. The Job will be run as soon as the
- * runtime constraints are satisfied.
- *
- * It is invalid to schedule an Immediate with a recurring Job.
- */
- public final static JobTrigger.ImmediateTrigger NOW = new JobTrigger.ImmediateTrigger();
-
- /**
- * Creates a new ExecutionWindow based on the provided time interval.
- *
- * @param windowStart The earliest time (in seconds) the job should be
- * considered eligible to run. Calculated from when the
- * job was scheduled (for new jobs) or last run (for
- * recurring jobs).
- * @param windowEnd The latest time (in seconds) the job should be run in
- * an ideal world. Calculated in the same way as
- * {@code windowStart}.
- * @throws IllegalArgumentException if the provided parameters are too
- * restrictive.
- */
- public static JobTrigger.ExecutionWindowTrigger executionWindow(int windowStart, int windowEnd) {
- if (windowStart < 0) {
- throw new IllegalArgumentException("Window start can't be less than 0");
- } else if (windowEnd < windowStart) {
- throw new IllegalArgumentException("Window end can't be less than window start");
- }
-
- return new JobTrigger.ExecutionWindowTrigger(windowStart, windowEnd);
- }
-
- /**
- * Creates a new ContentUriTrigger based on the provided list of {@link ObservedUri}.
- *
- * @param uris The list of URIs to observe. The trigger will be available if a piece of content,
- * corresponding to any of provided URIs, is updated.
- * @throws IllegalArgumentException if provided list of URIs is null or empty.
- */
- public static JobTrigger.ContentUriTrigger contentUriTrigger(@NonNull List uris) {
- if (uris == null || uris.isEmpty()) {
- throw new IllegalArgumentException("Uris must not be null or empty.");
- }
- return new JobTrigger.ContentUriTrigger(uris);
- }
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/TriggerReason.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/TriggerReason.java
deleted file mode 100644
index 00fc053b8..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/TriggerReason.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import android.net.Uri;
-import java.util.List;
-
-/** The class contains a summary of the events which caused the job to be executed. */
-public class TriggerReason {
- private final List mTriggeredContentUris;
-
- TriggerReason(List mTriggeredContentUris) {
- this.mTriggeredContentUris = mTriggeredContentUris;
- }
-
- public List getTriggeredContentUris() {
- return mTriggeredContentUris;
- }
-}
diff --git a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/ValidationEnforcer.java b/jobdispatcher/src/main/java/com/firebase/jobdispatcher/ValidationEnforcer.java
deleted file mode 100644
index d9cfbe02f..000000000
--- a/jobdispatcher/src/main/java/com/firebase/jobdispatcher/ValidationEnforcer.java
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.text.TextUtils;
-import java.util.List;
-
-/**
- * Wraps a JobValidator and provides helpful validation utilities.
- */
-public class ValidationEnforcer implements JobValidator {
- private final JobValidator mValidator;
-
- public ValidationEnforcer(JobValidator validator) {
- mValidator = validator;
- }
-
- /**
- * {@inheritDoc}
- */
- @Nullable
- @Override
- public List validate(JobParameters job) {
- return mValidator.validate(job);
- }
-
- /**
- * {@inheritDoc}
- * @param trigger
- */
- @Nullable
- @Override
- public List validate(JobTrigger trigger) {
- return mValidator.validate(trigger);
- }
-
- /**
- * {@inheritDoc}
- */
- @Nullable
- @Override
- public List validate(RetryStrategy retryStrategy) {
- return mValidator.validate(retryStrategy);
- }
-
- /**
- * Indicates whether the provided JobParameters is valid.
- */
- public final boolean isValid(JobParameters job) {
- return validate(job) == null;
- }
-
- /**
- * Indicates whether the provided JobTrigger is valid.
- */
- public final boolean isValid(JobTrigger trigger) {
- return validate(trigger) == null;
- }
-
- /**
- * Indicates whether the provided RetryStrategy is valid.
- */
- public final boolean isValid(RetryStrategy retryStrategy) {
- return validate(retryStrategy) == null;
- }
-
- /**
- * Throws a RuntimeException if the provided JobParameters is invalid.
- *
- * @throws ValidationException
- */
- public final void ensureValid(JobParameters job) {
- ensureNoErrors(validate(job));
- }
-
- /**
- * Throws a RuntimeException if the provided JobTrigger is invalid.
- *
- * @throws ValidationException
- */
- public final void ensureValid(JobTrigger trigger) {
- ensureNoErrors(validate(trigger));
- }
-
- /**
- * Throws a RuntimeException if the provided RetryStrategy is
- * invalid.
- *
- * @throws ValidationException
- */
- public final void ensureValid(RetryStrategy retryStrategy) {
- ensureNoErrors(validate(retryStrategy));
- }
-
- private void ensureNoErrors(List errors) {
- if (errors != null) {
- throw new ValidationException("JobParameters is invalid", errors);
- }
- }
-
- /**
- * An Exception thrown when a validation error is encountered.
- */
- public final static class ValidationException extends RuntimeException {
- private final List mErrors;
-
- public ValidationException(String msg, @NonNull List errors) {
- super(msg + ": " + TextUtils.join("\n - ", errors));
- mErrors = errors;
- }
-
- public List getErrors() {
- return mErrors;
- }
- }
-}
diff --git a/jobdispatcher/src/test/java/android/net/http/AndroidHttpClient.java b/jobdispatcher/src/test/java/android/net/http/AndroidHttpClient.java
deleted file mode 100644
index 0720a56f5..000000000
--- a/jobdispatcher/src/test/java/android/net/http/AndroidHttpClient.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package android.net.http;
-
-/**
- * Robolectric requires this class be available in the classpath, otherwise {@link
- * org.robolectric.Shadows#shadowOf(android.os.Looper)} fails. We don't use AndroidHttpClient, so
- * include a stub to make Robolectric happy.
- *
- * @see https://github.com/robolectric/robolectric/issues/1862
- */
-public class AndroidHttpClient {}
diff --git a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/ConstraintTest.java b/jobdispatcher/src/test/java/com/firebase/jobdispatcher/ConstraintTest.java
deleted file mode 100644
index 808d7a3c6..000000000
--- a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/ConstraintTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static org.junit.Assert.assertEquals;
-
-import android.text.TextUtils;
-import java.util.Arrays;
-import java.util.List;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, manifest = Config.NONE, sdk = 23)
-public class ConstraintTest {
-
- /**
- * Just to get 100% coverage.
- */
- @Test
- public void testPrivateConstructor() throws Exception {
- TestUtil.assertHasSinglePrivateConstructor(Constraint.class);
- }
-
- @Test
- public void testCompactAndUnCompact() {
- for (List combo : TestUtil.getAllConstraintCombinations()) {
- int[] input = TestUtil.toIntArray(combo);
- Arrays.sort(input);
-
- int[] output = Constraint.uncompact(Constraint.compact(input));
- Arrays.sort(output);
-
- for (int i = 0; i < combo.size(); i++) {
- assertEquals("Combination = " + TextUtils.join(", ", combo),
- input[i],
- output[i]);
- }
-
- assertEquals("Expected length of two arrays to be the same",
- input.length,
- output.length);
- }
- }
-
- @Test
- public void compactNull() {
- assertEquals(0, Constraint.compact(null));
- }
-}
diff --git a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/ContentUriTriggerTest.java b/jobdispatcher/src/test/java/com/firebase/jobdispatcher/ContentUriTriggerTest.java
deleted file mode 100644
index 5ea200af0..000000000
--- a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/ContentUriTriggerTest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static junit.framework.Assert.assertEquals;
-
-import android.provider.ContactsContract;
-import com.firebase.jobdispatcher.JobTrigger.ContentUriTrigger;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-/** Test for {@link ContentUriTrigger}. */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, manifest = Config.NONE, sdk = 21)
-public class ContentUriTriggerTest {
-
- @Test(expected = IllegalArgumentException.class)
- public void constrains_null() throws Exception {
- Trigger.contentUriTrigger(null);
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void constrains_emptyList() throws Exception {
- Trigger.contentUriTrigger(Collections.emptyList());
- }
-
- @Test
- public void constrains_valid() throws Exception {
- List uris = Arrays.asList(new ObservedUri(ContactsContract.AUTHORITY_URI, 0));
- ContentUriTrigger uriTrigger = Trigger.contentUriTrigger(uris);
- assertEquals(uris, uriTrigger.getUris());
- }
-}
diff --git a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/DefaultJobValidatorTest.java b/jobdispatcher/src/test/java/com/firebase/jobdispatcher/DefaultJobValidatorTest.java
deleted file mode 100644
index 2d5264175..000000000
--- a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/DefaultJobValidatorTest.java
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static java.util.Collections.singletonList;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.provider.ContactsContract;
-import com.firebase.jobdispatcher.JobTrigger.ContentUriTrigger;
-import com.firebase.jobdispatcher.ObservedUri.Flags;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, manifest = Config.NONE, sdk = 23)
-public class DefaultJobValidatorTest {
-
- @Mock
- private Context mMockContext;
-
- private DefaultJobValidator mValidator;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- mValidator = new DefaultJobValidator(mMockContext);
- }
-
- @SuppressWarnings("WrongConstant")
- @Test
- public void testValidate_retryStrategy() throws Exception {
- Map> testCases = new HashMap<>();
- testCases.put(
- new RetryStrategy(0 /* bad policy */, 30, 3600),
- singletonList("Unknown retry policy provided"));
- testCases.put(
- new RetryStrategy(RetryStrategy.RETRY_POLICY_LINEAR, 15, 3600),
- singletonList("Initial backoff must be at least 30s"));
- testCases.put(
- new RetryStrategy(RetryStrategy.RETRY_POLICY_EXPONENTIAL, 15, 3600),
- singletonList("Initial backoff must be at least 30s"));
- testCases.put(
- new RetryStrategy(RetryStrategy.RETRY_POLICY_LINEAR, 30, 60),
- singletonList("Maximum backoff must be greater than 300s (5 minutes)"));
- testCases.put(
- new RetryStrategy(RetryStrategy.RETRY_POLICY_EXPONENTIAL, 30, 60),
- singletonList("Maximum backoff must be greater than 300s (5 minutes)"));
- testCases.put(
- new RetryStrategy(RetryStrategy.RETRY_POLICY_LINEAR, 301, 300),
- singletonList("Maximum backoff must be greater than or equal to initial backoff"));
- testCases.put(
- new RetryStrategy(RetryStrategy.RETRY_POLICY_EXPONENTIAL, 301, 300),
- singletonList("Maximum backoff must be greater than or equal to initial backoff"));
-
- for (Entry> testCase : testCases.entrySet()) {
- List validationErrors = mValidator.validate(testCase.getKey());
- assertNotNull("Expected validation errors, but got null", validationErrors);
-
- for (String expected : testCase.getValue()) {
- assertTrue(
- "Expected validation errors to contain \"" + expected + "\"",
- validationErrors.contains(expected));
- }
- }
- }
-
- @Test
- public void testValidate_trigger() throws Exception {
- Map testCases = new HashMap<>();
-
- testCases.put(Trigger.NOW, null);
- testCases.put(Trigger.executionWindow(0, 100), null);
- ContentUriTrigger contentUriTrigger =
- Trigger.contentUriTrigger(
- Arrays.asList(
- new ObservedUri(
- ContactsContract.AUTHORITY_URI, Flags.FLAG_NOTIFY_FOR_DESCENDANTS)));
- testCases.put(contentUriTrigger, null);
-
- for (Entry testCase : testCases.entrySet()) {
- List validationErrors = mValidator.validate(testCase.getKey());
- if (testCase.getValue() == null) {
- assertNull("Expected no validation errors for trigger", validationErrors);
- } else {
- assertTrue(
- "Expected validation errors to contain \"" + testCase.getValue() + "\"",
- validationErrors.contains(testCase.getValue()));
- }
- }
- }
-}
diff --git a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/ExecutionDelegatorTest.java b/jobdispatcher/src/test/java/com/firebase/jobdispatcher/ExecutionDelegatorTest.java
deleted file mode 100644
index a523c4654..000000000
--- a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/ExecutionDelegatorTest.java
+++ /dev/null
@@ -1,224 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static com.firebase.jobdispatcher.TestUtil.getContentUriTrigger;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.support.annotation.NonNull;
-import com.firebase.jobdispatcher.JobService.JobResult;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-@SuppressWarnings("WrongConstant")
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, manifest = Config.NONE, sdk = 21)
-public class ExecutionDelegatorTest {
-
- private Context mMockContext;
- private TestJobReceiver mReceiver;
- private ExecutionDelegator mExecutionDelegator;
-
- @Before
- public void setUp() {
- mMockContext = spy(RuntimeEnvironment.application);
- doReturn("com.example.foo").when(mMockContext).getPackageName();
-
- mReceiver = new TestJobReceiver();
- mExecutionDelegator = new ExecutionDelegator(mMockContext, mReceiver);
- }
-
- @Test
- public void testExecuteJob_sendsBroadcastWithJobAndMessage() throws Exception {
- for (JobInvocation input : TestUtil.getJobInvocationCombinations()) {
- verifyExecuteJob(input);
- }
- }
-
- private void verifyExecuteJob(JobInvocation input) throws Exception {
- reset(mMockContext);
- mReceiver.lastResult = -1;
-
- mReceiver.setLatch(new CountDownLatch(1));
-
- mExecutionDelegator.executeJob(input);
-
- final ArgumentCaptor intentCaptor = ArgumentCaptor.forClass(Intent.class);
- final ArgumentCaptor connCaptor =
- ArgumentCaptor.forClass(ServiceConnection.class);
- verify(mMockContext).bindService(intentCaptor.capture(), connCaptor.capture(), anyInt());
-
- final Intent result = intentCaptor.getValue();
- // verify the intent was sent to the right place
- assertEquals(input.getService(), result.getComponent().getClassName());
- assertEquals(JobService.ACTION_EXECUTE, result.getAction());
-
- final ServiceConnection connection = connCaptor.getValue();
-
- ComponentName cname = mock(ComponentName.class);
- JobService.LocalBinder mockLocalBinder = mock(JobService.LocalBinder.class);
- final JobParameters[] out = new JobParameters[1];
-
- JobService mockJobService = new JobService() {
- @Override
- public boolean onStartJob(JobParameters job) {
- out[0] = job;
- return false;
- }
-
- @Override
- public boolean onStopJob(JobParameters job) {
- return false;
- }
- };
-
- when(mockLocalBinder.getService()).thenReturn(mockJobService);
-
- connection.onServiceConnected(cname, mockLocalBinder);
-
- TestUtil.assertJobsEqual(input, out[0]);
-
- // make sure the countdownlatch was decremented
- assertTrue(mReceiver.mLatch.await(1, TimeUnit.SECONDS));
-
- // verify the lastResult was set correctly
- assertEquals(JobService.RESULT_SUCCESS, mReceiver.lastResult);
- }
-
- @Test
- public void testExecuteJob_handlesNull() {
- assertFalse("Expected calling triggerExecution on null to fail and return false",
- mExecutionDelegator.executeJob(null));
- }
-
- @Test
- public void testHandleMessage_doesntCrashOnBadJobData() {
- JobInvocation j = new JobInvocation.Builder()
- .setService(TestJobService.class.getName())
- .setTag("tag")
- .setTrigger(Trigger.NOW)
- .build();
-
- mExecutionDelegator.executeJob(j);
-
- ArgumentCaptor intentCaptor =
- ArgumentCaptor.forClass(Intent.class);
- ArgumentCaptor connCaptor =
- ArgumentCaptor.forClass(ServiceConnection.class);
-
- //noinspection WrongConstant
- verify(mMockContext).bindService(intentCaptor.capture(), connCaptor.capture(), anyInt());
-
- Intent executeReq = intentCaptor.getValue();
- assertEquals(JobService.ACTION_EXECUTE, executeReq.getAction());
- }
-
- @Test
- public void onStop_mock() throws InterruptedException {
- JobInvocation job = new JobInvocation.Builder()
- .setTag("TAG")
- .setTrigger(getContentUriTrigger())
- .setService(TestJobService.class.getName())
- .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
- .build();
-
- reset(mMockContext);
- mReceiver.lastResult = -1;
-
- mExecutionDelegator.executeJob(job);
-
- final ArgumentCaptor intentCaptor = ArgumentCaptor.forClass(Intent.class);
- final ArgumentCaptor connCaptor =
- ArgumentCaptor.forClass(ServiceConnection.class);
- verify(mMockContext).bindService(intentCaptor.capture(), connCaptor.capture(), anyInt());
-
- final Intent result = intentCaptor.getValue();
- // verify the intent was sent to the right place
- assertEquals(job.getService(), result.getComponent().getClassName());
- assertEquals(JobService.ACTION_EXECUTE, result.getAction());
-
- final JobParameters[] out = new JobParameters[2];
-
- JobService mockJobService = new JobService() {
- @Override
- public boolean onStartJob(JobParameters job) {
- out[0] = job;
- return true;
- }
-
- @Override
- public boolean onStopJob(JobParameters job) {
- out[1] = job;
- return false;
- }
- };
-
- JobService.LocalBinder mockLocalBinder = mock(JobService.LocalBinder.class);
- when(mockLocalBinder.getService()).thenReturn(mockJobService);
-
- ComponentName componentName = mock(ComponentName.class);
- final ServiceConnection connection = connCaptor.getValue();
- connection.onServiceConnected(componentName, mockLocalBinder);
-
- mExecutionDelegator.stopJob(job);
-
- TestUtil.assertJobsEqual(job, out[0]);
- TestUtil.assertJobsEqual(job, out[1]);
- }
-
- private final static class TestJobReceiver implements ExecutionDelegator.JobFinishedCallback {
- int lastResult;
-
- private CountDownLatch mLatch;
-
- @Override
- public void onJobFinished(@NonNull JobInvocation js, @JobResult int result) {
- lastResult = result;
-
- if (mLatch != null) {
- mLatch.countDown();
- }
- }
-
- /**
- * Convenience method for tests.
- */
- public void setLatch(CountDownLatch latch) {
- mLatch = latch;
- }
- }
-}
diff --git a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/ExecutionWindowTriggerTest.java b/jobdispatcher/src/test/java/com/firebase/jobdispatcher/ExecutionWindowTriggerTest.java
deleted file mode 100644
index 6dfe85774..000000000
--- a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/ExecutionWindowTriggerTest.java
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, manifest = Config.NONE, sdk = 23)
-public class ExecutionWindowTriggerTest {
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
-
- @Test
- public void testNewInstance_withValidWindow() throws Exception {
- JobTrigger.ExecutionWindowTrigger trigger = Trigger.executionWindow(0, 60);
-
- assertEquals(0, trigger.getWindowStart());
- assertEquals(60, trigger.getWindowEnd());
- }
-
- @Test
- public void testNewInstance_withNegativeStart() throws Exception {
- expectedException.expect(IllegalArgumentException.class);
-
- Trigger.executionWindow(-10, 60);
- }
-
- @Test
- public void testNewInstance_withNegativeEnd() throws Exception {
- expectedException.expect(IllegalArgumentException.class);
-
- Trigger.executionWindow(0, -1);
- }
-
- @Test
- public void testNewInstance_withReversedValues() throws Exception {
- expectedException.expect(IllegalArgumentException.class);
-
- Trigger.executionWindow(60, 0);
- }
-
- @Test
- public void testNewInstance_withTooSmallWindow_now() throws Exception {
- expectedException.expect(IllegalArgumentException.class);
-
- Trigger.executionWindow(60, 59);
- }
-
- @Test
- public void testNewInstance_withTooSmallWindow_inFuture() throws Exception {
- expectedException.expect(IllegalArgumentException.class);
-
- Trigger.executionWindow(200, 100);
- }
-}
diff --git a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/ExtendedShadowParcel.java b/jobdispatcher/src/test/java/com/firebase/jobdispatcher/ExtendedShadowParcel.java
deleted file mode 100644
index e5ecf1042..000000000
--- a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/ExtendedShadowParcel.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.firebase.jobdispatcher;
-
-import android.os.IBinder;
-import android.os.Parcel;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-import org.robolectric.annotation.RealObject;
-import org.robolectric.shadows.ShadowParcel;
-
-/**
- * ShadowParcel doesn't correctly handle {@link Parcel#writeStrongBinder(IBinder)} or {@link
- * Parcel#readStrongBinder()}, so we shim a simple implementation that uses an in-memory map to read
- * and write Binder objects.
- */
-@Implements(Parcel.class)
-public class ExtendedShadowParcel extends ShadowParcel {
- @RealObject private Parcel realObject;
-
- // Map each IBinder to an integer, and use the super's int-writing capability to fake Binder
- // read/writes.
- private final AtomicInteger nextBinderId = new AtomicInteger(1);
- private final Map binderMap =
- Collections.synchronizedMap(new HashMap());
-
- @Implementation
- public void writeStrongBinder(IBinder binder) {
- int id = nextBinderId.getAndIncrement();
- binderMap.put(id, binder);
- realObject.writeInt(id);
- }
-
- @Implementation
- public IBinder readStrongBinder() {
- return binderMap.get(realObject.readInt());
- }
-}
diff --git a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/FirebaseJobDispatcherTest.java b/jobdispatcher/src/test/java/com/firebase/jobdispatcher/FirebaseJobDispatcherTest.java
deleted file mode 100644
index dd0b22ee6..000000000
--- a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/FirebaseJobDispatcherTest.java
+++ /dev/null
@@ -1,205 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import com.firebase.jobdispatcher.FirebaseJobDispatcher.ScheduleFailedException;
-import java.util.Arrays;
-import java.util.List;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, manifest = Config.NONE, sdk = 23)
-public class FirebaseJobDispatcherTest {
-
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
-
- @Mock
- private Driver mDriver;
-
- @Mock
- private JobValidator mValidator;
-
- private FirebaseJobDispatcher mDispatcher;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- when(mDriver.getValidator()).thenReturn(mValidator);
-
- mDispatcher = new FirebaseJobDispatcher(mDriver);
- setDriverAvailability(true);
- }
-
- @Test
- public void testSchedule_passThrough() throws Exception {
- final int[] possibleResults = {
- FirebaseJobDispatcher.SCHEDULE_RESULT_SUCCESS,
- FirebaseJobDispatcher.SCHEDULE_RESULT_NO_DRIVER_AVAILABLE,
- FirebaseJobDispatcher.SCHEDULE_RESULT_BAD_SERVICE,
- FirebaseJobDispatcher.SCHEDULE_RESULT_UNKNOWN_ERROR,
- FirebaseJobDispatcher.SCHEDULE_RESULT_UNSUPPORTED_TRIGGER};
-
- for (int result : possibleResults) {
- when(mDriver.schedule(null)).thenReturn(result);
- assertEquals(result, mDispatcher.schedule(null));
- }
-
- verify(mDriver, times(possibleResults.length)).schedule(null);
- }
-
- @Test
- public void testSchedule_unavailable() throws Exception {
- setDriverAvailability(false);
- assertEquals(
- FirebaseJobDispatcher.SCHEDULE_RESULT_NO_DRIVER_AVAILABLE,
- mDispatcher.schedule(null));
- verify(mDriver, never()).schedule(null);
- }
-
- @Test
- public void testCancelJob() throws Exception {
- final String tag = "foo";
-
- // simulate success
- when(mDriver.cancel(tag))
- .thenReturn(FirebaseJobDispatcher.CANCEL_RESULT_SUCCESS);
-
- assertEquals(
- "Expected dispatcher to pass the result of Driver#cancel(String, Class) through",
- FirebaseJobDispatcher.CANCEL_RESULT_SUCCESS,
- mDispatcher.cancel(tag));
-
- // verify the driver was indeed called
- verify(mDriver).cancel(tag);
- }
-
- @Test
- public void testCancelJob_unavailable() throws Exception {
- setDriverAvailability(false); // driver is unavailable
-
- assertEquals(
- FirebaseJobDispatcher.CANCEL_RESULT_NO_DRIVER_AVAILABLE,
- mDispatcher.cancel("foo"));
-
- // verify the driver was never even consulted
- verify(mDriver, never()).cancel("foo");
- }
-
- @Test
- public void testCancelAllJobs() throws Exception {
- when(mDriver.cancelAll()).thenReturn(FirebaseJobDispatcher.CANCEL_RESULT_SUCCESS);
-
- assertEquals(FirebaseJobDispatcher.CANCEL_RESULT_SUCCESS, mDispatcher.cancelAll());
- verify(mDriver).cancelAll();
- }
-
- @Test
- public void testCancelAllJobs_unavailable() throws Exception {
- setDriverAvailability(false); // driver is unavailable
-
- assertEquals(
- FirebaseJobDispatcher.CANCEL_RESULT_NO_DRIVER_AVAILABLE,
- mDispatcher.cancelAll());
-
- verify(mDriver, never()).cancelAll();
- }
-
- @Test
- public void testMustSchedule_success() throws Exception {
- when(mDriver.schedule(null)).thenReturn(FirebaseJobDispatcher.SCHEDULE_RESULT_SUCCESS);
-
- /* assert no exception is thrown */
- mDispatcher.mustSchedule(null);
- }
-
- @Test
- public void testMustSchedule_unavailable() throws Exception {
- setDriverAvailability(false); // driver is unavailable
- expectedException.expect(FirebaseJobDispatcher.ScheduleFailedException.class);
-
- mDispatcher.mustSchedule(null);
- }
-
- @Test
- public void testMustSchedule_failure() throws Exception {
- final int[] possibleErrors = {
- FirebaseJobDispatcher.SCHEDULE_RESULT_NO_DRIVER_AVAILABLE,
- FirebaseJobDispatcher.SCHEDULE_RESULT_BAD_SERVICE,
- FirebaseJobDispatcher.SCHEDULE_RESULT_UNKNOWN_ERROR,
- FirebaseJobDispatcher.SCHEDULE_RESULT_UNSUPPORTED_TRIGGER};
-
- for (int scheduleError : possibleErrors) {
- when(mDriver.schedule(null)).thenReturn(scheduleError);
-
- try {
- mDispatcher.mustSchedule(null);
-
- fail("Expected mustSchedule() with error code " + scheduleError + " to fail");
- } catch (ScheduleFailedException expected) { /* expected */ }
- }
-
- verify(mDriver, times(possibleErrors.length)).schedule(null);
- }
-
- @Test
- public void testNewRetryStrategyBuilder() {
- // custom validator that only approves strategies where initialbackoff == 30s
- when(mValidator.validate(any(RetryStrategy.class))).thenAnswer(new Answer>() {
- @Override
- public List answer(InvocationOnMock invocation) throws Throwable {
- RetryStrategy rs = (RetryStrategy) invocation.getArguments()[0];
- // only succeed if initialBackoff == 30s
- return rs.getInitialBackoff() == 30 ? null : Arrays.asList("foo", "bar");
- }
- });
-
- try {
- mDispatcher.newRetryStrategy(RetryStrategy.RETRY_POLICY_EXPONENTIAL, 0, 30);
- fail("Expected initial backoff != 30s to fail using custom validator");
- } catch (Exception unused) { /* unused */ }
-
- try {
- mDispatcher.newRetryStrategy(RetryStrategy.RETRY_POLICY_EXPONENTIAL, 30, 30);
- } catch (Exception unused) {
- fail("Expected initial backoff == 30s not to fail using custom validator");
- }
- }
-
- public void setDriverAvailability(boolean driverAvailability) {
- when(mDriver.isAvailable()).thenReturn(driverAvailability);
- }
-}
diff --git a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/GooglePlayCallbackExtractorTest.java b/jobdispatcher/src/test/java/com/firebase/jobdispatcher/GooglePlayCallbackExtractorTest.java
deleted file mode 100644
index f65918501..000000000
--- a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/GooglePlayCallbackExtractorTest.java
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.Pair;
-import com.firebase.jobdispatcher.TestUtil.InspectableBinder;
-import com.firebase.jobdispatcher.TestUtil.TransactionArguments;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(
- constants = BuildConfig.class,
- manifest = Config.NONE,
- sdk = 23,
- shadows = {ExtendedShadowParcel.class}
-)
-public final class GooglePlayCallbackExtractorTest {
- @Mock
- private IBinder mBinder;
-
- private GooglePlayCallbackExtractor mExtractor;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- mExtractor = new GooglePlayCallbackExtractor();
- }
-
- @Test
- public void testExtractCallback_nullBundle() {
- assertNull(mExtractor.extractCallback(null));
- }
-
- @Test
- public void testExtractCallback_nullParcelable() {
- Bundle emptyBundle = new Bundle();
- assertNull(extractCallback(emptyBundle));
- }
-
- @Test
- public void testExtractCallback_badParcelable() {
- Bundle misconfiguredBundle = new Bundle();
- misconfiguredBundle.putParcelable("callback", new BadParcelable(1));
-
- assertNull(extractCallback(misconfiguredBundle));
- }
-
- @Test
- public void testExtractCallback_goodParcelable() {
- InspectableBinder binder = new InspectableBinder();
- Bundle validBundle = new Bundle();
- validBundle.putParcelable("callback", binder.toPendingCallback());
-
- Pair extraction = extractCallback(validBundle);
- assertNotNull(extraction);
- assertEquals("should have stripped the 'callback' entry from the extracted bundle",
- 0, extraction.second.keySet().size());
- extraction.first.jobFinished(JobService.RESULT_SUCCESS);
-
- // Check our homemade Binder is doing the right things:
- TransactionArguments args = binder.getArguments().get(0);
- // Should have set the transaction code:
- assertEquals("transaction code", IBinder.FIRST_CALL_TRANSACTION + 1, args.code);
-
- // strong mode bit
- args.data.readInt();
- // interface token
- assertEquals("com.google.android.gms.gcm.INetworkTaskCallback", args.data.readString());
- // result
- assertEquals("result", JobService.RESULT_SUCCESS, args.data.readInt());
- }
-
- @Test
- public void testExtractCallback_extraMapValues() {
- Bundle validBundle = new Bundle();
- validBundle.putString("foo", "bar");
- validBundle.putInt("bar", 3);
- validBundle.putParcelable("parcelable", new Bundle());
- validBundle.putParcelable("callback", new InspectableBinder().toPendingCallback());
-
- Pair extraction = extractCallback(validBundle);
- assertNotNull(extraction);
- assertEquals("should have stripped the 'callback' entry from the extracted bundle",
- 3, extraction.second.keySet().size());
- }
-
- private Pair extractCallback(Bundle bundle) {
- return mExtractor.extractCallback(bundle);
- }
-
- private static final class BadParcelable implements Parcelable {
- public static final Parcelable.Creator CREATOR
- = new Parcelable.Creator() {
- @Override
- public BadParcelable createFromParcel(Parcel in) {
- return new BadParcelable(in);
- }
-
- @Override
- public BadParcelable[] newArray(int size) {
- return new BadParcelable[size];
- }
- };
- private final int mNum;
-
- public BadParcelable(int i) {
- mNum = i;
- }
-
- private BadParcelable(Parcel in) {
- mNum = in.readInt();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dst, int flags) {
- dst.writeInt(mNum);
- }
- }
-}
diff --git a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/GooglePlayDriverTest.java b/jobdispatcher/src/test/java/com/firebase/jobdispatcher/GooglePlayDriverTest.java
deleted file mode 100644
index 822a8f1d6..000000000
--- a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/GooglePlayDriverTest.java
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.os.Parcelable;
-import android.support.annotation.NonNull;
-import android.text.TextUtils;
-import java.util.Arrays;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, manifest = Config.NONE, sdk = 23)
-public class GooglePlayDriverTest {
- @Mock
- public Context mMockContext;
-
- private TestJobDriver mDriver;
- private FirebaseJobDispatcher mDispatcher;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- mDriver = new TestJobDriver(new GooglePlayDriver(mMockContext));
- mDispatcher = new FirebaseJobDispatcher(mDriver);
-
- when(mMockContext.getPackageName()).thenReturn("foo.bar.whatever");
- }
-
- @Test
- public void testSchedule_failsWhenPlayServicesIsUnavailable() throws Exception {
- markBackendUnavailable();
- mockPackageManagerInfo();
-
- Job job = null;
- try {
- job = mDispatcher.newJobBuilder()
- .setService(TestJobService.class)
- .setTag("foobar")
- .setConstraints(Constraint.DEVICE_CHARGING)
- .setTrigger(Trigger.executionWindow(0, 60))
- .build();
- } catch (ValidationEnforcer.ValidationException ve) {
- fail(TextUtils.join("\n", ve.getErrors()));
- }
-
- assertEquals("Expected schedule() request to fail when backend is unavailable",
- FirebaseJobDispatcher.SCHEDULE_RESULT_NO_DRIVER_AVAILABLE,
- mDispatcher.schedule(job));
- }
-
- @Test
- public void testCancelJobs_backendUnavailable() throws Exception {
- markBackendUnavailable();
-
- assertEquals("Expected cancelAll() request to fail when backend is unavailable",
- FirebaseJobDispatcher.CANCEL_RESULT_NO_DRIVER_AVAILABLE,
- mDispatcher.cancelAll());
- }
-
- @Test
- public void testSchedule_sendsAppropriateBroadcast() {
- ArgumentCaptor pmQueryIntentCaptor = mockPackageManagerInfo();
-
- Job job = mDispatcher.newJobBuilder()
- .setConstraints(Constraint.DEVICE_CHARGING)
- .setService(TestJobService.class)
- .setTrigger(Trigger.executionWindow(0, 60))
- .setRecurring(false)
- .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
- .setTag("foobar")
- .build();
-
- Intent pmQueryIntent = pmQueryIntentCaptor.getValue();
- assertEquals(JobService.ACTION_EXECUTE, pmQueryIntent.getAction());
- assertEquals(TestJobService.class.getName(), pmQueryIntent.getComponent().getClassName());
-
- assertEquals("Expected schedule() request to succeed",
- FirebaseJobDispatcher.SCHEDULE_RESULT_SUCCESS,
- mDispatcher.schedule(job));
-
- final ArgumentCaptor captor = ArgumentCaptor.forClass(Intent.class);
- verify(mMockContext).sendBroadcast(captor.capture());
-
- Intent broadcast = captor.getValue();
-
- assertNotNull(broadcast);
- assertEquals("com.google.android.gms.gcm.ACTION_SCHEDULE", broadcast.getAction());
- assertEquals("SCHEDULE_TASK", broadcast.getStringExtra("scheduler_action"));
- assertEquals("com.google.android.gms", broadcast.getPackage());
- assertEquals(8, broadcast.getIntExtra("source", -1));
- assertEquals(1, broadcast.getIntExtra("source_version", -1));
-
- final Parcelable parcelablePendingIntent = broadcast.getParcelableExtra("app");
- assertTrue("Expected 'app' value to be a PendingIntent",
- parcelablePendingIntent instanceof PendingIntent);
- }
-
- private ArgumentCaptor mockPackageManagerInfo() {
- PackageManager packageManager = mock(PackageManager.class);
- when(mMockContext.getPackageManager()).thenReturn(packageManager);
- ArgumentCaptor intentArgCaptor = ArgumentCaptor.forClass(Intent.class);
-
- ResolveInfo info = new ResolveInfo();
- info.serviceInfo = new ServiceInfo();
- info.serviceInfo.enabled = true;
-
- //noinspection WrongConstant
- when(packageManager.queryIntentServices(intentArgCaptor.capture(), eq(0)))
- .thenReturn(Arrays.asList(info));
-
- return intentArgCaptor;
- }
-
- @Test
- public void testCancel_sendsAppropriateBroadcast() {
- mDispatcher.cancel("foobar");
-
- ArgumentCaptor captor = ArgumentCaptor.forClass(Intent.class);
- verify(mMockContext).sendBroadcast(captor.capture());
-
- Intent broadcast = captor.getValue();
-
- assertNotNull(broadcast);
- assertEquals("foobar", broadcast.getStringExtra("tag"));
- }
-
- private void markBackendUnavailable() {
- mDriver.available = false;
- }
-
- public final static class TestJobDriver implements Driver {
- public boolean available = true;
-
- private final Driver wrappedDriver;
-
- public TestJobDriver(Driver wrappedDriver) {
- this.wrappedDriver = wrappedDriver;
- }
-
- @Override
- public int schedule(@NonNull Job job) {
- return this.wrappedDriver.schedule(job);
- }
-
- @Override
- public int cancel(@NonNull String tag) {
- return this.wrappedDriver.cancel(tag);
- }
-
- @Override
- public int cancelAll() {
- return this.wrappedDriver.cancelAll();
- }
-
- @NonNull
- @Override
- public JobValidator getValidator() {
- return this.wrappedDriver.getValidator();
- }
-
- @Override
- public boolean isAvailable() {
- return available;
- }
- }
-}
diff --git a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/GooglePlayJobWriterTest.java b/jobdispatcher/src/test/java/com/firebase/jobdispatcher/GooglePlayJobWriterTest.java
deleted file mode 100644
index c56ab0d08..000000000
--- a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/GooglePlayJobWriterTest.java
+++ /dev/null
@@ -1,268 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.ContactsContract;
-import com.firebase.jobdispatcher.Job.Builder;
-import com.firebase.jobdispatcher.JobTrigger.ContentUriTrigger;
-import com.firebase.jobdispatcher.ObservedUri.Flags;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, manifest = Config.NONE, sdk = 23)
-public class GooglePlayJobWriterTest {
-
- private static final boolean[] ALL_BOOLEANS = {true, false};
-
- private GooglePlayJobWriter mWriter;
-
- private static Builder initializeDefaultBuilder() {
- return TestUtil.getBuilderWithNoopValidator()
- .setConstraints(Constraint.DEVICE_CHARGING)
- .setExtras(null)
- .setLifetime(Lifetime.FOREVER)
- .setRecurring(false)
- .setReplaceCurrent(false)
- .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
- .setService(TestJobService.class)
- .setTag("tag")
- .setTrigger(Trigger.NOW);
- }
-
- @Before
- public void setUp() throws Exception {
- mWriter = new GooglePlayJobWriter();
- }
-
- @Test
- public void testWriteToBundle_tags() {
- for (String tag : Arrays.asList("foo", "bar", "foobar", "this is a tag")) {
- Bundle b = mWriter.writeToBundle(
- initializeDefaultBuilder().setTag(tag).build(),
- new Bundle());
-
- assertEquals("tag", tag, b.getString("tag"));
- }
- }
-
- @Test
- public void testWriteToBundle_updateCurrent() {
- for (boolean replaceCurrent : ALL_BOOLEANS) {
- Bundle b = mWriter.writeToBundle(
- initializeDefaultBuilder().setReplaceCurrent(replaceCurrent).build(),
- new Bundle());
-
- assertEquals("update_current", replaceCurrent, b.getBoolean("update_current"));
- }
- }
-
- @Test
- public void testWriteToBundle_persisted() {
- Bundle b = mWriter.writeToBundle(
- initializeDefaultBuilder().setLifetime(Lifetime.FOREVER).build(),
- new Bundle());
-
- assertTrue("persisted", b.getBoolean("persisted"));
-
- for (int lifetime : new int[]{Lifetime.UNTIL_NEXT_BOOT}) {
- b = mWriter.writeToBundle(
- initializeDefaultBuilder().setLifetime(lifetime).build(),
- new Bundle());
-
- assertFalse("persisted", b.getBoolean("persisted"));
- }
- }
-
- @Test
- public void testWriteToBundle_service() {
- Bundle b = mWriter.writeToBundle(
- initializeDefaultBuilder().setService(TestJobService.class).build(),
- new Bundle());
-
- assertEquals("service", GooglePlayReceiver.class.getName(), b.getString("service"));
- }
-
- @Test
- public void testWriteToBundle_requiredNetwork() {
- Map mapping = new HashMap<>();
- mapping.put(Constraint.ON_ANY_NETWORK, GooglePlayJobWriter.LEGACY_NETWORK_CONNECTED);
- mapping.put(Constraint.ON_UNMETERED_NETWORK, GooglePlayJobWriter.LEGACY_NETWORK_UNMETERED);
- mapping.put(0, GooglePlayJobWriter.LEGACY_NETWORK_ANY);
-
- for (Entry testCase : mapping.entrySet()) {
- @SuppressWarnings("WrongConstant")
- Bundle b = mWriter.writeToBundle(
- initializeDefaultBuilder().setConstraints(testCase.getKey()).build(),
- new Bundle());
-
- assertEquals("requiredNetwork", (int) testCase.getValue(), b.getInt("requiredNetwork"));
- }
- }
-
- @Test
- public void testWriteToBundle_unmeteredConstraintShouldTakePrecendence() {
- Bundle b = mWriter.writeToBundle(
- initializeDefaultBuilder()
- .setConstraints(Constraint.ON_ANY_NETWORK, Constraint.ON_UNMETERED_NETWORK)
- .build(),
- new Bundle());
-
- assertEquals("expected ON_UNMETERED_NETWORK to take precendence over ON_ANY_NETWORK",
- GooglePlayJobWriter.LEGACY_NETWORK_UNMETERED, b.getInt("requiredNetwork"));
- }
-
- @Test
- public void testWriteToBundle_requiresCharging() {
- assertTrue("requiresCharging", mWriter.writeToBundle(
- initializeDefaultBuilder().setConstraints(Constraint.DEVICE_CHARGING).build(),
- new Bundle()).getBoolean("requiresCharging"));
-
- for (Integer constraint : Arrays.asList(
- Constraint.ON_ANY_NETWORK,
- Constraint.ON_UNMETERED_NETWORK)) {
-
- assertFalse("requiresCharging", mWriter.writeToBundle(
- initializeDefaultBuilder().setConstraints(constraint).build(),
- new Bundle()).getBoolean("requiresCharging"));
- }
- }
-
- @Test
- public void testWriteToBundle_requiresIdle() {
- assertTrue("requiresIdle", mWriter.writeToBundle(
- initializeDefaultBuilder().setConstraints(Constraint.DEVICE_IDLE).build(),
- new Bundle()).getBoolean("requiresIdle"));
-
- for (Integer constraint : Arrays.asList(
- Constraint.ON_ANY_NETWORK,
- Constraint.ON_UNMETERED_NETWORK)) {
-
- assertFalse("requiresIdle", mWriter.writeToBundle(
- initializeDefaultBuilder().setConstraints(constraint).build(),
- new Bundle()).getBoolean("requiresIdle"));
- }
- }
-
- @Test
- public void testWriteToBundle_retryPolicy() {
- assertEquals("retry_policy",
- GooglePlayJobWriter.LEGACY_RETRY_POLICY_EXPONENTIAL,
- mWriter.writeToBundle(
- initializeDefaultBuilder()
- .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
- .build(),
- new Bundle()).getBundle("retryStrategy").getInt("retry_policy"));
-
- assertEquals("retry_policy",
- GooglePlayJobWriter.LEGACY_RETRY_POLICY_LINEAR,
- mWriter.writeToBundle(
- initializeDefaultBuilder()
- .setRetryStrategy(RetryStrategy.DEFAULT_LINEAR)
- .build(),
- new Bundle()).getBundle("retryStrategy").getInt("retry_policy"));
- }
-
- @Test
- public void testWriteToBundle_backoffSeconds() {
- for (RetryStrategy retryStrategy : Arrays
- .asList(RetryStrategy.DEFAULT_EXPONENTIAL, RetryStrategy.DEFAULT_LINEAR)) {
-
- Bundle b = mWriter.writeToBundle(
- initializeDefaultBuilder().setRetryStrategy(retryStrategy).build(),
- new Bundle()).getBundle("retryStrategy");
-
- assertEquals("initial_backoff_seconds",
- retryStrategy.getInitialBackoff(),
- b.getInt("initial_backoff_seconds"));
-
- assertEquals("maximum_backoff_seconds",
- retryStrategy.getMaximumBackoff(),
- b.getInt("maximum_backoff_seconds"));
-
- }
- }
-
- @Test
- public void testWriteToBundle_triggers() {
- // immediate
- Bundle b = mWriter.writeToBundle(
- initializeDefaultBuilder().setTrigger(Trigger.NOW).build(),
- new Bundle());
-
- assertEquals("window_start", 0, b.getLong("window_start"));
- assertEquals("window_end", 30, b.getLong("window_end"));
-
- // execution window (oneoff)
- JobTrigger.ExecutionWindowTrigger t = Trigger.executionWindow(631, 978);
- b = mWriter.writeToBundle(
- initializeDefaultBuilder().setTrigger(t).build(),
- new Bundle());
-
- assertEquals("window_start", t.getWindowStart(), b.getLong("window_start"));
- assertEquals("window_end", t.getWindowEnd(), b.getLong("window_end"));
-
- // execution window (periodic)
- b = mWriter.writeToBundle(
- initializeDefaultBuilder().setRecurring(true).setTrigger(t).build(),
- new Bundle());
-
- assertEquals("period", t.getWindowEnd(), b.getLong("period"));
- assertEquals("period_flex", t.getWindowEnd() - t.getWindowStart(), b.getLong("period_flex"));
- }
-
- @Test
- public void testWriteToBundle_contentUriTrigger() {
- ObservedUri observedUri = new ObservedUri(ContactsContract.AUTHORITY_URI,
- Flags.FLAG_NOTIFY_FOR_DESCENDANTS);
- ContentUriTrigger contentUriTrigger = Trigger.contentUriTrigger(Arrays.asList(observedUri));
- Bundle bundle = mWriter.writeToBundle(
- initializeDefaultBuilder().setTrigger(contentUriTrigger).build(), new Bundle());
- Uri[] uris =
- (Uri[]) bundle.getParcelableArray(BundleProtocol.PACKED_PARAM_CONTENT_URI_ARRAY);
- int[] flags = bundle.getIntArray(BundleProtocol.PACKED_PARAM_CONTENT_URI_FLAGS_ARRAY);
- assertTrue("Array size", uris.length == flags.length && flags.length == 1);
- assertEquals(BundleProtocol.PACKED_PARAM_CONTENT_URI_ARRAY,
- ContactsContract.AUTHORITY_URI, uris[0]);
- assertEquals(BundleProtocol.PACKED_PARAM_CONTENT_URI_FLAGS_ARRAY,
- Flags.FLAG_NOTIFY_FOR_DESCENDANTS, flags[0]);
- }
-
- @Test
- public void testWriteToBundle_extras() {
- Bundle extras = new Bundle();
-
- Bundle result = mWriter.writeToBundle(
- initializeDefaultBuilder().setExtras(extras).build(),
- new Bundle());
-
- assertEquals("extras", extras, result.getBundle("extras"));
- }
-}
diff --git a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/GooglePlayMessageHandlerTest.java b/jobdispatcher/src/test/java/com/firebase/jobdispatcher/GooglePlayMessageHandlerTest.java
deleted file mode 100644
index 31969a16e..000000000
--- a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/GooglePlayMessageHandlerTest.java
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static com.firebase.jobdispatcher.GooglePlayJobWriter.REQUEST_PARAM_TAG;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.AppOpsManager;
-import android.content.Context;
-import android.os.Bundle;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
-import com.firebase.jobdispatcher.JobInvocation.Builder;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-/**
- * Tests {@link GooglePlayMessageHandler}.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, manifest = Config.NONE, sdk = 21)
-public class GooglePlayMessageHandlerTest {
-
- @Mock
- Looper looper;
- @Mock
- GooglePlayReceiver receiverMock;
- @Mock
- Context context;
- @Mock
- AppOpsManager appOpsManager;
- @Mock
- Messenger messengerMock;
- @Mock
- ExecutionDelegator executionDelegatorMock;
-
- GooglePlayMessageHandler handler;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- handler = new GooglePlayMessageHandler(looper, receiverMock);
- when(receiverMock.getExecutionDelegator()).thenReturn(executionDelegatorMock);
- when(receiverMock.getApplicationContext()).thenReturn(context);
- when(context.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(appOpsManager);
- }
-
- @Test
- public void handleMessage_nullNoException() throws Exception {
- handler.handleMessage(null);
- }
-
- @Test
- public void handleMessage_ignoreIfSenderIsNotGcm() throws Exception {
- Message message = Message.obtain();
- message.what = GooglePlayMessageHandler.MSG_START_EXEC;
- Bundle data = new Bundle();
- data.putString(REQUEST_PARAM_TAG, "TAG");
- message.setData(data);
- message.replyTo = messengerMock;
- doThrow(new SecurityException()).when(appOpsManager)
- .checkPackage(message.sendingUid, GooglePlayDriver.BACKEND_PACKAGE);
- handler.handleMessage(message);
- verify(receiverMock, never()).prepareJob(any(GooglePlayMessengerCallback.class), eq(data));
- }
-
- @Test
- public void handleMessage_startExecution_noData() throws Exception {
- Message message = Message.obtain();
- message.what = GooglePlayMessageHandler.MSG_START_EXEC;
- message.replyTo = messengerMock;
-
- handler.handleMessage(message);
- verify(receiverMock, never())
- .prepareJob(any(GooglePlayMessengerCallback.class), any(Bundle.class));
- }
-
- @Test
- public void handleMessage_startExecution() throws Exception {
- Message message = Message.obtain();
- message.what = GooglePlayMessageHandler.MSG_START_EXEC;
- Bundle data = new Bundle();
- data.putString(REQUEST_PARAM_TAG, "TAG");
- message.setData(data);
- message.replyTo = messengerMock;
- JobInvocation jobInvocation = new Builder()
- .setTag("tag")
- .setService(TestJobService.class.getName())
- .setTrigger(Trigger.NOW).build();
- when(receiverMock.prepareJob(any(GooglePlayMessengerCallback.class), eq(data)))
- .thenReturn(jobInvocation);
-
- handler.handleMessage(message);
-
- verify(executionDelegatorMock).executeJob(jobInvocation);
- }
-
- @Test
- public void handleMessage_stopExecution() throws Exception {
- Message message = Message.obtain();
- message.what = GooglePlayMessageHandler.MSG_STOP_EXEC;
- JobCoder jobCoder = GooglePlayReceiver.getJobCoder();
- Bundle data = TestUtil.encodeContentUriJob(TestUtil.getContentUriTrigger(), jobCoder);
- JobInvocation jobInvocation = jobCoder.decode(data).build();
- message.setData(data);
- message.replyTo = messengerMock;
-
- handler.handleMessage(message);
-
- final ArgumentCaptor captor = ArgumentCaptor.forClass(JobInvocation.class);
-
- verify(executionDelegatorMock).stopJob(captor.capture());
-
- TestUtil.assertJobsEqual(jobInvocation, captor.getValue());
- }
-
- @Test
- public void handleMessage_stopExecution_invalidNoCrash() throws Exception {
- Message message = Message.obtain();
- message.what = GooglePlayMessageHandler.MSG_STOP_EXEC;
- message.replyTo = messengerMock;
-
- handler.handleMessage(message);
-
- verify(executionDelegatorMock, never()).stopJob(any(JobInvocation.class));
- }
-}
diff --git a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/GooglePlayMessengerCallbackTest.java b/jobdispatcher/src/test/java/com/firebase/jobdispatcher/GooglePlayMessengerCallbackTest.java
deleted file mode 100644
index b71cf003a..000000000
--- a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/GooglePlayMessengerCallbackTest.java
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static com.firebase.jobdispatcher.GooglePlayJobWriter.REQUEST_PARAM_TAG;
-import static org.junit.Assert.assertEquals;
-
-import android.os.Message;
-import android.os.Messenger;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-/**
- * Tests {@link GooglePlayMessengerCallback}.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, manifest = Config.NONE, sdk = 21)
-public class GooglePlayMessengerCallbackTest {
-
- @Mock
- Messenger messengerMock;
- GooglePlayMessengerCallback callback;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- callback = new GooglePlayMessengerCallback(messengerMock, "tag");
- }
-
- @Test
- public void jobFinished() throws Exception {
- final ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class);
-
- callback.jobFinished(JobService.RESULT_SUCCESS);
-
- Mockito.verify(messengerMock).send(messageCaptor.capture());
- Message message = messageCaptor.getValue();
- assertEquals(message.what, GooglePlayMessageHandler.MSG_RESULT);
- assertEquals(message.arg1, JobService.RESULT_SUCCESS);
- assertEquals(message.getData().getString(REQUEST_PARAM_TAG), "tag");
- }
-}
diff --git a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/GooglePlayReceiverTest.java b/jobdispatcher/src/test/java/com/firebase/jobdispatcher/GooglePlayReceiverTest.java
deleted file mode 100644
index 47d7da573..000000000
--- a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/GooglePlayReceiverTest.java
+++ /dev/null
@@ -1,327 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static com.firebase.jobdispatcher.TestUtil.encodeContentUriJob;
-import static com.firebase.jobdispatcher.TestUtil.encodeRecurringContentUriJob;
-import static com.firebase.jobdispatcher.TestUtil.getContentUriTrigger;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNull;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-import android.app.Service;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.Build.VERSION_CODES;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Messenger;
-import android.os.Parcel;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.Contacts;
-import android.provider.MediaStore.Images.Media;
-import android.support.annotation.NonNull;
-import com.firebase.jobdispatcher.GooglePlayReceiverTest.ShadowMessenger;
-import com.firebase.jobdispatcher.JobInvocation.Builder;
-import com.firebase.jobdispatcher.TestUtil.InspectableBinder;
-import com.google.android.gms.gcm.PendingCallback;
-import java.util.ArrayList;
-import java.util.Arrays;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-import org.robolectric.annotation.Implements;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(
- constants = BuildConfig.class,
- manifest = Config.NONE,
- sdk = 21,
- shadows = {ShadowMessenger.class}
-)
-public class GooglePlayReceiverTest {
-
- /**
- * The default ShadowMessenger implementation causes NPEs when using the
- * {@link Messenger#Messenger(Handler)} constructor. We create our own empty Shadow so we can
- * just use the standard Android implementation, which is totally fine.
- *
- * @see Robolectric issue
- *
- */
- @Implements(Messenger.class)
- public static class ShadowMessenger {}
-
- GooglePlayReceiver receiver;
-
- JobCoder jobCoder = new JobCoder(BundleProtocol.PACKED_PARAM_BUNDLE_PREFIX, true);
-
- @Mock
- Messenger messengerMock;
- @Mock
- IBinder binderMock;
- @Mock
- JobCallback callbackMock;
- @Mock
- ExecutionDelegator executionDelegatorMock;
- @Mock
- Driver driverMock;
- @Captor
- ArgumentCaptor jobArgumentCaptor;
-
- ArrayList triggeredUris = new ArrayList<>();
-
- {
- triggeredUris.add(ContactsContract.AUTHORITY_URI);
- triggeredUris.add(Media.EXTERNAL_CONTENT_URI);
- }
-
- Builder jobInvocationBuilder = new Builder()
- .setTag("tag")
- .setService(TestJobService.class.getName())
- .setTrigger(Trigger.NOW);
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- receiver = spy(new GooglePlayReceiver());
- when(receiver.getExecutionDelegator()).thenReturn(executionDelegatorMock);
- receiver.driver = driverMock;
- receiver.validationEnforcer = new ValidationEnforcer(new NoopJobValidator());
- }
-
- @Test
- public void onJobFinished_unknownJobCallbackIsNotPresent_ignoreNoException() {
- receiver.onJobFinished(jobInvocationBuilder.build(), JobService.RESULT_SUCCESS);
-
- verifyZeroInteractions(driverMock);
- }
-
- @Test
- public void onJobFinished_notRecurringContentJob_sendResult() {
- jobInvocationBuilder.setTrigger(
- Trigger.contentUriTrigger(Arrays.asList(new ObservedUri(Contacts.CONTENT_URI, 0))));
-
- JobInvocation jobInvocation = receiver
- .prepareJob(callbackMock, getBundleForContentJobExecution());
-
- receiver.onJobFinished(jobInvocation, JobService.RESULT_SUCCESS);
- verify(callbackMock).jobFinished(JobService.RESULT_SUCCESS);
- verifyZeroInteractions(driverMock);
- }
-
- @Test
- public void onJobFinished_successRecurringContentJob_reschedule() {
- JobInvocation jobInvocation = receiver
- .prepareJob(callbackMock, getBundleForContentJobExecutionRecurring());
-
- receiver.onJobFinished(jobInvocation, JobService.RESULT_SUCCESS);
-
- verify(driverMock).schedule(jobArgumentCaptor.capture());
-
- // No need to callback when job finished.
- // Reschedule request is treated as two events: completion of old job and scheduling of new
- // job with the same parameters.
- verifyZeroInteractions(callbackMock);
-
- Job rescheduledJob = jobArgumentCaptor.getValue();
- TestUtil.assertJobsEqual(jobInvocation, rescheduledJob);
- }
-
- @Test
- public void onJobFinished_failWithRetryRecurringContentJob_sendResult() {
- JobInvocation jobInvocation = receiver
- .prepareJob(callbackMock, getBundleForContentJobExecutionRecurring());
-
- receiver.onJobFinished(jobInvocation, JobService.RESULT_FAIL_RETRY);
-
- // If a job finishes with RESULT_FAIL_RETRY we don't need to send a reschedule request.
- // Rescheduling will erase previously triggered URIs.
- verify(callbackMock).jobFinished(JobService.RESULT_FAIL_RETRY);
-
- verifyZeroInteractions(driverMock);
- }
-
- @Test
- public void prepareJob() {
- Intent intent = new Intent();
-
- Bundle encode = encodeContentUriJob(getContentUriTrigger(), jobCoder);
- intent.putExtra(GooglePlayJobWriter.REQUEST_PARAM_EXTRAS, encode);
-
- Parcel container = Parcel.obtain();
- container.writeStrongBinder(new Binder());
- PendingCallback pcb = new PendingCallback(container);
- intent.putExtra("callback", pcb);
-
- ArrayList uris = new ArrayList<>();
- uris.add(ContactsContract.AUTHORITY_URI);
- uris.add(Media.EXTERNAL_CONTENT_URI);
- intent.putParcelableArrayListExtra(BundleProtocol.PACKED_PARAM_TRIGGERED_URIS, uris);
-
- JobInvocation jobInvocation = receiver.prepareJob(intent);
- assertEquals(jobInvocation.getTriggerReason().getTriggeredContentUris(), uris);
- }
-
- @Test
- public void prepareJob_messenger() {
- JobInvocation jobInvocation = receiver.prepareJob(callbackMock, new Bundle());
- assertNull(jobInvocation);
- verify(callbackMock).jobFinished(JobService.RESULT_FAIL_NORETRY);
- }
-
- @Test
- public void prepareJob_messenger_noExtras() {
- Bundle bundle = getBundleForContentJobExecution();
-
- JobInvocation jobInvocation = receiver.prepareJob(callbackMock, bundle);
- assertEquals(jobInvocation.getTriggerReason().getTriggeredContentUris(), triggeredUris);
- }
-
- @NonNull
- private Bundle getBundleForContentJobExecution() {
- Bundle bundle = new Bundle();
-
- Bundle encode = encodeContentUriJob(getContentUriTrigger(), jobCoder);
- bundle.putBundle(GooglePlayJobWriter.REQUEST_PARAM_EXTRAS, encode);
-
- bundle.putParcelableArrayList(BundleProtocol.PACKED_PARAM_TRIGGERED_URIS, triggeredUris);
- return bundle;
- }
-
- @NonNull
- private Bundle getBundleForContentJobExecutionRecurring() {
- Bundle bundle = new Bundle();
-
- Bundle encode = encodeRecurringContentUriJob(getContentUriTrigger(), jobCoder);
- bundle.putBundle(GooglePlayJobWriter.REQUEST_PARAM_EXTRAS, encode);
-
- bundle.putParcelableArrayList(BundleProtocol.PACKED_PARAM_TRIGGERED_URIS, triggeredUris);
- return bundle;
- }
-
- @Test
- public void onBind() {
- Intent intent = new Intent(GooglePlayReceiver.ACTION_EXECUTE);
- IBinder binderA = receiver.onBind(intent);
- IBinder binderB = receiver.onBind(intent);
-
- assertEquals(binderA, binderB);
- }
-
- @Test
- public void onBind_nullIntent() {
- IBinder binder = receiver.onBind(null);
- assertNull(binder);
- }
-
- @Test
- public void onBind_wrongAction() {
- Intent intent = new Intent("test");
- IBinder binder = receiver.onBind(intent);
- assertNull(binder);
- }
-
- @Test
- @Config(sdk = VERSION_CODES.KITKAT)
- public void onBind_wrongBuild() {
- Intent intent = new Intent(GooglePlayReceiver.ACTION_EXECUTE);
- IBinder binder = receiver.onBind(intent);
- assertNull(binder);
- }
-
- @Test
- public void onStartCommand_nullIntent() {
- assertResultWasStartNotSticky(receiver.onStartCommand(null, 0, 101));
- verify(receiver).stopSelf(101);
- }
-
- @Test
- public void onStartCommand_initAction() {
- Intent initIntent = new Intent("com.google.android.gms.gcm.SERVICE_ACTION_INITIALIZE");
- assertResultWasStartNotSticky(receiver.onStartCommand(initIntent, 0, 101));
- verify(receiver).stopSelf(101);
- }
-
- @Test
- public void onStartCommand_unknownAction() {
- Intent unknownIntent = new Intent("com.example.foo.bar");
- assertResultWasStartNotSticky(receiver.onStartCommand(unknownIntent, 0, 101));
- assertResultWasStartNotSticky(receiver.onStartCommand(unknownIntent, 0, 102));
- assertResultWasStartNotSticky(receiver.onStartCommand(unknownIntent, 0, 103));
-
- InOrder inOrder = inOrder(receiver);
- inOrder.verify(receiver).stopSelf(101);
- inOrder.verify(receiver).stopSelf(102);
- inOrder.verify(receiver).stopSelf(103);
- }
-
- @Test
- public void onStartCommand_executeActionWithEmptyExtras() {
- Intent execIntent = new Intent("com.google.android.gms.gcm.ACTION_TASK_READY");
- assertResultWasStartNotSticky(receiver.onStartCommand(execIntent, 0, 101));
- verify(receiver).stopSelf(101);
- }
-
- @Test
- public void onStartCommand_executeAction() {
- JobInvocation job = new JobInvocation.Builder()
- .setTag("tag")
- .setService("com.example.foo.FooService")
- .setTrigger(Trigger.NOW)
- .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
- .setLifetime(Lifetime.UNTIL_NEXT_BOOT)
- .setConstraints(new int[]{Constraint.DEVICE_IDLE})
- .build();
-
- Intent execIntent = new Intent("com.google.android.gms.gcm.ACTION_TASK_READY")
- .putExtra("extras", new JobCoder(BundleProtocol.PACKED_PARAM_BUNDLE_PREFIX, true)
- .encode(job, new Bundle()))
- .putExtra("callback", new InspectableBinder().toPendingCallback());
-
- when(executionDelegatorMock.executeJob(any(JobInvocation.class))).thenReturn(true);
-
- assertResultWasStartNotSticky(receiver.onStartCommand(execIntent, 0, 101));
-
- verify(receiver, never()).stopSelf(anyInt());
- verify(executionDelegatorMock).executeJob(any(JobInvocation.class));
-
- receiver.onJobFinished(job, JobService.RESULT_SUCCESS);
-
- verify(receiver).stopSelf(101);
- }
-
- private void assertResultWasStartNotSticky(int result) {
- assertEquals(
- "Result for onStartCommand wasn't START_NOT_STICKY", Service.START_NOT_STICKY, result);
- }
-}
diff --git a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/ImmediateTriggerTest.java b/jobdispatcher/src/test/java/com/firebase/jobdispatcher/ImmediateTriggerTest.java
deleted file mode 100644
index 1cf57ee68..000000000
--- a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/ImmediateTriggerTest.java
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, manifest = Config.NONE, sdk = 23)
-public class ImmediateTriggerTest {
- /**
- * Code coverage.
- */
- @Test
- public void testPrivateConstructor() throws Exception {
- TestUtil.assertHasSinglePrivateConstructor(JobTrigger.ImmediateTrigger.class);
- }
-}
diff --git a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/JobBuilderTest.java b/jobdispatcher/src/test/java/com/firebase/jobdispatcher/JobBuilderTest.java
deleted file mode 100644
index ffb4026e8..000000000
--- a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/JobBuilderTest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, manifest = Config.NONE, sdk = 23)
-public class JobBuilderTest {
- private static final int[] ALL_LIFETIMES = {Lifetime.UNTIL_NEXT_BOOT, Lifetime.FOREVER};
-
- private Job.Builder mBuilder;
-
- @Before
- public void setUp() throws Exception {
- mBuilder = TestUtil.getBuilderWithNoopValidator();
- }
-
- @Test
- public void testAddConstraints() {
- mBuilder.setConstraints()
- .addConstraint(Constraint.DEVICE_CHARGING)
- .addConstraint(Constraint.ON_UNMETERED_NETWORK);
-
- int[] expected = {Constraint.DEVICE_CHARGING, Constraint.ON_UNMETERED_NETWORK};
-
- assertEquals(Constraint.compact(expected), Constraint.compact(mBuilder.getConstraints()));
- }
-
- @Test
- public void testSetLifetime() {
- for (int lifetime : ALL_LIFETIMES) {
- mBuilder.setLifetime(lifetime);
- assertEquals(lifetime, mBuilder.getLifetime());
- }
- }
-
- @Test
- public void testSetShouldReplaceCurrent() {
- for (boolean replace : new boolean[]{true, false}) {
- mBuilder.setReplaceCurrent(replace);
- assertEquals(replace, mBuilder.shouldReplaceCurrent());
- }
- }
-}
diff --git a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/JobCoderTest.java b/jobdispatcher/src/test/java/com/firebase/jobdispatcher/JobCoderTest.java
deleted file mode 100644
index bd3ebfb94..000000000
--- a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/JobCoderTest.java
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static com.firebase.jobdispatcher.TestUtil.encodeContentUriJob;
-import static com.firebase.jobdispatcher.TestUtil.getContentUriTrigger;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.ContactsContract;
-import android.provider.MediaStore.Images.Media;
-import com.firebase.jobdispatcher.Job.Builder;
-import com.firebase.jobdispatcher.JobTrigger.ContentUriTrigger;
-import java.util.ArrayList;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, manifest = Config.NONE, sdk = 23)
-public class JobCoderTest {
- private final JobCoder mCoder = new JobCoder(PREFIX, true);
- private static final String PREFIX = "prefix";
- private Builder mBuilder;
-
- private static Builder setValidBuilderDefaults(Builder mBuilder) {
- return mBuilder
- .setTag("tag")
- .setTrigger(Trigger.NOW)
- .setService(TestJobService.class)
- .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL);
- }
-
- @Before
- public void setUp() throws Exception {
- mBuilder = TestUtil.getBuilderWithNoopValidator();
- }
-
- @Test
- public void testCodingIsLossless() {
- for (JobParameters input : TestUtil.getJobCombinations(mBuilder)) {
-
- JobParameters output = mCoder.decode(mCoder.encode(input, input.getExtras())).build();
-
- TestUtil.assertJobsEqual(input, output);
- }
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testEncode_throwsOnNullBundle() {
- mCoder.encode(mBuilder.build(), null);
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testDecode_throwsOnNullBundle() {
- mCoder.decode(null);
- }
-
- @Test
- public void testDecode_failsWhenMissingFields() {
- assertNull("Expected null tag to cause decoding to fail",
- mCoder.decode(mCoder.encode(
- setValidBuilderDefaults(mBuilder).setTag(null).build(),
- new Bundle())));
-
- assertNull("Expected null service to cause decoding to fail",
- mCoder.decode(mCoder.encode(
- setValidBuilderDefaults(mBuilder).setService(null).build(),
- new Bundle())));
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testDecode_failsUnsupportedTrigger() {
- mCoder.decode(mCoder.encode(setValidBuilderDefaults(mBuilder).setTrigger(null).build(),
- new Bundle()));
- }
-
- @Test
- public void testDecode_ignoresMissingRetryStrategy() {
- assertNotNull("Expected null retry strategy to cause decode to use a default",
- mCoder.decode(mCoder.encode(
- setValidBuilderDefaults(mBuilder).setRetryStrategy(null).build(),
- new Bundle())));
- }
-
- @Test
- public void encode_contentUriTrigger() {
- Bundle encode = TestUtil.encodeContentUriJob(TestUtil.getContentUriTrigger(), mCoder);
- int triggerType = encode.getInt(PREFIX + BundleProtocol.PACKED_PARAM_TRIGGER_TYPE);
- assertEquals("Trigger type", BundleProtocol.TRIGGER_TYPE_CONTENT_URI, triggerType);
-
- String json = encode.getString(PREFIX + BundleProtocol.PACKED_PARAM_OBSERVED_URI);
- String expectedJson = "{\"uri_flags\":[1,0],\"uris\":[\"content:\\/\\/com.android.contacts"
- + "\",\"content:\\/\\/media\\/external\\/images\\/media\"]}";
- assertEquals("Json trigger", expectedJson, json);
- }
-
- @Test
- public void decode_contentUriTrigger() {
- ContentUriTrigger contentUriTrigger = TestUtil.getContentUriTrigger();
- Bundle bundle = TestUtil.encodeContentUriJob(contentUriTrigger, mCoder);
- JobInvocation decode = mCoder.decode(bundle).build();
- ContentUriTrigger trigger = (ContentUriTrigger) decode.getTrigger();
- assertEquals(contentUriTrigger.getUris(), trigger.getUris());
- }
-
- @Test
- public void decode_addBundleAsExtras() {
- ContentUriTrigger contentUriTrigger = TestUtil.getContentUriTrigger();
- Bundle bundle = TestUtil.encodeContentUriJob(contentUriTrigger, mCoder);
- bundle.putString("test_key", "test_value");
- JobInvocation decode = mCoder.decode(bundle).build();
- assertEquals("test_value", decode.getExtras().getString("test_key"));
- }
-
- @Test
- public void decodeIntentBundle() {
- Bundle bundle = new Bundle();
-
- ContentUriTrigger uriTrigger = getContentUriTrigger();
- Bundle encode = encodeContentUriJob(uriTrigger, mCoder);
- bundle.putBundle(GooglePlayJobWriter.REQUEST_PARAM_EXTRAS, encode);
-
- ArrayList uris = new ArrayList<>();
- uris.add(ContactsContract.AUTHORITY_URI);
- uris.add(Media.EXTERNAL_CONTENT_URI);
- bundle.putParcelableArrayList(BundleProtocol.PACKED_PARAM_TRIGGERED_URIS, uris);
-
- JobInvocation jobInvocation = mCoder.decodeIntentBundle(bundle);
-
- assertEquals(uris, jobInvocation.getTriggerReason().getTriggeredContentUris());
- assertEquals("TAG", jobInvocation.getTag());
- assertEquals(uriTrigger.getUris(), ((ContentUriTrigger) jobInvocation.getTrigger())
- .getUris());
- assertEquals(TestJobService.class.getName(), jobInvocation.getService());
- assertEquals(RetryStrategy.DEFAULT_EXPONENTIAL.getPolicy(),
- jobInvocation.getRetryStrategy().getPolicy());
- }
-}
diff --git a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/JobInvocationTest.java b/jobdispatcher/src/test/java/com/firebase/jobdispatcher/JobInvocationTest.java
deleted file mode 100644
index 769dd19d6..000000000
--- a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/JobInvocationTest.java
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.os.Bundle;
-import com.firebase.jobdispatcher.JobInvocation.Builder;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, manifest = Config.NONE, sdk = 23)
-public class JobInvocationTest {
- private Builder builder;
-
- @Before
- public void setUp() {
- builder = new Builder()
- .setTag("tag")
- .setService(TestJobService.class.getName())
- .setTrigger(Trigger.NOW);
- }
-
- @SuppressWarnings("ConstantConditions")
- @Test
- public void testShouldReplaceCurrent() throws Exception {
- assertTrue("Expected shouldReplaceCurrent() to return value passed in constructor",
- builder.setReplaceCurrent(true).build().shouldReplaceCurrent());
- assertFalse("Expected shouldReplaceCurrent() to return value passed in constructor",
- builder.setReplaceCurrent(false).build().shouldReplaceCurrent());
- }
-
- @Test
- public void extras() throws Exception {
- assertNotNull(builder.build().getExtras());
-
- Bundle bundle = new Bundle();
- bundle.putLong("test", 1L);
- Bundle extras = builder.addExtras(bundle).build().getExtras();
- assertEquals(1, extras.size());
- assertEquals(1L, extras.getLong("test"));
- }
-
- @Test
- public void contract_hashCode_equals() {
- JobInvocation jobInvocation = builder.build();
- assertEquals(jobInvocation, builder.build());
- assertEquals(jobInvocation.hashCode(), builder.build().hashCode());
- JobInvocation jobInvocationNew = builder.setTag("new").build();
- assertNotEquals(jobInvocation, jobInvocationNew);
- assertNotEquals(jobInvocation.hashCode(), jobInvocationNew.hashCode());
- }
-
- @Test
- public void contract_hashCode_equals_triggerShouldBeIgnored() {
- JobInvocation jobInvocation = builder.build();
- JobInvocation periodic = builder.setTrigger(Trigger.executionWindow(0, 1)).build();
- assertEquals(jobInvocation, periodic);
- assertEquals(jobInvocation.hashCode(), periodic.hashCode());
- }
-}
diff --git a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/JobServiceConnectionTest.java b/jobdispatcher/src/test/java/com/firebase/jobdispatcher/JobServiceConnectionTest.java
deleted file mode 100644
index 8a8be89f3..000000000
--- a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/JobServiceConnectionTest.java
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.os.IBinder;
-import android.os.Message;
-import com.firebase.jobdispatcher.JobInvocation.Builder;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-/**
- * Test for {@link JobServiceConnection}.
- */
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, manifest = Config.NONE, sdk = 23)
-public class JobServiceConnectionTest {
-
- JobInvocation job = new Builder()
- .setTag("tag")
- .setService(TestJobService.class.getName())
- .setTrigger(Trigger.NOW)
- .build();
-
- @Mock
- Message messageMock;
- @Mock
- JobService.LocalBinder binderMock;
- @Mock
- JobService jobServiceMock;
-
- JobServiceConnection connection;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(binderMock.getService()).thenReturn(jobServiceMock);
- connection = new JobServiceConnection(job, messageMock);
- }
-
- @Test
- public void fullConnectionCycle() {
- assertFalse(connection.isBound());
-
- connection.onServiceConnected(null, binderMock);
- verify(jobServiceMock).start(job, messageMock);
- assertTrue(connection.isBound());
-
- connection.onStop();
- verify(jobServiceMock).stop(job);
- assertTrue(connection.isBound());
-
- connection.onServiceDisconnected(null);
- assertFalse(connection.isBound());
- }
-
- @Test
- public void onServiceConnected_shouldNotSendExecutionRequestTwice() {
- assertFalse(connection.isBound());
-
- connection.onServiceConnected(null, binderMock);
- verify(jobServiceMock).start(job, messageMock);
- assertTrue(connection.isBound());
- reset(jobServiceMock);
-
- connection.onServiceConnected(null, binderMock);
- verify(jobServiceMock, never()).start(job, messageMock); // start should not be called again
-
- connection.onStop();
- verify(jobServiceMock).stop(job);
- assertTrue(connection.isBound());
-
- connection.onServiceDisconnected(null);
- assertFalse(connection.isBound());
- }
-
- @Test
- public void stopOnUnboundConnection() {
- assertFalse(connection.isBound());
- connection.onStop();
- verify(jobServiceMock, never()).onStopJob(job);
- }
-
- @Test
- public void onServiceConnectedWrongBinder() {
- IBinder binder = mock(IBinder.class);
- connection.onServiceConnected(null, binder);
- assertFalse(connection.isBound());
- }
-}
diff --git a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/JobServiceTest.java b/jobdispatcher/src/test/java/com/firebase/jobdispatcher/JobServiceTest.java
deleted file mode 100644
index 83c7134f4..000000000
--- a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/JobServiceTest.java
+++ /dev/null
@@ -1,346 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-import android.content.Intent;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Parcel;
-import com.firebase.jobdispatcher.JobInvocation.Builder;
-import com.google.android.gms.gcm.PendingCallback;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, manifest = Config.NONE, sdk = 23)
-public class JobServiceTest {
- private static CountDownLatch countDownLatch;
-
- @Before
- public void setUp() throws Exception {}
-
- @After
- public void tearDown() throws Exception {
- countDownLatch = null;
- }
-
- @Test
- public void testOnStartCommand_handlesNullIntent() throws Exception {
- JobService service = spy(new ExampleJobService());
- int startId = 7;
-
- try {
- service.onStartCommand(null, 0, startId);
-
- verify(service).stopSelf(startId);
- } catch (NullPointerException npe) {
- fail("Unexpected NullPointerException after calling onStartCommand with a null Intent.");
- }
- }
-
- @Test
- public void testOnStartCommand_handlesNullAction() throws Exception {
- JobService service = spy(new ExampleJobService());
- int startId = 7;
-
- Intent nullActionIntent = new Intent();
- service.onStartCommand(nullActionIntent, 0, startId);
-
- verify(service).stopSelf(startId);
- }
-
- @Test
- public void testOnStartCommand_handlesEmptyAction() throws Exception {
- JobService service = spy(new ExampleJobService());
- int startId = 7;
-
- Intent emptyActionIntent = new Intent("");
- service.onStartCommand(emptyActionIntent, 0, startId);
-
- verify(service).stopSelf(startId);
- }
-
- @Test
- public void testOnStartCommand_handlesUnknownAction() throws Exception {
- JobService service = spy(new ExampleJobService());
- int startId = 7;
-
- Intent emptyActionIntent = new Intent("foo.bar.baz");
- service.onStartCommand(emptyActionIntent, 0, startId);
-
- verify(service).stopSelf(startId);
- }
-
- @Test
- public void testOnStartCommand_handlesStartJob_nullData() {
- JobService service = spy(new ExampleJobService());
- int startId = 7;
-
- Intent executeJobIntent = new Intent(JobService.ACTION_EXECUTE);
- service.onStartCommand(executeJobIntent, 0, startId);
-
- verify(service).stopSelf(startId);
- }
-
- @Test
- public void testOnStartCommand_handlesStartJob_noTag() {
- JobService service = spy(new ExampleJobService());
- int startId = 7;
-
- Intent executeJobIntent = new Intent(JobService.ACTION_EXECUTE);
- Parcel p = Parcel.obtain();
- p.writeStrongBinder(mock(IBinder.class));
- executeJobIntent.putExtra("callback", new PendingCallback(p));
-
- service.onStartCommand(executeJobIntent, 0, startId);
-
- verify(service).stopSelf(startId);
-
- p.recycle();
- }
-
- @Test
- public void testOnStartCommand_handlesStartJob_noCallback() {
- JobService service = spy(new ExampleJobService());
- int startId = 7;
-
- Intent executeJobIntent = new Intent(JobService.ACTION_EXECUTE);
- executeJobIntent.putExtra("tag", "foobar");
-
- service.onStartCommand(executeJobIntent, 0, startId);
-
- verify(service).stopSelf(startId);
- }
-
- @Test
- public void testOnStartCommand_handlesStartJob_validRequest() throws InterruptedException {
- JobService service = spy(new ExampleJobService());
-
- HandlerThread ht = new HandlerThread("handler");
- ht.start();
- Handler h = new Handler(ht.getLooper());
-
- Intent executeJobIntent = new Intent(JobService.ACTION_EXECUTE);
-
- Job jobSpec = TestUtil.getBuilderWithNoopValidator()
- .setTag("tag")
- .setService(ExampleJobService.class)
- .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
- .setTrigger(Trigger.NOW)
- .setLifetime(Lifetime.FOREVER)
- .build();
-
- countDownLatch = new CountDownLatch(1);
-
- ((JobService.LocalBinder) service.onBind(executeJobIntent))
- .getService()
- .start(jobSpec, h.obtainMessage(ExecutionDelegator.JOB_FINISHED, jobSpec));
-
- assertTrue("Expected job to run to completion", countDownLatch.await(5, TimeUnit.SECONDS));
- }
-
- @Test
- public void testOnStartCommand_handlesStartJob_doNotStartRunningJobAgain() {
- StoppableJobService service = new StoppableJobService(false);
-
- Job jobSpec = TestUtil.getBuilderWithNoopValidator()
- .setTag("tag")
- .setService(StoppableJobService.class)
- .setTrigger(Trigger.NOW)
- .build();
-
- ((JobService.LocalBinder) service.onBind(null)).getService().start(jobSpec, null);
- ((JobService.LocalBinder) service.onBind(null)).getService().start(jobSpec, null);
-
- assertEquals(1, service.getNumberOfExecutionRequestsReceived());
- }
-
- @Test
- public void stop_noCallback_finished() {
- JobService service = spy(new StoppableJobService(false));
- JobInvocation job = new Builder()
- .setTag("Tag")
- .setTrigger(Trigger.NOW)
- .setService(StoppableJobService.class.getName())
- .build();
- service.stop(job);
- verify(service, never()).onStopJob(job);
- }
-
- @Test
- public void stop_withCallback_retry() {
- JobService service = spy(new StoppableJobService(false));
-
- JobInvocation job = new Builder()
- .setTag("Tag")
- .setTrigger(Trigger.NOW)
- .setService(StoppableJobService.class.getName())
- .build();
-
- Handler handlerMock = mock(Handler.class);
- Message message = Message.obtain(handlerMock);
- service.start(job, message);
-
- service.stop(job);
- verify(service).onStopJob(job);
- verify(handlerMock).sendMessage(message);
- assertEquals(message.arg1, JobService.RESULT_SUCCESS);
- }
-
- @Test
- public void stop_withCallback_done() {
- JobService service = spy(new StoppableJobService(true));
-
- JobInvocation job = new Builder()
- .setTag("Tag")
- .setTrigger(Trigger.NOW)
- .setService(StoppableJobService.class.getName())
- .build();
-
- Handler handlerMock = mock(Handler.class);
- Message message = Message.obtain(handlerMock);
- service.start(job, message);
-
- service.stop(job);
- verify(service).onStopJob(job);
- verify(handlerMock).sendMessage(message);
- assertEquals(message.arg1, JobService.RESULT_FAIL_RETRY);
- }
-
- @Test
- public void onStartJob_jobFinishedReschedule() {
- // Verify that a retry request from within onStartJob will cause the retry result to be sent
- // to the bouncer service's handler, regardless of what value is ultimately returned from
- // onStartJob.
- JobService reschedulingService = new JobService() {
- @Override
- public boolean onStartJob(JobParameters job) {
- // Reschedules job.
- jobFinished(job, true /* retry this job */);
- return false;
- }
-
- @Override
- public boolean onStopJob(JobParameters job) {
- return false;
- }
- };
-
- Job jobSpec = TestUtil.getBuilderWithNoopValidator()
- .setTag("tag")
- .setService(reschedulingService.getClass())
- .setTrigger(Trigger.NOW)
- .build();
- Handler mock = mock(Handler.class);
- Message message = new Message();
- message.setTarget(mock);
- reschedulingService.start(jobSpec, message);
-
- verify(mock).sendMessage(message);
- assertEquals(message.arg1, JobService.RESULT_FAIL_RETRY);
- }
-
- @Test
- public void onStartJob_jobFinishedNotReschedule() {
- // Verify that a termination request from within onStartJob will cause the result to be sent
- // to the bouncer service's handler, regardless of what value is ultimately returned from
- // onStartJob.
- JobService reschedulingService = new JobService() {
- @Override
- public boolean onStartJob(JobParameters job) {
- jobFinished(job, false /* don't retry this job */);
- return false;
- }
-
- @Override
- public boolean onStopJob(JobParameters job) {
- return false;
- }
- };
-
- Job jobSpec = TestUtil.getBuilderWithNoopValidator()
- .setTag("tag")
- .setService(reschedulingService.getClass())
- .setTrigger(Trigger.NOW)
- .build();
- Handler mock = mock(Handler.class);
- Message message = new Message();
- message.setTarget(mock);
- reschedulingService.start(jobSpec, message);
-
- verify(mock).sendMessage(message);
- assertEquals(message.arg1, JobService.RESULT_SUCCESS);
- }
-
- public static class ExampleJobService extends JobService {
- @Override
- public boolean onStartJob(JobParameters job) {
- countDownLatch.countDown();
- return false;
- }
-
- @Override
- public boolean onStopJob(JobParameters job) {
- return false;
- }
- }
-
- public static class StoppableJobService extends JobService {
-
- private final boolean shouldReschedule;
-
- public int getNumberOfExecutionRequestsReceived() {
- return amountOfExecutionRequestReceived.get();
- }
-
- private final AtomicInteger amountOfExecutionRequestReceived = new AtomicInteger();
-
- public StoppableJobService(boolean shouldReschedule) {
- this.shouldReschedule = shouldReschedule;
- }
-
- @Override
- public boolean onStartJob(JobParameters job) {
- amountOfExecutionRequestReceived.incrementAndGet();
- return true;
- }
-
- @Override
- public boolean onStopJob(JobParameters job) {
- return shouldReschedule;
- }
-
-
- }
-}
diff --git a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/ValidationEnforcerTest.java b/jobdispatcher/src/test/java/com/firebase/jobdispatcher/ValidationEnforcerTest.java
deleted file mode 100644
index 2e4e939ac..000000000
--- a/jobdispatcher/src/test/java/com/firebase/jobdispatcher/ValidationEnforcerTest.java
+++ /dev/null
@@ -1,187 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.Collections;
-import java.util.List;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(constants = BuildConfig.class, manifest = Config.NONE, sdk = 23)
-public class ValidationEnforcerTest {
- private static final List ERROR_LIST = Collections.singletonList("error: foo");
-
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
-
- @Mock
- private JobValidator mValidator;
-
- @Mock
- private JobParameters mMockJobParameters;
-
- @Mock
- private JobTrigger mMockTrigger;
-
- private ValidationEnforcer mEnforcer;
- private RetryStrategy mRetryStrategy = RetryStrategy.DEFAULT_EXPONENTIAL;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- mEnforcer = new ValidationEnforcer(mValidator);
- }
-
- @Test
- public void testValidate_retryStrategy() throws Exception {
- mEnforcer.validate(mRetryStrategy);
- verify(mValidator).validate(mRetryStrategy);
- }
-
- @Test
- public void testValidate_jobSpec() throws Exception {
- mEnforcer.validate(mMockJobParameters);
- verify(mValidator).validate(mMockJobParameters);
- }
-
- @Test
- public void testValidate_trigger() throws Exception {
- mEnforcer.validate(mMockTrigger);
- verify(mValidator).validate(mMockTrigger);
- }
-
- @Test
- public void testIsValid_retryStrategy_invalid() throws Exception {
- when(mValidator.validate(mRetryStrategy))
- .thenReturn(Collections.singletonList("error: foo"));
-
- assertFalse("isValid", mEnforcer.isValid(mRetryStrategy));
- }
-
- @Test
- public void testIsValid_retryStrategy_valid() throws Exception {
- when(mValidator.validate(mRetryStrategy)).thenReturn(null);
-
- assertTrue("isValid", mEnforcer.isValid(mRetryStrategy));
-
- }
-
- @Test
- public void testIsValid_trigger_invalid() throws Exception {
- when(mValidator.validate(mMockTrigger))
- .thenReturn(Collections.singletonList("error: foo"));
-
- assertFalse("isValid", mEnforcer.isValid(mMockTrigger));
- }
-
- @Test
- public void testIsValid_trigger_valid() throws Exception {
- when(mValidator.validate(mMockTrigger)).thenReturn(null);
-
- assertTrue("isValid", mEnforcer.isValid(mMockTrigger));
- }
-
- @Test
- public void testIsValid_jobSpec_invalid() throws Exception {
- when(mValidator.validate(mMockJobParameters)).thenReturn(ERROR_LIST);
-
- assertFalse("isValid", mEnforcer.isValid(mMockJobParameters));
- }
-
- @Test
- public void testIsValid_jobSpec_valid() throws Exception {
- when(mValidator.validate(mMockJobParameters)).thenReturn(null);
-
- assertTrue("isValid", mEnforcer.isValid(mMockJobParameters));
- }
-
- @Test
- public void testEnsureValid_retryStrategy_valid() throws Exception {
- when(mValidator.validate(mRetryStrategy)).thenReturn(null);
-
- mEnforcer.ensureValid(mRetryStrategy);
- }
-
- @Test
- public void testEnsureValid_trigger_valid() throws Exception {
- when(mValidator.validate(mMockTrigger)).thenReturn(null);
-
- mEnforcer.ensureValid(mMockTrigger);
- }
-
- @Test
- public void testEnsureValid_jobSpec_valid() throws Exception {
- when(mValidator.validate(mMockJobParameters)).thenReturn(null);
-
- mEnforcer.ensureValid(mMockJobParameters);
- }
-
- @Test
- public void testEnsureValid_retryStrategy_invalid() throws Exception {
- expectedException.expect(ValidationEnforcer.ValidationException.class);
-
- when(mValidator.validate(mRetryStrategy)).thenReturn(ERROR_LIST);
- mEnforcer.ensureValid(mRetryStrategy);
- }
-
- @Test
- public void testEnsureValid_trigger_invalid() throws Exception {
- expectedException.expect(ValidationEnforcer.ValidationException.class);
-
- when(mValidator.validate(mMockTrigger)).thenReturn(ERROR_LIST);
- mEnforcer.ensureValid(mMockTrigger);
- }
-
- @Test
- public void testEnsureValid_jobSpec_invalid() throws Exception {
- expectedException.expect(ValidationEnforcer.ValidationException.class);
-
- when(mValidator.validate(mMockJobParameters)).thenReturn(ERROR_LIST);
- mEnforcer.ensureValid(mMockJobParameters);
- }
-
- @Test
- public void testValidationMessages() throws Exception {
- when(mValidator.validate(mMockJobParameters)).thenReturn(ERROR_LIST);
-
- try {
- mEnforcer.ensureValid(mMockJobParameters);
-
- fail("Expected ensureValid to fail");
- } catch (ValidationEnforcer.ValidationException ve) {
- assertEquals("Expected ValidationException to have 1 error message",
- 1,
- ve.getErrors().size());
- }
- }
-}
diff --git a/jobdispatcher/src/testLib/java/com/firebase/jobdispatcher/NoopJobValidator.java b/jobdispatcher/src/testLib/java/com/firebase/jobdispatcher/NoopJobValidator.java
deleted file mode 100644
index 079a6eed2..000000000
--- a/jobdispatcher/src/testLib/java/com/firebase/jobdispatcher/NoopJobValidator.java
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import android.support.annotation.Nullable;
-import java.util.List;
-
-/**
- * A very simple Validator that thinks that everything is ok. Used for testing.
- */
-class NoopJobValidator implements JobValidator {
-
- @Nullable
- @Override
- public List validate(JobParameters job) {
- return null;
- }
-
- @Nullable
- @Override
- public List validate(JobTrigger trigger) {
- return null;
- }
-
- @Nullable
- @Override
- public List validate(RetryStrategy retryStrategy) {
- return null;
- }
-}
diff --git a/jobdispatcher/src/testLib/java/com/firebase/jobdispatcher/TestJobService.java b/jobdispatcher/src/testLib/java/com/firebase/jobdispatcher/TestJobService.java
deleted file mode 100644
index 77b3604ab..000000000
--- a/jobdispatcher/src/testLib/java/com/firebase/jobdispatcher/TestJobService.java
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-/** A very simple JobService that can be configured for individual tests. */
-public class TestJobService extends JobService {
-
- public interface JobServiceProxy {
- boolean onStartJob(JobParameters job);
-
- boolean onStopJob(JobParameters job);
- }
-
- public static final JobServiceProxy NOOP_PROXY =
- new JobServiceProxy() {
- @Override
- public boolean onStartJob(JobParameters job) {
- return false;
- }
-
- @Override
- public boolean onStopJob(JobParameters job) {
- return false;
- }
- };
-
- private static final Object lock = new Object();
-
- // GuardedBy("lock")
- private static JobServiceProxy currentProxy = NOOP_PROXY;
-
- public static void setProxy(JobServiceProxy proxy) {
- synchronized (lock) {
- currentProxy = proxy;
- }
- }
-
- public static void reset() {
- synchronized (lock) {
- currentProxy = NOOP_PROXY;
- }
- }
-
- @Override
- public boolean onStartJob(JobParameters job) {
- synchronized (lock) {
- return currentProxy.onStartJob(job);
- }
- }
-
- @Override
- public boolean onStopJob(JobParameters job) {
- synchronized (lock) {
- return currentProxy.onStopJob(job);
- }
- }
-}
diff --git a/jobdispatcher/src/testLib/java/com/firebase/jobdispatcher/TestUtil.java b/jobdispatcher/src/testLib/java/com/firebase/jobdispatcher/TestUtil.java
deleted file mode 100644
index 85f9fadcd..000000000
--- a/jobdispatcher/src/testLib/java/com/firebase/jobdispatcher/TestUtil.java
+++ /dev/null
@@ -1,375 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.firebase.jobdispatcher;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.provider.ContactsContract;
-import android.provider.MediaStore.Images.Media;
-import android.support.annotation.NonNull;
-import com.firebase.jobdispatcher.Job.Builder;
-import com.firebase.jobdispatcher.JobTrigger.ContentUriTrigger;
-import com.firebase.jobdispatcher.ObservedUri.Flags;
-import com.google.android.gms.gcm.PendingCallback;
-import java.lang.reflect.Constructor;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Provides common utilities helpful for testing.
- */
-public class TestUtil {
-
- private static final String TAG = "TAG";
- private static final String[] TAG_COMBINATIONS = {"tag", "foobar", "fooooooo", "bz", "100"};
-
- private static final int[] LIFETIME_COMBINATIONS = {
- Lifetime.UNTIL_NEXT_BOOT,
- Lifetime.FOREVER};
-
- private static final JobTrigger[] TRIGGER_COMBINATIONS = {
- Trigger.executionWindow(0, 30),
- Trigger.executionWindow(300, 600),
- Trigger.executionWindow(86400, 86400 * 2),
- Trigger.NOW,
- Trigger.contentUriTrigger(
- Arrays.asList(new ObservedUri(ContactsContract.AUTHORITY_URI, 0))),
- Trigger.contentUriTrigger(Arrays.asList(new ObservedUri(ContactsContract.AUTHORITY_URI, 0),
- new ObservedUri(ContactsContract.AUTHORITY_URI, Flags.FLAG_NOTIFY_FOR_DESCENDANTS)))
- };
-
- @SuppressWarnings("unchecked")
- private static final List> SERVICE_COMBINATIONS =
- Arrays.asList(TestJobService.class);
-
- private static final RetryStrategy[] RETRY_STRATEGY_COMBINATIONS = {
- RetryStrategy.DEFAULT_LINEAR,
- new RetryStrategy(RetryStrategy.RETRY_POLICY_LINEAR, 60, 300),
- RetryStrategy.DEFAULT_EXPONENTIAL,
- new RetryStrategy(RetryStrategy.RETRY_POLICY_EXPONENTIAL, 300, 600),
- };
-
- public static void assertHasSinglePrivateConstructor(Class> cls) throws Exception {
- Constructor>[] constructors = cls.getDeclaredConstructors();
- assertEquals("expected number of constructors to be == 1", 1, constructors.length);
-
- Constructor> constructor = constructors[0];
- assertFalse("expected constructor to be inaccessible", constructor.isAccessible());
-
- constructor.setAccessible(true);
- constructor.newInstance();
- }
-
- static List> getAllConstraintCombinations() {
- List> combos = new LinkedList<>();
-
- combos.add(Collections.emptyList());
- for (Integer cur : Constraint.ALL_CONSTRAINTS) {
- for (int l = combos.size() - 1; l >= 0; l--) {
- List oldCombo = combos.get(l);
- List newCombo = Arrays.asList(new Integer[oldCombo.size() + 1]);
-
- Collections.copy(newCombo, oldCombo);
- newCombo.set(oldCombo.size(), cur);
- combos.add(newCombo);
- }
- combos.add(Collections.singletonList(cur));
- }
-
- return combos;
- }
-
- static int[] toIntArray(List list) {
- int[] input = new int[list.size()];
- for (int i = 0; i < list.size(); i++) {
- input[i] = list.get(i);
- }
- return input;
- }
-
- static List getJobCombinations(Builder builder) {
- return getCombination(new JobBuilder(builder));
- }
-
- static List getJobInvocationCombinations() {
- return getCombination(new JobInvocationBuilder());
- }
-
- private static List getCombination(
- JobParameterBuilder buildJobParam) {
-
- List result = new ArrayList<>();
- for (String tag : TAG_COMBINATIONS) {
- for (List constraintList : getAllConstraintCombinations()) {
- for (boolean recurring : new boolean[]{true, false}) {
- for (boolean replaceCurrent : new boolean[]{true, false}) {
- for (int lifetime : LIFETIME_COMBINATIONS) {
- for (JobTrigger trigger : TRIGGER_COMBINATIONS) {
- for (Class service : SERVICE_COMBINATIONS) {
- for (Bundle extras : getBundleCombinations()) {
- for (RetryStrategy rs : RETRY_STRATEGY_COMBINATIONS) {
- result.add(buildJobParam.build(
- tag,
- replaceCurrent,
- constraintList,
- recurring,
- lifetime,
- trigger,
- service,
- extras,
- rs));
- }
- }
- }
- }
- }
- }
- }
- }
- }
- return result;
- }
-
- private static Bundle[] getBundleCombinations() {
- List bundles = new LinkedList<>();
- bundles.add(new Bundle());
-
- Bundle b = new Bundle();
- b.putString("foo", "bar");
- b.putInt("bar", 1);
- b.putLong("baz", 3L);
- bundles.add(b);
-
- return bundles.toArray(new Bundle[bundles.size()]);
- }
-
- static void assertJobsEqual(JobParameters input, JobParameters output) {
- assertNotNull("input", input);
- assertNotNull("output", output);
-
- assertEquals("isRecurring()", input.isRecurring(), output.isRecurring());
- assertEquals("shouldReplaceCurrent()",
- input.shouldReplaceCurrent(),
- output.shouldReplaceCurrent());
- assertEquals("getLifetime()", input.getLifetime(), output.getLifetime());
- assertEquals("getTag()", input.getTag(), output.getTag());
- assertEquals("getService()", input.getService(), output.getService());
- assertEquals("getConstraints()",
- Constraint.compact(input.getConstraints()),
- Constraint.compact(output.getConstraints()));
-
- assertTriggersEqual(input.getTrigger(), output.getTrigger());
- assertBundlesEqual(input.getExtras(), output.getExtras());
- assertRetryStrategiesEqual(input.getRetryStrategy(), output.getRetryStrategy());
- }
-
- static void assertRetryStrategiesEqual(RetryStrategy in, RetryStrategy out) {
- String prefix = "getRetryStrategy().";
-
- assertEquals(prefix + "getPolicy()",
- in.getPolicy(), out.getPolicy());
- assertEquals(prefix + "getInitialBackoff()",
- in.getInitialBackoff(), out.getInitialBackoff());
- assertEquals(prefix + "getMaximumBackoff()",
- in.getMaximumBackoff(), out.getMaximumBackoff());
- }
-
- static void assertBundlesEqual(Bundle inExtras, Bundle outExtras) {
- if (inExtras == null || outExtras == null) {
- assertNull(inExtras);
- assertNull(outExtras);
- return;
- }
-
- assertEquals("getExtras().size()", inExtras.size(), outExtras.size());
- final Set inKeys = inExtras.keySet();
- for (String key : inKeys) {
- assertTrue("getExtras().containsKey(\"" + key + "\")", outExtras.containsKey(key));
- assertEquals("getExtras().get(\"" + key + "\")", inExtras.get(key), outExtras.get(key));
- }
- }
-
- static void assertTriggersEqual(JobTrigger inTrigger, JobTrigger outTrigger) {
- assertEquals("", inTrigger.getClass(), outTrigger.getClass());
-
- if (inTrigger instanceof JobTrigger.ExecutionWindowTrigger) {
- assertEquals("getTrigger().getWindowStart()",
- ((JobTrigger.ExecutionWindowTrigger) inTrigger).getWindowStart(),
- ((JobTrigger.ExecutionWindowTrigger) outTrigger).getWindowStart());
- assertEquals("getTrigger().getWindowEnd()",
- ((JobTrigger.ExecutionWindowTrigger) inTrigger).getWindowEnd(),
- ((JobTrigger.ExecutionWindowTrigger) outTrigger).getWindowEnd());
- } else if (inTrigger == Trigger.NOW) {
- assertEquals(inTrigger, outTrigger);
- } else if (inTrigger instanceof JobTrigger.ContentUriTrigger) {
- assertEquals("Collection of URIs",
- ((ContentUriTrigger) inTrigger).getUris(),
- ((ContentUriTrigger) outTrigger).getUris());
- } else {
- fail("Unknown Trigger class: " + inTrigger.getClass());
- }
- }
-
- @NonNull
- public static Builder getBuilderWithNoopValidator() {
- return new Builder(new ValidationEnforcer(new NoopJobValidator()));
- }
-
- @NonNull
- static Bundle encodeContentUriJob(ContentUriTrigger trigger, JobCoder coder) {
- Job job = getBuilderWithNoopValidator()
- .setTag(TAG)
- .setTrigger(trigger)
- .setService(TestJobService.class)
- .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
- .build();
- return coder.encode(job, new Bundle());
- }
-
- @NonNull
- static Bundle encodeRecurringContentUriJob(ContentUriTrigger trigger, JobCoder coder) {
- Job job = getBuilderWithNoopValidator()
- .setTag(TAG)
- .setTrigger(trigger)
- .setService(TestJobService.class)
- .setReplaceCurrent(true)
- .setRecurring(true)
- .build();
- return coder.encode(job, new Bundle());
- }
-
- static ContentUriTrigger getContentUriTrigger() {
- ObservedUri contactUri = new ObservedUri(
- ContactsContract.AUTHORITY_URI, Flags.FLAG_NOTIFY_FOR_DESCENDANTS);
- ObservedUri imageUri = new ObservedUri(Media.EXTERNAL_CONTENT_URI, 0);
- return Trigger.contentUriTrigger(Arrays.asList(contactUri, imageUri));
- }
-
- public static class TransactionArguments {
- public final int code;
- public final Parcel data;
- public final int flags;
-
- public TransactionArguments(int code, Parcel data, int flags) {
- this.code = code;
- this.data = data;
- this.flags = flags;
- }
- }
-
- public static class InspectableBinder extends Binder {
- private final List transactionArguments = new LinkedList<>();
-
- public InspectableBinder() {}
-
- @Override
- protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
- transactionArguments.add(new TransactionArguments(code, copyParcel(data), flags));
- return true;
- }
-
- public PendingCallback toPendingCallback() {
- Parcel container = Parcel.obtain();
- try {
- container.writeStrongBinder(this);
- container.setDataPosition(0);
- return new PendingCallback(container);
- } finally {
- container.recycle();
- }
- }
-
- private Parcel copyParcel(Parcel data) {
- Parcel clone = Parcel.obtain();
- clone.appendFrom(data, 0, data.dataSize());
- clone.setDataPosition(0);
- return clone;
- }
-
- public List getArguments() {
- return Collections.unmodifiableList(transactionArguments);
- }
- }
-
- private static class JobInvocationBuilder implements
- JobParameterBuilder {
-
- @Override
- public JobInvocation build(String tag, boolean replaceCurrent, List constraintList,
- boolean recurring, int lifetime, JobTrigger trigger, Class service,
- Bundle extras, RetryStrategy rs) {
- //noinspection WrongConstant
- return new JobInvocation.Builder()
- .setTag(tag)
- .setReplaceCurrent(replaceCurrent)
- .setRecurring(recurring)
- .setConstraints(toIntArray(constraintList))
- .setLifetime(lifetime)
- .setTrigger(trigger)
- .setService(service.getName())
- .addExtras(extras)
- .setRetryStrategy(rs)
- .build();
- }
- }
-
- private static class JobBuilder implements JobParameterBuilder {
-
- private final Builder builder;
-
- public JobBuilder(Builder builder){
- this.builder = builder;
- }
-
- @Override
- public Job build(String tag, boolean replaceCurrent, List constraintList,
- boolean recurring, int lifetime, JobTrigger trigger, Class service,
- Bundle extras, RetryStrategy rs) {
- //noinspection WrongConstant
- return builder
- .setTag(tag)
- .setReplaceCurrent(replaceCurrent)
- .setRecurring(recurring)
- .setConstraints(toIntArray(constraintList))
- .setLifetime(lifetime)
- .setTrigger(trigger)
- .setService(service)
- .setExtras(extras)
- .setRetryStrategy(rs)
- .build();
- }
- }
-
- private interface JobParameterBuilder {
-
- T build(String tag, boolean replaceCurrent, List constraintList, boolean recurring,
- int lifetime, JobTrigger trigger, Class service, Bundle extras,
- RetryStrategy rs);
- }
-}
diff --git a/jobdispatcher/src/testLib/java/com/google/android/gms/gcm/PendingCallback.java b/jobdispatcher/src/testLib/java/com/google/android/gms/gcm/PendingCallback.java
deleted file mode 100644
index a12317c8a..000000000
--- a/jobdispatcher/src/testLib/java/com/google/android/gms/gcm/PendingCallback.java
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2016 Google, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-////////////////////////////////////////////////////////////////////////////////
-
-package com.google.android.gms.gcm;
-
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.support.annotation.Keep;
-
-/**
- * Parcelable class to wrap the binder we send to the client over IPC. Only included for the benefit
- * of tests.
- */
-@Keep
-public final class PendingCallback implements Parcelable {
- public static final Creator CREATOR =
- new Creator() {
- @Override
- public PendingCallback createFromParcel(Parcel parcel) {
- return new PendingCallback(parcel);
- }
-
- @Override
- public PendingCallback[] newArray(int i) {
- return new PendingCallback[i];
- }
- };
- private final IBinder mBinder;
-
- public PendingCallback(Parcel in) {
- mBinder = in.readStrongBinder();
- }
-
- public IBinder getIBinder() {
- return mBinder;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeStrongBinder(mBinder);
- }
-}
diff --git a/settings.gradle b/settings.gradle
index 570872419..e7b4def49 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-include ':app', ':jobdispatcher'
+include ':app'
From 2fa39454d8d694cafe12dfc51ed57421bc800555 Mon Sep 17 00:00:00 2001
From: Apply55gx
Date: Sun, 1 Oct 2017 15:09:02 +0200
Subject: [PATCH 16/36] Changed "Orgs" to "Organisation"
For better understanding
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 7e437c556..cd288188b 100644
--- a/README.md
+++ b/README.md
@@ -67,7 +67,7 @@ Yet another **open-source** GitHub client app but unlike any other app, FastHub
- Edit Gist & Gist Files
- React to Commit comments with reactions
- Comment on line number in Files/Code changes.
-- **Orgs**
+- **Organisations**
- Overview
- Feeds
- Teams & Teams repos
From 051e47de3cf64b71a2262811168fb8bb8b74c133 Mon Sep 17 00:00:00 2001
From: cozyplanes
Date: Sun, 1 Oct 2017 23:00:58 +0900
Subject: [PATCH 17/36] Update strings.xml
Korean translation update for changes made in 4.4.0
Changes complete 1 out of 4 (1/4)
---
app/src/main/res/values-ko/strings.xml | 32 +++++++++++++++++++++++++-
1 file changed, 31 insertions(+), 1 deletion(-)
diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml
index e291578a5..db87efb20 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -433,6 +433,36 @@
%s %s가 추가함
변경사항이 너무 많습니다. 브라우저로 보세요
프로젝트
- 읽어주세요
+ 꼭 읽어주세요
자주하는 질문
+ 댓글을 성공적으로 추가하였습니다.
+
+ • 왜 Private 이나 Public으로 되어진 제 Organizations 을 볼 수 없나요?
+ Open up https://github.com/settings/applications 를 열고 Fasthub라는 것을 찾아보세요. 그것을 열고, Organization access 부분에서 Grant를 눌러주세요. 또는 초기 로그인시 엑세스 토큰 으로 로그인하면 편리합니다.
+ • Access Token & OTP 으로 로그인을 시도했는데 로그인이 되질 않아요...
+ OTP는 일회용 코드입니다. 따리서 유효기간에 인해 엑세스 토큰 + OTP로 로그인이 불가합니다. 이렇게 로그인을 하게 되면 몇 초에 한 번씩 앱이 로그인을 하라고 합니다. 다른 방법을 사용해 주세요.
+ • 제 비공개 리포지토리와 엔터프라이즈 위키가 보이질 않아요!
+ 위 두 정보를 스크랩하려면 특별한 세션 토큰이 필요한데 본 앱을 이 토큰을 받을 수 없습니다. 깃허브 API의 한계이므로 API문의는 깃허브에게 해주세요. 본 앱의 개발자는 API문의를 받지 않습니다.
+ • 제가 엔터프라이즈 계정으로 로그인했는데 Enterprise GitHub 외의 다른 것들은 볼 수 없나요?
\n
+ 결론부터 말하자면 불가능합니다. 본 앱은 여러분이 다른 것들을 볼 수 있게 해 주고 있지만, 기술적 한계로 크게 도움을 드릴 수는 없습니다. 대부분의 경우에는 여러분의 로그인 계정이 깃허브 서버에 상주하고 있기 때문입니다. 그러나 소수/b>의 경우에는 여러분의 OAuth 토큰이 다른 활동을 하게 해 줄 수 있습니다.
+ • Why am I having problems editing Issues/PRs?
+ If you are editing a public Org repo, then please contact your Org to grant access to FastHub or use Access Token to login!.
+ • I\'m having this issue or I want this & that!!
+ Head to https://github.com/k0shk0sh/FastHub/issues/new and create new issue for bugs or feature requests, I really do encourage you to
+ search before opening a ticket. Any duplicate request will result in it being closed immediately.
+ • How do I get PROMO CODE?
+ If you are a student, you\'ll have to provide me via Email that you are student, you will need below documents:
+
+ - Your university identity card & your identity card (that shows your name & your face to compare it!)
+ - Your university start & end date
+ - Rate FastHub in the Play Store
+
+ If you aren\'t a student and you can\'t afford to pay for PRO, you\'ll need:
+
+ - Write an article about FastHub in social media such as (Medium)
+ - Rate FastHub in the Play Store
+
+ 본 한국어 번역자는 이 앱의 개발에 참여하지 않았습니다. 따라서 기술적 문의는 이 앱의 개발자인 Kosh Sergani에게 해주시기 바랍니다. 본 번역이 앱 사용에 도움이 되셨기를 바랍니다. 감사합니다.
+
From 6f6fb9d38e49d672eebf44db50d429a3bebe2bed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Javier=20Segovia=20C=C3=B3rdoba?=
Date: Sun, 1 Oct 2017 16:27:49 +0200
Subject: [PATCH 18/36] Update strings.xml
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
"Tenés" is not used in Spain and "Repórtalo" has accent mark.
---
app/src/main/res/values-es/strings.xml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 0baed60c1..ed9932dda 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -217,10 +217,10 @@
Autor
Fork en GitHub
Enviar un email
- ¿Tenés preguntas sobre FastHub?
+ ¿Tienes preguntas sobre FastHub?
Comentarios
Reportar un error
- ¿Tenés un problema? Reportalo aquí
+ ¿Tienes un problema? Repórtalo aquí
Acerca de
Notificación
Apagar
From 365d13ad68826ed4fd74291ee3f456f4bb506041 Mon Sep 17 00:00:00 2001
From: Yakov
Date: Sun, 1 Oct 2017 13:42:27 -0400
Subject: [PATCH 19/36] Fixed #956 and a small issue template correction
---
.../provider/markdown/CachedComments.kt | 4 +---
.../viewholder/PullRequestEventViewHolder.kt | 4 ++--
.../viewholder/UnknownTypeViewHolder.kt | 2 +-
.../com/fastaccess/ui/base/MainNavDrawer.kt | 6 ++---
.../modules/editor/emoji/EmojiBottomSheet.kt | 6 ++---
.../main/donation/CheckPurchaseActivity.kt | 2 +-
.../repos/extras/branches/BranchesFragment.kt | 6 ++---
.../branches/pager/BranchesPagerFragment.kt | 6 ++---
.../delete/DeleteFileBottomSheetFragment.kt | 5 ++--
.../projects/RepoProjectsFragmentPager.kt | 2 +-
.../projects/columns/ProjectColumnFragment.kt | 2 +-
.../reviews/changes/ReviewChangesActivity.kt | 2 +-
.../sound/NotificationSoundBottomSheet.kt | 6 ++---
.../ui/modules/trending/TrendingActivity.kt | 24 +++++++++----------
build.gradle | 2 +-
gradle/wrapper/gradle-wrapper.properties | 2 +-
16 files changed, 39 insertions(+), 42 deletions(-)
diff --git a/app/src/main/java/com/fastaccess/provider/markdown/CachedComments.kt b/app/src/main/java/com/fastaccess/provider/markdown/CachedComments.kt
index d84591524..87a90ee19 100644
--- a/app/src/main/java/com/fastaccess/provider/markdown/CachedComments.kt
+++ b/app/src/main/java/com/fastaccess/provider/markdown/CachedComments.kt
@@ -17,9 +17,7 @@ class CachedComments private constructor() {
return map["$repo/$login/$number"]
}
- fun clear() {
- map.clear()
- }
+ fun clear() = map.clear()
private object Holder {
val INSTANCE = CachedComments()
diff --git a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/PullRequestEventViewHolder.kt b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/PullRequestEventViewHolder.kt
index 6b29ed9e6..6e2bfb6f9 100644
--- a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/PullRequestEventViewHolder.kt
+++ b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/PullRequestEventViewHolder.kt
@@ -402,8 +402,8 @@ class PullRequestEventViewHolder private constructor(view: View, adapter: BaseRe
if (value == null) {
return ""
}
- if (value.length <= 7) return value
- else return value.substring(0, 7)
+ return if (value.length <= 7) value
+ else value.substring(0, 7)
}
companion object {
diff --git a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/UnknownTypeViewHolder.kt b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/UnknownTypeViewHolder.kt
index 6fe1a3cfb..3fa035890 100644
--- a/app/src/main/java/com/fastaccess/ui/adapter/viewholder/UnknownTypeViewHolder.kt
+++ b/app/src/main/java/com/fastaccess/ui/adapter/viewholder/UnknownTypeViewHolder.kt
@@ -6,6 +6,6 @@ import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder
/**
* Created by kosh on 07/08/2017.
*/
-class UnknownTypeViewHolder(private val view: View) : BaseViewHolder(view) {
+class UnknownTypeViewHolder(view: View) : BaseViewHolder(view) {
override fun bind(t: Any) {} //DO NOTHING
}
\ No newline at end of file
diff --git a/app/src/main/java/com/fastaccess/ui/base/MainNavDrawer.kt b/app/src/main/java/com/fastaccess/ui/base/MainNavDrawer.kt
index 1bd5b451f..238e55a9e 100644
--- a/app/src/main/java/com/fastaccess/ui/base/MainNavDrawer.kt
+++ b/app/src/main/java/com/fastaccess/ui/base/MainNavDrawer.kt
@@ -39,13 +39,13 @@ class MainNavDrawer(val view: BaseActivity<*, *>, private val extraNav: Navigati
: BaseViewHolder.OnItemClickListener {
private var menusHolder: ViewGroup? = null
- private val togglePinned: View? = view.findViewById(R.id.togglePinned)
- private val pinnedList: DynamicRecyclerView? = view.findViewById(R.id.pinnedList)
+ private val togglePinned: View? = view.findViewById(R.id.togglePinned)
+ private val pinnedList: DynamicRecyclerView? = view.findViewById(R.id.pinnedList)
private val pinnedListAdapter = PinnedReposAdapter(true)
private val userModel: Login? = Login.getUser()
init {
- menusHolder = view.findViewById(R.id.menusHolder)
+ menusHolder = view.findViewById(R.id.menusHolder)
pinnedListAdapter.listener = object : BaseViewHolder.OnItemClickListener {
override fun onItemClick(position: Int, v: View?, item: PinnedRepos?) {
if (v != null && item != null) {
diff --git a/app/src/main/java/com/fastaccess/ui/modules/editor/emoji/EmojiBottomSheet.kt b/app/src/main/java/com/fastaccess/ui/modules/editor/emoji/EmojiBottomSheet.kt
index 3e46961f6..4e06b396b 100644
--- a/app/src/main/java/com/fastaccess/ui/modules/editor/emoji/EmojiBottomSheet.kt
+++ b/app/src/main/java/com/fastaccess/ui/modules/editor/emoji/EmojiBottomSheet.kt
@@ -34,9 +34,9 @@ class EmojiBottomSheet : BaseMvpBottomSheetDialogFragment emojiCallback = parentFragment as EmojiMvp.EmojiCallback
- context is EmojiMvp.EmojiCallback -> emojiCallback = context
+ emojiCallback = when {
+ parentFragment is EmojiMvp.EmojiCallback -> parentFragment as EmojiMvp.EmojiCallback
+ context is EmojiMvp.EmojiCallback -> context
else -> throw IllegalArgumentException("${context.javaClass.simpleName} must implement EmojiMvp.EmojiCallback")
}
}
diff --git a/app/src/main/java/com/fastaccess/ui/modules/main/donation/CheckPurchaseActivity.kt b/app/src/main/java/com/fastaccess/ui/modules/main/donation/CheckPurchaseActivity.kt
index 2948d88c1..23db135d7 100644
--- a/app/src/main/java/com/fastaccess/ui/modules/main/donation/CheckPurchaseActivity.kt
+++ b/app/src/main/java/com/fastaccess/ui/modules/main/donation/CheckPurchaseActivity.kt
@@ -38,7 +38,7 @@ class CheckPurchaseActivity : Activity() {
}
}
- override fun onBackPressed() {}
+ override fun onBackPressed() = Unit
private fun startMainActivity() {
startActivity(Intent(this, MainActivity::class.java))
diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/branches/BranchesFragment.kt b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/branches/BranchesFragment.kt
index 1ffed6abb..96c929f16 100644
--- a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/branches/BranchesFragment.kt
+++ b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/branches/BranchesFragment.kt
@@ -34,9 +34,9 @@ class BranchesFragment : BaseFragment(), Br
override fun onAttach(context: Context) {
super.onAttach(context)
- if (parentFragment is BranchesPagerListener) {
- branchCallback = parentFragment as BranchesPagerListener
- } else branchCallback = context as BranchesPagerListener
+ branchCallback = if (parentFragment is BranchesPagerListener) {
+ parentFragment as BranchesPagerListener
+ } else context as BranchesPagerListener
}
override fun onDetach() {
diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/branches/pager/BranchesPagerFragment.kt b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/branches/pager/BranchesPagerFragment.kt
index ecf94306e..5eb08b4ca 100644
--- a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/branches/pager/BranchesPagerFragment.kt
+++ b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/branches/pager/BranchesPagerFragment.kt
@@ -31,9 +31,9 @@ class BranchesPagerFragment : BaseDialogFragment(), Tr
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
- when (item?.itemId) {
+ return when (item?.itemId) {
R.id.menu -> {
drawerLayout.openDrawer(Gravity.END)
- return true
+ true
}
android.R.id.home -> {
startActivity(Intent(this, MainActivity::class.java))
finish()
- return true
+ true
}
- else -> return super.onOptionsItemSelected(item)
+ else -> super.onOptionsItemSelected(item)
}
}
@@ -156,9 +156,9 @@ class TrendingActivity : BaseActivity(), Tr
}
private fun onItemClicked(item: MenuItem?): Boolean {
- when (item?.title.toString()) {
- "All Language" -> selectedTitle = ""
- else -> selectedTitle = item?.title.toString()
+ selectedTitle = when (item?.title.toString()) {
+ "All Language" -> ""
+ else -> item?.title.toString()
}
Logger.e(selectedTitle)
setValues()
@@ -176,11 +176,11 @@ class TrendingActivity : BaseActivity(), Tr
}
private fun getSince(): String {
- when {
- daily.isSelected -> return "daily"
- weekly.isSelected -> return "weekly"
- monthly.isSelected -> return "monthly"
- else -> return "daily"
+ return when {
+ daily.isSelected -> "daily"
+ weekly.isSelected -> "weekly"
+ monthly.isSelected -> "monthly"
+ else -> "daily"
}
}
diff --git a/build.gradle b/build.gradle
index 831bd8c31..f60a37cd9 100644
--- a/build.gradle
+++ b/build.gradle
@@ -13,7 +13,7 @@ buildscript {
assertjVersion = '2.5.0'
espresseVersion = '2.2.2'
requery = '1.3.2'
- kotlin_version = '1.1.4-3'
+ kotlin_version = '1.1.50'
commonmark = '0.9.0'
}
repositories {
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 15eb24ec2..7d171b3b1 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,5 +3,5 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.2-all.zip
android.enableD8=true
\ No newline at end of file
From 81a8cc3a2d5c4588a59a32f1ec4b06b656b7f2e8 Mon Sep 17 00:00:00 2001
From: Yakov
Date: Sun, 1 Oct 2017 17:08:09 -0400
Subject: [PATCH 20/36] kotlin update
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index f60a37cd9..d3b2f8204 100644
--- a/build.gradle
+++ b/build.gradle
@@ -13,7 +13,7 @@ buildscript {
assertjVersion = '2.5.0'
espresseVersion = '2.2.2'
requery = '1.3.2'
- kotlin_version = '1.1.50'
+ kotlin_version = '1.1.51'
commonmark = '0.9.0'
}
repositories {
From d526db5846289b564f25ca68dabc7ca7b71793f0 Mon Sep 17 00:00:00 2001
From: maple
Date: Mon, 2 Oct 2017 07:50:44 +0800
Subject: [PATCH 21/36] zh-rTW FAQ text fix
---
app/src/main/res/values-zh-rTW/strings.xml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index 9ab4b395f..9a927f25d 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -449,8 +449,8 @@ APP
在新視窗中開啟
差異太多無法顯示。請於瀏覽器檢視它們
專案
- FAQ
-
+ FAQ
+
• 為何我無法看到我的 組織 的 私人 / 公開 的東西?
打開 https://github.com/settings/applications 並找到 FastHub, 點擊它並滑到 Organization access 並點擊 Grant 按鈕,
From ed95b552ad716da7f6bb5a5d0c65e00a48fceb22 Mon Sep 17 00:00:00 2001
From: cozyplanes
Date: Mon, 2 Oct 2017 14:21:15 +0900
Subject: [PATCH 22/36] Update strings.xml
---
app/src/main/res/values-ko/strings.xml | 29 +++++++++++++-------------
1 file changed, 14 insertions(+), 15 deletions(-)
diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml
index db87efb20..57503b5cd 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -439,30 +439,29 @@
• 왜 Private 이나 Public으로 되어진 제 Organizations 을 볼 수 없나요?
- Open up https://github.com/settings/applications 를 열고 Fasthub라는 것을 찾아보세요. 그것을 열고, Organization access 부분에서 Grant를 눌러주세요. 또는 초기 로그인시 엑세스 토큰 으로 로그인하면 편리합니다.
+ Open up https://github.com/settings/applications 를 열고 Fasthub라는 것을 찾아보세요. 그것을 열고, Organization access 부분에서 Grant를 눌러주세요. 또는 초기 로그인시 엑세스 토큰 으로 로그인하면 편리합니다.
\n
• Access Token & OTP 으로 로그인을 시도했는데 로그인이 되질 않아요...
OTP는 일회용 코드입니다. 따리서 유효기간에 인해 엑세스 토큰 + OTP로 로그인이 불가합니다. 이렇게 로그인을 하게 되면 몇 초에 한 번씩 앱이 로그인을 하라고 합니다. 다른 방법을 사용해 주세요.
• 제 비공개 리포지토리와 엔터프라이즈 위키가 보이질 않아요!
위 두 정보를 스크랩하려면 특별한 세션 토큰이 필요한데 본 앱을 이 토큰을 받을 수 없습니다. 깃허브 API의 한계이므로 API문의는 깃허브에게 해주세요. 본 앱의 개발자는 API문의를 받지 않습니다.
• 제가 엔터프라이즈 계정으로 로그인했는데 Enterprise GitHub 외의 다른 것들은 볼 수 없나요?
\n
- 결론부터 말하자면 불가능합니다. 본 앱은 여러분이 다른 것들을 볼 수 있게 해 주고 있지만, 기술적 한계로 크게 도움을 드릴 수는 없습니다. 대부분의 경우에는 여러분의 로그인 계정이 깃허브 서버에 상주하고 있기 때문입니다. 그러나 소수/b>의 경우에는 여러분의 OAuth 토큰이 다른 활동을 하게 해 줄 수 있습니다.
- • Why am I having problems editing Issues/PRs?
- If you are editing a public Org repo, then please contact your Org to grant access to FastHub or use Access Token to login!.
- • I\'m having this issue or I want this & that!!
- Head to https://github.com/k0shk0sh/FastHub/issues/new and create new issue for bugs or feature requests, I really do encourage you to
- search before opening a ticket. Any duplicate request will result in it being closed immediately.
- • How do I get PROMO CODE?
- If you are a student, you\'ll have to provide me via Email that you are student, you will need below documents:
+ 결론부터 말하자면 불가능합니다. 본 앱은 여러분이 다른 것들을 볼 수 있게 해 주고 있지만, 기술적 한계로 크게 도움을 드릴 수는 없습니다. 대부분의 경우에는 여러분의 로그인 계정이 깃허브 서버에 상주하고 있기 때문입니다. 그러나 소수/b>의 경우에는 여러분의 OAuth 토큰이 다른 활동을 하게 해 줄 수 있습니다.
\n
+ • Issues/PR 를 수정 하는데 문제가 있습니다.
+ 공개 Organization 리포지토리를 수정하면, 여러분의 Organization에게 문의하여 Fasthub 권환을 받거나 최초 로그인시 엑세스 토큰으로 로그인하세요.
\n
+ • 앱을 사용하는데 문제를 발견했어요! / 혹시 이러한 기능을 추가해주실 수 있나요?
+ 그럼요! https://github.com/k0shk0sh/FastHub/issues/new 로 간 후 새로운 티켓을 만드세요. 티켓을 만들기 전 먼저 전에 있었던 티켓 중 중복되는 것이 없는지 검색해 주세요. 중복시 티켓은 바로 Close됩니다.
\n
+ • PROMO CODE는 어떻게 받나요?
+ 학생이신가요? 자신이 학생이라는 증명 서류가 필요합니다 :
- - Your university identity card & your identity card (that shows your name & your face to compare it!)
- - Your university start & end date
+ - 자신의 대학(학교) 학생증 & 신분증 복사본 (이름 및 얼굴 대조를 위한 것 입니다. 관련 서류는 인증 후 폐기됩니다.)
+ - 자신의 대학(학교)의 시작일 및 졸업일
- Rate FastHub in the Play Store
- If you aren\'t a student and you can\'t afford to pay for PRO, you\'ll need:
+ 자신의 학생이 아니지만 PRO를 구매하실 수 없다구요?
- - Write an article about FastHub in social media such as (Medium)
+ - SNS에 Fasthub에 대한해 추천 글 및 평가를 올려주세요.
- Rate FastHub in the Play Store
- 본 한국어 번역자는 이 앱의 개발에 참여하지 않았습니다. 따라서 기술적 문의는 이 앱의 개발자인 Kosh Sergani에게 해주시기 바랍니다. 본 번역이 앱 사용에 도움이 되셨기를 바랍니다. 감사합니다.
-
+ 위 조건을 만족시킨 후 본 앱의 개발자인 Kosh Sergani에게 이메일을 보내면 검토후 PROMO CODE를 보내 드립니다.
\n
+ 본 한국어 번역자는 이 앱의 개발에 참여하지 않았습니다. 따라서 기술적 문의는 이 앱의 개발자인 Kosh Sergani에게 해주시기 바랍니다. 본 번역이 앱 사용에 도움이 되셨기를 바랍니다. 감사합니다.
From 8bf4482018da9702261e88c48d5e7bee62c309f7 Mon Sep 17 00:00:00 2001
From: cozyplanes
Date: Mon, 2 Oct 2017 14:35:46 +0900
Subject: [PATCH 23/36] Update strings.xml
---
app/src/main/res/values-ko/strings.xml | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml
index 57503b5cd..3ad77dc4f 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -439,9 +439,9 @@
• 왜 Private 이나 Public으로 되어진 제 Organizations 을 볼 수 없나요?
- Open up https://github.com/settings/applications 를 열고 Fasthub라는 것을 찾아보세요. 그것을 열고, Organization access 부분에서 Grant를 눌러주세요. 또는 초기 로그인시 엑세스 토큰 으로 로그인하면 편리합니다.
\n
- • Access Token & OTP 으로 로그인을 시도했는데 로그인이 되질 않아요...
- OTP는 일회용 코드입니다. 따리서 유효기간에 인해 엑세스 토큰 + OTP로 로그인이 불가합니다. 이렇게 로그인을 하게 되면 몇 초에 한 번씩 앱이 로그인을 하라고 합니다. 다른 방법을 사용해 주세요.
+ Open up https://github.com/settings/applications 를 열고 Fasthub라는 것을 찾아보세요. 그것을 선택한 후, Organization Access 부분에서 Grant를 눌러주세요. 또는 초기 로그인시 엑세스 토큰 으로 로그인하면 편리합니다.
\n
+ • Access Token 과 OTP 으로 로그인을 시도했는데 로그인이 되질 않아요...
+ OTP는 일회용 코드입니다. 따리서 유효기간에 인해 엑세스 토큰 + OTP로 로그인이 불가합니다. 이렇게 로그인을 하게 되면 몇 초에 한 번씩 앱이 로그인을 하라고 합니다. 다른 방법을 사용해 주세요.
\n
• 제 비공개 리포지토리와 엔터프라이즈 위키가 보이질 않아요!
위 두 정보를 스크랩하려면 특별한 세션 토큰이 필요한데 본 앱을 이 토큰을 받을 수 없습니다. 깃허브 API의 한계이므로 API문의는 깃허브에게 해주세요. 본 앱의 개발자는 API문의를 받지 않습니다.
• 제가 엔터프라이즈 계정으로 로그인했는데 Enterprise GitHub 외의 다른 것들은 볼 수 없나요?
\n
@@ -449,17 +449,14 @@
• Issues/PR 를 수정 하는데 문제가 있습니다.
공개 Organization 리포지토리를 수정하면, 여러분의 Organization에게 문의하여 Fasthub 권환을 받거나 최초 로그인시 엑세스 토큰으로 로그인하세요.
\n
• 앱을 사용하는데 문제를 발견했어요! / 혹시 이러한 기능을 추가해주실 수 있나요?
- 그럼요! https://github.com/k0shk0sh/FastHub/issues/new 로 간 후 새로운 티켓을 만드세요. 티켓을 만들기 전 먼저 전에 있었던 티켓 중 중복되는 것이 없는지 검색해 주세요. 중복시 티켓은 바로 Close됩니다.
\n
+ 그럼요! https://github.com/k0shk0sh/FastHub/issues/new 로 간 후 새로운 티켓을 만드세요. 티켓을 만들기 전 먼저 전에 있었던 티켓 중 중복되는 것이 없는지 검색해 주세요. 중복시 티켓은 바로 닫힙니다.
\n
• PROMO CODE는 어떻게 받나요?
- 학생이신가요? 자신이 학생이라는 증명 서류가 필요합니다 :
-
- - 자신의 대학(학교) 학생증 & 신분증 복사본 (이름 및 얼굴 대조를 위한 것 입니다. 관련 서류는 인증 후 폐기됩니다.)
+ - 학생이시면 자신의 대학(학교) 학생증 & 신분증 복사본이 필요합니다. (이름 및 얼굴 대조를 위한 것 입니다. 관련 서류는 인증 후 폐기됩니다.)
- 자신의 대학(학교)의 시작일 및 졸업일
- Rate FastHub in the Play Store
- 자신의 학생이 아니지만 PRO를 구매하실 수 없다구요?
- - SNS에 Fasthub에 대한해 추천 글 및 평가를 올려주세요.
+ - 학생이 아니지만 PRO버전을 구매하실 수 없다면 SNS에 Fasthub에 대한 추천 글 및 평가를 올려주세요.
- Rate FastHub in the Play Store
위 조건을 만족시킨 후 본 앱의 개발자인 Kosh Sergani에게 이메일을 보내면 검토후 PROMO CODE를 보내 드립니다.
\n
From 691f4f23ebb1f308ba2713576db53504ebf1795e Mon Sep 17 00:00:00 2001
From: cozyplanes
Date: Mon, 2 Oct 2017 15:58:27 +0900
Subject: [PATCH 24/36] Update strings.xml
---
app/src/main/res/values-ko/strings.xml | 25 ++++++++++++++-----------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml
index 3ad77dc4f..2af1254df 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -439,26 +439,29 @@
• 왜 Private 이나 Public으로 되어진 제 Organizations 을 볼 수 없나요?
- Open up https://github.com/settings/applications 를 열고 Fasthub라는 것을 찾아보세요. 그것을 선택한 후, Organization Access 부분에서 Grant를 눌러주세요. 또는 초기 로그인시 엑세스 토큰 으로 로그인하면 편리합니다.
\n
+ Open up https://github.com/settings/applications 를 열고 Fasthub라는 것을 찾아보세요. 그것을 선택한 후, Organization Access 부분에서 Grant를 눌러주세요. 또는 초기 로그인시 엑세스 토큰 으로 로그인하면 편리합니다.
• Access Token 과 OTP 으로 로그인을 시도했는데 로그인이 되질 않아요...
- OTP는 일회용 코드입니다. 따리서 유효기간에 인해 엑세스 토큰 + OTP로 로그인이 불가합니다. 이렇게 로그인을 하게 되면 몇 초에 한 번씩 앱이 로그인을 하라고 합니다. 다른 방법을 사용해 주세요.
\n
+ OTP는 일회용 코드입니다. 따리서 유효기간에 인해 엑세스 토큰 + OTP로 로그인이 불가합니다. 이렇게 로그인을 하게 되면 몇 초에 한 번씩 앱이 로그인을 하라고 합니다. 다른 방법을 사용해 주세요.
• 제 비공개 리포지토리와 엔터프라이즈 위키가 보이질 않아요!
위 두 정보를 스크랩하려면 특별한 세션 토큰이 필요한데 본 앱을 이 토큰을 받을 수 없습니다. 깃허브 API의 한계이므로 API문의는 깃허브에게 해주세요. 본 앱의 개발자는 API문의를 받지 않습니다.
- • 제가 엔터프라이즈 계정으로 로그인했는데 Enterprise GitHub 외의 다른 것들은 볼 수 없나요?
\n
- 결론부터 말하자면 불가능합니다. 본 앱은 여러분이 다른 것들을 볼 수 있게 해 주고 있지만, 기술적 한계로 크게 도움을 드릴 수는 없습니다. 대부분의 경우에는 여러분의 로그인 계정이 깃허브 서버에 상주하고 있기 때문입니다. 그러나 소수/b>의 경우에는 여러분의 OAuth 토큰이 다른 활동을 하게 해 줄 수 있습니다.
\n
+ • 제가 엔터프라이즈 계정으로 로그인했는데 Enterprise GitHub 외의 다른 것들은 볼 수 없나요?
+ 결론부터 말하자면 불가능합니다. 본 앱은 여러분이 다른 것들을 볼 수 있게 해 주고 있지만, 기술적 한계로 크게 도움을 드릴 수는 없습니다. 대부분의 경우에는 여러분의 로그인 계정이 깃허브 서버에 상주하고 있기 때문입니다. 그러나 소수/b>의 경우에는 여러분의 OAuth 토큰이 다른 활동을 하게 해 줄 수 있습니다.
• Issues/PR 를 수정 하는데 문제가 있습니다.
- 공개 Organization 리포지토리를 수정하면, 여러분의 Organization에게 문의하여 Fasthub 권환을 받거나 최초 로그인시 엑세스 토큰으로 로그인하세요.
\n
+ 공개 Organization 리포지토리를 수정하면, 여러분의 Organization에게 문의하여 Fasthub 권환을 받거나 최초 로그인시 엑세스 토큰으로 로그인하세요.
• 앱을 사용하는데 문제를 발견했어요! / 혹시 이러한 기능을 추가해주실 수 있나요?
- 그럼요! https://github.com/k0shk0sh/FastHub/issues/new 로 간 후 새로운 티켓을 만드세요. 티켓을 만들기 전 먼저 전에 있었던 티켓 중 중복되는 것이 없는지 검색해 주세요. 중복시 티켓은 바로 닫힙니다.
\n
+ 그럼요! https://github.com/k0shk0sh/FastHub/issues/new 로 간 후 새로운 티켓을 만드세요. 티켓을 만들기 전 먼저 전에 있었던 티켓 중 중복되는 것이 없는지 검색해 주세요. 중복시 티켓은 바로 닫힙니다.
• PROMO CODE는 어떻게 받나요?
- 학생이시면 자신의 대학(학교) 학생증 & 신분증 복사본이 필요합니다. (이름 및 얼굴 대조를 위한 것 입니다. 관련 서류는 인증 후 폐기됩니다.)
+ 학생인 경우:
+ 자신의 대학(학교) 학생증 & 신분증 복사본 (이름 및 얼굴 대조를 위한 것 입니다. 관련 서류는 인증 후 폐기됩니다.)
자신의 대학(학교)의 시작일 및 졸업일
- Rate FastHub in the Play Store
+ 플레이 스토어에서 FastHub 별점 매기기
위 조건을 만족시킨 후 본 앱의 개발자인 Kosh Sergani에게 이메일을 보내면 검토후 PROMO CODE를 보내 드립니다.
\n
- 본 한국어 번역자는 이 앱의 개발에 참여하지 않았습니다. 따라서 기술적 문의는 이 앱의 개발자인 Kosh Sergani에게 해주시기 바랍니다. 본 번역이 앱 사용에 도움이 되셨기를 바랍니다. 감사합니다.
+ 본 한국어 번역자는 이 앱의 개발에 참여하지 않았습니다. 따라서 기술적 문의는 이 앱의 개발자인 Kosh Sergani에게 해주시기 바랍니다. 본 번역이 앱 사용에 도움이 되셨기를 바랍니다. 감사합니다.
+ ]]>
From a9ea6a4bb21ed4d689d321041791864b98780e5f Mon Sep 17 00:00:00 2001
From: cozyplanes
Date: Mon, 2 Oct 2017 16:01:34 +0900
Subject: [PATCH 25/36] Possible newline typo
Possible newline typo, not sure
---
app/src/main/res/values/strings.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 1a5c453ff..ee862b9c8 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -581,7 +581,7 @@
• Why are my Private Repo & Enterprise Wiki not showing up?
It\'s due to FastHub scraping GitHub Wiki page & Private Repos require session token that FastHub is unable to obtain.
- • I login with Enterprise account but can\'t interact with anything other than my Enterprise GitHub?
\n
+ • I login with Enterprise account but can\'t interact with anything other than my Enterprise GitHub?
Well, logically, you can\'t access anything else other than your Enterprise. FastHub tries to allow as much possible, but can\'t do much about it
in most cases, since your login credential doesn\'t exists in GitHub server. But in a few
cases your GitHub account Oauth token will do the trick.
From 2302f02396c5a173b223dec36e0888d97720bf9b Mon Sep 17 00:00:00 2001
From: k0shk0sh
Date: Tue, 3 Oct 2017 06:50:35 +0200
Subject: [PATCH 26/36] this commit fixes #657
---
.../fastaccess/data/dao/CreateIssueModel.java | 13 +-
.../create/MilestoneDialogFragment.java | 11 +-
.../issues/create/CreateIssueActivity.java | 117 +++++++++++++-
.../repos/issues/create/CreateIssueMvp.java | 22 ++-
.../issues/create/CreateIssuePresenter.java | 77 ++++++++-
.../layout/create_issue_layout.xml | 150 +++++++++++++++++-
.../layout/issue_popup_layout.xml | 4 +-
7 files changed, 377 insertions(+), 17 deletions(-)
diff --git a/app/src/main/java/com/fastaccess/data/dao/CreateIssueModel.java b/app/src/main/java/com/fastaccess/data/dao/CreateIssueModel.java
index d1f82c123..97fddc879 100644
--- a/app/src/main/java/com/fastaccess/data/dao/CreateIssueModel.java
+++ b/app/src/main/java/com/fastaccess/data/dao/CreateIssueModel.java
@@ -3,6 +3,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.ArrayList;
+
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@@ -15,17 +17,26 @@
public class CreateIssueModel implements Parcelable {
private String title;
private String body;
+ private ArrayList labels;
+ private ArrayList assignees;
+ private MilestoneModel milestone;
@Override public int describeContents() { return 0; }
@Override public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.title);
dest.writeString(this.body);
+ dest.writeStringList(this.labels);
+ dest.writeStringList(this.assignees);
+ dest.writeParcelable(this.milestone, flags);
}
- @SuppressWarnings("WeakerAccess") protected CreateIssueModel(Parcel in) {
+ protected CreateIssueModel(Parcel in) {
this.title = in.readString();
this.body = in.readString();
+ this.labels = in.createStringArrayList();
+ this.assignees = in.createStringArrayList();
+ this.milestone = in.readParcelable(MilestoneModel.class.getClassLoader());
}
public static final Creator CREATOR = new Creator() {
diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/milestone/create/MilestoneDialogFragment.java b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/milestone/create/MilestoneDialogFragment.java
index 7d2a8fbcd..05afccb92 100644
--- a/app/src/main/java/com/fastaccess/ui/modules/repos/extras/milestone/create/MilestoneDialogFragment.java
+++ b/app/src/main/java/com/fastaccess/ui/modules/repos/extras/milestone/create/MilestoneDialogFragment.java
@@ -26,6 +26,7 @@ public class MilestoneDialogFragment extends BaseDialogFragment implements Miles
private IssuePagerMvp.View issueCallback;
private PullRequestPagerMvp.View pullRequestCallback;
+ private MilestoneMvp.OnMilestoneSelected milestoneCallback;
public static MilestoneDialogFragment newInstance(@NonNull String login, @NonNull String repo) {
MilestoneDialogFragment view = new MilestoneDialogFragment();
@@ -48,6 +49,12 @@ public static MilestoneDialogFragment newInstance(@NonNull String login, @NonNul
} else if (getParentFragment() instanceof PullRequestPagerMvp.View) {
pullRequestCallback = (PullRequestPagerMvp.View) getParentFragment();
}
+
+ if (context instanceof MilestoneMvp.OnMilestoneSelected) {
+ milestoneCallback = (MilestoneMvp.OnMilestoneSelected) context;
+ } else if (getParentFragment() instanceof MilestoneMvp.OnMilestoneSelected) {
+ milestoneCallback = (MilestoneMvp.OnMilestoneSelected) getParentFragment();
+ }
}
@Override public void onDetach() {
@@ -65,7 +72,8 @@ public static MilestoneDialogFragment newInstance(@NonNull String login, @NonNul
@Override protected void onFragmentCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
if (savedInstanceState == null) {
Bundle bundle = getArguments();
- com.fastaccess.ui.modules.repos.extras.milestone.MilestoneDialogFragment milestoneView = new com.fastaccess.ui.modules.repos.extras.milestone.MilestoneDialogFragment();
+ com.fastaccess.ui.modules.repos.extras.milestone.MilestoneDialogFragment milestoneView = new com.fastaccess.ui.modules.repos.extras
+ .milestone.MilestoneDialogFragment();
milestoneView.setArguments(bundle);
getChildFragmentManager()
.beginTransaction()
@@ -77,5 +85,6 @@ public static MilestoneDialogFragment newInstance(@NonNull String login, @NonNul
@Override public void onMilestoneSelected(@NonNull MilestoneModel milestoneModel) {
if (issueCallback != null) issueCallback.onMileStoneSelected(milestoneModel);
if (pullRequestCallback != null) pullRequestCallback.onMileStoneSelected(milestoneModel);
+ if (milestoneCallback != null) milestoneCallback.onMilestoneSelected(milestoneModel);
}
}
diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/issues/create/CreateIssueActivity.java b/app/src/main/java/com/fastaccess/ui/modules/repos/issues/create/CreateIssueActivity.java
index 75f5de0da..8a82c4251 100644
--- a/app/src/main/java/com/fastaccess/ui/modules/repos/issues/create/CreateIssueActivity.java
+++ b/app/src/main/java/com/fastaccess/ui/modules/repos/issues/create/CreateIssueActivity.java
@@ -3,34 +3,49 @@
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
+import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.TextInputLayout;
+import android.support.transition.TransitionManager;
import android.support.v4.app.Fragment;
import android.support.v7.app.AlertDialog;
import android.view.MotionEvent;
import android.view.View;
+import android.widget.LinearLayout;
import com.danielstone.materialaboutlibrary.ConvenienceBuilder;
import com.evernote.android.state.State;
import com.fastaccess.App;
import com.fastaccess.BuildConfig;
import com.fastaccess.R;
+import com.fastaccess.data.dao.LabelListModel;
+import com.fastaccess.data.dao.LabelModel;
+import com.fastaccess.data.dao.MilestoneModel;
import com.fastaccess.data.dao.model.Issue;
import com.fastaccess.data.dao.model.PullRequest;
+import com.fastaccess.data.dao.model.User;
import com.fastaccess.helper.ActivityHelper;
import com.fastaccess.helper.AppHelper;
import com.fastaccess.helper.BundleConstant;
import com.fastaccess.helper.Bundler;
import com.fastaccess.helper.InputHelper;
+import com.fastaccess.helper.Logger;
import com.fastaccess.helper.ViewHelper;
import com.fastaccess.provider.markdown.MarkDownProvider;
import com.fastaccess.ui.base.BaseActivity;
import com.fastaccess.ui.modules.editor.EditorActivity;
+import com.fastaccess.ui.modules.repos.extras.assignees.AssigneesDialogFragment;
+import com.fastaccess.ui.modules.repos.extras.labels.LabelsDialogFragment;
+import com.fastaccess.ui.modules.repos.extras.milestone.create.MilestoneDialogFragment;
import com.fastaccess.ui.widgets.FontTextView;
+import com.fastaccess.ui.widgets.LabelSpan;
+import com.fastaccess.ui.widgets.SpannableBuilder;
import com.fastaccess.ui.widgets.dialog.MessageDialogView;
+import java.util.ArrayList;
+
import butterknife.BindView;
import butterknife.OnClick;
import butterknife.OnTouch;
@@ -45,11 +60,20 @@ public class CreateIssueActivity extends BaseActivity labelModels = new ArrayList<>();
+ @State MilestoneModel milestoneModel;
+ @State ArrayList users = new ArrayList<>();
private AlertDialog alertDialog;
private CharSequence savedText;
@@ -177,6 +201,12 @@ public static void startForResult(@NonNull Activity activity, @NonNull Intent in
finish();
}
+ @Override public void onShowIssueMisc() {
+ TransitionManager.beginDelayedTransition(findViewById(R.id.parent));
+ issueMiscLayout.setVisibility(getPresenter().isCollaborator() ? View.VISIBLE : View.GONE);
+ //TODO
+ }
+
@NonNull @Override public CreateIssuePresenter providePresenter() {
return new CreateIssuePresenter();
}
@@ -214,6 +244,17 @@ public static void startForResult(@NonNull Activity activity, @NonNull Intent in
}
}
if (issue != null) {
+ Logger.e(issue.getLabels(), issue.getMilestone(), issue.getAssignees());
+ if (issue.getLabels() != null) {
+ onSelectedLabels(new ArrayList<>(issue.getLabels()));
+ }
+ if (issue.getAssignees() != null) {
+ onSelectedAssignees(new ArrayList<>(issue.getAssignees()), false);
+ }
+ if (issue.getMilestone() != null) {
+ milestoneModel = issue.getMilestone();
+ onMilestoneSelected(milestoneModel);
+ }
if (!InputHelper.isEmpty(issue.getTitle())) {
if (title.getEditText() != null) title.getEditText().setText(issue.getTitle());
}
@@ -222,6 +263,17 @@ public static void startForResult(@NonNull Activity activity, @NonNull Intent in
}
}
if (pullRequest != null) {
+ if (pullRequest.getLabels() != null) {
+ onSelectedLabels(new ArrayList<>(pullRequest.getLabels()));
+ }
+ if (pullRequest.getAssignees() != null) {
+ users.addAll(pullRequest.getAssignees());
+ onSelectedAssignees(new ArrayList<>(pullRequest.getAssignees()), false);
+ }
+ if (pullRequest.getMilestone() != null) {
+ milestoneModel = pullRequest.getMilestone();
+ onMilestoneSelected(milestoneModel);
+ }
if (!InputHelper.isEmpty(pullRequest.getTitle())) {
if (title.getEditText() != null) title.getEditText().setText(pullRequest.getTitle());
}
@@ -230,6 +282,7 @@ public static void startForResult(@NonNull Activity activity, @NonNull Intent in
}
}
}
+ getPresenter().checkAuthority(login, repoId);
if (isFeedback || ("k0shk0sh".equalsIgnoreCase(login) && repoId.equalsIgnoreCase("FastHub"))) {
setTitle(R.string.submit_feedback);
getPresenter().onCheckAppVersion();
@@ -295,6 +348,68 @@ public static void startForResult(@NonNull Activity activity, @NonNull Intent in
}
@OnClick(R.id.submit) public void onClick() {
- getPresenter().onSubmit(InputHelper.toString(title), savedText, login, repoId, issue, pullRequest);
+ getPresenter().onSubmit(InputHelper.toString(title), savedText, login, repoId, issue, pullRequest, labelModels, milestoneModel, users);
+ }
+
+ @OnClick({R.id.addAssignee, R.id.addLabels, R.id.addMilestone}) public void onViewClicked(View view) {
+ switch (view.getId()) {
+ case R.id.addAssignee:
+ AssigneesDialogFragment.newInstance(login, repoId, false)
+ .show(getSupportFragmentManager(), "AssigneesDialogFragment");
+ break;
+ case R.id.addLabels:
+ LabelListModel labelModels = new LabelListModel();
+ labelModels.addAll(this.labelModels);
+ LabelsDialogFragment.newInstance(labelModels, repoId, login)
+ .show(getSupportFragmentManager(), "LabelsDialogFragment");
+ break;
+ case R.id.addMilestone:
+ MilestoneDialogFragment.newInstance(login, repoId)
+ .show(getSupportFragmentManager(), "MilestoneDialogFragment");
+ break;
+ }
+ }
+
+ @Override public void onSelectedLabels(@NonNull ArrayList labelModels) {
+ this.labelModels.clear();
+ this.labelModels.addAll(labelModels);
+ SpannableBuilder builder = SpannableBuilder.builder();
+ for (int i = 0; i < labelModels.size(); i++) {
+ LabelModel labelModel = labelModels.get(i);
+ int color = Color.parseColor("#" + labelModel.getColor());
+ if (i > 0) {
+ builder.append(" ").append(" " + labelModel.getName() + " ", new LabelSpan(color));
+ } else {
+ builder.append(labelModel.getName() + " ", new LabelSpan(color));
+ }
+ }
+ this.labels.setText(builder);
+ }
+
+ @Override public void onMilestoneSelected(@NonNull MilestoneModel milestoneModel) {
+ Logger.e(milestoneModel.getTitle(), milestoneModel.getDescription(), milestoneModel.getNumber());
+ this.milestoneModel = milestoneModel;
+ milestoneTitle.setText(milestoneModel.getTitle());
+ if (!InputHelper.isEmpty(milestoneModel.getDescription())) {
+ milestoneDescription.setText(milestoneModel.getDescription());
+ milestoneDescription.setVisibility(View.VISIBLE);
+ } else {
+ milestoneDescription.setText(null);
+ milestoneDescription.setVisibility(View.GONE);
+ }
+ }
+
+ @Override public void onSelectedAssignees(@NonNull ArrayList users, boolean isAssignees) {
+ this.users.clear();
+ this.users.addAll(users);
+ SpannableBuilder builder = SpannableBuilder.builder();
+ for (int i = 0; i < users.size(); i++) {
+ User user = users.get(i);
+ builder.append(user.getLogin());
+ if (i != users.size() - 1) {
+ builder.append(", ");
+ }
+ }
+ assignee.setText(builder);
}
}
diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/issues/create/CreateIssueMvp.java b/app/src/main/java/com/fastaccess/ui/modules/repos/issues/create/CreateIssueMvp.java
index 7fe572bec..7740da182 100644
--- a/app/src/main/java/com/fastaccess/ui/modules/repos/issues/create/CreateIssueMvp.java
+++ b/app/src/main/java/com/fastaccess/ui/modules/repos/issues/create/CreateIssueMvp.java
@@ -4,9 +4,17 @@
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import com.fastaccess.data.dao.LabelModel;
+import com.fastaccess.data.dao.MilestoneModel;
import com.fastaccess.data.dao.model.Issue;
import com.fastaccess.data.dao.model.PullRequest;
+import com.fastaccess.data.dao.model.User;
import com.fastaccess.ui.base.mvp.BaseMvp;
+import com.fastaccess.ui.modules.repos.extras.assignees.AssigneesMvp;
+import com.fastaccess.ui.modules.repos.extras.labels.LabelsMvp;
+import com.fastaccess.ui.modules.repos.extras.milestone.MilestoneMvp;
+
+import java.util.ArrayList;
/**
* Created by Kosh on 19 Feb 2017, 12:12 PM
@@ -14,7 +22,8 @@
public interface CreateIssueMvp {
- interface View extends BaseMvp.FAView {
+ interface View extends BaseMvp.FAView, LabelsMvp.SelectedLabelsListener, AssigneesMvp.SelectedAssigneesListener,
+ MilestoneMvp.OnMilestoneSelected {
void onSetCode(@NonNull CharSequence charSequence);
void onTitleError(boolean isEmptyTitle);
@@ -26,14 +35,23 @@ interface View extends BaseMvp.FAView {
void onSuccessSubmission(PullRequest issueModel);
void onShowUpdate();
+
+ void onShowIssueMisc();
}
interface Presenter extends BaseMvp.FAPresenter {
+
+ void checkAuthority(@NonNull String login, @NonNull String repoId);
+
void onActivityForResult(int resultCode, int requestCode, Intent intent);
void onSubmit(@NonNull String title, @NonNull CharSequence description, @NonNull String login,
- @NonNull String repo, @Nullable Issue issueModel, @Nullable PullRequest pullRequestModel);
+ @NonNull String repo, @Nullable Issue issueModel, @Nullable PullRequest pullRequestModel,
+ @Nullable ArrayList labels, @Nullable MilestoneModel milestoneModel,
+ @Nullable ArrayList users);
void onCheckAppVersion();
+
+ boolean isCollaborator();
}
}
diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/issues/create/CreateIssuePresenter.java b/app/src/main/java/com/fastaccess/ui/modules/repos/issues/create/CreateIssuePresenter.java
index 00d5989f6..a788b45d4 100644
--- a/app/src/main/java/com/fastaccess/ui/modules/repos/issues/create/CreateIssuePresenter.java
+++ b/app/src/main/java/com/fastaccess/ui/modules/repos/issues/create/CreateIssuePresenter.java
@@ -5,24 +5,47 @@
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import com.annimon.stream.Collectors;
+import com.annimon.stream.Stream;
import com.fastaccess.BuildConfig;
import com.fastaccess.R;
import com.fastaccess.data.dao.CreateIssueModel;
import com.fastaccess.data.dao.IssueRequestModel;
+import com.fastaccess.data.dao.LabelListModel;
+import com.fastaccess.data.dao.LabelModel;
+import com.fastaccess.data.dao.MilestoneModel;
+import com.fastaccess.data.dao.UsersListModel;
import com.fastaccess.data.dao.model.Issue;
+import com.fastaccess.data.dao.model.Login;
import com.fastaccess.data.dao.model.PullRequest;
+import com.fastaccess.data.dao.model.User;
import com.fastaccess.helper.BundleConstant;
import com.fastaccess.helper.InputHelper;
+import com.fastaccess.helper.RxHelper;
import com.fastaccess.provider.rest.RestProvider;
import com.fastaccess.ui.base.mvp.BaseMvp;
import com.fastaccess.ui.base.mvp.presenter.BasePresenter;
+import java.util.ArrayList;
+
/**
* Created by Kosh on 19 Feb 2017, 12:18 PM
*/
public class CreateIssuePresenter extends BasePresenter implements CreateIssueMvp.Presenter {
+ @com.evernote.android.state.State boolean isCollaborator;
+
+
+ @Override public void checkAuthority(@NonNull String login, @NonNull String repoId) {
+ manageViewDisposable(RxHelper.getObservable(RestProvider.getRepoService(isEnterprise()).
+ isCollaborator(login, repoId, Login.getUser().getLogin()))
+ .subscribe(booleanResponse -> {
+ isCollaborator = booleanResponse.code() == 204;
+ sendToView(CreateIssueMvp.View::onShowIssueMisc);
+ }, Throwable::printStackTrace));
+ }
+
@Override public void onActivityForResult(int resultCode, int requestCode, Intent intent) {
if (resultCode == Activity.RESULT_OK && requestCode == BundleConstant.REQUEST_CODE) {
if (intent != null && intent.getExtras() != null) {
@@ -34,9 +57,11 @@ public class CreateIssuePresenter extends BasePresenter imp
}
}
- @Override public void onSubmit(@NonNull String title, @NonNull CharSequence description,
- @NonNull String login, @NonNull String repo,
- @Nullable Issue issue, @Nullable PullRequest pullRequestModel) {
+ @Override public void onSubmit(@NonNull String title, @NonNull CharSequence description, @NonNull String login,
+ @NonNull String repo, @Nullable Issue issue, @Nullable PullRequest pullRequestModel,
+ @Nullable ArrayList labels, @Nullable MilestoneModel milestoneModel,
+ @Nullable ArrayList users) {
+
boolean isEmptyTitle = InputHelper.isEmpty(title);
if (getView() != null) {
getView().onTitleError(isEmptyTitle);
@@ -46,6 +71,17 @@ public class CreateIssuePresenter extends BasePresenter imp
CreateIssueModel createIssue = new CreateIssueModel();
createIssue.setBody(InputHelper.toString(description));
createIssue.setTitle(title);
+ if (isCollaborator) {
+ if (labels != null && !labels.isEmpty()) {
+ createIssue.setLabels(Stream.of(labels).map(LabelModel::getName).collect(Collectors.toCollection(ArrayList::new)));
+ }
+ if (users != null && !users.isEmpty()) {
+ createIssue.setAssignees(Stream.of(users).map(User::getLogin).collect(Collectors.toCollection(ArrayList::new)));
+ }
+ if (milestoneModel != null) {
+ createIssue.setMilestone(milestoneModel);
+ }
+ }
makeRestCall(RestProvider.getIssueService(isEnterprise()).createIssue(login, repo, createIssue),
issueModel -> {
if (issueModel != null) {
@@ -59,6 +95,21 @@ public class CreateIssuePresenter extends BasePresenter imp
issue.setBody(InputHelper.toString(description));
issue.setTitle(title);
int number = issue.getNumber();
+ if (isCollaborator) {
+ if (labels != null) {
+ LabelListModel labelModels = new LabelListModel();
+ labelModels.addAll(labels);
+ issue.setLabels(labelModels);
+ }
+ if (milestoneModel != null) {
+ issue.setMilestone(milestoneModel);
+ }
+ if (users != null) {
+ UsersListModel usersListModel = new UsersListModel();
+ usersListModel.addAll(users);
+ issue.setAssignees(usersListModel);
+ }
+ }
IssueRequestModel requestModel = IssueRequestModel.clone(issue, false);
makeRestCall(RestProvider.getIssueService(isEnterprise()).editIssue(login, repo, number, requestModel),
issueModel -> {
@@ -73,6 +124,21 @@ public class CreateIssuePresenter extends BasePresenter imp
int number = pullRequestModel.getNumber();
pullRequestModel.setBody(InputHelper.toString(description));
pullRequestModel.setTitle(title);
+ if (isCollaborator) {
+ if (labels != null) {
+ LabelListModel labelModels = new LabelListModel();
+ labelModels.addAll(labels);
+ pullRequestModel.setLabels(labelModels);
+ }
+ if (milestoneModel != null) {
+ pullRequestModel.setMilestone(milestoneModel);
+ }
+ if (users != null) {
+ UsersListModel usersListModel = new UsersListModel();
+ usersListModel.addAll(users);
+ pullRequestModel.setAssignees(usersListModel);
+ }
+ }
IssueRequestModel requestModel = IssueRequestModel.clone(pullRequestModel, false);
makeRestCall(RestProvider.getPullRequestService(isEnterprise()).editPullRequest(login, repo, number, requestModel)
.flatMap(pullRequest1 -> RestProvider.getIssueService(isEnterprise()).getIssue(login, repo, number),
@@ -91,6 +157,7 @@ public class CreateIssuePresenter extends BasePresenter imp
}
}
}
+
}
@Override public void onCheckAppVersion() {
@@ -105,4 +172,8 @@ public class CreateIssuePresenter extends BasePresenter imp
}
}, false);
}
+
+ @Override public boolean isCollaborator() {
+ return isCollaborator;
+ }
}
diff --git a/app/src/main/res/layouts/main_layouts/layout/create_issue_layout.xml b/app/src/main/res/layouts/main_layouts/layout/create_issue_layout.xml
index 21cb1d0bc..fc09b8e39 100644
--- a/app/src/main/res/layouts/main_layouts/layout/create_issue_layout.xml
+++ b/app/src/main/res/layouts/main_layouts/layout/create_issue_layout.xml
@@ -1,7 +1,9 @@
-
+ android:orientation="vertical"
+ android:visibility="gone"
+ tools:visibility="visible">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layouts/main_layouts/layout/issue_popup_layout.xml b/app/src/main/res/layouts/main_layouts/layout/issue_popup_layout.xml
index 09ebef370..94eba3c58 100644
--- a/app/src/main/res/layouts/main_layouts/layout/issue_popup_layout.xml
+++ b/app/src/main/res/layouts/main_layouts/layout/issue_popup_layout.xml
@@ -193,8 +193,6 @@
style="@style/TextAppearance.AppCompat.Medium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingBottom="@dimen/spacing_normal"
- android:paddingTop="@dimen/spacing_normal"
tools:text="Label 1"/>
From b4ea0d2f5138301efce41037dec2fd72cb2547e4 Mon Sep 17 00:00:00 2001
From: k0shk0sh
Date: Tue, 3 Oct 2017 11:29:57 +0200
Subject: [PATCH 27/36] made promo codes more easier to handle
---
.../fastaccess/data/dao/ProUsersModel.java | 56 +++++++++++++++++++
.../main/premium/GmsTaskListeners.java | 48 ++++++++++++++++
.../modules/main/premium/PremiumPresenter.kt | 44 ++++++++++-----
3 files changed, 133 insertions(+), 15 deletions(-)
create mode 100644 app/src/main/java/com/fastaccess/data/dao/ProUsersModel.java
create mode 100644 app/src/main/java/com/fastaccess/ui/modules/main/premium/GmsTaskListeners.java
diff --git a/app/src/main/java/com/fastaccess/data/dao/ProUsersModel.java b/app/src/main/java/com/fastaccess/data/dao/ProUsersModel.java
new file mode 100644
index 000000000..b6be38500
--- /dev/null
+++ b/app/src/main/java/com/fastaccess/data/dao/ProUsersModel.java
@@ -0,0 +1,56 @@
+package com.fastaccess.data.dao;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Created by Hashemsergani on 03.10.17.
+ */
+
+public class ProUsersModel implements Parcelable {
+ private int count;
+ private boolean allowed;
+ private int type;
+
+ public int getCount() { return count;}
+
+ public void setCount(int count) { this.count = count;}
+
+ public boolean isAllowed() { return allowed;}
+
+ public void setAllowed(boolean allowed) { this.allowed = allowed;}
+
+ public int getType() { return type;}
+
+ public void setType(int type) { this.type = type;}
+
+ @Override public String toString() {
+ return "ProUsersModel{" +
+ ", count=" + count +
+ ", allowed=" + allowed +
+ ", type=" + type +
+ '}';
+ }
+
+ public ProUsersModel() {}
+
+ @Override public int describeContents() { return 0; }
+
+ @Override public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(this.count);
+ dest.writeByte(this.allowed ? (byte) 1 : (byte) 0);
+ dest.writeInt(this.type);
+ }
+
+ protected ProUsersModel(Parcel in) {
+ this.count = in.readInt();
+ this.allowed = in.readByte() != 0;
+ this.type = in.readInt();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override public ProUsersModel createFromParcel(Parcel source) {return new ProUsersModel(source);}
+
+ @Override public ProUsersModel[] newArray(int size) {return new ProUsersModel[size];}
+ };
+}
diff --git a/app/src/main/java/com/fastaccess/ui/modules/main/premium/GmsTaskListeners.java b/app/src/main/java/com/fastaccess/ui/modules/main/premium/GmsTaskListeners.java
new file mode 100644
index 000000000..e15fd70c5
--- /dev/null
+++ b/app/src/main/java/com/fastaccess/ui/modules/main/premium/GmsTaskListeners.java
@@ -0,0 +1,48 @@
+package com.github.b3er.rxfirebase.common;
+
+import android.support.annotation.NonNull;
+import com.google.android.gms.tasks.OnCompleteListener;
+import com.google.android.gms.tasks.Task;
+import io.reactivex.CompletableEmitter;
+import io.reactivex.SingleEmitter;
+
+public final class GmsTaskListeners {
+
+ private GmsTaskListeners() {
+ throw new AssertionError("No instances");
+ }
+
+ public static OnCompleteListener listener(@NonNull final SingleEmitter emitter) {
+ return new OnCompleteListener() {
+ @Override public void onComplete(@NonNull Task task) {
+ if (!task.isSuccessful()) {
+ if (!emitter.isDisposed()) {
+ emitter.onError(task.getException());
+ }
+ return;
+ }
+
+ if (!emitter.isDisposed()) {
+ emitter.onSuccess(task.getResult());
+ }
+ }
+ };
+ }
+
+ public static OnCompleteListener listener(@NonNull final CompletableEmitter emitter) {
+ return new OnCompleteListener() {
+ @Override public void onComplete(@NonNull Task task) {
+ if (!task.isSuccessful()) {
+ if (!emitter.isDisposed()) {
+ emitter.onError(task.getException());
+ }
+ return;
+ }
+
+ if (!emitter.isDisposed()) {
+ emitter.onComplete();
+ }
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/fastaccess/ui/modules/main/premium/PremiumPresenter.kt b/app/src/main/java/com/fastaccess/ui/modules/main/premium/PremiumPresenter.kt
index ac73d355c..034deaeaf 100644
--- a/app/src/main/java/com/fastaccess/ui/modules/main/premium/PremiumPresenter.kt
+++ b/app/src/main/java/com/fastaccess/ui/modules/main/premium/PremiumPresenter.kt
@@ -1,9 +1,12 @@
package com.fastaccess.ui.modules.main.premium
+import com.fastaccess.data.dao.ProUsersModel
+import com.fastaccess.helper.Logger
import com.fastaccess.helper.PrefGetter
import com.fastaccess.helper.RxHelper
import com.fastaccess.ui.base.mvp.presenter.BasePresenter
import com.github.b3er.rxfirebase.database.data
+import com.github.b3er.rxfirebase.database.rxUpdateChildren
import com.google.firebase.database.FirebaseDatabase
import com.google.firebase.database.GenericTypeIndicator
import io.reactivex.Observable
@@ -15,32 +18,43 @@ import io.reactivex.Observable
class PremiumPresenter : BasePresenter(), PremiumMvp.Presenter {
override fun onCheckPromoCode(promo: String) {
val ref = FirebaseDatabase.getInstance().reference
- manageDisposable(RxHelper.getObservable(ref.child("promoCodes")
+ manageDisposable(RxHelper.getObservable(ref.child("fasthub_pro").child(promo)
.data()
.toObservable())
.doOnSubscribe { sendToView { it.showProgress(0) } }
.flatMap {
- var exists: Boolean? = false
+ var user = ProUsersModel()
+ Logger.e(it.exists(), it.hasChildren(), it.value)
if (it.exists()) {
- val gti = object : GenericTypeIndicator>() {}
- val map = it.getValue(gti)
- exists = map?.contains(promo)
- }
- return@flatMap Observable.just(exists)
- }
- .doOnComplete { sendToView { it.hideProgress() } }
- .subscribe({
- when (it) {
- true -> sendToView {
- if (promo.contains("student")) {
+ val gti = object : GenericTypeIndicator() {}
+ user = it.getValue(gti) ?: ProUsersModel()
+ Logger.e(user)
+ if (user.isAllowed) {
+ if (user.type == 1) {
PrefGetter.setProItems()
+ user.isAllowed = false
+ user.count = user.count + 1
+ return@flatMap ref.child("fasthub_pro").rxUpdateChildren(hashMapOf(Pair(promo, user)))
+ .toObservable()
+ .map { true }
} else {
PrefGetter.setProItems()
PrefGetter.setEnterpriseItem()
+ user.count = user.count + 1
+ return@flatMap ref.child("fasthub_pro").rxUpdateChildren(hashMapOf(Pair(promo, user)))
+ .toObservable()
+ .map { true }
}
- it.onSuccessfullyActivated()
}
- else -> sendToView { it.onNoMatch() }
+ }
+ return@flatMap Observable.just(user.isAllowed)
+ }
+ .doOnComplete { sendToView { it.hideProgress() } }
+ .subscribe({
+ if (it) {
+ sendToView { it.onSuccessfullyActivated() }
+ } else {
+ sendToView { it.onNoMatch() }
}
}, ::println))
}
From 22828a8785e1d1be50b064ecb7737cf3a3fac7f6 Mon Sep 17 00:00:00 2001
From: k0shk0sh
Date: Tue, 3 Oct 2017 16:04:35 +0200
Subject: [PATCH 28/36] fixed milestone
---
.../main/java/com/fastaccess/data/dao/CreateIssueModel.java | 6 +++---
.../modules/repos/issues/create/CreateIssuePresenter.java | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/app/src/main/java/com/fastaccess/data/dao/CreateIssueModel.java b/app/src/main/java/com/fastaccess/data/dao/CreateIssueModel.java
index 97fddc879..aee571f83 100644
--- a/app/src/main/java/com/fastaccess/data/dao/CreateIssueModel.java
+++ b/app/src/main/java/com/fastaccess/data/dao/CreateIssueModel.java
@@ -19,7 +19,7 @@ public class CreateIssueModel implements Parcelable {
private String body;
private ArrayList labels;
private ArrayList assignees;
- private MilestoneModel milestone;
+ private long milestone;
@Override public int describeContents() { return 0; }
@@ -28,7 +28,7 @@ public class CreateIssueModel implements Parcelable {
dest.writeString(this.body);
dest.writeStringList(this.labels);
dest.writeStringList(this.assignees);
- dest.writeParcelable(this.milestone, flags);
+ dest.writeLong(this.milestone);
}
protected CreateIssueModel(Parcel in) {
@@ -36,7 +36,7 @@ protected CreateIssueModel(Parcel in) {
this.body = in.readString();
this.labels = in.createStringArrayList();
this.assignees = in.createStringArrayList();
- this.milestone = in.readParcelable(MilestoneModel.class.getClassLoader());
+ this.milestone = in.readLong();
}
public static final Creator CREATOR = new Creator() {
diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/issues/create/CreateIssuePresenter.java b/app/src/main/java/com/fastaccess/ui/modules/repos/issues/create/CreateIssuePresenter.java
index a788b45d4..79314186b 100644
--- a/app/src/main/java/com/fastaccess/ui/modules/repos/issues/create/CreateIssuePresenter.java
+++ b/app/src/main/java/com/fastaccess/ui/modules/repos/issues/create/CreateIssuePresenter.java
@@ -79,7 +79,7 @@ public class CreateIssuePresenter extends BasePresenter imp
createIssue.setAssignees(Stream.of(users).map(User::getLogin).collect(Collectors.toCollection(ArrayList::new)));
}
if (milestoneModel != null) {
- createIssue.setMilestone(milestoneModel);
+ createIssue.setMilestone(milestoneModel.getNumber());
}
}
makeRestCall(RestProvider.getIssueService(isEnterprise()).createIssue(login, repo, createIssue),
From 5c4bf2dce60ded169689a3e25e9784c215cb9591 Mon Sep 17 00:00:00 2001
From: k0shk0sh
Date: Tue, 3 Oct 2017 16:32:50 +0200
Subject: [PATCH 29/36] this commit fixes #1067 and readying to release 4.4.1
---
app/build.gradle | 4 ++--
.../fastaccess/provider/markdown/MarkDownProvider.java | 5 +++--
.../com/fastaccess/ui/widgets/markdown/MarkDownLayout.kt | 2 +-
app/src/main/res/raw/changelog.html | 8 +++++---
4 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index 0b373ce27..c20628ef9 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -29,8 +29,8 @@ android {
applicationId "com.fastaccess.github"
minSdkVersion 21
targetSdkVersion 26
- versionCode 440
- versionName "4.4.0"
+ versionCode 441
+ versionName "4.4.1"
buildConfigString "GITHUB_CLIENT_ID", (buildProperties.secrets['github_client_id'] | buildProperties.notThere['github_client_id']).string
buildConfigString "GITHUB_SECRET", (buildProperties.secrets['github_secret'] | buildProperties.notThere['github_secret']).string
buildConfigString "IMGUR_CLIENT_ID", (buildProperties.secrets['imgur_client_id'] | buildProperties.notThere['imgur_client_id']).string
diff --git a/app/src/main/java/com/fastaccess/provider/markdown/MarkDownProvider.java b/app/src/main/java/com/fastaccess/provider/markdown/MarkDownProvider.java
index 4a7efc615..290149bbb 100644
--- a/app/src/main/java/com/fastaccess/provider/markdown/MarkDownProvider.java
+++ b/app/src/main/java/com/fastaccess/provider/markdown/MarkDownProvider.java
@@ -314,11 +314,12 @@ public static void insertAtCursor(@NonNull EditText editText, @NonNull String te
String oriContent = editText.getText().toString();
int start = editText.getSelectionStart();
int end = editText.getSelectionEnd();
- int index = start >= 0 ? start : 0;
Logger.e(start, end);
- if (start >= 0 && end > 0) {
+ if (start >= 0 && end > 0 && start != end) {
editText.setText(editText.getText().replace(start, end, text));
} else {
+ int index = editText.getSelectionStart() >= 0 ? editText.getSelectionStart() : 0;
+ Logger.e(start, end, index);
StringBuilder builder = new StringBuilder(oriContent);
builder.insert(index, text);
editText.setText(builder.toString());
diff --git a/app/src/main/java/com/fastaccess/ui/widgets/markdown/MarkDownLayout.kt b/app/src/main/java/com/fastaccess/ui/widgets/markdown/MarkDownLayout.kt
index 9074e878c..835e35794 100644
--- a/app/src/main/java/com/fastaccess/ui/widgets/markdown/MarkDownLayout.kt
+++ b/app/src/main/java/com/fastaccess/ui/widgets/markdown/MarkDownLayout.kt
@@ -162,7 +162,7 @@ class MarkDownLayout : LinearLayout {
}
}
- fun getSelectedText(): String? {
+ private fun getSelectedText(): String? {
markdownListener?.getEditText()?.let {
if (!it.text.toString().isBlank()) {
val selectionStart = it.selectionStart
diff --git a/app/src/main/res/raw/changelog.html b/app/src/main/res/raw/changelog.html
index 14695aae0..bb2d14077 100644
--- a/app/src/main/res/raw/changelog.html
+++ b/app/src/main/res/raw/changelog.html
@@ -8,16 +8,18 @@
FastHub changelog
- Version 4.4.0 (Org Project Columns and Cards)
+ Version 4.4.1 (Org Project Columns and Cards)
Please report the issues in FastHub repo instead, by opening the Drawer Menu and clicking on “Report an Issue”
PLEASE USE IT.
- Bugs , Enhancements & new Features (4.4.0)
+ Bugs , Enhancements & new Features (4.4.1)
+ - (New 4.4.1) Add Labels, Assignees & Milestone when creating/editing Issue
+ - (New) Improvements to handle Students PRO.
- (New) Org Project Columns & Cards (Edit, Create & Delete)
- (New) Displaying Labels under Issue/Pr description.
- (Enhancement) Removal of PR review limit.
@@ -25,7 +27,7 @@ Bugs , Enhancements &
- (Enhancement) Removed Loading background.
- (Enhancement) More markdown enhancement.
- (Fix) Lots of bug fixes.
- - There are more stuff are not mentioned, find them out :stuck_out_tongue:
+ - There are more stuff are not mentioned, find them out ;).
What left in FastHub?
From bc91df1470311ac3532c2fa1935bf131ffa44b8a Mon Sep 17 00:00:00 2001
From: cozyplanes
Date: Wed, 4 Oct 2017 00:55:41 +0900
Subject: [PATCH 30/36] Update README.md (#1060)
* Update README.md
---
README.md | 28 +++++++++++++++++++++-------
1 file changed, 21 insertions(+), 7 deletions(-)
diff --git a/README.md b/README.md
index cd288188b..0cc324982 100644
--- a/README.md
+++ b/README.md
@@ -27,7 +27,7 @@ Yet another **open-source** GitHub client app but unlike any other app, FastHub
- Offline-mode
- Markdown and code highlighting support
- Notifications overview and "Mark all as read"
- - Search users/orgs, repos, issues/prs & code.
+ - Search Users/Orgs, Repos, Issues/PRs & Code.
- FastHub & GitHub Pinned Repos
- Trending
- Wiki
@@ -115,6 +115,7 @@ Read the [**contribution guide**](.github/CONTRIBUTING.md) for more detailed inf
Thanks for those who contributed to FastHub by adding their language
+
- Chinese (Simplified) @Devifish
- Chinese (Traditional) @maple3142
- German @failex234
@@ -128,6 +129,7 @@ Read the [**contribution guide**](.github/CONTRIBUTING.md) for more detailed inf
- Czech @hejsekvojtech
- Spanish @alete89
- French @ptt-homme
+ - Korean @Astro36
@cozyplanes
## FAQ
@@ -139,21 +141,33 @@ Read the [**contribution guide**](.github/CONTRIBUTING.md) for more detailed inf
- I tried to login via Access Token & OTP but it does not work?
+ I tried to login via Access Token & OTP but why isn't it working?
You can't login via Access Token & OTP all together due to the lifetime of the OTP code, you'll be required to login in every few seconds.
- Why my Private Repo Wiki does not show up?
+ Why are my Private Repo and Enterprise Wiki not showing up?
It's due to FastHub scraping GitHub Wiki page & Private Repos require session token that FastHub doesn't have.
- I login with Enterprise account but can't interact with anything other than my Enterprise GitHub
- Well, logically, you can't access anything else other than your Enterprise, but FastHub made that possible but can't do much about it,
- in most cases since your login credential doesn't exists in GitHub server. But in few
- cases your GitHub account Oauth token will do the trick.
+ I login with Enterprise account but can't interact with anything other than my Enterprise GitHub.
+ Well, logically, you can't access anything else other than your Enterprise, but FastHub made that possible but can't do much about it, in most cases since your login credential doesn't exists in GitHub server. But in few cases your GitHub account Oauth token will do the trick.
+
+
+
+ Why am I having problems editing Issues/PRs?
+ If you are unable to edit an issue in a public organization, please contact your Organization Admin to grant access to FastHub. Alternatively you can login using an Access Token with the correct permissions granted.
+
+
+ I'm having this issue! / I want this and that!
+ Head to https://github.com/k0shk0sh/FastHub/issues/new and create new issue for bugs or feature requests. I really encourage you to search before opening a ticket. Any duplicate request will result in it being closed immediately.
+
+
+
+ How do I get PROMO CODE?
+ Please refer to the in-app FAQ for details.
From b7090e5eb3176e5433a1eb77049d619c0f93dbc7 Mon Sep 17 00:00:00 2001
From: Apply55gx
Date: Wed, 4 Oct 2017 08:42:54 +0200
Subject: [PATCH 31/36] Added Fabric and Kotlin Link
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 0cc324982..2a0faf832 100644
--- a/README.md
+++ b/README.md
@@ -87,7 +87,7 @@ _Ads currently not available._
## Specs / Open-source libraries:
- Minimum **SDK 21**, _but AppCompat is used all the way ;-)_
-- **Kotlin** all new modules starting from 2.5.3 will be written in **#Kotlin**.
+- [**Kotlin**](https://github.com/JetBrains/kotlin) all new modules starting from 2.5.3 will be written in **#Kotlin**.
- **MVP**-architecture: [**ThirtyInch**](https://github.com/grandcentrix/ThirtyInch) because its ThirtyInch.
- [**RxJava2**](https://github.com/ReactiveX/RxJava) & [**RxAndroid**](https://github.com/ReactiveX/RxAndroid) for Retrofit & background threads
- [**Retrofit**](https://github.com/square/retrofit) for constructing the REST API
@@ -102,7 +102,7 @@ _Ads currently not available._
- [**Toasty**](https://github.com/GrenderG/Toasty) for displaying error/success messages
- [**ShapedImageView**](https://github.com/gavinliu/ShapedImageView) for round avatars
- [**Material-About-Library**](https://github.com/daniel-stoneuk/material-about-library) for the about screen
-- **Fabric** analytics & crash reporting.
+- [**Fabric**](https://fabric.io/kits/ios/crashlytics) analytics & crash reporting.
- **Android Support Libraries**, the almighty ;-)
## Contribution
From 559a2b813c40350aa7fd86c53081feaea4347d77 Mon Sep 17 00:00:00 2001
From: Apply55gx
Date: Wed, 4 Oct 2017 08:46:23 +0200
Subject: [PATCH 32/36] Fixed fabric link
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 2a0faf832..a03f716f2 100644
--- a/README.md
+++ b/README.md
@@ -102,7 +102,7 @@ _Ads currently not available._
- [**Toasty**](https://github.com/GrenderG/Toasty) for displaying error/success messages
- [**ShapedImageView**](https://github.com/gavinliu/ShapedImageView) for round avatars
- [**Material-About-Library**](https://github.com/daniel-stoneuk/material-about-library) for the about screen
-- [**Fabric**](https://fabric.io/kits/ios/crashlytics) analytics & crash reporting.
+- [**Fabric**](https://fabric.io/kits/android/crashlytics) analytics & crash reporting.
- **Android Support Libraries**, the almighty ;-)
## Contribution
From 0bf000df38bfba5eb0e48562f23ae756840e219d Mon Sep 17 00:00:00 2001
From: cozyplanes
Date: Wed, 4 Oct 2017 22:59:17 +0900
Subject: [PATCH 33/36] Update README.md (Newline Issue Again, Header Size
Inconsistency) (#1078)
* Update README.md
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 0cc324982..57876c35f 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@ Yet another **open-source** GitHub client app but unlike any other app, FastHub
alt="Direct apk download"
height="80">](https://github.com/k0shk0sh/FastHub/releases/latest)
-# Features
+## Features
- **App**
- Three login types (Basic Auth), (Access Token) or via (OAuth)
- Multiple Accounts
@@ -129,7 +129,7 @@ Read the [**contribution guide**](.github/CONTRIBUTING.md) for more detailed inf
- Czech @hejsekvojtech
- Spanish @alete89
- French @ptt-homme
- - Korean @Astro36
@cozyplanes
+ - Korean @Astro36 @cozyplanes
## FAQ
From 8f131ca43518361ac917ee8f24d59f11ac77a0ec Mon Sep 17 00:00:00 2001
From: Stargamers
Date: Thu, 5 Oct 2017 17:02:43 +0200
Subject: [PATCH 34/36] Updated German translation again
---
app/src/main/res/values-de/strings.xml | 56 ++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 6dacd3b78..97e8742cf 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -399,6 +399,62 @@
Benachrichtigungs Ton auswählen
Deaktiviere automatische wiedergabe von GIFs
Deaktiviere GIF wiedergabe
+ angeforderte Änderungen
+ Google Play-Dienste sind nicht verfügbar
+ GIST bearbeiten
+ Inhalt
+ erweitern
+ SHA-1 Kopieren
+ Als Code anzeigen
+ In-App-Animationen deaktivieren
+ Deaktiviere in-App-Animationen überall.
+ Dieser PR kann jetzt\jetzt nicht zusammengeführt werden.
+ Projekte
+ Keine Projekte
+ Keine Karten
+ Hinzugefügt von %s %s
+ Zu viele Unterschiede zur Anzeige. Bitte, sehe Sie Sie dir über den Browser an
+ Projekt
+ BITTE lESEN!
+
+ • Warum kann ich meine Organisationen entweder private oder öffentliche sehen\nicht sehen?
+ Öffne https://github.com/Settings/Applications und suche nach FastHub, öffne es dann Blätter zu Organisation Zugang und klicke auf den Grant Knopf,
+ Alternativ melde dich über einen Zugang Token an welches das Setup vereinfacht.
+
+ • Ich habe versuchtt mich mit einem Zugangs Token anzumelden amp; OTP aber es funtioniert nicht?
+ Du kannst dich nicht mit einem zugangs token anmelden & OTP alle Zusammen wegen der Lebenszeit des OTP codes, du musst dich alle paar sekunden anmelden
+
+ • Warum werden mein privates Repo & Enterprise Wiki nicht angezeigt?
+ Es wie FastHub die GitHub Wiki page holt & Private Repos benötigen einen Sitzungs token denn FastHub nicht bekommen kann.
+
+ • Ich habe mich mit meinen Enterprise account angemeldet kann\kann nicht mit anderen sachen interagieren außer meinem Enterprise GitHub?
+ Nun, logisch, kannst du nicht auf etwas anderes als Ihr Unternehmen zugreifen. FastHub versucht, so viel möglich zu erlauben, aber kann
+ in den meisten Fällen nicht viel dafür tun, da Ihre Anmeldedaten auf den GitHub Server nicht vorhanden sind. Aber in einem paar
+ fällen Ihr GitHub Konto OAuth Token wird den Trick tun.
+
+ • Warum habe ich Probleme bei der Bearbeitung von Problemen/PRS?
+ Wenn du ein öffentliches organisations-repo bearbeiten willst, wende dich bitte an deine organisation, um Zugang zu FastHub zu gewähren oder Zugangsdaten zu verwenden!.
+
+ • Ich habe das problem oder Ich möchte dies & das!!
+ Gehe zu https://github.com/k0shk0sh/FastHub/issues/new und erstelle ein neues issue für bugs oder Feature Requests, Ich möchte dich ermutigen
+ das du vor dem erstellen eines Tickets suchst ob es das schon existiert.Jeder doppelter Request wird dazu führen dass du sofort ausgeschlossen wirst.
+
+ • Wie bekomme ich einen PROMO CODE?
+ Wenn du ein Student bist musst du mir eine e-Mail schicken,in der du mir beweist das du ein Student bist, Du brauchst die unten stehen den dokumente:
+
+ - Deine Universitätenausweis & deinen Personalausweis (der deinen Namen zeigt & und dein Gesicht um es zu vergleichen!)
+ - Dein Uni-Start & Enddatum
+ - Bewerte FastHub im Play Store
+
+ Wenn du kein Student bist und du kannst es dir nicht leisten für PRO zu bezahlen, musst du:
+
+ - Einen Arctikel über Fasthub schreiben in Social Media wie (Medium)
+ - Bewerte FastHub im Play Store
+
+ ]]>
+ FAQ
+ Kommentare erfolgreich hinzugefügt
From df73a96611d4a5a09a4644493caa68d85569d73b Mon Sep 17 00:00:00 2001
From: k0shk0sh
Date: Fri, 6 Oct 2017 21:17:54 +0200
Subject: [PATCH 35/36] this commit fixes #1088 fixes #1085 fixes #1081 fixes
#1073 fixes #1028
---
app/build.gradle | 2 +-
app/src/main/assets/md/github_dark.css | 2 +-
.../timeline/handler/QouteHandler.java | 5 +-
.../timeline/handler/TableHandler.java | 106 ++++++------------
.../popup/EditorLinkImageDialogFragment.java | 2 +-
.../ui/modules/gists/GistsListActivity.java | 11 ++
.../ui/modules/gists/gist/GistActivity.java | 5 +
.../modules/main/premium/PremiumActivity.kt | 2 +-
.../modules/main/premium/PremiumPresenter.kt | 13 +--
.../issues/create/CreateIssuePresenter.java | 2 +-
.../layout/emoji_popup_layout.xml | 3 +-
build.gradle | 2 +-
12 files changed, 62 insertions(+), 93 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index c20628ef9..f940a283f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -24,7 +24,7 @@ android {
}
}
compileSdkVersion 26
- buildToolsVersion "26.0.1"
+ buildToolsVersion '26.0.2'
defaultConfig {
applicationId "com.fastaccess.github"
minSdkVersion 21
diff --git a/app/src/main/assets/md/github_dark.css b/app/src/main/assets/md/github_dark.css
index c0d70c222..a695448c7 100644
--- a/app/src/main/assets/md/github_dark.css
+++ b/app/src/main/assets/md/github_dark.css
@@ -82,7 +82,7 @@ body kbd {
padding: 3px 5px;
font-size: 11px;
line-height: 10px;
- color: #656d78;
+ color: #fff;
vertical-align: middle;
border: solid 1px #656d78;
border-bottom-color: #bbb;
diff --git a/app/src/main/java/com/fastaccess/provider/timeline/handler/QouteHandler.java b/app/src/main/java/com/fastaccess/provider/timeline/handler/QouteHandler.java
index 2b098cec0..e26b26774 100644
--- a/app/src/main/java/com/fastaccess/provider/timeline/handler/QouteHandler.java
+++ b/app/src/main/java/com/fastaccess/provider/timeline/handler/QouteHandler.java
@@ -21,10 +21,7 @@
public void handleTagNode(TagNode node, SpannableStringBuilder builder, int start, int end) {
builder.append("\n");
- builder.setSpan(new MarkDownQuoteSpan(color), start + 1, builder.length() - 1, 33);
+ builder.setSpan(new MarkDownQuoteSpan(color), (start > builder.length() - 1) ? start + 1 : start, builder.length() - 1, 33);
builder.append("\n");
}
-
-
-
}
diff --git a/app/src/main/java/com/fastaccess/provider/timeline/handler/TableHandler.java b/app/src/main/java/com/fastaccess/provider/timeline/handler/TableHandler.java
index 7aac34c2a..141946f4e 100644
--- a/app/src/main/java/com/fastaccess/provider/timeline/handler/TableHandler.java
+++ b/app/src/main/java/com/fastaccess/provider/timeline/handler/TableHandler.java
@@ -19,7 +19,6 @@
import android.text.style.ImageSpan;
import net.nightwhistler.htmlspanner.TagNodeHandler;
-import net.nightwhistler.htmlspanner.spans.CenterSpan;
import org.htmlcleaner.TagNode;
@@ -38,55 +37,40 @@ public class TableHandler extends TagNodeHandler {
private int tableWidth = 500;
private Typeface typeFace = Typeface.DEFAULT;
- private float textSize = 30f;
+ private float textSize = 28f;
private int textColor = Color.BLACK;
-
private static final int PADDING = 20;
- /**
- * Sets how wide the table should be.
- *
- * @param tableWidth
- */
- public void setTableWidth(int tableWidth) {
- this.tableWidth = tableWidth;
+ @Override public boolean rendersContent() {
+ return true;
}
- /**
- * Sets the text colour to use.
- *
- * Default is black.
- *
- * @param textColor
- */
- public void setTextColor(int textColor) {
- this.textColor = textColor;
- }
+ @Override public void handleTagNode(TagNode node, SpannableStringBuilder builder, int start, int end) {
+ Table table = getTable(node);
+ for (int i = 0; i < table.getRows().size(); i++) {
+ List row = table.getRows().get(i);
+ builder.append("\uFFFC");
+ TableRowDrawable drawable = new TableRowDrawable(row, table.isDrawBorder());
+ drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
+ drawable.getIntrinsicHeight());
+ builder.setSpan(new ImageSpan(drawable), start + i, builder.length(), 33);
- /**
- * Sets the font size to use.
- *
- * Default is 16f.
- *
- * @param textSize
- */
- public void setTextSize(float textSize) {
- this.textSize = textSize;
+ }
+ builder.append("\uFFFC");
+ Drawable drawable = new TableRowDrawable(new ArrayList(), table.isDrawBorder());
+ drawable.setBounds(0, 0, tableWidth, 1);
+ builder.setSpan(new ImageSpan(drawable), builder.length() - 1, builder.length(),
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ builder.setSpan((AlignmentSpan) () -> Alignment.ALIGN_CENTER, start, builder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ builder.append("\n");
}
- /**
- * Sets the TypeFace to use.
- *
- * Default is Typeface.DEFAULT
- *
- * @param typeFace
- */
- public void setTypeFace(Typeface typeFace) {
- this.typeFace = typeFace;
+ public void setTableWidth(int tableWidth) {
+ this.tableWidth = tableWidth;
}
- @Override public boolean rendersContent() {
- return true;
+ public void setTextColor(int textColor) {
+ this.textColor = textColor;
}
private void readNode(Object node, Table table) {
@@ -143,45 +127,19 @@ private int calculateRowHeight(List row) {
int rowHeight = 0;
- if (columnWidth > 0) {
- for (Spanned cell : row) {
- StaticLayout layout = new StaticLayout(cell, textPaint, columnWidth
- - 2 * PADDING, Alignment.ALIGN_NORMAL, 1f, 0f, true);
- if (layout.getHeight() > rowHeight) {
- rowHeight = layout.getHeight();
- }
+ for (Spanned cell : row) {
+
+ StaticLayout layout = new StaticLayout(cell, textPaint, columnWidth
+ - 2 * PADDING, Alignment.ALIGN_NORMAL, 1.5f, 0.5f, true);
+
+ if (layout.getHeight() > rowHeight) {
+ rowHeight = layout.getHeight();
}
}
return rowHeight;
}
- @Override public void handleTagNode(TagNode node, SpannableStringBuilder builder, int start, int end) {
- builder.append("\n");
- Table table = getTable(node);
- for (int i = 0; i < table.getRows().size(); i++) {
- List row = table.getRows().get(i);
- builder.append("\uFFFC");
- TableRowDrawable drawable = new TableRowDrawable(row, table.isDrawBorder());
- drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
- drawable.getIntrinsicHeight());
- builder.setSpan(new ImageSpan(drawable), start + i, builder.length(), 33);
- }
- builder.append("\uFFFC");
- Drawable drawable = new TableRowDrawable(new ArrayList<>(), table.isDrawBorder());
- drawable.setBounds(0, 0, tableWidth, 1);
- builder.setSpan(new ImageSpan(drawable), builder.length() - 1, builder.length(),
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- builder.setSpan((AlignmentSpan) () -> Alignment.ALIGN_CENTER, start, builder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- builder.setSpan(new CenterSpan(), start, builder.length(), 33);
- builder.append("\n");
- }
-
- /**
- * Drawable of the table, which does the actual rendering.
- *
- * @author Alex Kuiper.
- */
private class TableRowDrawable extends Drawable {
private List tableRow;
@@ -222,7 +180,7 @@ private class TableRowDrawable extends Drawable {
StaticLayout layout = new StaticLayout(tableRow.get(i),
getTextPaint(), (columnWidth - 2 * PADDING),
- Alignment.ALIGN_NORMAL, 1f, 0f, true);
+ Alignment.ALIGN_NORMAL, 1.5f, 0.5f, true);
canvas.translate(offset + PADDING, 0);
layout.draw(canvas);
diff --git a/app/src/main/java/com/fastaccess/ui/modules/editor/popup/EditorLinkImageDialogFragment.java b/app/src/main/java/com/fastaccess/ui/modules/editor/popup/EditorLinkImageDialogFragment.java
index 8dba5f1d9..a79a2b803 100644
--- a/app/src/main/java/com/fastaccess/ui/modules/editor/popup/EditorLinkImageDialogFragment.java
+++ b/app/src/main/java/com/fastaccess/ui/modules/editor/popup/EditorLinkImageDialogFragment.java
@@ -77,7 +77,7 @@ public static EditorLinkImageDialogFragment newInstance(boolean isLink, @Nullabl
@Override protected void onFragmentCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
select.setVisibility(isLink() ? View.GONE : View.VISIBLE);
if (savedInstanceState == null) {
- link.getEditText().setText(getArguments().getString(BundleConstant.ITEM));
+ title.getEditText().setText(getArguments().getString(BundleConstant.ITEM));
}
}
diff --git a/app/src/main/java/com/fastaccess/ui/modules/gists/GistsListActivity.java b/app/src/main/java/com/fastaccess/ui/modules/gists/GistsListActivity.java
index 6d511c8b1..c84edd429 100644
--- a/app/src/main/java/com/fastaccess/ui/modules/gists/GistsListActivity.java
+++ b/app/src/main/java/com/fastaccess/ui/modules/gists/GistsListActivity.java
@@ -7,6 +7,7 @@
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
+import android.view.MenuItem;
import com.fastaccess.R;
import com.fastaccess.data.dao.FragmentPagerAdapterModel;
@@ -17,6 +18,7 @@
import com.fastaccess.ui.base.BaseFragment;
import com.fastaccess.ui.base.mvp.presenter.BasePresenter;
import com.fastaccess.ui.modules.gists.create.CreateGistActivity;
+import com.fastaccess.ui.modules.main.MainActivity;
import com.fastaccess.ui.widgets.ViewPagerView;
import net.grandcentrix.thirtyinch.TiPresenter;
@@ -93,6 +95,15 @@ public static void startActivity(@NonNull Context context) {
}
}
+ @Override public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ startActivity(new Intent(this, MainActivity.class));
+ finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
private void setupTabs() {
pager.setAdapter(new FragmentsPagerAdapter(getSupportFragmentManager(), FragmentPagerAdapterModel.buildForGists(this)));
tabs.setupWithViewPager(pager);
diff --git a/app/src/main/java/com/fastaccess/ui/modules/gists/gist/GistActivity.java b/app/src/main/java/com/fastaccess/ui/modules/gists/gist/GistActivity.java
index a0223b5d0..130dfe4e9 100644
--- a/app/src/main/java/com/fastaccess/ui/modules/gists/gist/GistActivity.java
+++ b/app/src/main/java/com/fastaccess/ui/modules/gists/gist/GistActivity.java
@@ -31,6 +31,7 @@
import com.fastaccess.ui.base.BaseActivity;
import com.fastaccess.ui.base.BaseFragment;
import com.fastaccess.ui.modules.editor.comment.CommentEditorFragment;
+import com.fastaccess.ui.modules.gists.GistsListActivity;
import com.fastaccess.ui.modules.gists.create.CreateGistActivity;
import com.fastaccess.ui.modules.gists.gist.comments.GistCommentsFragment;
import com.fastaccess.ui.modules.main.premium.PremiumActivity;
@@ -164,6 +165,10 @@ public static Intent createIntent(@NonNull Context context, @NonNull String gist
.put(BundleConstant.EXTRA, true).end())
.show(getSupportFragmentManager(), MessageDialogView.TAG);
return true;
+ } else if (item.getItemId() == android.R.id.home) {
+ GistsListActivity.startActivity(this);
+ finish();
+ return true;
}
return super.onOptionsItemSelected(item);
}
diff --git a/app/src/main/java/com/fastaccess/ui/modules/main/premium/PremiumActivity.kt b/app/src/main/java/com/fastaccess/ui/modules/main/premium/PremiumActivity.kt
index 9801b3141..8150393ed 100644
--- a/app/src/main/java/com/fastaccess/ui/modules/main/premium/PremiumActivity.kt
+++ b/app/src/main/java/com/fastaccess/ui/modules/main/premium/PremiumActivity.kt
@@ -92,10 +92,10 @@ class PremiumActivity : BaseActivity(), Premi
override fun onSuccessfullyActivated() {
hideProgress()
successActivationHolder.visibility = View.VISIBLE
+ FabricProvider.logPurchase(InputHelper.toString(editText))
successActivationView.addAnimatorListener(object : Animator.AnimatorListener {
override fun onAnimationRepeat(p0: Animator?) {}
override fun onAnimationEnd(p0: Animator?) {
- FabricProvider.logPurchase(InputHelper.toString(editText))
showMessage(R.string.success, R.string.success)
successResult()
}
diff --git a/app/src/main/java/com/fastaccess/ui/modules/main/premium/PremiumPresenter.kt b/app/src/main/java/com/fastaccess/ui/modules/main/premium/PremiumPresenter.kt
index 034deaeaf..418ca69a8 100644
--- a/app/src/main/java/com/fastaccess/ui/modules/main/premium/PremiumPresenter.kt
+++ b/app/src/main/java/com/fastaccess/ui/modules/main/premium/PremiumPresenter.kt
@@ -1,7 +1,6 @@
package com.fastaccess.ui.modules.main.premium
import com.fastaccess.data.dao.ProUsersModel
-import com.fastaccess.helper.Logger
import com.fastaccess.helper.PrefGetter
import com.fastaccess.helper.RxHelper
import com.fastaccess.ui.base.mvp.presenter.BasePresenter
@@ -24,25 +23,23 @@ class PremiumPresenter : BasePresenter(), PremiumMvp.Presenter
.doOnSubscribe { sendToView { it.showProgress(0) } }
.flatMap {
var user = ProUsersModel()
- Logger.e(it.exists(), it.hasChildren(), it.value)
- if (it.exists()) {
+ if (it.exists() && it.hasChildren()) {
val gti = object : GenericTypeIndicator() {}
user = it.getValue(gti) ?: ProUsersModel()
- Logger.e(user)
if (user.isAllowed) {
if (user.type == 1) {
PrefGetter.setProItems()
user.isAllowed = false
user.count = user.count + 1
- return@flatMap ref.child("fasthub_pro").rxUpdateChildren(hashMapOf(Pair(promo, user)))
- .toObservable()
+ return@flatMap RxHelper.getObservable(ref.child("fasthub_pro").rxUpdateChildren(hashMapOf(Pair(promo, user)))
+ .toObservable())
.map { true }
} else {
PrefGetter.setProItems()
PrefGetter.setEnterpriseItem()
user.count = user.count + 1
- return@flatMap ref.child("fasthub_pro").rxUpdateChildren(hashMapOf(Pair(promo, user)))
- .toObservable()
+ return@flatMap RxHelper.getObservable(ref.child("fasthub_pro").rxUpdateChildren(hashMapOf(Pair(promo, user)))
+ .toObservable())
.map { true }
}
}
diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/issues/create/CreateIssuePresenter.java b/app/src/main/java/com/fastaccess/ui/modules/repos/issues/create/CreateIssuePresenter.java
index 79314186b..4452103f6 100644
--- a/app/src/main/java/com/fastaccess/ui/modules/repos/issues/create/CreateIssuePresenter.java
+++ b/app/src/main/java/com/fastaccess/ui/modules/repos/issues/create/CreateIssuePresenter.java
@@ -79,7 +79,7 @@ public class CreateIssuePresenter extends BasePresenter imp
createIssue.setAssignees(Stream.of(users).map(User::getLogin).collect(Collectors.toCollection(ArrayList::new)));
}
if (milestoneModel != null) {
- createIssue.setMilestone(milestoneModel.getNumber());
+ createIssue.setMilestone((long) milestoneModel.getNumber());
}
}
makeRestCall(RestProvider.getIssueService(isEnterprise()).createIssue(login, repo, createIssue),
diff --git a/app/src/main/res/layouts/main_layouts/layout/emoji_popup_layout.xml b/app/src/main/res/layouts/main_layouts/layout/emoji_popup_layout.xml
index 5a84280b2..417978f3a 100644
--- a/app/src/main/res/layouts/main_layouts/layout/emoji_popup_layout.xml
+++ b/app/src/main/res/layouts/main_layouts/layout/emoji_popup_layout.xml
@@ -51,7 +51,8 @@
android:background="@color/transparent"
android:hint="@string/search"
android:paddingEnd="@dimen/spacing_xs_large"
- android:paddingStart="@dimen/spacing_xs_large"/>
+ android:paddingStart="@dimen/spacing_xs_large"
+ android:singleLine="true"/>
diff --git a/build.gradle b/build.gradle
index 831bd8c31..e6fa10eb4 100644
--- a/build.gradle
+++ b/build.gradle
@@ -22,7 +22,7 @@ buildscript {
google()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.0.0-beta6'
+ classpath 'com.android.tools.build:gradle:3.0.0-beta7'
classpath 'com.google.gms:google-services:3.0.0'
classpath 'com.novoda:gradle-build-properties-plugin:0.3'
classpath 'com.dicedmelon.gradle:jacoco-android:0.1.2'
From 522fa585252345851dbbd02a1eee1328dd713852 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Javier=20Segovia=20C=C3=B3rdoba?=
Date: Sun, 8 Oct 2017 23:17:26 +0200
Subject: [PATCH 36/36] Update strings.xml (#1098)
Close = cerrar
Clone = clonar
Close issue = Cerrar issue (issue really is "problema", but the original translator used the English term)
---
app/src/main/res/values-es/strings.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index ed9932dda..570fabc34 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -39,7 +39,7 @@
Colaboradores
Colaboraciones
por
- Clonar Issue
+ Cerrar Issue
Reabrir Issue
Reabrir
Cerrar