aboutsummaryrefslogtreecommitdiff
path: root/src/com/android/tv/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/tv/util')
-rw-r--r--src/com/android/tv/util/AsyncDbTask.java240
-rw-r--r--src/com/android/tv/util/CaptionSettings.java13
-rw-r--r--src/com/android/tv/util/Clock.java65
-rw-r--r--src/com/android/tv/util/CompositeComparator.java4
-rw-r--r--src/com/android/tv/util/Debug.java60
-rw-r--r--src/com/android/tv/util/DurationTimer.java91
-rw-r--r--src/com/android/tv/util/Filter.java8
-rw-r--r--src/com/android/tv/util/LocationUtils.java143
-rw-r--r--src/com/android/tv/util/MainThreadExecutor.java19
-rw-r--r--src/com/android/tv/util/MultiLongSparseArray.java21
-rw-r--r--src/com/android/tv/util/NamedThreadFactory.java48
-rw-r--r--src/com/android/tv/util/NetworkTrafficTags.java64
-rw-r--r--src/com/android/tv/util/NetworkUtils.java11
-rw-r--r--src/com/android/tv/util/OnboardingUtils.java43
-rw-r--r--src/com/android/tv/util/Partner.java3
-rw-r--r--src/com/android/tv/util/PermissionUtils.java55
-rw-r--r--src/com/android/tv/util/RecurringRunner.java39
-rw-r--r--src/com/android/tv/util/SetupUtils.java245
-rw-r--r--src/com/android/tv/util/SqlParams.java74
-rw-r--r--src/com/android/tv/util/StringUtils.java38
-rw-r--r--src/com/android/tv/util/SystemProperties.java68
-rw-r--r--src/com/android/tv/util/TimeShiftUtils.java18
-rw-r--r--src/com/android/tv/util/ToastUtils.java9
-rw-r--r--src/com/android/tv/util/TvInputManagerHelper.java440
-rw-r--r--src/com/android/tv/util/TvSettings.java126
-rw-r--r--src/com/android/tv/util/TvTrackInfoUtils.java50
-rw-r--r--src/com/android/tv/util/TvUriMatcher.java31
-rw-r--r--src/com/android/tv/util/Utils.java484
-rw-r--r--src/com/android/tv/util/ViewCache.java52
-rw-r--r--src/com/android/tv/util/account/AccountHelper.java38
-rw-r--r--src/com/android/tv/util/account/AccountHelperImpl.java (renamed from src/com/android/tv/util/AccountHelper.java)52
-rw-r--r--src/com/android/tv/util/images/BitmapUtils.java (renamed from src/com/android/tv/util/BitmapUtils.java)103
-rw-r--r--src/com/android/tv/util/images/ImageCache.java (renamed from src/com/android/tv/util/ImageCache.java)74
-rw-r--r--src/com/android/tv/util/images/ImageLoader.java (renamed from src/com/android/tv/util/ImageLoader.java)205
34 files changed, 1307 insertions, 1727 deletions
diff --git a/src/com/android/tv/util/AsyncDbTask.java b/src/com/android/tv/util/AsyncDbTask.java
index 477412e4..60fa3018 100644
--- a/src/com/android/tv/util/AsyncDbTask.java
+++ b/src/com/android/tv/util/AsyncDbTask.java
@@ -27,24 +27,20 @@ import android.support.annotation.Nullable;
import android.support.annotation.WorkerThread;
import android.util.Log;
import android.util.Range;
-
+import com.android.tv.TvSingletons;
+import com.android.tv.common.BuildConfig;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.data.Channel;
+import com.android.tv.data.ChannelImpl;
import com.android.tv.data.Program;
+import com.android.tv.data.api.Channel;
import com.android.tv.dvr.data.RecordedProgram;
-
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.Executor;
/**
* {@link AsyncTask} that defaults to executing on its own single threaded Executor Service.
*
- * <p>Instances of this class should only be executed this using {@link
- * #executeOnDbThread(Object[])}.
- *
* @param <Params> the type of the parameters sent to the task upon execution.
* @param <Progress> the type of the progress units published during the background computation.
* @param <Result> the type of the result of the background computation.
@@ -54,38 +50,19 @@ public abstract class AsyncDbTask<Params, Progress, Result>
private static final String TAG = "AsyncDbTask";
private static final boolean DEBUG = false;
- private static final NamedThreadFactory THREAD_FACTORY = new NamedThreadFactory(
- AsyncDbTask.class.getSimpleName());
- private static final ExecutorService DB_EXECUTOR = Executors
- .newSingleThreadExecutor(THREAD_FACTORY);
+ private final Executor mExecutor;
+ boolean mCalledExecuteOnDbThread;
- /**
- * Returns the single tread executor used for DbTasks.
- */
- public static ExecutorService getExecutor() {
- return DB_EXECUTOR;
- }
-
- /**
- * Executes the given command at some time in the future.
- *
- * <p>The command will be executed by {@link #getExecutor()}.
- *
- * @param command the runnable task
- * @throws RejectedExecutionException if this task cannot be
- * accepted for execution
- * @throws NullPointerException if command is null
- */
- public static void executeOnDbThread(Runnable command) {
- DB_EXECUTOR.execute(command);
+ protected AsyncDbTask(Executor mExecutor) {
+ this.mExecutor = mExecutor;
}
/**
* Returns the result of a {@link ContentResolver#query(Uri, String[], String, String[],
* String)}.
*
- * <p> {@link #doInBackground(Void...)} executes the query on call {@link #onQuery(Cursor)}
- * which is implemented by subclasses.
+ * <p>{@link #doInBackground(Void...)} executes the query on call {@link #onQuery(Cursor)} which
+ * is implemented by subclasses.
*
* @param <Result> the type of result returned by {@link #onQuery(Cursor)}
*/
@@ -97,9 +74,15 @@ public abstract class AsyncDbTask<Params, Progress, Result>
private final String[] mSelectionArgs;
private final String mOrderBy;
-
- public AsyncQueryTask(ContentResolver contentResolver, Uri uri, String[] projection,
- String selection, String[] selectionArgs, String orderBy) {
+ public AsyncQueryTask(
+ Executor executor,
+ ContentResolver contentResolver,
+ Uri uri,
+ String[] projection,
+ String selection,
+ String[] selectionArgs,
+ String orderBy) {
+ super(executor);
mContentResolver = contentResolver;
mUri = uri;
mProjection = projection;
@@ -110,13 +93,15 @@ public abstract class AsyncDbTask<Params, Progress, Result>
@Override
protected final Result doInBackground(Void... params) {
- if (!THREAD_FACTORY.namedWithPrefix(Thread.currentThread())) {
- IllegalStateException e = new IllegalStateException(this
- + " should only be executed using executeOnDbThread, "
- + "but it was called on thread "
- + Thread.currentThread());
+ if (!mCalledExecuteOnDbThread) {
+ IllegalStateException e =
+ new IllegalStateException(
+ this
+ + " should only be executed using executeOnDbThread, "
+ + "but it was called on thread "
+ + Thread.currentThread());
Log.w(TAG, e);
- if (DEBUG) {
+ if (BuildConfig.ENG) {
throw e;
}
}
@@ -128,8 +113,9 @@ public abstract class AsyncDbTask<Params, Progress, Result>
if (DEBUG) {
Log.v(TAG, "Starting query for " + this);
}
- try (Cursor c = mContentResolver
- .query(mUri, mProjection, mSelection, mSelectionArgs, mOrderBy)) {
+ try (Cursor c =
+ mContentResolver.query(
+ mUri, mProjection, mSelection, mSelectionArgs, mOrderBy)) {
if (c != null && !isCancelled()) {
Result result = onQuery(c);
if (DEBUG) {
@@ -147,7 +133,7 @@ public abstract class AsyncDbTask<Params, Progress, Result>
return null;
}
} catch (Exception e) {
- SoftPreconditions.warn(TAG, null, "Error querying " + this, e);
+ SoftPreconditions.warn(TAG, null, e, "Error querying " + this);
return null;
}
}
@@ -176,14 +162,35 @@ public abstract class AsyncDbTask<Params, Progress, Result>
public abstract static class AsyncQueryListTask<T> extends AsyncQueryTask<List<T>> {
private final CursorFilter mFilter;
- public AsyncQueryListTask(ContentResolver contentResolver, Uri uri, String[] projection,
- String selection, String[] selectionArgs, String orderBy) {
- this(contentResolver, uri, projection, selection, selectionArgs, orderBy, null);
+ public AsyncQueryListTask(
+ Executor executor,
+ ContentResolver contentResolver,
+ Uri uri,
+ String[] projection,
+ String selection,
+ String[] selectionArgs,
+ String orderBy) {
+ this(
+ executor,
+ contentResolver,
+ uri,
+ projection,
+ selection,
+ selectionArgs,
+ orderBy,
+ null);
}
- public AsyncQueryListTask(ContentResolver contentResolver, Uri uri, String[] projection,
- String selection, String[] selectionArgs, String orderBy, CursorFilter filter) {
- super(contentResolver, uri, projection, selection, selectionArgs, orderBy);
+ public AsyncQueryListTask(
+ Executor executor,
+ ContentResolver contentResolver,
+ Uri uri,
+ String[] projection,
+ String selection,
+ String[] selectionArgs,
+ String orderBy,
+ CursorFilter filter) {
+ super(executor, contentResolver, uri, projection, selection, selectionArgs, orderBy);
mFilter = filter;
}
@@ -228,9 +235,15 @@ public abstract class AsyncDbTask<Params, Progress, Result>
*/
public abstract static class AsyncQueryItemTask<T> extends AsyncQueryTask<T> {
- public AsyncQueryItemTask(ContentResolver contentResolver, Uri uri, String[] projection,
- String selection, String[] selectionArgs, String orderBy) {
- super(contentResolver, uri, projection, selection, selectionArgs, orderBy);
+ public AsyncQueryItemTask(
+ Executor executor,
+ ContentResolver contentResolver,
+ Uri uri,
+ String[] projection,
+ String selection,
+ String[] selectionArgs,
+ String orderBy) {
+ super(executor, contentResolver, uri, projection, selection, selectionArgs, orderBy);
}
@Override
@@ -251,7 +264,6 @@ public abstract class AsyncDbTask<Params, Progress, Result>
}
return null;
}
-
}
/**
@@ -268,33 +280,55 @@ public abstract class AsyncDbTask<Params, Progress, Result>
protected abstract T fromCursor(Cursor c);
}
- /**
- * Gets an {@link List} of {@link Channel}s from {@link TvContract.Channels#CONTENT_URI}.
- */
+ /** Gets an {@link List} of {@link Channel}s from {@link TvContract.Channels#CONTENT_URI}. */
public abstract static class AsyncChannelQueryTask extends AsyncQueryListTask<Channel> {
- public AsyncChannelQueryTask(ContentResolver contentResolver) {
- super(contentResolver, TvContract.Channels.CONTENT_URI, Channel.PROJECTION,
- null, null, null);
+ public AsyncChannelQueryTask(Executor executor, ContentResolver contentResolver) {
+ super(
+ executor,
+ contentResolver,
+ TvContract.Channels.CONTENT_URI,
+ ChannelImpl.PROJECTION,
+ null,
+ null,
+ null);
}
@Override
protected final Channel fromCursor(Cursor c) {
- return Channel.fromCursor(c);
+ return ChannelImpl.fromCursor(c);
}
}
- /**
- * Gets an {@link List} of {@link Program}s from {@link TvContract.Programs#CONTENT_URI}.
- */
+ /** Gets an {@link List} of {@link Program}s from {@link TvContract.Programs#CONTENT_URI}. */
public abstract static class AsyncProgramQueryTask extends AsyncQueryListTask<Program> {
- public AsyncProgramQueryTask(ContentResolver contentResolver) {
- super(contentResolver, Programs.CONTENT_URI, Program.PROJECTION, null, null, null);
+ public AsyncProgramQueryTask(Executor executor, ContentResolver contentResolver) {
+ super(
+ executor,
+ contentResolver,
+ Programs.CONTENT_URI,
+ Program.PROJECTION,
+ null,
+ null,
+ null);
}
- public AsyncProgramQueryTask(ContentResolver contentResolver, Uri uri, String selection,
- String[] selectionArgs, String sortOrder, CursorFilter filter) {
- super(contentResolver, uri, Program.PROJECTION, selection, selectionArgs, sortOrder,
+ public AsyncProgramQueryTask(
+ Executor executor,
+ ContentResolver contentResolver,
+ Uri uri,
+ String selection,
+ String[] selectionArgs,
+ String sortOrder,
+ CursorFilter filter) {
+ super(
+ executor,
+ contentResolver,
+ uri,
+ Program.PROJECTION,
+ selection,
+ selectionArgs,
+ sortOrder,
filter);
}
@@ -304,13 +338,12 @@ public abstract class AsyncDbTask<Params, Progress, Result>
}
}
- /**
- * Gets an {@link List} of {@link TvContract.RecordedPrograms}s.
- */
+ /** Gets an {@link List} of {@link TvContract.RecordedPrograms}s. */
public abstract static class AsyncRecordedProgramQueryTask
extends AsyncQueryListTask<RecordedProgram> {
- public AsyncRecordedProgramQueryTask(ContentResolver contentResolver, Uri uri) {
- super(contentResolver, uri, RecordedProgram.PROJECTION, null, null, null);
+ public AsyncRecordedProgramQueryTask(
+ Executor executor, ContentResolver contentResolver, Uri uri) {
+ super(executor, contentResolver, uri, RecordedProgram.PROJECTION, null, null, null);
}
@Override
@@ -319,31 +352,39 @@ public abstract class AsyncDbTask<Params, Progress, Result>
}
}
- /**
- * Execute the task on the {@link #DB_EXECUTOR} thread.
- */
+ /** Execute the task on {@link TvSingletons#getDbExecutor()}. */
@SafeVarargs
@MainThread
public final void executeOnDbThread(Params... params) {
- executeOnExecutor(DB_EXECUTOR, params);
+ mCalledExecuteOnDbThread = true;
+ executeOnExecutor(mExecutor, params);
}
/**
* Gets an {@link List} of {@link Program}s for a given channel and period {@link
- * TvContract#buildProgramsUriForChannel(long, long, long)}. If the {@code period} is
- * {@code null}, then all the programs is queried.
+ * TvContract#buildProgramsUriForChannel(long, long, long)}. If the {@code period} is {@code
+ * null}, then all the programs is queried.
*/
public static class LoadProgramsForChannelTask extends AsyncProgramQueryTask {
protected final Range<Long> mPeriod;
protected final long mChannelId;
- public LoadProgramsForChannelTask(ContentResolver contentResolver, long channelId,
+ public LoadProgramsForChannelTask(
+ Executor executor,
+ ContentResolver contentResolver,
+ long channelId,
@Nullable Range<Long> period) {
- super(contentResolver, period == null
- ? TvContract.buildProgramsUriForChannel(channelId)
- : TvContract.buildProgramsUriForChannel(channelId, period.getLower(),
- period.getUpper()),
- null, null, null, null);
+ super(
+ executor,
+ contentResolver,
+ period == null
+ ? TvContract.buildProgramsUriForChannel(channelId)
+ : TvContract.buildProgramsUriForChannel(
+ channelId, period.getLower(), period.getUpper()),
+ null,
+ null,
+ null,
+ null);
mPeriod = period;
mChannelId = channelId;
}
@@ -357,14 +398,19 @@ public abstract class AsyncDbTask<Params, Progress, Result>
}
}
- /**
- * Gets a single {@link Program} from {@link TvContract.Programs#CONTENT_URI}.
- */
+ /** Gets a single {@link Program} from {@link TvContract.Programs#CONTENT_URI}. */
public static class AsyncQueryProgramTask extends AsyncQueryItemTask<Program> {
- public AsyncQueryProgramTask(ContentResolver contentResolver, long programId) {
- super(contentResolver, TvContract.buildProgramUri(programId), Program.PROJECTION, null,
- null, null);
+ public AsyncQueryProgramTask(
+ Executor executor, ContentResolver contentResolver, long programId) {
+ super(
+ executor,
+ contentResolver,
+ TvContract.buildProgramUri(programId),
+ Program.PROJECTION,
+ null,
+ null,
+ null);
}
@Override
@@ -373,8 +419,6 @@ public abstract class AsyncDbTask<Params, Progress, Result>
}
}
- /**
- * An interface which filters the row.
- */
- public interface CursorFilter extends Filter<Cursor> { }
+ /** An interface which filters the row. */
+ public interface CursorFilter extends Filter<Cursor> {}
}
diff --git a/src/com/android/tv/util/CaptionSettings.java b/src/com/android/tv/util/CaptionSettings.java
index 3b38905b..6d7e9901 100644
--- a/src/com/android/tv/util/CaptionSettings.java
+++ b/src/com/android/tv/util/CaptionSettings.java
@@ -18,7 +18,6 @@ package com.android.tv.util;
import android.content.Context;
import android.view.accessibility.CaptioningManager;
-
import java.util.Locale;
public class CaptionSettings {
@@ -32,8 +31,8 @@ public class CaptionSettings {
private String mTrackId;
public CaptionSettings(Context context) {
- mCaptioningManager = (CaptioningManager) context.getSystemService(
- Context.CAPTIONING_SERVICE);
+ mCaptioningManager =
+ (CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE);
}
public final String getSystemLanguage() {
@@ -84,16 +83,12 @@ public class CaptionSettings {
mLanguage = language;
}
- /**
- * Returns the track ID to be used as an alternative key.
- */
+ /** Returns the track ID to be used as an alternative key. */
public String getTrackId() {
return mTrackId;
}
- /**
- * Sets the track ID to be used as an alternative key.
- */
+ /** Sets the track ID to be used as an alternative key. */
public void setTrackId(String trackId) {
mTrackId = trackId;
}
diff --git a/src/com/android/tv/util/Clock.java b/src/com/android/tv/util/Clock.java
deleted file mode 100644
index c5e96431..00000000
--- a/src/com/android/tv/util/Clock.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * 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.android.tv.util;
-
-import android.os.SystemClock;
-
-/**
- * An interface through which system clocks can be read. The {@link #SYSTEM} implementation
- * must be used for all non-test cases.
- */
-public interface Clock {
- /**
- * Returns the current time in milliseconds since January 1, 1970 00:00:00.0 UTC.
- * See {@link System#currentTimeMillis()}.
- */
- long currentTimeMillis();
-
- /**
- * Returns milliseconds since boot, including time spent in sleep.
- *
- * @see SystemClock#elapsedRealtime()
- */
- long elapsedRealtime();
-
- /**
- * Waits a given number of milliseconds (of uptimeMillis) before returning.
- *
- * @param ms to sleep before returning, in milliseconds of uptime.
- * @see SystemClock#sleep(long)
- */
- void sleep(long ms);
-
- /**
- * The default implementation of Clock.
- */
- Clock SYSTEM = new Clock() {
- @Override
- public long currentTimeMillis() {
- return System.currentTimeMillis();
- }
-
- @Override
- public long elapsedRealtime() {
- return SystemClock.elapsedRealtime();
- }
-
- @Override
- public void sleep(long ms) {
- SystemClock.sleep(ms);
- }
- };
-}
diff --git a/src/com/android/tv/util/CompositeComparator.java b/src/com/android/tv/util/CompositeComparator.java
index 47cf50fe..ccf4e944 100644
--- a/src/com/android/tv/util/CompositeComparator.java
+++ b/src/com/android/tv/util/CompositeComparator.java
@@ -18,9 +18,7 @@ package com.android.tv.util;
import java.util.Comparator;
-/**
- * A comparator which runs multiple comparators sequentially.
- */
+/** A comparator which runs multiple comparators sequentially. */
public class CompositeComparator<T> implements Comparator<T> {
private final Comparator<T>[] mComparators;
diff --git a/src/com/android/tv/util/Debug.java b/src/com/android/tv/util/Debug.java
deleted file mode 100644
index 67a2683d..00000000
--- a/src/com/android/tv/util/Debug.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * 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.android.tv.util;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-/**
- * A class only for help developers.
- */
-public class Debug {
- /**
- * A threshold of start up time, when the start up time of Live TV is more than it,
- * a warning will show to the developer.
- */
- public static final long TIME_START_UP_DURATION_THRESHOLD = TimeUnit.SECONDS.toMillis(6);
- /**
- * Tag for measuring start up time of Live TV.
- */
- public static final String TAG_START_UP_TIMER = "start_up_timer";
-
- /**
- * A global map for duration timers.
- */
- private final static Map<String, DurationTimer> sTimerMap = new HashMap<>();
-
- /**
- * Returns the global duration timer by tag.
- */
- public static DurationTimer getTimer(String tag) {
- if (sTimerMap.get(tag) != null) {
- return sTimerMap.get(tag);
- }
- DurationTimer timer = new DurationTimer(tag, true);
- sTimerMap.put(tag, timer);
- return timer;
- }
-
- /**
- * Removes the global duration timer by tag.
- */
- public static DurationTimer removeTimer(String tag) {
- return sTimerMap.remove(tag);
- }
-}
diff --git a/src/com/android/tv/util/DurationTimer.java b/src/com/android/tv/util/DurationTimer.java
deleted file mode 100644
index 1f057bf6..00000000
--- a/src/com/android/tv/util/DurationTimer.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * 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.android.tv.util;
-
-import android.os.SystemClock;
-import android.util.Log;
-
-import com.android.tv.common.BuildConfig;
-
-/**
- * Times a duration.
- */
-public final class DurationTimer {
- private static final String TAG = "DurationTimer";
- public static final long TIME_NOT_SET = -1;
-
- private long mStartTimeMs = TIME_NOT_SET;
- private String mTag = TAG;
- private boolean mLogEngOnly;
-
- public DurationTimer() { }
-
- public DurationTimer(String tag, boolean logEngOnly) {
- mTag = tag;
- mLogEngOnly = logEngOnly;
- }
-
- /**
- * Returns true if the timer is running.
- */
- public boolean isRunning() {
- return mStartTimeMs != TIME_NOT_SET;
- }
-
- /**
- * Start the timer.
- */
- public void start() {
- mStartTimeMs = SystemClock.elapsedRealtime();
- }
-
- /**
- * Returns true if timer is started.
- */
- public boolean isStarted() {
- return mStartTimeMs != TIME_NOT_SET;
- }
-
- /**
- * Returns the current duration in milliseconds or {@link #TIME_NOT_SET} if the timer is not
- * running.
- */
- public long getDuration() {
- return isRunning() ? SystemClock.elapsedRealtime() - mStartTimeMs : TIME_NOT_SET;
- }
-
- /**
- * Stops the timer and resets its value to {@link #TIME_NOT_SET}.
- *
- * @return the current duration in milliseconds or {@link #TIME_NOT_SET} if the timer is not
- * running.
- */
- public long reset() {
- long duration = getDuration();
- mStartTimeMs = TIME_NOT_SET;
- return duration;
- }
-
- /**
- * Adds information and duration time to the log.
- */
- public void log(String message) {
- if (isRunning() && (!mLogEngOnly || BuildConfig.ENG)) {
- Log.i(mTag, message + " : " + getDuration() + "ms");
- }
- }
-}
diff --git a/src/com/android/tv/util/Filter.java b/src/com/android/tv/util/Filter.java
index d5b356e4..3e24a496 100644
--- a/src/com/android/tv/util/Filter.java
+++ b/src/com/android/tv/util/Filter.java
@@ -16,12 +16,8 @@
package com.android.tv.util;
-/**
- * Interface to decide whether an input is filtered out or not.
- */
+/** Interface to decide whether an input is filtered out or not. */
public interface Filter<T> {
- /**
- * Returns true, if {@code input} is acceptable.
- */
+ /** Returns true, if {@code input} is acceptable. */
boolean filter(T input);
}
diff --git a/src/com/android/tv/util/LocationUtils.java b/src/com/android/tv/util/LocationUtils.java
deleted file mode 100644
index d5d7bee3..00000000
--- a/src/com/android/tv/util/LocationUtils.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * 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.android.tv.util;
-
-import android.Manifest;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.location.Address;
-import android.location.Geocoder;
-import android.location.Location;
-import android.location.LocationListener;
-import android.location.LocationManager;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.tv.tuner.util.PostalCodeUtils;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.Locale;
-
-/**
- * A utility class to get the current location.
- */
-public class LocationUtils {
- private static final String TAG = "LocationUtils";
- private static final boolean DEBUG = false;
-
- private static Context sApplicationContext;
- private static Address sAddress;
- private static String sCountry;
- private static IOException sError;
-
- /**
- * Checks the current location.
- */
- public static synchronized Address getCurrentAddress(Context context) throws IOException,
- SecurityException {
- if (sAddress != null) {
- return sAddress;
- }
- if (sError != null) {
- throw sError;
- }
- if (sApplicationContext == null) {
- sApplicationContext = context.getApplicationContext();
- }
- LocationUtilsHelper.startLocationUpdates();
- return null;
- }
-
- /** Returns the current country. */
- @NonNull
- public static synchronized String getCurrentCountry(Context context) {
- if (sCountry != null) {
- return sCountry;
- }
- if (TextUtils.isEmpty(sCountry)) {
- sCountry = context.getResources().getConfiguration().locale.getCountry();
- }
- return sCountry;
- }
-
- private static void updateAddress(Location location) {
- if (DEBUG) Log.d(TAG, "Updating address with " + location);
- if (location == null) {
- return;
- }
- Geocoder geocoder = new Geocoder(sApplicationContext, Locale.getDefault());
- try {
- List<Address> addresses = geocoder.getFromLocation(
- location.getLatitude(), location.getLongitude(), 1);
- if (addresses != null && !addresses.isEmpty()) {
- sAddress = addresses.get(0);
- if (DEBUG) Log.d(TAG, "Got " + sAddress);
- try {
- PostalCodeUtils.updatePostalCode(sApplicationContext);
- } catch (Exception e) {
- // Do nothing
- }
- } else {
- if (DEBUG) Log.d(TAG, "No address returned");
- }
- sError = null;
- } catch (IOException e) {
- Log.w(TAG, "Error in updating address", e);
- sError = e;
- }
- }
-
- private LocationUtils() { }
-
- private static class LocationUtilsHelper {
- private static final LocationListener LOCATION_LISTENER = new LocationListener() {
- @Override
- public void onLocationChanged(Location location) {
- updateAddress(location);
- }
-
- @Override
- public void onStatusChanged(String provider, int status, Bundle extras) { }
-
- @Override
- public void onProviderEnabled(String provider) { }
-
- @Override
- public void onProviderDisabled(String provider) { }
- };
-
- private static LocationManager sLocationManager;
-
- public static void startLocationUpdates() {
- if (sLocationManager == null) {
- sLocationManager = (LocationManager) sApplicationContext.getSystemService(
- Context.LOCATION_SERVICE);
- try {
- sLocationManager.requestLocationUpdates(
- LocationManager.NETWORK_PROVIDER, 1000, 10, LOCATION_LISTENER, null);
- } catch (SecurityException e) {
- // Enables requesting the location updates again.
- sLocationManager = null;
- throw e;
- }
- }
- }
- }
-}
diff --git a/src/com/android/tv/util/MainThreadExecutor.java b/src/com/android/tv/util/MainThreadExecutor.java
index ce8f8ff3..5102ddbd 100644
--- a/src/com/android/tv/util/MainThreadExecutor.java
+++ b/src/com/android/tv/util/MainThreadExecutor.java
@@ -18,7 +18,6 @@ package com.android.tv.util;
import android.os.Handler;
import android.os.Looper;
-
import java.util.List;
import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.TimeUnit;
@@ -26,11 +25,11 @@ import java.util.concurrent.TimeUnit;
/**
* An executor service that executes its tasks on the main thread.
*
- * Shutting down this executor is not supported.
+ * <p>Shutting down this executor is not supported.
*/
public class MainThreadExecutor extends AbstractExecutorService {
- private final static MainThreadExecutor INSTANCE = new MainThreadExecutor();
+ private static final MainThreadExecutor INSTANCE = new MainThreadExecutor();
public static MainThreadExecutor getInstance() {
return INSTANCE;
@@ -47,18 +46,14 @@ public class MainThreadExecutor extends AbstractExecutorService {
}
}
- /**
- * Not supported and throws an exception when used.
- */
+ /** Not supported and throws an exception when used. */
@Override
@Deprecated
public void shutdown() {
throw new UnsupportedOperationException();
}
- /**
- * Not supported and throws an exception when used.
- */
+ /** Not supported and throws an exception when used. */
@Override
@Deprecated
public List<Runnable> shutdownNow() {
@@ -75,12 +70,10 @@ public class MainThreadExecutor extends AbstractExecutorService {
return false;
}
- /**
- * Not supported and throws an exception when used.
- */
+ /** Not supported and throws an exception when used. */
@Override
@Deprecated
public boolean awaitTermination(long l, TimeUnit timeUnit) throws InterruptedException {
throw new UnsupportedOperationException();
}
-} \ No newline at end of file
+}
diff --git a/src/com/android/tv/util/MultiLongSparseArray.java b/src/com/android/tv/util/MultiLongSparseArray.java
index 1d5fa80b..a456df91 100644
--- a/src/com/android/tv/util/MultiLongSparseArray.java
+++ b/src/com/android/tv/util/MultiLongSparseArray.java
@@ -19,7 +19,6 @@ package com.android.tv.util;
import android.support.annotation.VisibleForTesting;
import android.util.ArraySet;
import android.util.LongSparseArray;
-
import java.util.Collections;
import java.util.Set;
@@ -29,8 +28,7 @@ import java.util.Set;
* <p>This has the same memory and performance trade offs listed in {@link LongSparseArray}.
*/
public class MultiLongSparseArray<T> {
- @VisibleForTesting
- static final int DEFAULT_MAX_EMPTIES_KEPT = 4;
+ @VisibleForTesting static final int DEFAULT_MAX_EMPTIES_KEPT = 4;
private final LongSparseArray<Set<T>> mSparseArray;
private final Set<T>[] mEmptySets;
private int mEmptyIndex = -1;
@@ -46,9 +44,8 @@ public class MultiLongSparseArray<T> {
}
/**
- * Adds a mapping from the specified key to the specified value,
- * replacing the previous mapping from the specified key if there
- * was one.
+ * Adds a mapping from the specified key to the specified value, replacing the previous mapping
+ * from the specified key if there was one.
*/
public void put(long key, T value) {
Set<T> values = mSparseArray.get(key);
@@ -59,9 +56,7 @@ public class MultiLongSparseArray<T> {
values.add(value);
}
- /**
- * Removes the value at the specified index.
- */
+ /** Removes the value at the specified index. */
public void remove(long key, T value) {
Set<T> values = mSparseArray.get(key);
if (values != null) {
@@ -74,17 +69,15 @@ public class MultiLongSparseArray<T> {
}
/**
- * Gets the set of Objects mapped from the specified key, or an empty set
- * if no such mapping has been made.
+ * Gets the set of Objects mapped from the specified key, or an empty set if no such mapping has
+ * been made.
*/
public Iterable<T> get(long key) {
Set<T> values = mSparseArray.get(key);
return values == null ? Collections.EMPTY_SET : values;
}
- /**
- * Clears cached empty sets.
- */
+ /** Clears cached empty sets. */
public void clearEmptyCache() {
while (mEmptyIndex >= 0) {
mEmptySets[mEmptyIndex--] = null;
diff --git a/src/com/android/tv/util/NamedThreadFactory.java b/src/com/android/tv/util/NamedThreadFactory.java
deleted file mode 100644
index fcdde952..00000000
--- a/src/com/android/tv/util/NamedThreadFactory.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * 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.android.tv.util;
-
-import android.support.annotation.NonNull;
-
-import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * A thread factory that creates threads with a suffix.
- */
-public class NamedThreadFactory implements ThreadFactory {
- private final AtomicInteger mCount = new AtomicInteger(0);
- private final ThreadFactory mDefaultThreadFactory;
- private final String mPrefix;
-
- public NamedThreadFactory(final String baseName) {
- mDefaultThreadFactory = Executors.defaultThreadFactory();
- mPrefix = baseName + "-";
- }
-
- @Override
- public Thread newThread(@NonNull final Runnable runnable) {
- final Thread thread = mDefaultThreadFactory.newThread(runnable);
- thread.setName(mPrefix + mCount.getAndIncrement());
- return thread;
- }
-
- public boolean namedWithPrefix(Thread thread) {
- return thread.getName().startsWith(mPrefix);
- }
-}
diff --git a/src/com/android/tv/util/NetworkTrafficTags.java b/src/com/android/tv/util/NetworkTrafficTags.java
deleted file mode 100644
index 2dca613c..00000000
--- a/src/com/android/tv/util/NetworkTrafficTags.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * 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.android.tv.util;
-
-import android.net.TrafficStats;
-import android.support.annotation.NonNull;
-
-import java.util.concurrent.Executor;
-
-/** Constants for tagging network traffic in the Live channels app. */
-public final class NetworkTrafficTags {
-
- public static final int DEFAULT_LIVE_CHANNELS = 1;
- public static final int LOGO_FETCHER = 2;
- public static final int HDHOMERUN = 3;
- public static final int EPG_FETCH = 4;
-
- /**
- * An executor which simply wraps a provided delegate executor, but calls {@link
- * TrafficStats#setThreadStatsTag(int)} before executing any task.
- */
- public static class TrafficStatsTaggingExecutor implements Executor {
- private final Executor delegateExecutor;
- private final int tag;
-
- public TrafficStatsTaggingExecutor(Executor delegateExecutor, int tag) {
- this.delegateExecutor = delegateExecutor;
- this.tag = tag;
- }
-
- @Override
- public void execute(final @NonNull Runnable command) {
- // TODO(b/62038127): robolectric does not support lamdas in unbundled apps
- delegateExecutor.execute(
- new Runnable() {
- @Override
- public void run() {
- TrafficStats.setThreadStatsTag(tag);
- try {
- command.run();
- } finally {
- TrafficStats.clearThreadStatsTag();
- }
- }
- });
- }
- }
-
- private NetworkTrafficTags() {}
-}
diff --git a/src/com/android/tv/util/NetworkUtils.java b/src/com/android/tv/util/NetworkUtils.java
index ed3ce383..94581d5a 100644
--- a/src/com/android/tv/util/NetworkUtils.java
+++ b/src/com/android/tv/util/NetworkUtils.java
@@ -20,21 +20,16 @@ import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.annotation.Nullable;
import android.support.annotation.WorkerThread;
-
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
-/**
- * A utility class to check the connectivity.
- */
+/** A utility class to check the connectivity. */
@WorkerThread
public class NetworkUtils {
private static final String GENERATE_204 = "http://clients3.google.com/generate_204";
- /**
- * Checks if the internet connection is available.
- */
+ /** Checks if the internet connection is available. */
public static boolean isNetworkAvailable(@Nullable ConnectivityManager connectivityManager) {
if (connectivityManager == null) {
return false;
@@ -62,5 +57,5 @@ public class NetworkUtils {
return false;
}
- private NetworkUtils() { }
+ private NetworkUtils() {}
}
diff --git a/src/com/android/tv/util/OnboardingUtils.java b/src/com/android/tv/util/OnboardingUtils.java
index 49b02b82..3b72e091 100644
--- a/src/com/android/tv/util/OnboardingUtils.java
+++ b/src/com/android/tv/util/OnboardingUtils.java
@@ -21,9 +21,7 @@ import android.content.Intent;
import android.net.Uri;
import android.preference.PreferenceManager;
-/**
- * A utility class related to onboarding experience.
- */
+/** A utility class related to onboarding experience. */
public final class OnboardingUtils {
private static final String PREF_KEY_IS_FIRST_BOOT = "pref_onbaording_is_first_boot";
private static final String PREF_KEY_ONBOARDING_VERSION_CODE = "pref_onbaording_versionCode";
@@ -31,23 +29,17 @@ public final class OnboardingUtils {
private static final String MERCHANT_COLLECTION_URL_STRING = getMerchantCollectionUrl();
- /**
- * Intent to show merchant collection in online store.
- */
- public static final Intent ONLINE_STORE_INTENT = new Intent(Intent.ACTION_VIEW,
- Uri.parse(MERCHANT_COLLECTION_URL_STRING));
+ /** Intent to show merchant collection in online store. */
+ public static final Intent ONLINE_STORE_INTENT =
+ new Intent(Intent.ACTION_VIEW, Uri.parse(MERCHANT_COLLECTION_URL_STRING));
- /**
- * Checks if this is the first boot after the onboarding experience has been applied.
- */
+ /** Checks if this is the first boot after the onboarding experience has been applied. */
public static boolean isFirstBoot(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context)
.getBoolean(PREF_KEY_IS_FIRST_BOOT, true);
}
- /**
- * Marks that the first boot has been completed.
- */
+ /** Marks that the first boot has been completed. */
public static void setFirstBootCompleted(Context context) {
PreferenceManager.getDefaultSharedPreferences(context)
.edit()
@@ -56,27 +48,28 @@ public final class OnboardingUtils {
}
/**
- * Checks if this is the first run of {@link com.android.tv.MainActivity} with the
- * current onboarding version.
+ * Checks if this is the first run of {@link com.android.tv.MainActivity} with the current
+ * onboarding version.
*/
public static boolean isFirstRunWithCurrentVersion(Context context) {
- int versionCode = PreferenceManager.getDefaultSharedPreferences(context)
- .getInt(PREF_KEY_ONBOARDING_VERSION_CODE, 0);
+ int versionCode =
+ PreferenceManager.getDefaultSharedPreferences(context)
+ .getInt(PREF_KEY_ONBOARDING_VERSION_CODE, 0);
return versionCode != ONBOARDING_VERSION;
}
/**
- * Marks that the first run of {@link com.android.tv.MainActivity} with the current
- * onboarding version has been completed.
+ * Marks that the first run of {@link com.android.tv.MainActivity} with the current onboarding
+ * version has been completed.
*/
public static void setFirstRunWithCurrentVersionCompleted(Context context) {
- PreferenceManager.getDefaultSharedPreferences(context).edit()
- .putInt(PREF_KEY_ONBOARDING_VERSION_CODE, ONBOARDING_VERSION).apply();
+ PreferenceManager.getDefaultSharedPreferences(context)
+ .edit()
+ .putInt(PREF_KEY_ONBOARDING_VERSION_CODE, ONBOARDING_VERSION)
+ .apply();
}
- /**
- * Returns merchant collection URL.
- */
+ /** Returns merchant collection URL. */
private static String getMerchantCollectionUrl() {
return "TODO: add a merchant collection url";
}
diff --git a/src/com/android/tv/util/Partner.java b/src/com/android/tv/util/Partner.java
index e3688392..c5e9aad2 100644
--- a/src/com/android/tv/util/Partner.java
+++ b/src/com/android/tv/util/Partner.java
@@ -26,7 +26,6 @@ import android.content.res.Resources;
import android.media.tv.TvInputInfo;
import android.text.TextUtils;
import android.util.Log;
-
import java.util.HashMap;
import java.util.Map;
@@ -42,6 +41,7 @@ public class Partner {
/** ID tags for device input types */
public static final String INPUT_TYPE_BUNDLED_TUNER = "input_type_combined_tuners";
+
public static final String INPUT_TYPE_TUNER = "input_type_tuner";
public static final String INPUT_TYPE_CEC_LOGICAL = "input_type_cec_logical";
public static final String INPUT_TYPE_CEC_RECORDER = "input_type_cec_recorder";
@@ -68,6 +68,7 @@ public class Partner {
private final Resources mResources;
private static final Map<String, Integer> INPUT_TYPE_MAP = new HashMap<>();
+
static {
INPUT_TYPE_MAP.put(INPUT_TYPE_BUNDLED_TUNER, TvInputManagerHelper.TYPE_BUNDLED_TUNER);
INPUT_TYPE_MAP.put(INPUT_TYPE_TUNER, TvInputInfo.TYPE_TUNER);
diff --git a/src/com/android/tv/util/PermissionUtils.java b/src/com/android/tv/util/PermissionUtils.java
deleted file mode 100644
index a355be99..00000000
--- a/src/com/android/tv/util/PermissionUtils.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.android.tv.util;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-
-/**
- * Util class to handle permissions.
- */
-public class PermissionUtils {
- /**
- * Permission to read the TV listings.
- */
- public static final String PERMISSION_READ_TV_LISTINGS = "android.permission.READ_TV_LISTINGS";
-
- private static Boolean sHasAccessAllEpgPermission;
- private static Boolean sHasAccessWatchedHistoryPermission;
- private static Boolean sHasModifyParentalControlsPermission;
-
- public static boolean hasAccessAllEpg(Context context) {
- if (sHasAccessAllEpgPermission == null) {
- sHasAccessAllEpgPermission = context.checkSelfPermission(
- "com.android.providers.tv.permission.ACCESS_ALL_EPG_DATA")
- == PackageManager.PERMISSION_GRANTED;
- }
- return sHasAccessAllEpgPermission;
- }
-
- public static boolean hasAccessWatchedHistory(Context context) {
- if (sHasAccessWatchedHistoryPermission == null) {
- sHasAccessWatchedHistoryPermission = context.checkSelfPermission(
- "com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS")
- == PackageManager.PERMISSION_GRANTED;
- }
- return sHasAccessWatchedHistoryPermission;
- }
-
- public static boolean hasModifyParentalControls(Context context) {
- if (sHasModifyParentalControlsPermission == null) {
- sHasModifyParentalControlsPermission = context.checkSelfPermission(
- "android.permission.MODIFY_PARENTAL_CONTROLS")
- == PackageManager.PERMISSION_GRANTED;
- }
- return sHasModifyParentalControlsPermission;
- }
-
- public static boolean hasReadTvListings(Context context) {
- return context.checkSelfPermission(PERMISSION_READ_TV_LISTINGS)
- == PackageManager.PERMISSION_GRANTED;
- }
-
- public static boolean hasInternet(Context context) {
- return context.checkSelfPermission("android.permission.INTERNET")
- == PackageManager.PERMISSION_GRANTED;
- }
-}
diff --git a/src/com/android/tv/util/RecurringRunner.java b/src/com/android/tv/util/RecurringRunner.java
index 8b45131b..764689c2 100644
--- a/src/com/android/tv/util/RecurringRunner.java
+++ b/src/com/android/tv/util/RecurringRunner.java
@@ -22,10 +22,8 @@ import android.os.AsyncTask;
import android.os.Handler;
import android.support.annotation.WorkerThread;
import android.util.Log;
-
-import com.android.tv.common.SharedPreferencesUtils;
import com.android.tv.common.SoftPreconditions;
-
+import com.android.tv.common.util.SharedPreferencesUtils;
import java.util.Date;
/**
@@ -46,8 +44,8 @@ public final class RecurringRunner {
private final String mName;
private boolean mRunning;
- public RecurringRunner(Context context, long intervalMs, Runnable runnable,
- Runnable onStopRunnable) {
+ public RecurringRunner(
+ Context context, long intervalMs, Runnable runnable, Runnable onStopRunnable) {
mContext = context.getApplicationContext();
mRunnable = runnable;
mOnStopRunnable = onStopRunnable;
@@ -99,18 +97,21 @@ public final class RecurringRunner {
// Run it anyways even if it is in the past
if (DEBUG) Log.i(TAG, "Next run of " + mName + " at " + new Date(next));
long delay = Math.max(next - now, 0);
- boolean posted = mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- try {
- if (DEBUG) Log.i(TAG, "Starting " + mName);
- mRunnable.run();
- } catch (Exception e) {
- Log.w(TAG, "Error running " + mName, e);
- }
- postAt(resetNextRunTime());
- }
- }, delay);
+ boolean posted =
+ mHandler.postDelayed(
+ new Runnable() {
+ @Override
+ public void run() {
+ try {
+ if (DEBUG) Log.i(TAG, "Starting " + mName);
+ mRunnable.run();
+ } catch (Exception e) {
+ Log.w(TAG, "Error running " + mName, e);
+ }
+ postAt(resetNextRunTime());
+ }
+ },
+ delay);
if (!posted) {
Log.w(TAG, "Scheduling a future run of " + mName + " at " + new Date(next) + "failed");
}
@@ -118,8 +119,8 @@ public final class RecurringRunner {
}
private SharedPreferences getSharedPreferences() {
- return mContext.getSharedPreferences(SharedPreferencesUtils.SHARED_PREF_RECURRING_RUNNER,
- Context.MODE_PRIVATE);
+ return mContext.getSharedPreferences(
+ SharedPreferencesUtils.SHARED_PREF_RECURRING_RUNNER, Context.MODE_PRIVATE);
}
@WorkerThread
diff --git a/src/com/android/tv/util/SetupUtils.java b/src/com/android/tv/util/SetupUtils.java
index 32e3a81f..0d536320 100644
--- a/src/com/android/tv/util/SetupUtils.java
+++ b/src/com/android/tv/util/SetupUtils.java
@@ -28,24 +28,20 @@ import android.media.tv.TvInputManager;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
+import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
-
-import com.android.tv.ApplicationSingletons;
-import com.android.tv.TvApplication;
+import com.android.tv.TvSingletons;
+import com.android.tv.common.BaseApplication;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
-import com.android.tv.tuner.tvinput.TunerTvInputService;
-
+import com.android.tv.data.api.Channel;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
-/**
- * A utility class related to input setup.
- */
+/** A utility class related to input setup. */
public class SetupUtils {
private static final String TAG = "SetupUtils";
private static final boolean DEBUG = false;
@@ -58,9 +54,8 @@ public class SetupUtils {
// Recognized inputs means that the user already knows the inputs are installed.
private static final String PREF_KEY_RECOGNIZED_INPUTS = "recognized_inputs";
private static final String PREF_KEY_IS_FIRST_TUNE = "is_first_tune";
- private static SetupUtils sSetupUtils;
- private final TvApplication mTvApplication;
+ private final Context mContext;
private final SharedPreferences mSharedPreferences;
private final Set<String> mKnownInputs;
private final Set<String> mSetUpInputs;
@@ -68,106 +63,104 @@ public class SetupUtils {
private boolean mIsFirstTune;
private final String mTunerInputId;
- private SetupUtils(TvApplication tvApplication) {
- mTvApplication = tvApplication;
- mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(tvApplication);
+ @VisibleForTesting
+ protected SetupUtils(Context context) {
+ mContext = context;
+ mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
mSetUpInputs = new ArraySet<>();
- mSetUpInputs.addAll(mSharedPreferences.getStringSet(PREF_KEY_SET_UP_INPUTS,
- Collections.emptySet()));
+ mSetUpInputs.addAll(
+ mSharedPreferences.getStringSet(PREF_KEY_SET_UP_INPUTS, Collections.emptySet()));
mKnownInputs = new ArraySet<>();
- mKnownInputs.addAll(mSharedPreferences.getStringSet(PREF_KEY_KNOWN_INPUTS,
- Collections.emptySet()));
+ mKnownInputs.addAll(
+ mSharedPreferences.getStringSet(PREF_KEY_KNOWN_INPUTS, Collections.emptySet()));
mRecognizedInputs = new ArraySet<>();
- mRecognizedInputs.addAll(mSharedPreferences.getStringSet(PREF_KEY_RECOGNIZED_INPUTS,
- mKnownInputs));
+ mRecognizedInputs.addAll(
+ mSharedPreferences.getStringSet(PREF_KEY_RECOGNIZED_INPUTS, mKnownInputs));
mIsFirstTune = mSharedPreferences.getBoolean(PREF_KEY_IS_FIRST_TUNE, true);
- mTunerInputId = TvContract.buildInputId(new ComponentName(tvApplication,
- TunerTvInputService.class));
+ mTunerInputId = BaseApplication.getSingletons(context).getEmbeddedTunerInputId();
}
/**
- * Gets an instance of {@link SetupUtils}.
+ * Creates an instance of {@link SetupUtils}.
+ *
+ * <p><b>WARNING</b> this should only be called by the top level application.
*/
- public static SetupUtils getInstance(Context context) {
- if (sSetupUtils != null) {
- return sSetupUtils;
- }
- sSetupUtils = new SetupUtils((TvApplication) context.getApplicationContext());
- return sSetupUtils;
+ public static SetupUtils createForTvSingletons(Context context) {
+ return new SetupUtils(context.getApplicationContext());
}
- /**
- * Additional work after the setup of TV input.
- */
- public void onTvInputSetupFinished(final String inputId,
- @Nullable final Runnable postRunnable) {
+ /** Additional work after the setup of TV input. */
+ public void onTvInputSetupFinished(
+ final String inputId, @Nullable final Runnable postRunnable) {
// When TIS adds several channels, ChannelDataManager.Listener.onChannelList
// Updated() can be called several times. In this case, it is hard to detect
// which one is the last callback. To reduce error prune, we update channel
// list again and make all channels of {@code inputId} browsable.
onSetupDone(inputId);
- final ChannelDataManager manager = mTvApplication.getChannelDataManager();
+ final ChannelDataManager manager =
+ TvSingletons.getSingletons(mContext).getChannelDataManager();
if (!manager.isDbLoadFinished()) {
- manager.addListener(new ChannelDataManager.Listener() {
- @Override
- public void onLoadFinished() {
- manager.removeListener(this);
- updateChannelsAfterSetup(mTvApplication, inputId, postRunnable);
- }
+ manager.addListener(
+ new ChannelDataManager.Listener() {
+ @Override
+ public void onLoadFinished() {
+ manager.removeListener(this);
+ updateChannelsAfterSetup(mContext, inputId, postRunnable);
+ }
- @Override
- public void onChannelListUpdated() { }
+ @Override
+ public void onChannelListUpdated() {}
- @Override
- public void onChannelBrowsableChanged() { }
- });
+ @Override
+ public void onChannelBrowsableChanged() {}
+ });
} else {
- updateChannelsAfterSetup(mTvApplication, inputId, postRunnable);
+ updateChannelsAfterSetup(mContext, inputId, postRunnable);
}
}
- private static void updateChannelsAfterSetup(Context context, final String inputId,
- final Runnable postRunnable) {
- ApplicationSingletons appSingletons = TvApplication.getSingletons(context);
- final ChannelDataManager manager = appSingletons.getChannelDataManager();
- manager.updateChannels(new Runnable() {
- @Override
- public void run() {
- Channel firstChannelForInput = null;
- boolean browsableChanged = false;
- for (Channel channel : manager.getChannelList()) {
- if (channel.getInputId().equals(inputId)) {
- if (!channel.isBrowsable()) {
- manager.updateBrowsable(channel.getId(), true, true);
- browsableChanged = true;
+ private static void updateChannelsAfterSetup(
+ Context context, final String inputId, final Runnable postRunnable) {
+ TvSingletons tvSingletons = TvSingletons.getSingletons(context);
+ final ChannelDataManager manager = tvSingletons.getChannelDataManager();
+ manager.updateChannels(
+ new Runnable() {
+ @Override
+ public void run() {
+ Channel firstChannelForInput = null;
+ boolean browsableChanged = false;
+ for (Channel channel : manager.getChannelList()) {
+ if (channel.getInputId().equals(inputId)) {
+ if (!channel.isBrowsable()) {
+ manager.updateBrowsable(channel.getId(), true, true);
+ browsableChanged = true;
+ }
+ if (firstChannelForInput == null) {
+ firstChannelForInput = channel;
+ }
+ }
+ }
+ if (firstChannelForInput != null) {
+ Utils.setLastWatchedChannel(context, firstChannelForInput);
}
- if (firstChannelForInput == null) {
- firstChannelForInput = channel;
+ if (browsableChanged) {
+ manager.notifyChannelBrowsableChanged();
+ manager.applyUpdatedValuesToDb();
+ }
+ if (postRunnable != null) {
+ postRunnable.run();
}
}
- }
- if (firstChannelForInput != null) {
- Utils.setLastWatchedChannel(context, firstChannelForInput);
- }
- if (browsableChanged) {
- manager.notifyChannelBrowsableChanged();
- manager.applyUpdatedValuesToDb();
- }
- if (postRunnable != null) {
- postRunnable.run();
- }
- }
- });
+ });
}
- /**
- * Marks the channels in newly installed inputs browsable.
- */
+ /** Marks the channels in newly installed inputs browsable. */
@UiThread
public void markNewChannelsBrowsable() {
Set<String> newInputsWithChannels = new HashSet<>();
- TvInputManagerHelper tvInputManagerHelper = mTvApplication.getTvInputManagerHelper();
- ChannelDataManager channelDataManager = mTvApplication.getChannelDataManager();
+ TvSingletons singletons = TvSingletons.getSingletons(mContext);
+ TvInputManagerHelper tvInputManagerHelper = singletons.getTvInputManagerHelper();
+ ChannelDataManager channelDataManager = singletons.getChannelDataManager();
SoftPreconditions.checkState(channelDataManager.isDbLoadFinished());
for (TvInputInfo input : tvInputManagerHelper.getTvInputInfos(true, true)) {
String inputId = input.getId();
@@ -175,9 +168,13 @@ public class SetupUtils {
onSetupDone(inputId);
newInputsWithChannels.add(inputId);
if (DEBUG) {
- Log.d(TAG, "New input " + inputId + " has "
- + channelDataManager.getChannelCountForInput(inputId)
- + " channels");
+ Log.d(
+ TAG,
+ "New input "
+ + inputId
+ + " has "
+ + channelDataManager.getChannelCountForInput(inputId)
+ + " channels");
}
}
}
@@ -195,9 +192,7 @@ public class SetupUtils {
return mIsFirstTune;
}
- /**
- * Returns true, if the input with {@code inputId} is newly installed.
- */
+ /** Returns true, if the input with {@code inputId} is newly installed. */
public boolean isNewInput(String inputId) {
return !mKnownInputs.contains(inputId);
}
@@ -209,13 +204,14 @@ public class SetupUtils {
public void markAsKnownInput(String inputId) {
mKnownInputs.add(inputId);
mRecognizedInputs.add(inputId);
- mSharedPreferences.edit().putStringSet(PREF_KEY_KNOWN_INPUTS, mKnownInputs)
- .putStringSet(PREF_KEY_RECOGNIZED_INPUTS, mRecognizedInputs).apply();
+ mSharedPreferences
+ .edit()
+ .putStringSet(PREF_KEY_KNOWN_INPUTS, mKnownInputs)
+ .putStringSet(PREF_KEY_RECOGNIZED_INPUTS, mRecognizedInputs)
+ .apply();
}
- /**
- * Returns {@code true}, if {@code inputId}'s setup has been done before.
- */
+ /** Returns {@code true}, if {@code inputId}'s setup has been done before. */
public boolean isSetupDone(String inputId) {
boolean done = mSetUpInputs.contains(inputId);
if (DEBUG) {
@@ -224,9 +220,7 @@ public class SetupUtils {
return done;
}
- /**
- * Returns true, if there is any newly installed input.
- */
+ /** Returns true, if there is any newly installed input. */
public boolean hasNewInput(TvInputManagerHelper inputManager) {
for (TvInputInfo input : inputManager.getTvInputInfos(true, true)) {
if (isNewInput(input.getId())) {
@@ -236,9 +230,7 @@ public class SetupUtils {
return false;
}
- /**
- * Checks whether the given input is already recognized by the user or not.
- */
+ /** Checks whether the given input is already recognized by the user or not. */
private boolean isRecognizedInput(String inputId) {
return mRecognizedInputs.contains(inputId);
}
@@ -251,13 +243,13 @@ public class SetupUtils {
for (TvInputInfo input : inputManager.getTvInputInfos(true, true)) {
mRecognizedInputs.add(input.getId());
}
- mSharedPreferences.edit().putStringSet(PREF_KEY_RECOGNIZED_INPUTS, mRecognizedInputs)
+ mSharedPreferences
+ .edit()
+ .putStringSet(PREF_KEY_RECOGNIZED_INPUTS, mRecognizedInputs)
.apply();
}
- /**
- * Checks whether there are any unrecognized inputs.
- */
+ /** Checks whether there are any unrecognized inputs. */
public boolean hasUnrecognizedInput(TvInputManagerHelper inputManager) {
for (TvInputInfo input : inputManager.getTvInputInfos(true, true)) {
if (!isRecognizedInput(input.getId())) {
@@ -276,8 +268,8 @@ public class SetupUtils {
// Find all already-verified packages.
Set<String> setUpPackages = new HashSet<>();
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
- for (String input : sp.getStringSet(PREF_KEY_SET_UP_INPUTS,
- Collections.<String>emptySet())) {
+ for (String input :
+ sp.getStringSet(PREF_KEY_SET_UP_INPUTS, Collections.<String>emptySet())) {
if (!TextUtils.isEmpty(input)) {
ComponentName componentName = ComponentName.unflattenFromString(input);
if (componentName != null) {
@@ -299,23 +291,28 @@ public class SetupUtils {
*/
public static void grantEpgPermission(Context context, String packageName) {
if (DEBUG) {
- Log.d(TAG, "grantEpgPermission(context=" + context + ", packageName=" + packageName
- + ")");
+ Log.d(
+ TAG,
+ "grantEpgPermission(context=" + context + ", packageName=" + packageName + ")");
}
try {
- int modeFlags = Intent.FLAG_GRANT_WRITE_URI_PERMISSION
- | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
+ int modeFlags =
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+ | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
context.grantUriPermission(packageName, TvContract.Channels.CONTENT_URI, modeFlags);
context.grantUriPermission(packageName, TvContract.Programs.CONTENT_URI, modeFlags);
} catch (SecurityException e) {
- Log.e(TAG, "Either TvProvider does not allow granting of Uri permissions or the app"
- + " does not have permission.", e);
+ Log.e(
+ TAG,
+ "Either TvProvider does not allow granting of Uri permissions or the app"
+ + " does not have permission.",
+ e);
}
}
/**
- * Called when Live channels app is launched. Once it is called, {@link
- * #isFirstTune} will return false.
+ * Called when Live channels app is launched. Once it is called, {@link #isFirstTune} will
+ * return false.
*/
public void onTuned() {
if (!mIsFirstTune) {
@@ -325,9 +322,7 @@ public class SetupUtils {
mSharedPreferences.edit().putBoolean(PREF_KEY_IS_FIRST_TUNE, false).apply();
}
- /**
- * Called when input list is changed. It mainly handles input removals.
- */
+ /** Called when input list is changed. It mainly handles input removals. */
public void onInputListUpdated(TvInputManager manager) {
// mRecognizedInputs > mKnownInputs > mSetUpInputs.
Set<String> removedInputList = new HashSet<>(mRecognizedInputs);
@@ -345,9 +340,10 @@ public class SetupUtils {
try {
// Just after booting, input list from TvInputManager are not reliable.
// So we need to double-check package existence. b/29034900
- mTvApplication.getPackageManager().getPackageInfo(
- ComponentName.unflattenFromString(input)
- .getPackageName(), PackageManager.GET_ACTIVITIES);
+ mContext.getPackageManager()
+ .getPackageInfo(
+ ComponentName.unflattenFromString(input).getPackageName(),
+ PackageManager.GET_ACTIVITIES);
Log.i(TAG, "TV input (" + input + ") is removed but package is not deleted");
} catch (NameNotFoundException e) {
Log.i(TAG, "TV input (" + input + ") and its package are removed");
@@ -358,9 +354,12 @@ public class SetupUtils {
}
}
if (inputPackageDeleted) {
- mSharedPreferences.edit().putStringSet(PREF_KEY_SET_UP_INPUTS, mSetUpInputs)
+ mSharedPreferences
+ .edit()
+ .putStringSet(PREF_KEY_SET_UP_INPUTS, mSetUpInputs)
.putStringSet(PREF_KEY_KNOWN_INPUTS, mKnownInputs)
- .putStringSet(PREF_KEY_RECOGNIZED_INPUTS, mRecognizedInputs).apply();
+ .putStringSet(PREF_KEY_RECOGNIZED_INPUTS, mRecognizedInputs)
+ .apply();
}
}
}
@@ -375,7 +374,9 @@ public class SetupUtils {
if (!mRecognizedInputs.contains(inputId)) {
Log.i(TAG, "An unrecognized input's setup has been done. inputId=" + inputId);
mRecognizedInputs.add(inputId);
- mSharedPreferences.edit().putStringSet(PREF_KEY_RECOGNIZED_INPUTS, mRecognizedInputs)
+ mSharedPreferences
+ .edit()
+ .putStringSet(PREF_KEY_RECOGNIZED_INPUTS, mRecognizedInputs)
.apply();
}
if (!mKnownInputs.contains(inputId)) {
@@ -388,4 +389,4 @@ public class SetupUtils {
mSharedPreferences.edit().putStringSet(PREF_KEY_SET_UP_INPUTS, mSetUpInputs).apply();
}
}
-} \ No newline at end of file
+}
diff --git a/src/com/android/tv/util/SqlParams.java b/src/com/android/tv/util/SqlParams.java
new file mode 100644
index 00000000..c4b803b6
--- /dev/null
+++ b/src/com/android/tv/util/SqlParams.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.android.tv.util;
+
+import android.database.DatabaseUtils;
+import java.util.Arrays;
+
+/** Convenience class for SQL operations. */
+public class SqlParams {
+ private String mTables;
+ private String mSelection;
+ private String[] mSelectionArgs;
+
+ public SqlParams(String tables, String selection, String... selectionArgs) {
+ setTables(tables);
+ setWhere(selection, selectionArgs);
+ }
+
+ public String getTables() {
+ return mTables;
+ }
+
+ public String getSelection() {
+ return mSelection;
+ }
+
+ public String[] getSelectionArgs() {
+ return mSelectionArgs;
+ }
+
+ public void setTables(String tables) {
+ mTables = tables;
+ }
+
+ public void setWhere(String selection, String... selectionArgs) {
+ mSelection = selection;
+ mSelectionArgs = selectionArgs;
+ }
+
+ public void appendWhere(String selection, String... selectionArgs) {
+ mSelection = DatabaseUtils.concatenateWhere(mSelection, selection);
+ if (selectionArgs != null) {
+ mSelectionArgs = DatabaseUtils.appendSelectionArgs(mSelectionArgs, selectionArgs);
+ }
+ }
+
+ public void appendWhereEquals(String name, String value) {
+ appendWhere(name + "=?", value);
+ }
+
+ @Override
+ public String toString() {
+ return "tables "
+ + getTables()
+ + " where "
+ + getSelection()
+ + " with "
+ + Arrays.toString(getSelectionArgs());
+ }
+}
diff --git a/src/com/android/tv/util/StringUtils.java b/src/com/android/tv/util/StringUtils.java
deleted file mode 100644
index 659807e2..00000000
--- a/src/com/android/tv/util/StringUtils.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * 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.android.tv.util;
-
-/**
- * Utility class for handling {@link String}.
- */
-public final class StringUtils {
-
- private StringUtils() { }
-
- /**
- * Returns compares two strings lexicographically and handles null values quietly.
- */
- public static int compare(String a, String b) {
- if (a == null) {
- return b == null ? 0 : -1;
- }
- if (b == null) {
- return 1;
- }
- return a.compareTo(b);
- }
-}
diff --git a/src/com/android/tv/util/SystemProperties.java b/src/com/android/tv/util/SystemProperties.java
deleted file mode 100644
index e737f233..00000000
--- a/src/com/android/tv/util/SystemProperties.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * 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.android.tv.util;
-
-import com.android.tv.common.BooleanSystemProperty;
-
-/**
- * A convenience class for getting TV related system properties.
- */
-public final class SystemProperties {
-
- /**
- * Allow Google Analytics for eng builds.
- */
- public static final BooleanSystemProperty ALLOW_ANALYTICS_IN_ENG = new BooleanSystemProperty(
- "tv_allow_analytics_in_eng", false);
-
- /**
- * Allow Strict mode for debug builds.
- */
- public static final BooleanSystemProperty ALLOW_STRICT_MODE = new BooleanSystemProperty(
- "tv_allow_strict_mode", true);
-
- /**
- * When true {@link android.view.KeyEvent}s are logged. Defaults to false.
- */
- public static final BooleanSystemProperty LOG_KEYEVENT = new BooleanSystemProperty(
- "tv_log_keyevent", false);
- /**
- * When true debug keys are used. Defaults to false.
- */
- public static final BooleanSystemProperty USE_DEBUG_KEYS = new BooleanSystemProperty(
- "tv_use_debug_keys", false);
-
- /**
- * Send {@link com.android.tv.analytics.Tracker} information. Defaults to {@code true}.
- */
- public static final BooleanSystemProperty USE_TRACKER = new BooleanSystemProperty(
- "tv_use_tracker", true);
-
- static {
- updateSystemProperties();
- }
-
- private SystemProperties() {
- }
-
- /**
- * Update the TV related system properties.
- */
- public static void updateSystemProperties() {
- BooleanSystemProperty.resetAll();
- }
-}
diff --git a/src/com/android/tv/util/TimeShiftUtils.java b/src/com/android/tv/util/TimeShiftUtils.java
index 8038a78f..977f3333 100644
--- a/src/com/android/tv/util/TimeShiftUtils.java
+++ b/src/com/android/tv/util/TimeShiftUtils.java
@@ -18,9 +18,7 @@ package com.android.tv.util;
import java.util.concurrent.TimeUnit;
-/**
- * A class that includes convenience methods for time shift plays.
- */
+/** A class that includes convenience methods for time shift plays. */
public class TimeShiftUtils {
private static final String TAG = "TimeShiftUtils";
private static final boolean DEBUG = false;
@@ -30,8 +28,8 @@ public class TimeShiftUtils {
private static final int[] LONG_PROGRAM_SPEED_FACTORS = new int[] {2, 8, 32, 128};
/**
- * The maximum play speed level support by time shift play. In other words, the valid
- * speed levels are ranged from 0 to MAX_SPEED_LEVEL (included).
+ * The maximum play speed level support by time shift play. In other words, the valid speed
+ * levels are ranged from 0 to MAX_SPEED_LEVEL (included).
*/
public static final int MAX_SPEED_LEVEL = SHORT_PROGRAM_SPEED_FACTORS.length - 1;
@@ -45,17 +43,19 @@ public class TimeShiftUtils {
*/
public static int getPlaybackSpeed(int speedLevel, long programDurationMillis)
throws IndexOutOfBoundsException {
- return (programDurationMillis > SHORT_PROGRAM_THRESHOLD_MILLIS) ?
- LONG_PROGRAM_SPEED_FACTORS[speedLevel] : SHORT_PROGRAM_SPEED_FACTORS[speedLevel];
+ return (programDurationMillis > SHORT_PROGRAM_THRESHOLD_MILLIS)
+ ? LONG_PROGRAM_SPEED_FACTORS[speedLevel]
+ : SHORT_PROGRAM_SPEED_FACTORS[speedLevel];
}
/**
* Returns the maxium possible play speed according to the program's length.
+ *
* @param programDurationMillis the length of program under playing.
*/
public static int getMaxPlaybackSpeed(long programDurationMillis) {
- return (programDurationMillis > SHORT_PROGRAM_THRESHOLD_MILLIS) ?
- LONG_PROGRAM_SPEED_FACTORS[MAX_SPEED_LEVEL]
+ return (programDurationMillis > SHORT_PROGRAM_THRESHOLD_MILLIS)
+ ? LONG_PROGRAM_SPEED_FACTORS[MAX_SPEED_LEVEL]
: SHORT_PROGRAM_SPEED_FACTORS[MAX_SPEED_LEVEL];
}
}
diff --git a/src/com/android/tv/util/ToastUtils.java b/src/com/android/tv/util/ToastUtils.java
index 34346b2a..a25653f6 100644
--- a/src/com/android/tv/util/ToastUtils.java
+++ b/src/com/android/tv/util/ToastUtils.java
@@ -19,18 +19,13 @@ package com.android.tv.util;
import android.content.Context;
import android.support.annotation.MainThread;
import android.widget.Toast;
-
import java.lang.ref.WeakReference;
-/**
- * A utility class for the toast message.
- */
+/** A utility class for the toast message. */
public class ToastUtils {
private static WeakReference<Toast> sToast;
- /**
- * Shows the toast message after canceling the previous one.
- */
+ /** Shows the toast message after canceling the previous one. */
@MainThread
public static void show(Context context, CharSequence text, int duration) {
if (sToast != null && sToast.get() != null) {
diff --git a/src/com/android/tv/util/TvInputManagerHelper.java b/src/com/android/tv/util/TvInputManagerHelper.java
index 730a985b..625fb7b2 100644
--- a/src/com/android/tv/util/TvInputManagerHelper.java
+++ b/src/com/android/tv/util/TvInputManagerHelper.java
@@ -21,21 +21,23 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.hardware.hdmi.HdmiDeviceInfo;
+import android.media.tv.TvContentRatingSystemInfo;
import android.media.tv.TvInputInfo;
import android.media.tv.TvInputManager;
import android.media.tv.TvInputManager.TvInputCallback;
import android.os.Handler;
+import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
-
-import com.android.tv.Features;
+import com.android.tv.TvFeatures;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.common.TvCommonUtils;
+import com.android.tv.common.util.CommonUtils;
import com.android.tv.parental.ContentRatingsManager;
import com.android.tv.parental.ParentalControlSettings;
-
+import com.android.tv.util.images.ImageCache;
+import com.android.tv.util.images.ImageLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -49,10 +51,61 @@ public class TvInputManagerHelper {
private static final String TAG = "TvInputManagerHelper";
private static final boolean DEBUG = false;
- /**
- * Types of HDMI device and bundled tuner.
- */
+ public interface TvInputManagerInterface {
+ TvInputInfo getTvInputInfo(String inputId);
+
+ Integer getInputState(String inputId);
+
+ void registerCallback(TvInputCallback internalCallback, Handler handler);
+
+ void unregisterCallback(TvInputCallback internalCallback);
+
+ List<TvInputInfo> getTvInputList();
+
+ List<TvContentRatingSystemInfo> getTvContentRatingSystemList();
+ }
+
+ private static final class TvInputManagerImpl implements TvInputManagerInterface {
+ private final TvInputManager delegate;
+
+ private TvInputManagerImpl(TvInputManager delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public TvInputInfo getTvInputInfo(String inputId) {
+ return delegate.getTvInputInfo(inputId);
+ }
+
+ @Override
+ public Integer getInputState(String inputId) {
+ return delegate.getInputState(inputId);
+ }
+
+ @Override
+ public void registerCallback(TvInputCallback internalCallback, Handler handler) {
+ delegate.registerCallback(internalCallback, handler);
+ }
+
+ @Override
+ public void unregisterCallback(TvInputCallback internalCallback) {
+ delegate.unregisterCallback(internalCallback);
+ }
+
+ @Override
+ public List<TvInputInfo> getTvInputList() {
+ return delegate.getTvInputList();
+ }
+
+ @Override
+ public List<TvContentRatingSystemInfo> getTvContentRatingSystemList() {
+ return delegate.getTvContentRatingSystemList();
+ }
+ }
+
+ /** Types of HDMI device and bundled tuner. */
public static final int TYPE_CEC_DEVICE = -2;
+
public static final int TYPE_BUNDLED_TUNER = -3;
public static final int TYPE_CEC_DEVICE_RECORDER = -4;
public static final int TYPE_CEC_DEVICE_PLAYBACK = -5;
@@ -60,14 +113,13 @@ public class TvInputManagerHelper {
private static final String PERMISSION_ACCESS_ALL_EPG_DATA =
"com.android.providers.tv.permission.ACCESS_ALL_EPG_DATA";
- private static final String [] mPhysicalTunerBlackList = {
+ private static final String[] mPhysicalTunerBlackList = {
};
private static final String META_LABEL_SORT_KEY = "input_sort_key";
- /**
- * The default tv input priority to show.
- */
+ /** The default tv input priority to show. */
private static final ArrayList<Integer> DEFAULT_TV_INPUT_PRIORITY = new ArrayList<>();
+
static {
DEFAULT_TV_INPUT_PRIORITY.add(TYPE_BUNDLED_TUNER);
DEFAULT_TV_INPUT_PRIORITY.add(TvInputInfo.TYPE_TUNER);
@@ -90,12 +142,12 @@ public class TvInputManagerHelper {
};
private static final String[] TESTABLE_INPUTS = {
- "com.android.tv.testinput/.TestTvInputService"
+ "com.android.tv.testinput/.TestTvInputService"
};
private final Context mContext;
private final PackageManager mPackageManager;
- private final TvInputManager mTvInputManager;
+ protected final TvInputManagerInterface mTvInputManager;
private final Map<String, Integer> mInputStateMap = new HashMap<>();
private final Map<String, TvInputInfo> mInputMap = new HashMap<>();
private final Map<String, String> mTvInputLabels = new ArrayMap<>();
@@ -106,100 +158,105 @@ public class TvInputManagerHelper {
private final Map<String, Drawable> mTvInputApplicationIcons = new ArrayMap<>();
private final Map<String, Drawable> mTvInputAppliactionBanners = new ArrayMap<>();
- private final TvInputCallback mInternalCallback = new TvInputCallback() {
- @Override
- public void onInputStateChanged(String inputId, int state) {
- if (DEBUG) Log.d(TAG, "onInputStateChanged " + inputId + " state=" + state);
- if (isInBlackList(inputId)) {
- return;
- }
- mInputStateMap.put(inputId, state);
- for (TvInputCallback callback : mCallbacks) {
- callback.onInputStateChanged(inputId, state);
- }
- }
+ private final TvInputCallback mInternalCallback =
+ new TvInputCallback() {
+ @Override
+ public void onInputStateChanged(String inputId, int state) {
+ if (DEBUG) Log.d(TAG, "onInputStateChanged " + inputId + " state=" + state);
+ if (isInBlackList(inputId)) {
+ return;
+ }
+ mInputStateMap.put(inputId, state);
+ for (TvInputCallback callback : mCallbacks) {
+ callback.onInputStateChanged(inputId, state);
+ }
+ }
- @Override
- public void onInputAdded(String inputId) {
- if (DEBUG) Log.d(TAG, "onInputAdded " + inputId);
- if (isInBlackList(inputId)) {
- return;
- }
- TvInputInfo info = mTvInputManager.getTvInputInfo(inputId);
- if (info != null) {
- mInputMap.put(inputId, info);
- mTvInputLabels.put(inputId, info.loadLabel(mContext).toString());
- CharSequence inputCustomLabel = info.loadCustomLabel(mContext);
- if (inputCustomLabel != null) {
- mTvInputCustomLabels.put(inputId, inputCustomLabel.toString());
+ @Override
+ public void onInputAdded(String inputId) {
+ if (DEBUG) Log.d(TAG, "onInputAdded " + inputId);
+ if (isInBlackList(inputId)) {
+ return;
+ }
+ TvInputInfo info = mTvInputManager.getTvInputInfo(inputId);
+ if (info != null) {
+ mInputMap.put(inputId, info);
+ CharSequence label = info.loadLabel(mContext);
+ // in tests the label may be missing just use the input id
+ mTvInputLabels.put(inputId, label != null ? label.toString() : inputId);
+ CharSequence inputCustomLabel = info.loadCustomLabel(mContext);
+ if (inputCustomLabel != null) {
+ mTvInputCustomLabels.put(inputId, inputCustomLabel.toString());
+ }
+ mInputStateMap.put(inputId, mTvInputManager.getInputState(inputId));
+ mInputIdToPartnerInputMap.put(inputId, isPartnerInput(info));
+ }
+ mContentRatingsManager.update();
+ for (TvInputCallback callback : mCallbacks) {
+ callback.onInputAdded(inputId);
+ }
}
- mInputStateMap.put(inputId, mTvInputManager.getInputState(inputId));
- mInputIdToPartnerInputMap.put(inputId, isPartnerInput(info));
- }
- mContentRatingsManager.update();
- for (TvInputCallback callback : mCallbacks) {
- callback.onInputAdded(inputId);
- }
- }
- @Override
- public void onInputRemoved(String inputId) {
- if (DEBUG) Log.d(TAG, "onInputRemoved " + inputId);
- mInputMap.remove(inputId);
- mTvInputLabels.remove(inputId);
- mTvInputCustomLabels.remove(inputId);
- mTvInputApplicationLabels.remove(inputId);
- mTvInputApplicationIcons.remove(inputId);
- mTvInputAppliactionBanners.remove(inputId);
- mInputStateMap.remove(inputId);
- mInputIdToPartnerInputMap.remove(inputId);
- mContentRatingsManager.update();
- for (TvInputCallback callback : mCallbacks) {
- callback.onInputRemoved(inputId);
- }
- ImageCache.getInstance().remove(ImageLoader.LoadTvInputLogoTask.getTvInputLogoKey(
- inputId));
- }
+ @Override
+ public void onInputRemoved(String inputId) {
+ if (DEBUG) Log.d(TAG, "onInputRemoved " + inputId);
+ mInputMap.remove(inputId);
+ mTvInputLabels.remove(inputId);
+ mTvInputCustomLabels.remove(inputId);
+ mTvInputApplicationLabels.remove(inputId);
+ mTvInputApplicationIcons.remove(inputId);
+ mTvInputAppliactionBanners.remove(inputId);
+ mInputStateMap.remove(inputId);
+ mInputIdToPartnerInputMap.remove(inputId);
+ mContentRatingsManager.update();
+ for (TvInputCallback callback : mCallbacks) {
+ callback.onInputRemoved(inputId);
+ }
+ ImageCache.getInstance()
+ .remove(ImageLoader.LoadTvInputLogoTask.getTvInputLogoKey(inputId));
+ }
- @Override
- public void onInputUpdated(String inputId) {
- if (DEBUG) Log.d(TAG, "onInputUpdated " + inputId);
- if (isInBlackList(inputId)) {
- return;
- }
- TvInputInfo info = mTvInputManager.getTvInputInfo(inputId);
- mInputMap.put(inputId, info);
- mTvInputLabels.put(inputId, info.loadLabel(mContext).toString());
- CharSequence inputCustomLabel = info.loadCustomLabel(mContext);
- if (inputCustomLabel != null) {
- mTvInputCustomLabels.put(inputId, inputCustomLabel.toString());
- }
- mTvInputApplicationLabels.remove(inputId);
- mTvInputApplicationIcons.remove(inputId);
- mTvInputAppliactionBanners.remove(inputId);
- for (TvInputCallback callback : mCallbacks) {
- callback.onInputUpdated(inputId);
- }
- ImageCache.getInstance().remove(ImageLoader.LoadTvInputLogoTask.getTvInputLogoKey(
- inputId));
- }
+ @Override
+ public void onInputUpdated(String inputId) {
+ if (DEBUG) Log.d(TAG, "onInputUpdated " + inputId);
+ if (isInBlackList(inputId)) {
+ return;
+ }
+ TvInputInfo info = mTvInputManager.getTvInputInfo(inputId);
+ mInputMap.put(inputId, info);
+ mTvInputLabels.put(inputId, info.loadLabel(mContext).toString());
+ CharSequence inputCustomLabel = info.loadCustomLabel(mContext);
+ if (inputCustomLabel != null) {
+ mTvInputCustomLabels.put(inputId, inputCustomLabel.toString());
+ }
+ mTvInputApplicationLabels.remove(inputId);
+ mTvInputApplicationIcons.remove(inputId);
+ mTvInputAppliactionBanners.remove(inputId);
+ for (TvInputCallback callback : mCallbacks) {
+ callback.onInputUpdated(inputId);
+ }
+ ImageCache.getInstance()
+ .remove(ImageLoader.LoadTvInputLogoTask.getTvInputLogoKey(inputId));
+ }
- @Override
- public void onTvInputInfoUpdated(TvInputInfo inputInfo) {
- if (DEBUG) Log.d(TAG, "onTvInputInfoUpdated " + inputInfo);
- mInputMap.put(inputInfo.getId(), inputInfo);
- mTvInputLabels.put(inputInfo.getId(), inputInfo.loadLabel(mContext).toString());
- CharSequence inputCustomLabel = inputInfo.loadCustomLabel(mContext);
- if (inputCustomLabel != null) {
- mTvInputCustomLabels.put(inputInfo.getId(), inputCustomLabel.toString());
- }
- for (TvInputCallback callback : mCallbacks) {
- callback.onTvInputInfoUpdated(inputInfo);
- }
- ImageCache.getInstance().remove(ImageLoader.LoadTvInputLogoTask.getTvInputLogoKey(
- inputInfo.getId()));
- }
- };
+ @Override
+ public void onTvInputInfoUpdated(TvInputInfo inputInfo) {
+ if (DEBUG) Log.d(TAG, "onTvInputInfoUpdated " + inputInfo);
+ mInputMap.put(inputInfo.getId(), inputInfo);
+ mTvInputLabels.put(inputInfo.getId(), inputInfo.loadLabel(mContext).toString());
+ CharSequence inputCustomLabel = inputInfo.loadCustomLabel(mContext);
+ if (inputCustomLabel != null) {
+ mTvInputCustomLabels.put(inputInfo.getId(), inputCustomLabel.toString());
+ }
+ for (TvInputCallback callback : mCallbacks) {
+ callback.onTvInputInfoUpdated(inputInfo);
+ }
+ ImageCache.getInstance()
+ .remove(
+ ImageLoader.LoadTvInputLogoTask.getTvInputLogoKey(
+ inputInfo.getId()));
+ }
+ };
private final Handler mHandler = new Handler();
private boolean mStarted;
@@ -209,10 +266,23 @@ public class TvInputManagerHelper {
private final Comparator<TvInputInfo> mTvInputInfoComparator;
public TvInputManagerHelper(Context context) {
+ this(context, createTvInputManagerWrapper(context));
+ }
+
+ @Nullable
+ protected static TvInputManagerImpl createTvInputManagerWrapper(Context context) {
+ TvInputManager tvInputManager =
+ (TvInputManager) context.getSystemService(Context.TV_INPUT_SERVICE);
+ return tvInputManager == null ? null : new TvInputManagerImpl(tvInputManager);
+ }
+
+ @VisibleForTesting
+ protected TvInputManagerHelper(
+ Context context, @Nullable TvInputManagerInterface tvInputManager) {
mContext = context.getApplicationContext();
mPackageManager = context.getPackageManager();
- mTvInputManager = (TvInputManager) context.getSystemService(Context.TV_INPUT_SERVICE);
- mContentRatingsManager = new ContentRatingsManager(context);
+ mTvInputManager = tvInputManager;
+ mContentRatingsManager = new ContentRatingsManager(context, tvInputManager);
mParentalControlSettings = new ParentalControlSettings(context);
mTvInputInfoComparator = new InputComparatorInternal(this);
}
@@ -247,7 +317,9 @@ public class TvInputManagerHelper {
mInputStateMap.put(inputId, state);
mInputIdToPartnerInputMap.put(inputId, isPartnerInput(input));
}
- SoftPreconditions.checkState(mInputStateMap.size() == mInputMap.size(), TAG,
+ SoftPreconditions.checkState(
+ mInputStateMap.size() == mInputMap.size(),
+ TAG,
"mInputStateMap not the same size as mInputMap");
mContentRatingsManager.update();
}
@@ -264,13 +336,12 @@ public class TvInputManagerHelper {
mTvInputCustomLabels.clear();
mTvInputApplicationLabels.clear();
mTvInputApplicationIcons.clear();
- mTvInputAppliactionBanners.clear();;
+ mTvInputAppliactionBanners.clear();
+ ;
mInputIdToPartnerInputMap.clear();
}
- /**
- * Clears the TvInput labels map.
- */
+ /** Clears the TvInput labels map. */
public void clearTvInputLabels() {
mTvInputLabels.clear();
mTvInputCustomLabels.clear();
@@ -294,8 +365,8 @@ public class TvInputManagerHelper {
}
/**
- * Returns the default comparator for {@link TvInputInfo}.
- * See {@link InputComparatorInternal} for detail.
+ * Returns the default comparator for {@link TvInputInfo}. See {@link InputComparatorInternal}
+ * for detail.
*/
public Comparator<TvInputInfo> getDefaultTvInputInfoComparator() {
return mTvInputInfoComparator;
@@ -304,35 +375,31 @@ public class TvInputManagerHelper {
/**
* Checks if the input is from a partner.
*
- * It's visible for comparator test.
- * Package private is enough for this method, but public is necessary to workaround mockito
- * bug.
+ * <p>It's visible for comparator test. Package private is enough for this method, but public is
+ * necessary to workaround mockito bug.
*/
@VisibleForTesting
public boolean isPartnerInput(TvInputInfo inputInfo) {
return isSystemInput(inputInfo) && !isBundledInput(inputInfo);
}
- /**
- * Does the input have {@link ApplicationInfo#FLAG_SYSTEM} set.
- */
+ /** Does the input have {@link ApplicationInfo#FLAG_SYSTEM} set. */
public boolean isSystemInput(TvInputInfo inputInfo) {
return inputInfo != null
- && (inputInfo.getServiceInfo().applicationInfo.flags
- & ApplicationInfo.FLAG_SYSTEM) != 0;
+ && (inputInfo.getServiceInfo().applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
+ != 0;
}
- /**
- * Is the input one known bundled inputs not written by OEM/SOCs.
- */
+ /** Is the input one known bundled inputs not written by OEM/SOCs. */
public boolean isBundledInput(TvInputInfo inputInfo) {
- return inputInfo != null && Utils.isInBundledPackageSet(inputInfo.getServiceInfo()
- .applicationInfo.packageName);
+ return inputInfo != null
+ && CommonUtils.isInBundledPackageSet(
+ inputInfo.getServiceInfo().applicationInfo.packageName);
}
/**
- * Returns if the given input is bundled and written by OEM/SOCs.
- * This returns the cached result.
+ * Returns if the given input is bundled and written by OEM/SOCs. This returns the cached
+ * result.
*/
public boolean isPartnerInput(String inputId) {
Boolean isPartnerInput = mInputIdToPartnerInputMap.get(inputId);
@@ -348,9 +415,7 @@ public class TvInputManagerHelper {
return mTvInputManager != null;
}
- /**
- * Loads label of {@code info}.
- */
+ /** Loads label of {@code info}. */
public String loadLabel(TvInputInfo info) {
String label = mTvInputLabels.get(info.getId());
if (label == null) {
@@ -360,9 +425,7 @@ public class TvInputManagerHelper {
return label;
}
- /**
- * Loads custom label of {@code info}
- */
+ /** Loads custom label of {@code info} */
public String loadCustomLabel(TvInputInfo info) {
String customLabel = mTvInputCustomLabels.get(info.getId());
if (customLabel == null) {
@@ -375,60 +438,46 @@ public class TvInputManagerHelper {
return customLabel;
}
- /**
- * Gets the tv input application's label.
- */
+ /** Gets the tv input application's label. */
public CharSequence getTvInputApplicationLabel(CharSequence inputId) {
return mTvInputApplicationLabels.get(inputId);
}
- /**
- * Stores the tv input application's label.
- */
+ /** Stores the tv input application's label. */
public void setTvInputApplicationLabel(String inputId, CharSequence label) {
mTvInputApplicationLabels.put(inputId, label);
}
- /**
- * Gets the tv input application's icon.
- */
+ /** Gets the tv input application's icon. */
public Drawable getTvInputApplicationIcon(String inputId) {
return mTvInputApplicationIcons.get(inputId);
}
- /**
- * Stores the tv input application's icon.
- */
+ /** Stores the tv input application's icon. */
public void setTvInputApplicationIcon(String inputId, Drawable icon) {
mTvInputApplicationIcons.put(inputId, icon);
}
- /**
- * Gets the tv input application's banner.
- */
+ /** Gets the tv input application's banner. */
public Drawable getTvInputApplicationBanner(String inputId) {
return mTvInputAppliactionBanners.get(inputId);
}
- /**
- * Stores the tv input application's banner.
- */
+ /** Stores the tv input application's banner. */
public void setTvInputApplicationBanner(String inputId, Drawable banner) {
mTvInputAppliactionBanners.put(inputId, banner);
}
- /**
- * Returns if TV input exists with the input id.
- */
+ /** Returns if TV input exists with the input id. */
public boolean hasTvInputInfo(String inputId) {
- SoftPreconditions.checkState(mStarted, TAG,
- "hasTvInputInfo() called before TvInputManagerHelper was started.");
+ SoftPreconditions.checkState(
+ mStarted, TAG, "hasTvInputInfo() called before TvInputManagerHelper was started.");
return mStarted && !TextUtils.isEmpty(inputId) && mInputMap.get(inputId) != null;
}
public TvInputInfo getTvInputInfo(String inputId) {
- SoftPreconditions.checkState(mStarted, TAG,
- "getTvInputInfo() called before TvInputManagerHelper was started.");
+ SoftPreconditions.checkState(
+ mStarted, TAG, "getTvInputInfo() called before TvInputManagerHelper was started.");
if (!mStarted) {
return null;
}
@@ -452,16 +501,23 @@ public class TvInputManagerHelper {
}
return size;
}
-
- public int getInputState(TvInputInfo inputInfo) {
- return getInputState(inputInfo.getId());
+ /**
+ * Returns TvInputInfo's input state.
+ *
+ * @param inputInfo
+ * @return An Integer which stands for the input state {@link
+ * TvInputManager.INPUT_STATE_DISCONNECTED} if inputInfo is null
+ */
+ public int getInputState(@Nullable TvInputInfo inputInfo) {
+ return inputInfo == null
+ ? TvInputManager.INPUT_STATE_DISCONNECTED
+ : getInputState(inputInfo.getId());
}
public int getInputState(String inputId) {
SoftPreconditions.checkState(mStarted, TAG, "AvailabilityManager not started");
if (!mStarted) {
return TvInputManager.INPUT_STATE_DISCONNECTED;
-
}
Integer state = mInputStateMap.get(inputId);
if (state == null) {
@@ -483,16 +539,13 @@ public class TvInputManagerHelper {
return mParentalControlSettings;
}
- /**
- * Returns a ContentRatingsManager instance for a given application context.
- */
+ /** Returns a ContentRatingsManager instance for a given application context. */
public ContentRatingsManager getContentRatingsManager() {
return mContentRatingsManager;
}
private int getInputSortKey(TvInputInfo input) {
- return input.getServiceInfo().metaData.getInt(META_LABEL_SORT_KEY,
- Integer.MAX_VALUE);
+ return input.getServiceInfo().metaData.getInt(META_LABEL_SORT_KEY, Integer.MAX_VALUE);
}
private boolean isInputPhysicalTuner(TvInputInfo input) {
@@ -504,15 +557,20 @@ public class TvInputManagerHelper {
if (input.createSetupIntent() == null) {
return false;
} else {
- boolean mayBeTunerInput = mPackageManager.checkPermission(
- PERMISSION_ACCESS_ALL_EPG_DATA, input.getServiceInfo().packageName)
- == PackageManager.PERMISSION_GRANTED;
+ boolean mayBeTunerInput =
+ mPackageManager.checkPermission(
+ PERMISSION_ACCESS_ALL_EPG_DATA,
+ input.getServiceInfo().packageName)
+ == PackageManager.PERMISSION_GRANTED;
if (!mayBeTunerInput) {
try {
- ApplicationInfo ai = mPackageManager.getApplicationInfo(
- input.getServiceInfo().packageName, 0);
- if ((ai.flags & (ApplicationInfo.FLAG_SYSTEM
- | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) == 0) {
+ ApplicationInfo ai =
+ mPackageManager.getApplicationInfo(
+ input.getServiceInfo().packageName, 0);
+ if ((ai.flags
+ & (ApplicationInfo.FLAG_SYSTEM
+ | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP))
+ == 0) {
return false;
}
} catch (PackageManager.NameNotFoundException e) {
@@ -524,14 +582,15 @@ public class TvInputManagerHelper {
}
private boolean isInBlackList(String inputId) {
- if (Features.USE_PARTNER_INPUT_BLACKLIST.isEnabled(mContext)) {
+ if (TvFeatures.USE_PARTNER_INPUT_BLACKLIST.isEnabled(mContext)) {
for (String disabledTunerInputPrefix : PARTNER_TUNER_INPUT_PREFIX_BLACKLIST) {
if (inputId.contains(disabledTunerInputPrefix)) {
return true;
}
}
}
- if (TvCommonUtils.isRunningInTest()) {
+ if (CommonUtils.isRoboTest()) return false;
+ if (CommonUtils.isRunningInTest()) {
for (String testableInput : TESTABLE_INPUTS) {
if (testableInput.equals(inputId)) {
return false;
@@ -545,10 +604,9 @@ public class TvInputManagerHelper {
/**
* Default comparator for TvInputInfo.
*
- * It's static class that accepts {@link TvInputManagerHelper} as parameter to test.
- * To test comparator, we need to mock API in parent class such as {@link #isPartnerInput},
- * but it's impossible for an inner class to use mocked methods.
- * (i.e. Mockito's spy doesn't work)
+ * <p>It's static class that accepts {@link TvInputManagerHelper} as parameter to test. To test
+ * comparator, we need to mock API in parent class such as {@link #isPartnerInput}, but it's
+ * impossible for an inner class to use mocked methods. (i.e. Mockito's spy doesn't work)
*/
@VisibleForTesting
static class InputComparatorInternal implements Comparator<TvInputInfo> {
@@ -568,8 +626,8 @@ public class TvInputManagerHelper {
}
/**
- * A comparator used for {@link com.android.tv.ui.SelectInputView} to show the list of
- * TV inputs.
+ * A comparator used for {@link com.android.tv.ui.SelectInputView} to show the list of TV
+ * inputs.
*/
public static class HardwareInputComparator implements Comparator<TvInputInfo> {
private Map<Integer, Integer> mTypePriorities = new HashMap<>();
@@ -591,10 +649,12 @@ public class TvInputManagerHelper {
return -1;
}
- boolean enabledL = (mTvInputManagerHelper.getInputState(lhs)
- != TvInputManager.INPUT_STATE_DISCONNECTED);
- boolean enabledR = (mTvInputManagerHelper.getInputState(rhs)
- != TvInputManager.INPUT_STATE_DISCONNECTED);
+ boolean enabledL =
+ (mTvInputManagerHelper.getInputState(lhs)
+ != TvInputManager.INPUT_STATE_DISCONNECTED);
+ boolean enabledR =
+ (mTvInputManagerHelper.getInputState(rhs)
+ != TvInputManager.INPUT_STATE_DISCONNECTED);
if (enabledL != enabledR) {
return enabledL ? -1 : 1;
}
@@ -620,11 +680,13 @@ public class TvInputManagerHelper {
return sortKeyR - sortKeyL;
}
- String parentLabelL = lhs.getParentId() != null
- ? getLabel(mTvInputManagerHelper.getTvInputInfo(lhs.getParentId()))
+ String parentLabelL =
+ lhs.getParentId() != null
+ ? getLabel(mTvInputManagerHelper.getTvInputInfo(lhs.getParentId()))
: getLabel(mTvInputManagerHelper.getTvInputInfo(lhs.getId()));
- String parentLabelR = rhs.getParentId() != null
- ? getLabel(mTvInputManagerHelper.getTvInputInfo(rhs.getParentId()))
+ String parentLabelR =
+ rhs.getParentId() != null
+ ? getLabel(mTvInputManagerHelper.getTvInputInfo(rhs.getParentId()))
: getLabel(mTvInputManagerHelper.getTvInputInfo(rhs.getId()));
if (!TextUtils.equals(parentLabelL, parentLabelR)) {
diff --git a/src/com/android/tv/util/TvSettings.java b/src/com/android/tv/util/TvSettings.java
index c5fde317..ae79e7e5 100644
--- a/src/com/android/tv/util/TvSettings.java
+++ b/src/com/android/tv/util/TvSettings.java
@@ -21,7 +21,6 @@ import android.content.SharedPreferences;
import android.media.tv.TvTrackInfo;
import android.preference.PreferenceManager;
import android.support.annotation.IntDef;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Collections;
@@ -29,11 +28,11 @@ import java.util.HashSet;
import java.util.Set;
/**
- * A class about the constants for TV settings.
- * Objects that are returned from the various {@code get} methods must be treated as immutable.
+ * A class about the constants for TV settings. Objects that are returned from the various {@code
+ * get} methods must be treated as immutable.
*/
public final class TvSettings {
- public static final String PREF_DISPLAY_MODE = "display_mode"; // int value
+ public static final String PREF_DISPLAY_MODE = "display_mode"; // int value
public static final String PREF_PIN = "pin"; // 4-digit string value. Otherwise, it's not set.
// Multi-track audio settings
@@ -56,9 +55,14 @@ public final class TvSettings {
@Retention(RetentionPolicy.SOURCE)
@IntDef({
- CONTENT_RATING_LEVEL_NONE, CONTENT_RATING_LEVEL_HIGH, CONTENT_RATING_LEVEL_MEDIUM,
- CONTENT_RATING_LEVEL_LOW, CONTENT_RATING_LEVEL_CUSTOM })
+ CONTENT_RATING_LEVEL_NONE,
+ CONTENT_RATING_LEVEL_HIGH,
+ CONTENT_RATING_LEVEL_MEDIUM,
+ CONTENT_RATING_LEVEL_LOW,
+ CONTENT_RATING_LEVEL_CUSTOM
+ })
public @interface ContentRatingLevel {}
+
public static final int CONTENT_RATING_LEVEL_NONE = 0;
public static final int CONTENT_RATING_LEVEL_HIGH = 1;
public static final int CONTENT_RATING_LEVEL_MEDIUM = 2;
@@ -69,61 +73,74 @@ public final class TvSettings {
// Multi-track audio settings
public static String getMultiAudioId(Context context) {
- return PreferenceManager.getDefaultSharedPreferences(context).getString(
- PREF_MULTI_AUDIO_ID, null);
+ return PreferenceManager.getDefaultSharedPreferences(context)
+ .getString(PREF_MULTI_AUDIO_ID, null);
}
public static void setMultiAudioId(Context context, String language) {
- PreferenceManager.getDefaultSharedPreferences(context).edit().putString(
- PREF_MULTI_AUDIO_ID, language).apply();
+ PreferenceManager.getDefaultSharedPreferences(context)
+ .edit()
+ .putString(PREF_MULTI_AUDIO_ID, language)
+ .apply();
}
public static String getMultiAudioLanguage(Context context) {
- return PreferenceManager.getDefaultSharedPreferences(context).getString(
- PREF_MULTI_AUDIO_LANGUAGE, null);
+ return PreferenceManager.getDefaultSharedPreferences(context)
+ .getString(PREF_MULTI_AUDIO_LANGUAGE, null);
}
public static void setMultiAudioLanguage(Context context, String language) {
- PreferenceManager.getDefaultSharedPreferences(context).edit().putString(
- PREF_MULTI_AUDIO_LANGUAGE, language).apply();
+ PreferenceManager.getDefaultSharedPreferences(context)
+ .edit()
+ .putString(PREF_MULTI_AUDIO_LANGUAGE, language)
+ .apply();
}
public static int getMultiAudioChannelCount(Context context) {
- return PreferenceManager.getDefaultSharedPreferences(context).getInt(
- PREF_MULTI_AUDIO_CHANNEL_COUNT, 0);
+ return PreferenceManager.getDefaultSharedPreferences(context)
+ .getInt(PREF_MULTI_AUDIO_CHANNEL_COUNT, 0);
}
public static void setMultiAudioChannelCount(Context context, int channelCount) {
- PreferenceManager.getDefaultSharedPreferences(context).edit().putInt(
- PREF_MULTI_AUDIO_CHANNEL_COUNT, channelCount).apply();
+ PreferenceManager.getDefaultSharedPreferences(context)
+ .edit()
+ .putInt(PREF_MULTI_AUDIO_CHANNEL_COUNT, channelCount)
+ .apply();
}
- public static void setDvrPlaybackTrackSettings(Context context, int trackType,
- TvTrackInfo info) {
+ public static void setDvrPlaybackTrackSettings(
+ Context context, int trackType, TvTrackInfo info) {
if (trackType == TvTrackInfo.TYPE_AUDIO) {
if (info == null) {
- PreferenceManager.getDefaultSharedPreferences(context).edit()
- .remove(PREF_DVR_MULTI_AUDIO_ID).apply();
+ PreferenceManager.getDefaultSharedPreferences(context)
+ .edit()
+ .remove(PREF_DVR_MULTI_AUDIO_ID)
+ .apply();
} else {
- PreferenceManager.getDefaultSharedPreferences(context).edit()
+ PreferenceManager.getDefaultSharedPreferences(context)
+ .edit()
.putString(PREF_DVR_MULTI_AUDIO_LANGUAGE, info.getLanguage())
.putInt(PREF_DVR_MULTI_AUDIO_CHANNEL_COUNT, info.getAudioChannelCount())
- .putString(PREF_DVR_MULTI_AUDIO_ID, info.getId()).apply();
+ .putString(PREF_DVR_MULTI_AUDIO_ID, info.getId())
+ .apply();
}
} else if (trackType == TvTrackInfo.TYPE_SUBTITLE) {
if (info == null) {
- PreferenceManager.getDefaultSharedPreferences(context).edit()
- .remove(PREF_DVR_SUBTITLE_ID).apply();
+ PreferenceManager.getDefaultSharedPreferences(context)
+ .edit()
+ .remove(PREF_DVR_SUBTITLE_ID)
+ .apply();
} else {
- PreferenceManager.getDefaultSharedPreferences(context).edit()
+ PreferenceManager.getDefaultSharedPreferences(context)
+ .edit()
.putString(PREF_DVR_SUBTITLE_LANGUAGE, info.getLanguage())
- .putString(PREF_DVR_SUBTITLE_ID, info.getId()).apply();
+ .putString(PREF_DVR_SUBTITLE_ID, info.getId())
+ .apply();
}
}
}
- public static TvTrackInfo getDvrPlaybackTrackSettings(Context context,
- int trackType) {
+ public static TvTrackInfo getDvrPlaybackTrackSettings(Context context, int trackType) {
String language;
String trackId;
int channelCount;
@@ -136,7 +153,9 @@ public final class TvSettings {
language = pref.getString(PREF_DVR_MULTI_AUDIO_LANGUAGE, null);
channelCount = pref.getInt(PREF_DVR_MULTI_AUDIO_CHANNEL_COUNT, 0);
return new TvTrackInfo.Builder(trackType, trackId)
- .setLanguage(language).setAudioChannelCount(channelCount).build();
+ .setLanguage(language)
+ .setAudioChannelCount(channelCount)
+ .build();
} else if (trackType == TvTrackInfo.TYPE_SUBTITLE) {
trackId = pref.getString(PREF_DVR_SUBTITLE_ID, null);
if (trackId == null) {
@@ -153,16 +172,20 @@ public final class TvSettings {
public static void addContentRatingSystem(Context context, String id) {
Set<String> contentRatingSystemSet = getContentRatingSystemSet(context);
if (contentRatingSystemSet.add(id)) {
- PreferenceManager.getDefaultSharedPreferences(context).edit()
- .putStringSet(PREF_CONTENT_RATING_SYSTEMS, contentRatingSystemSet).apply();
+ PreferenceManager.getDefaultSharedPreferences(context)
+ .edit()
+ .putStringSet(PREF_CONTENT_RATING_SYSTEMS, contentRatingSystemSet)
+ .apply();
}
}
public static void removeContentRatingSystem(Context context, String id) {
Set<String> contentRatingSystemSet = getContentRatingSystemSet(context);
if (contentRatingSystemSet.remove(id)) {
- PreferenceManager.getDefaultSharedPreferences(context).edit()
- .putStringSet(PREF_CONTENT_RATING_SYSTEMS, contentRatingSystemSet).apply();
+ PreferenceManager.getDefaultSharedPreferences(context)
+ .edit()
+ .putStringSet(PREF_CONTENT_RATING_SYSTEMS, contentRatingSystemSet)
+ .apply();
}
}
@@ -176,25 +199,28 @@ public final class TvSettings {
*/
public static boolean isContentRatingSystemSet(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context)
- .getStringSet(PREF_CONTENT_RATING_SYSTEMS, null) != null;
+ .getStringSet(PREF_CONTENT_RATING_SYSTEMS, null)
+ != null;
}
private static Set<String> getContentRatingSystemSet(Context context) {
- return new HashSet<>(PreferenceManager.getDefaultSharedPreferences(context)
- .getStringSet(PREF_CONTENT_RATING_SYSTEMS, Collections.emptySet()));
+ return new HashSet<>(
+ PreferenceManager.getDefaultSharedPreferences(context)
+ .getStringSet(PREF_CONTENT_RATING_SYSTEMS, Collections.emptySet()));
}
@ContentRatingLevel
@SuppressWarnings("ResourceType")
public static int getContentRatingLevel(Context context) {
- return PreferenceManager.getDefaultSharedPreferences(context).getInt(
- PREF_CONTENT_RATING_LEVEL, CONTENT_RATING_LEVEL_NONE);
+ return PreferenceManager.getDefaultSharedPreferences(context)
+ .getInt(PREF_CONTENT_RATING_LEVEL, CONTENT_RATING_LEVEL_NONE);
}
- public static void setContentRatingLevel(Context context,
- @ContentRatingLevel int level) {
- PreferenceManager.getDefaultSharedPreferences(context).edit().putInt(
- PREF_CONTENT_RATING_LEVEL, level).apply();
+ public static void setContentRatingLevel(Context context, @ContentRatingLevel int level) {
+ PreferenceManager.getDefaultSharedPreferences(context)
+ .edit()
+ .putInt(PREF_CONTENT_RATING_LEVEL, level)
+ .apply();
}
/**
@@ -202,8 +228,8 @@ public final class TvSettings {
* repeatedly).
*/
public static long getDisablePinUntil(Context context) {
- return PreferenceManager.getDefaultSharedPreferences(context).getLong(
- PREF_DISABLE_PIN_UNTIL, 0);
+ return PreferenceManager.getDefaultSharedPreferences(context)
+ .getLong(PREF_DISABLE_PIN_UNTIL, 0);
}
/**
@@ -211,7 +237,9 @@ public final class TvSettings {
* repeatedly).
*/
public static void setDisablePinUntil(Context context, long timeMillis) {
- PreferenceManager.getDefaultSharedPreferences(context).edit().putLong(
- PREF_DISABLE_PIN_UNTIL, timeMillis).apply();
+ PreferenceManager.getDefaultSharedPreferences(context)
+ .edit()
+ .putLong(PREF_DISABLE_PIN_UNTIL, timeMillis)
+ .apply();
}
-} \ No newline at end of file
+}
diff --git a/src/com/android/tv/util/TvTrackInfoUtils.java b/src/com/android/tv/util/TvTrackInfoUtils.java
index 667cc9bf..09874502 100644
--- a/src/com/android/tv/util/TvTrackInfoUtils.java
+++ b/src/com/android/tv/util/TvTrackInfoUtils.java
@@ -16,27 +16,24 @@
package com.android.tv.util;
import android.media.tv.TvTrackInfo;
-
import java.util.Comparator;
import java.util.List;
-/**
- * Static utilities for {@link TvTrackInfo}.
- */
+/** Static utilities for {@link TvTrackInfo}. */
public class TvTrackInfoUtils {
/**
* Compares how closely two {@link android.media.tv.TvTrackInfo}s match {@code language}, {@code
* channelCount} and {@code id} in that precedence.
*
- * @param id The track id to match.
- * @param language The language to match.
+ * @param id The track id to match.
+ * @param language The language to match.
* @param channelCount The channel count to match.
* @return -1 if lhs is a worse match, 0 if lhs and rhs match equally and 1 if lhs is a better
- * match.
+ * match.
*/
- public static Comparator<TvTrackInfo> createComparator(final String id, final String language,
- final int channelCount) {
+ public static Comparator<TvTrackInfo> createComparator(
+ final String id, final String language, final int channelCount) {
return new Comparator<TvTrackInfo>() {
@Override
@@ -52,15 +49,17 @@ public class TvTrackInfoUtils {
}
// Assumes {@code null} language matches to any language since it means user hasn't
// selected any track before or selected a track without language information.
- boolean lhsLangMatch = language == null || Utils.isEqualLanguage(lhs.getLanguage(),
- language);
- boolean rhsLangMatch = language == null || Utils.isEqualLanguage(rhs.getLanguage(),
- language);
+ boolean lhsLangMatch =
+ language == null || Utils.isEqualLanguage(lhs.getLanguage(), language);
+ boolean rhsLangMatch =
+ language == null || Utils.isEqualLanguage(rhs.getLanguage(), language);
if (lhsLangMatch && rhsLangMatch) {
- boolean lhsCountMatch = lhs.getType() != TvTrackInfo.TYPE_AUDIO
- || lhs.getAudioChannelCount() == channelCount;
- boolean rhsCountMatch = rhs.getType() != TvTrackInfo.TYPE_AUDIO
- || rhs.getAudioChannelCount() == channelCount;
+ boolean lhsCountMatch =
+ lhs.getType() != TvTrackInfo.TYPE_AUDIO
+ || lhs.getAudioChannelCount() == channelCount;
+ boolean rhsCountMatch =
+ rhs.getType() != TvTrackInfo.TYPE_AUDIO
+ || rhs.getAudioChannelCount() == channelCount;
if (lhsCountMatch && rhsCountMatch) {
return Boolean.compare(lhs.getId().equals(id), rhs.getId().equals(id));
} else {
@@ -74,16 +73,16 @@ public class TvTrackInfoUtils {
}
/**
- * Selects the best TvTrackInfo available or the first if none matches.
+ * Selects the best TvTrackInfo available or the first if none matches.
*
- * @param tracks The tracks to choose from
- * @param id The track id to match.
- * @param language The language to match.
+ * @param tracks The tracks to choose from
+ * @param id The track id to match.
+ * @param language The language to match.
* @param channelCount The channel count to match.
* @return the best matching track or the first one if none matches.
*/
- public static TvTrackInfo getBestTrackInfo(List<TvTrackInfo> tracks, String id, String language,
- int channelCount) {
+ public static TvTrackInfo getBestTrackInfo(
+ List<TvTrackInfo> tracks, String id, String language, int channelCount) {
if (tracks == null) {
return null;
}
@@ -97,6 +96,5 @@ public class TvTrackInfoUtils {
return best;
}
- private TvTrackInfoUtils() {
- }
-} \ No newline at end of file
+ private TvTrackInfoUtils() {}
+}
diff --git a/src/com/android/tv/util/TvUriMatcher.java b/src/com/android/tv/util/TvUriMatcher.java
index 3d91cdad..9e74117e 100644
--- a/src/com/android/tv/util/TvUriMatcher.java
+++ b/src/com/android/tv/util/TvUriMatcher.java
@@ -21,22 +21,25 @@ import android.content.UriMatcher;
import android.media.tv.TvContract;
import android.net.Uri;
import android.support.annotation.IntDef;
-
import com.android.tv.search.LocalSearchProvider;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-/**
- * Utility class to aid in matching URIs in TvProvider.
- */
+/** Utility class to aid in matching URIs in TvProvider. */
public class TvUriMatcher {
private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
@Retention(RetentionPolicy.SOURCE)
- @IntDef({MATCH_CHANNEL, MATCH_CHANNEL_ID, MATCH_PROGRAM, MATCH_PROGRAM_ID,
- MATCH_RECORDED_PROGRAM, MATCH_RECORDED_PROGRAM_ID, MATCH_WATCHED_PROGRAM_ID,
- MATCH_ON_DEVICE_SEARCH})
+ @IntDef({
+ MATCH_CHANNEL,
+ MATCH_CHANNEL_ID,
+ MATCH_PROGRAM,
+ MATCH_PROGRAM_ID,
+ MATCH_RECORDED_PROGRAM,
+ MATCH_RECORDED_PROGRAM_ID,
+ MATCH_WATCHED_PROGRAM_ID,
+ MATCH_ON_DEVICE_SEARCH
+ })
private @interface TvProviderUriMatchCode {}
/** The code for the channels URI. */
public static final int MATCH_CHANNEL = 1;
@@ -54,6 +57,7 @@ public class TvUriMatcher {
public static final int MATCH_WATCHED_PROGRAM_ID = 7;
/** The code for the on-device search URI. */
public static final int MATCH_ON_DEVICE_SEARCH = 8;
+
static {
URI_MATCHER.addURI(TvContract.AUTHORITY, "channel", MATCH_CHANNEL);
URI_MATCHER.addURI(TvContract.AUTHORITY, "channel/#", MATCH_CHANNEL_ID);
@@ -62,11 +66,13 @@ public class TvUriMatcher {
URI_MATCHER.addURI(TvContract.AUTHORITY, "recorded_program", MATCH_RECORDED_PROGRAM);
URI_MATCHER.addURI(TvContract.AUTHORITY, "recorded_program/#", MATCH_RECORDED_PROGRAM_ID);
URI_MATCHER.addURI(TvContract.AUTHORITY, "watched_program/#", MATCH_WATCHED_PROGRAM_ID);
- URI_MATCHER.addURI(LocalSearchProvider.AUTHORITY,
- SearchManager.SUGGEST_URI_PATH_QUERY + "/*", MATCH_ON_DEVICE_SEARCH);
+ URI_MATCHER.addURI(
+ LocalSearchProvider.AUTHORITY,
+ SearchManager.SUGGEST_URI_PATH_QUERY + "/*",
+ MATCH_ON_DEVICE_SEARCH);
}
- private TvUriMatcher() { }
+ private TvUriMatcher() {}
/**
* Try to match against the path in a url.
@@ -74,7 +80,8 @@ public class TvUriMatcher {
* @see UriMatcher#match
*/
@SuppressWarnings("WrongConstant")
- @TvProviderUriMatchCode public static int match(Uri uri) {
+ @TvProviderUriMatchCode
+ public static int match(Uri uri) {
return URI_MATCHER.match(uri);
}
}
diff --git a/src/com/android/tv/util/Utils.java b/src/com/android/tv/util/Utils.java
index d11bab3c..a75bd446 100644
--- a/src/com/android/tv/util/Utils.java
+++ b/src/com/android/tv/util/Utils.java
@@ -38,22 +38,16 @@ import android.support.annotation.VisibleForTesting;
import android.support.annotation.WorkerThread;
import android.text.TextUtils;
import android.text.format.DateUtils;
-import android.util.ArraySet;
import android.util.Log;
import android.view.View;
-
-import com.android.tv.ApplicationSingletons;
import com.android.tv.R;
-import com.android.tv.TvApplication;
-import com.android.tv.common.BuildConfig;
+import com.android.tv.TvSingletons;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.data.Channel;
+import com.android.tv.common.util.Clock;
import com.android.tv.data.GenreItems;
import com.android.tv.data.Program;
import com.android.tv.data.StreamInfo;
-import com.android.tv.experiments.Experiments;
-
-import java.io.File;
+import com.android.tv.data.api.Channel;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
@@ -69,18 +63,13 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
-/**
- * A class that includes convenience methods for accessing TvProvider database.
- */
+/** A class that includes convenience methods for accessing TvProvider database. */
public class Utils {
private static final String TAG = "Utils";
private static final boolean DEBUG = false;
- private static final SimpleDateFormat ISO_8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ",
- Locale.US);
-
public static final String EXTRA_KEY_ACTION = "action";
- public static final String EXTRA_ACTION_SHOW_TV_INPUT ="show_tv_input";
+ public static final String EXTRA_ACTION_SHOW_TV_INPUT = "show_tv_input";
public static final String EXTRA_KEY_FROM_LAUNCHER = "from_launcher";
public static final String EXTRA_KEY_RECORDED_PROGRAM_ID = "recorded_program_id";
public static final String EXTRA_KEY_RECORDED_PROGRAM_SEEK_TIME = "recorded_program_seek_time";
@@ -97,8 +86,7 @@ public class Utils {
private static final String PREF_KEY_LAST_WATCHED_CHANNEL_URI = "last_watched_channel_uri";
private static final String PREF_KEY_LAST_WATCHED_TUNER_INPUT_ID =
"last_watched_tuner_input_id";
- private static final String PREF_KEY_RECORDING_FAILED_REASONS =
- "recording_failed_reasons";
+ private static final String PREF_KEY_RECORDING_FAILED_REASONS = "recording_failed_reasons";
private static final String PREF_KEY_FAILED_SCHEDULED_RECORDING_INFO_SET =
"failed_scheduled_recording_info_set";
@@ -121,15 +109,6 @@ public class Utils {
private static final long HALF_MINUTE_MS = TimeUnit.SECONDS.toMillis(30);
private static final long ONE_DAY_MS = TimeUnit.DAYS.toMillis(1);
- // Hardcoded list for known bundled inputs not written by OEM/SOCs.
- // Bundled (system) inputs not in the list will get the high priority
- // so they and their channels come first in the UI.
- private static final Set<String> BUNDLED_PACKAGE_SET = new ArraySet<>();
-
- static {
- BUNDLED_PACKAGE_SET.add("com.android.tv");
- }
-
private enum AspectRatio {
ASPECT_RATIO_4_3(4, 3),
ASPECT_RATIO_16_9(16, 9),
@@ -150,13 +129,11 @@ public class Utils {
}
}
- private Utils() {
- }
+ private Utils() {}
public static String buildSelectionForIds(String idName, List<Long> ids) {
StringBuilder sb = new StringBuilder();
- sb.append(idName).append(" in (")
- .append(ids.get(0));
+ sb.append(idName).append(" in (").append(ids.get(0));
for (int i = 1; i < ids.size(); ++i) {
sb.append(",").append(ids.get(i));
}
@@ -171,8 +148,8 @@ public class Utils {
}
Uri channelUri = TvContract.buildChannelUri(channelId);
String[] projection = {TvContract.Channels.COLUMN_INPUT_ID};
- try (Cursor cursor = context.getContentResolver()
- .query(channelUri, projection, null, null, null)) {
+ try (Cursor cursor =
+ context.getContentResolver().query(channelUri, projection, null, null, null)) {
if (cursor != null && cursor.moveToNext()) {
return Utils.intern(cursor.getString(0));
}
@@ -185,60 +162,61 @@ public class Utils {
Log.e(TAG, "setLastWatchedChannel: channel cannot be null");
return;
}
- PreferenceManager.getDefaultSharedPreferences(context).edit()
- .putString(PREF_KEY_LAST_WATCHED_CHANNEL_URI, channel.getUri().toString()).apply();
+ PreferenceManager.getDefaultSharedPreferences(context)
+ .edit()
+ .putString(PREF_KEY_LAST_WATCHED_CHANNEL_URI, channel.getUri().toString())
+ .apply();
if (!channel.isPassthrough()) {
long channelId = channel.getId();
if (channel.getId() < 0) {
throw new IllegalArgumentException("channelId should be equal to or larger than 0");
}
- PreferenceManager.getDefaultSharedPreferences(context).edit()
+ PreferenceManager.getDefaultSharedPreferences(context)
+ .edit()
.putLong(PREF_KEY_LAST_WATCHED_CHANNEL_ID, channelId)
- .putLong(PREF_KEY_LAST_WATCHED_CHANNEL_ID_FOR_INPUT + channel.getInputId(),
+ .putLong(
+ PREF_KEY_LAST_WATCHED_CHANNEL_ID_FOR_INPUT + channel.getInputId(),
channelId)
.putString(PREF_KEY_LAST_WATCHED_TUNER_INPUT_ID, channel.getInputId())
.apply();
}
}
- /**
- * Sets recording failed reason.
- */
+ /** Sets recording failed reason. */
public static void setRecordingFailedReason(Context context, int reason) {
long reasons = getRecordingFailedReasons(context) | 0x1 << reason;
- PreferenceManager.getDefaultSharedPreferences(context).edit()
+ PreferenceManager.getDefaultSharedPreferences(context)
+ .edit()
.putLong(PREF_KEY_RECORDING_FAILED_REASONS, reasons)
.apply();
}
- /**
- * Adds the info of failed scheduled recording.
- */
- public static void addFailedScheduledRecordingInfo(Context context,
- String scheduledRecordingInfo) {
+ /** Adds the info of failed scheduled recording. */
+ public static void addFailedScheduledRecordingInfo(
+ Context context, String scheduledRecordingInfo) {
Set<String> failedScheduledRecordingInfoSet = getFailedScheduledRecordingInfoSet(context);
failedScheduledRecordingInfoSet.add(scheduledRecordingInfo);
- PreferenceManager.getDefaultSharedPreferences(context).edit()
- .putStringSet(PREF_KEY_FAILED_SCHEDULED_RECORDING_INFO_SET,
+ PreferenceManager.getDefaultSharedPreferences(context)
+ .edit()
+ .putStringSet(
+ PREF_KEY_FAILED_SCHEDULED_RECORDING_INFO_SET,
failedScheduledRecordingInfoSet)
.apply();
}
- /**
- * Clears the failed scheduled recording info set.
- */
+ /** Clears the failed scheduled recording info set. */
public static void clearFailedScheduledRecordingInfoSet(Context context) {
- PreferenceManager.getDefaultSharedPreferences(context).edit()
+ PreferenceManager.getDefaultSharedPreferences(context)
+ .edit()
.remove(PREF_KEY_FAILED_SCHEDULED_RECORDING_INFO_SET)
.apply();
}
- /**
- * Clears recording failed reason.
- */
+ /** Clears recording failed reason. */
public static void clearRecordingFailedReason(Context context, int reason) {
long reasons = getRecordingFailedReasons(context) & ~(0x1 << reason);
- PreferenceManager.getDefaultSharedPreferences(context).edit()
+ PreferenceManager.getDefaultSharedPreferences(context)
+ .edit()
.putLong(PREF_KEY_RECORDING_FAILED_REASONS, reasons)
.apply();
}
@@ -258,9 +236,7 @@ public class Utils {
.getString(PREF_KEY_LAST_WATCHED_CHANNEL_URI, null);
}
- /**
- * Returns the last watched tuner input id.
- */
+ /** Returns the last watched tuner input id. */
public static String getLastWatchedTunerInputId(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context)
.getString(PREF_KEY_LAST_WATCHED_TUNER_INPUT_ID, null);
@@ -268,32 +244,28 @@ public class Utils {
private static long getRecordingFailedReasons(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context)
- .getLong(PREF_KEY_RECORDING_FAILED_REASONS,
- RECORDING_FAILED_REASON_NONE);
+ .getLong(PREF_KEY_RECORDING_FAILED_REASONS, RECORDING_FAILED_REASON_NONE);
}
- /**
- * Returns the failed scheduled recordings info set.
- */
+ /** Returns the failed scheduled recordings info set. */
public static Set<String> getFailedScheduledRecordingInfoSet(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context)
.getStringSet(PREF_KEY_FAILED_SCHEDULED_RECORDING_INFO_SET, new HashSet<>());
}
- /**
- * Checks do recording failed reason exist.
- */
+ /** Checks do recording failed reason exist. */
public static boolean hasRecordingFailedReason(Context context, int reason) {
long reasons = getRecordingFailedReasons(context);
return (reasons & 0x1 << reason) != 0;
}
/**
- * Returns {@code true}, if {@code uri} specifies an input, which is usually generated
- * from {@link TvContract#buildChannelsUriForInput}.
+ * Returns {@code true}, if {@code uri} specifies an input, which is usually generated from
+ * {@link TvContract#buildChannelsUriForInput}.
*/
public static boolean isChannelUriForInput(Uri uri) {
- return isTvUri(uri) && PATH_CHANNEL.equals(uri.getPathSegments().get(0))
+ return isTvUri(uri)
+ && PATH_CHANNEL.equals(uri.getPathSegments().get(0))
&& !TextUtils.isEmpty(uri.getQueryParameter("input"));
}
@@ -314,7 +286,8 @@ public class Utils {
}
private static boolean isTvUri(Uri uri) {
- return uri != null && ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())
+ return uri != null
+ && ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())
&& TvContract.AUTHORITY.equals(uri.getAuthority());
}
@@ -323,23 +296,17 @@ public class Utils {
return pathSegments.size() == 2 && pathSegment.equals(pathSegments.get(0));
}
- /**
- * Returns {@code true}, if {@code uri} is a programs URI.
- */
+ /** Returns {@code true}, if {@code uri} is a programs URI. */
public static boolean isProgramsUri(Uri uri) {
return isTvUri(uri) && PATH_PROGRAM.equals(uri.getPathSegments().get(0));
}
- /**
- * Returns {@code true}, if {@code uri} is a programs URI.
- */
+ /** Returns {@code true}, if {@code uri} is a programs URI. */
public static boolean isRecordedProgramsUri(Uri uri) {
return isTvUri(uri) && PATH_RECORDED_PROGRAM.equals(uri.getPathSegments().get(0));
}
- /**
- * Gets the info of the program on particular time.
- */
+ /** Gets the info of the program on particular time. */
@WorkerThread
public static Program getProgramAt(Context context, long channelId, long timeMs) {
if (channelId == Channel.INVALID_ID) {
@@ -355,10 +322,11 @@ public class Utils {
Log.w(TAG, message);
}
}
- Uri uri = TvContract.buildProgramsUriForChannel(TvContract.buildChannelUri(channelId),
- timeMs, timeMs);
- try (Cursor cursor = context.getContentResolver().query(uri, Program.PROJECTION,
- null, null, null)) {
+ Uri uri =
+ TvContract.buildProgramsUriForChannel(
+ TvContract.buildChannelUri(channelId), timeMs, timeMs);
+ try (Cursor cursor =
+ context.getContentResolver().query(uri, Program.PROJECTION, null, null, null)) {
if (cursor != null && cursor.moveToNext()) {
return Program.fromCursor(cursor);
}
@@ -366,55 +334,98 @@ public class Utils {
return null;
}
- /**
- * Gets the info of the current program.
- */
+ /** Gets the info of the current program. */
@WorkerThread
public static Program getCurrentProgram(Context context, long channelId) {
return getProgramAt(context, channelId, System.currentTimeMillis());
}
- /**
- * Returns the round off minutes when convert milliseconds to minutes.
- */
+ /** Returns the round off minutes when convert milliseconds to minutes. */
public static int getRoundOffMinsFromMs(long millis) {
// Round off the result by adding half minute to the original ms.
return (int) TimeUnit.MILLISECONDS.toMinutes(millis + HALF_MINUTE_MS);
}
/**
- * Returns duration string according to the date & time format.
- * If {@code startUtcMillis} and {@code endUtcMills} are equal,
- * formatted time will be returned instead.
+ * Returns duration string according to the date & time format. If {@code startUtcMillis} and
+ * {@code endUtcMills} are equal, formatted time will be returned instead.
*
* @param startUtcMillis start of duration in millis. Should be less than {code endUtcMillis}.
* @param endUtcMillis end of duration in millis. Should be larger than {@code startUtcMillis}.
- * @param useShortFormat {@code true} if abbreviation is needed to save space.
- * In that case, date will be omitted if duration starts from today
- * and is less than a day. If it's necessary,
- * {@link DateUtils#FORMAT_NUMERIC_DATE} is used otherwise.
+ * @param useShortFormat {@code true} if abbreviation is needed to save space. In that case,
+ * date will be omitted if duration starts from today and is less than a day. If it's
+ * necessary, {@link DateUtils#FORMAT_NUMERIC_DATE} is used otherwise.
*/
public static String getDurationString(
Context context, long startUtcMillis, long endUtcMillis, boolean useShortFormat) {
- return getDurationString(context, System.currentTimeMillis(), startUtcMillis, endUtcMillis,
- useShortFormat, 0);
+ return getDurationString(
+ context,
+ System.currentTimeMillis(),
+ startUtcMillis,
+ endUtcMillis,
+ useShortFormat,
+ 0);
}
- @VisibleForTesting
- static String getDurationString(Context context, long baseMillis, long startUtcMillis,
- long endUtcMillis, boolean useShortFormat, int flag) {
- return getDurationString(context, startUtcMillis, endUtcMillis,
- useShortFormat, !isInGivenDay(baseMillis, startUtcMillis), true, flag);
+ /**
+ * Returns duration string according to the date & time format. If {@code startUtcMillis} and
+ * {@code endUtcMills} are equal, formatted time will be returned instead.
+ *
+ * @param clock the clock used to get the current time.
+ * @param startUtcMillis start of duration in millis. Should be less than {code endUtcMillis}.
+ * @param endUtcMillis end of duration in millis. Should be larger than {@code startUtcMillis}.
+ * @param useShortFormat {@code true} if abbreviation is needed to save space. In that case,
+ * date will be omitted if duration starts from today and is less than a day. If it's
+ * necessary, {@link DateUtils#FORMAT_NUMERIC_DATE} is used otherwise.
+ */
+ public static String getDurationString(
+ Context context,
+ Clock clock,
+ long startUtcMillis,
+ long endUtcMillis,
+ boolean useShortFormat) {
+ return getDurationString(
+ context,
+ clock.currentTimeMillis(),
+ startUtcMillis,
+ endUtcMillis,
+ useShortFormat,
+ 0);
}
- /**
- * Returns duration string according to the time format, may not contain date information.
- * Note: At least one of showDate and showTime should be true.
+ @VisibleForTesting
+ static String getDurationString(
+ Context context,
+ long baseMillis,
+ long startUtcMillis,
+ long endUtcMillis,
+ boolean useShortFormat,
+ int flag) {
+ return getDurationString(
+ context,
+ startUtcMillis,
+ endUtcMillis,
+ useShortFormat,
+ !isInGivenDay(baseMillis, startUtcMillis),
+ true,
+ flag);
+ }
+
+ /**
+ * Returns duration string according to the time format, may not contain date information. Note:
+ * At least one of showDate and showTime should be true.
*/
- public static String getDurationString(Context context, long startUtcMillis, long endUtcMillis,
- boolean useShortFormat, boolean showDate, boolean showTime, int flag) {
- flag |= DateUtils.FORMAT_ABBREV_MONTH
- | ((useShortFormat) ? DateUtils.FORMAT_NUMERIC_DATE : 0);
+ public static String getDurationString(
+ Context context,
+ long startUtcMillis,
+ long endUtcMillis,
+ boolean useShortFormat,
+ boolean showDate,
+ boolean showTime,
+ int flag) {
+ flag |=
+ DateUtils.FORMAT_ABBREV_MONTH
+ | ((useShortFormat) ? DateUtils.FORMAT_NUMERIC_DATE : 0);
SoftPreconditions.checkArgument(showTime || showDate);
if (showTime) {
flag |= DateUtils.FORMAT_SHOW_TIME;
@@ -431,20 +442,21 @@ public class Utils {
// Do not show date for short format.
// Subtracting one day is needed because {@link DateUtils@formatDateRange}
// automatically shows date if the duration covers multiple days.
- return DateUtils.formatDateRange(context,
- startUtcMillis, endUtcMillis - TimeUnit.DAYS.toMillis(1), flag);
+ return DateUtils.formatDateRange(
+ context, startUtcMillis, endUtcMillis - TimeUnit.DAYS.toMillis(1), flag);
}
}
// Workaround of b/28740989.
// Add 1 msec to endUtcMillis to avoid DateUtils' bug with a duration of 12:00AM~12:00AM.
String dateRange = DateUtils.formatDateRange(context, startUtcMillis, endUtcMillis, flag);
- return startUtcMillis == endUtcMillis || dateRange.contains("–") ? dateRange
+ return startUtcMillis == endUtcMillis || dateRange.contains("–")
+ ? dateRange
: DateUtils.formatDateRange(context, startUtcMillis, endUtcMillis + 1, flag);
}
/**
- * Checks if two given time (in milliseconds) are in the same day with regard to the
- * locale timezone.
+ * Checks if two given time (in milliseconds) are in the same day with regard to the locale
+ * timezone.
*/
public static boolean isInGivenDay(long dayToMatchInMillis, long subjectTimeInMillis) {
TimeZone timeZone = Calendar.getInstance().getTimeZone();
@@ -456,9 +468,7 @@ public class Utils {
== Utils.floorTime(subjectTimeInMillis + offset, ONE_DAY_MS);
}
- /**
- * Calculate how many days between two milliseconds.
- */
+ /** Calculate how many days between two milliseconds. */
public static int computeDateDifference(long startTimeMs, long endTimeMs) {
Calendar calFrom = Calendar.getInstance();
Calendar calTo = Calendar.getInstance();
@@ -476,17 +486,23 @@ public class Utils {
cal.set(Calendar.MILLISECOND, 0);
}
- /**
- * Returns the last millisecond of a day which the millis belongs to.
- */
+ /** Returns the last millisecond of a day which the millis belongs to. */
public static long getLastMillisecondOfDay(long millis) {
- Calendar calender = Calendar.getInstance();
- calender.setTime(new Date(millis));
- calender.set(Calendar.HOUR_OF_DAY, 23);
- calender.set(Calendar.MINUTE, 59);
- calender.set(Calendar.SECOND, 59);
- calender.set(Calendar.MILLISECOND, 999);
- return calender.getTimeInMillis();
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(new Date(millis));
+ calendar.set(Calendar.HOUR_OF_DAY, 23);
+ calendar.set(Calendar.MINUTE, 59);
+ calendar.set(Calendar.SECOND, 59);
+ calendar.set(Calendar.MILLISECOND, 999);
+ return calendar.getTimeInMillis();
+ }
+
+ /** Returns the last millisecond of a day which the millis belongs to. */
+ public static long getFirstMillisecondOfDay(long millis) {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(new Date(millis));
+ resetCalendar(calendar);
+ return calendar.getTimeInMillis();
}
public static String getAspectRatioString(int width, int height) {
@@ -494,7 +510,7 @@ public class Utils {
return "";
}
- for (AspectRatio ratio: AspectRatio.values()) {
+ for (AspectRatio ratio : AspectRatio.values()) {
if (Math.abs((float) ratio.height / ratio.width - (float) height / width) < 0.05f) {
return ratio.toString();
}
@@ -531,11 +547,9 @@ public class Utils {
public static String getVideoDefinitionLevelString(Context context, int videoFormat) {
switch (videoFormat) {
case StreamInfo.VIDEO_DEFINITION_LEVEL_ULTRA_HD:
- return context.getResources().getString(
- R.string.video_definition_level_ultra_hd);
+ return context.getResources().getString(R.string.video_definition_level_ultra_hd);
case StreamInfo.VIDEO_DEFINITION_LEVEL_FULL_HD:
- return context.getResources().getString(
- R.string.video_definition_level_full_hd);
+ return context.getResources().getString(R.string.video_definition_level_full_hd);
case StreamInfo.VIDEO_DEFINITION_LEVEL_HD:
return context.getResources().getString(R.string.video_definition_level_hd);
case StreamInfo.VIDEO_DEFINITION_LEVEL_SD:
@@ -570,8 +584,8 @@ public class Utils {
return false;
}
- public static String getMultiAudioString(Context context, TvTrackInfo track,
- boolean showSampleRate) {
+ public static String getMultiAudioString(
+ Context context, TvTrackInfo track, boolean showSampleRate) {
if (track.getType() != TvTrackInfo.TYPE_AUDIO) {
throw new IllegalArgumentException("Not an audio track: " + track);
}
@@ -600,11 +614,17 @@ public class Utils {
break;
default:
if (track.getAudioChannelCount() > 0) {
- metadata.append(context.getString(R.string.multi_audio_channel_suffix,
- track.getAudioChannelCount()));
+ metadata.append(
+ context.getString(
+ R.string.multi_audio_channel_suffix,
+ track.getAudioChannelCount()));
} else {
- Log.d(TAG, "Invalid audio channel count (" + track.getAudioChannelCount()
- + ") found for the audio track: " + track);
+ Log.d(
+ TAG,
+ "Invalid audio channel count ("
+ + track.getAudioChannelCount()
+ + ") found for the audio track: "
+ + track);
}
break;
}
@@ -628,8 +648,8 @@ public class Utils {
if (metadata.length() == 0) {
return language;
}
- return context.getString(R.string.multi_audio_display_string_with_channel, language,
- metadata.toString());
+ return context.getString(
+ R.string.multi_audio_display_string_with_channel, language, metadata.toString());
}
public static boolean isEqualLanguage(String lang1, String lang2) {
@@ -647,19 +667,19 @@ public class Utils {
}
public static boolean isIntentAvailable(Context context, Intent intent) {
- return context.getPackageManager().queryIntentActivities(
- intent, PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
+ return context.getPackageManager()
+ .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)
+ .size()
+ > 0;
}
- /**
- * Returns the label for a given input. Returns the custom label, if any.
- */
+ /** Returns the label for a given input. Returns the custom label, if any. */
public static String loadLabel(Context context, TvInputInfo input) {
if (input == null) {
return null;
}
TvInputManagerHelper inputManager =
- TvApplication.getSingletons(context).getTvInputManagerHelper();
+ TvSingletons.getSingletons(context).getTvInputManagerHelper();
CharSequence customLabel = inputManager.loadCustomLabel(input);
String label = (customLabel == null) ? null : customLabel.toString();
if (TextUtils.isEmpty(label)) {
@@ -668,9 +688,7 @@ public class Utils {
return label;
}
- /**
- * Enable all channels synchronously.
- */
+ /** Enable all channels synchronously. */
@WorkerThread
public static void enableAllChannels(Context context) {
ContentValues values = new ContentValues();
@@ -681,46 +699,48 @@ public class Utils {
/**
* Converts time in milliseconds to a String.
*
- * @param fullFormat {@code true} for returning date string with a full format
- * (e.g., Mon Aug 15 20:08:35 GMT 2016). {@code false} for a short format,
- * {e.g., [8/15/16] 8:08 AM}, in which date information would only appears
- * when the target time is not today.
+ * @param fullFormat {@code true} for returning date string with a full format (e.g., Mon Aug 15
+ * 20:08:35 GMT 2016). {@code false} for a short format, {e.g., 8/15/16 or 8:08 AM}, in
+ * which only the time is shown if the time is on the same day as now, and only the date is
+ * shown if it's a different day.
*/
public static String toTimeString(long timeMillis, boolean fullFormat) {
if (fullFormat) {
return new Date(timeMillis).toString();
} else {
long currentTime = System.currentTimeMillis();
- return (String) DateUtils.formatSameDayTime(timeMillis, System.currentTimeMillis(),
- SimpleDateFormat.SHORT, SimpleDateFormat.SHORT);
+ return (String)
+ DateUtils.formatSameDayTime(
+ timeMillis,
+ System.currentTimeMillis(),
+ SimpleDateFormat.SHORT,
+ SimpleDateFormat.SHORT);
}
}
- /**
- * Converts time in milliseconds to a String.
- */
+ /** Converts time in milliseconds to a String. */
public static String toTimeString(long timeMillis) {
return toTimeString(timeMillis, true);
}
/**
- * Converts time in milliseconds to a ISO 8061 string.
- */
- public static String toIsoDateTimeString(long timeMillis) {
- return ISO_8601.format(new Date(timeMillis));
- }
-
- /**
* Returns a {@link String} object which contains the layout information of the {@code view}.
*/
public static String toRectString(View view) {
return "{"
- + "l=" + view.getLeft()
- + ",r=" + view.getRight()
- + ",t=" + view.getTop()
- + ",b=" + view.getBottom()
- + ",w=" + view.getWidth()
- + ",h=" + view.getHeight() + "}";
+ + "l="
+ + view.getLeft()
+ + ",r="
+ + view.getRight()
+ + ",t="
+ + view.getTop()
+ + ",b="
+ + view.getBottom()
+ + ",w="
+ + view.getWidth()
+ + ",h="
+ + view.getHeight()
+ + "}";
}
/**
@@ -732,16 +752,14 @@ public class Utils {
}
/**
- * Ceils time to the given {@code timeUnit}. For example, if time is 5:32:11 and timeUnit is
- * one hour (60 * 60 * 1000), then the output will be 6:00:00.
+ * Ceils time to the given {@code timeUnit}. For example, if time is 5:32:11 and timeUnit is one
+ * hour (60 * 60 * 1000), then the output will be 6:00:00.
*/
public static long ceilTime(long timeMs, long timeUnit) {
return timeMs + timeUnit - (timeMs % timeUnit);
}
- /**
- * Returns an {@link String#intern() interned} string or null if the input is null.
- */
+ /** Returns an {@link String#intern() interned} string or null if the input is null. */
@Nullable
public static String intern(@Nullable String string) {
return string == null ? null : string.intern();
@@ -749,6 +767,7 @@ public class Utils {
/**
* Check if the index is valid for the collection,
+ *
* @param collection the collection
* @param index the index position to test
* @return index >= 0 && index < collection.size().
@@ -757,9 +776,7 @@ public class Utils {
return collection != null && (index >= 0 && index < collection.size());
}
- /**
- * Returns a localized version of the text resource specified by resourceId.
- */
+ /** Returns a localized version of the text resource specified by resourceId. */
public static CharSequence getTextForLocale(Context context, Locale locale, int resourceId) {
if (locale.equals(context.getResources().getConfiguration().locale)) {
return context.getText(resourceId);
@@ -769,12 +786,12 @@ public class Utils {
return context.createConfigurationContext(config).getText(resourceId);
}
- /**
- * Checks where there is any internal TV input.
- */
+ /** Checks where there is any internal TV input. */
public static boolean hasInternalTvInputs(Context context, boolean tunerInputOnly) {
- for (TvInputInfo input : TvApplication.getSingletons(context).getTvInputManagerHelper()
- .getTvInputInfos(true, tunerInputOnly)) {
+ for (TvInputInfo input :
+ TvSingletons.getSingletons(context)
+ .getTvInputManagerHelper()
+ .getTvInputInfos(true, tunerInputOnly)) {
if (isInternalTvInput(context, input.getId())) {
return true;
}
@@ -782,13 +799,13 @@ public class Utils {
return false;
}
- /**
- * Returns the internal TV inputs.
- */
+ /** Returns the internal TV inputs. */
public static List<TvInputInfo> getInternalTvInputs(Context context, boolean tunerInputOnly) {
List<TvInputInfo> inputs = new ArrayList<>();
- for (TvInputInfo input : TvApplication.getSingletons(context).getTvInputManagerHelper()
- .getTvInputInfos(true, tunerInputOnly)) {
+ for (TvInputInfo input :
+ TvSingletons.getSingletons(context)
+ .getTvInputManagerHelper()
+ .getTvInputInfos(true, tunerInputOnly)) {
if (isInternalTvInput(context, input.getId())) {
inputs.add(input);
}
@@ -796,81 +813,41 @@ public class Utils {
return inputs;
}
- /**
- * Checks whether the input is internal or not.
- */
+ /** Checks whether the input is internal or not. */
public static boolean isInternalTvInput(Context context, String inputId) {
- return context.getPackageName().equals(ComponentName.unflattenFromString(inputId)
- .getPackageName());
+ return context.getPackageName()
+ .equals(ComponentName.unflattenFromString(inputId).getPackageName());
}
- /**
- * Returns the TV input for the given {@code program}.
- */
+ /** Returns the TV input for the given {@code program}. */
@Nullable
public static TvInputInfo getTvInputInfoForProgram(Context context, Program program) {
- if (!Program.isValid(program)) {
+ if (!Program.isProgramValid(program)) {
return null;
}
return getTvInputInfoForChannelId(context, program.getChannelId());
}
- /**
- * Returns the TV input for the given channel ID.
- */
+ /** Returns the TV input for the given channel ID. */
@Nullable
public static TvInputInfo getTvInputInfoForChannelId(Context context, long channelId) {
- ApplicationSingletons appSingletons = TvApplication.getSingletons(context);
- Channel channel = appSingletons.getChannelDataManager().getChannel(channelId);
+ TvSingletons tvSingletons = TvSingletons.getSingletons(context);
+ Channel channel = tvSingletons.getChannelDataManager().getChannel(channelId);
if (channel == null) {
return null;
}
- return appSingletons.getTvInputManagerHelper().getTvInputInfo(channel.getInputId());
+ return tvSingletons.getTvInputManagerHelper().getTvInputInfo(channel.getInputId());
}
- /**
- * Returns the {@link TvInputInfo} for the given input ID.
- */
+ /** Returns the {@link TvInputInfo} for the given input ID. */
@Nullable
public static TvInputInfo getTvInputInfoForInputId(Context context, String inputId) {
- return TvApplication.getSingletons(context).getTvInputManagerHelper()
+ return TvSingletons.getSingletons(context)
+ .getTvInputManagerHelper()
.getTvInputInfo(inputId);
}
- /**
- * Deletes a file or a directory.
- */
- public static void deleteDirOrFile(File fileOrDirectory) {
- if (fileOrDirectory.isDirectory()) {
- for (File child : fileOrDirectory.listFiles()) {
- deleteDirOrFile(child);
- }
- }
- fileOrDirectory.delete();
- }
-
- /**
- * Checks whether a given package is in our bundled package set.
- */
- public static boolean isInBundledPackageSet(String packageName) {
- return BUNDLED_PACKAGE_SET.contains(packageName);
- }
-
- /**
- * Checks whether a given input is a bundled input.
- */
- public static boolean isBundledInput(String inputId) {
- for (String prefix : BUNDLED_PACKAGE_SET) {
- if (inputId.startsWith(prefix + "/")) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns the canonical genre ID's from the {@code genres}.
- */
+ /** Returns the canonical genre ID's from the {@code genres}. */
public static int[] getCanonicalGenreIds(String genres) {
if (TextUtils.isEmpty(genres)) {
return null;
@@ -878,9 +855,7 @@ public class Utils {
return getCanonicalGenreIds(Genres.decode(genres));
}
- /**
- * Returns the canonical genre ID's from the {@code genres}.
- */
+ /** Returns the canonical genre ID's from the {@code genres}. */
public static int[] getCanonicalGenreIds(String[] canonicalGenres) {
if (canonicalGenres != null && canonicalGenres.length > 0) {
int[] results = new int[canonicalGenres.length];
@@ -901,9 +876,7 @@ public class Utils {
return null;
}
- /**
- * Returns the canonical genres for database.
- */
+ /** Returns the canonical genres for database. */
public static String getCanonicalGenre(int[] canonicalGenreIds) {
if (canonicalGenreIds == null || canonicalGenreIds.length == 0) {
return null;
@@ -916,15 +889,8 @@ public class Utils {
}
/**
- * Returns true if the current user is a developer.
- */
- public static boolean isDeveloper() {
- return BuildConfig.ENG || Experiments.ENABLE_DEVELOPER_FEATURES.get();
- }
-
- /**
- * Runs the method in main thread. If the current thread is not main thread, block it util
- * the method is finished.
+ * Runs the method in main thread. If the current thread is not main thread, block it util the
+ * method is finished.
*/
public static void runInMainThreadAndWait(Runnable runnable) {
if (Looper.myLooper() == Looper.getMainLooper()) {
diff --git a/src/com/android/tv/util/ViewCache.java b/src/com/android/tv/util/ViewCache.java
index ed9a8ff6..b8bdb6b8 100644
--- a/src/com/android/tv/util/ViewCache.java
+++ b/src/com/android/tv/util/ViewCache.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.android.tv.util;
import android.content.Context;
@@ -5,22 +20,17 @@ import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-
import java.util.ArrayList;
-/**
- * A cache for the views.
- */
+/** A cache for the views. */
public class ViewCache {
- private final static SparseArray<ArrayList<View>> mViews = new SparseArray();
+ private static final SparseArray<ArrayList<View>> mViews = new SparseArray();
private static ViewCache sViewCache;
- private ViewCache() { }
+ private ViewCache() {}
- /**
- * Returns an instance of the view cache.
- */
+ /** Returns an instance of the view cache. */
public static ViewCache getInstance() {
if (sViewCache == null) {
sViewCache = new ViewCache();
@@ -28,16 +38,12 @@ public class ViewCache {
return sViewCache;
}
- /**
- * Returns if the view cache is empty.
- */
+ /** Returns if the view cache is empty. */
public boolean isEmpty() {
return mViews.size() == 0;
}
- /**
- * Stores a view into this view cache.
- */
+ /** Stores a view into this view cache. */
public void putView(int resId, View view) {
ArrayList<View> views = mViews.get(resId);
if (views == null) {
@@ -47,9 +53,7 @@ public class ViewCache {
views.add(view);
}
- /**
- * Stores multi specific views into the view cache.
- */
+ /** Stores multi specific views into the view cache. */
public void putView(Context context, int resId, ViewGroup fakeParent, int num) {
LayoutInflater inflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -64,9 +68,7 @@ public class ViewCache {
}
}
- /**
- * Returns the view for specific resource id.
- */
+ /** Returns the view for specific resource id. */
public View getView(int resId) {
ArrayList<View> views = mViews.get(resId);
if (views != null && !views.isEmpty()) {
@@ -80,9 +82,7 @@ public class ViewCache {
}
}
- /**
- * Returns the view if exists, or create a new view for the specific resource id.
- */
+ /** Returns the view if exists, or create a new view for the specific resource id. */
public View getOrCreateView(LayoutInflater inflater, int resId, ViewGroup container) {
View view = getView(resId);
if (view == null) {
@@ -91,9 +91,7 @@ public class ViewCache {
return view;
}
- /**
- * Clears the view cache.
- */
+ /** Clears the view cache. */
public void clear() {
mViews.clear();
}
diff --git a/src/com/android/tv/util/account/AccountHelper.java b/src/com/android/tv/util/account/AccountHelper.java
new file mode 100644
index 00000000..e98b42ec
--- /dev/null
+++ b/src/com/android/tv/util/account/AccountHelper.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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.android.tv.util.account;
+
+import android.accounts.Account;
+import android.support.annotation.Nullable;
+
+/** Helper methods for getting and selecting a user account. */
+public interface AccountHelper {
+ /** Returns the currently selected account or {@code null} if none is selected. */
+ @Nullable
+ Account getSelectedAccount();
+ /**
+ * Selects the first account available.
+ *
+ * @return selected account or {@code null} if none is selected.
+ */
+ @Nullable
+ Account selectFirstAccount();
+
+ /** Returns all eligible accounts . */
+ @Nullable
+ Account getFirstEligibleAccount();
+}
diff --git a/src/com/android/tv/util/AccountHelper.java b/src/com/android/tv/util/account/AccountHelperImpl.java
index ece13de1..58fbd27e 100644
--- a/src/com/android/tv/util/AccountHelper.java
+++ b/src/com/android/tv/util/account/AccountHelperImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,43 +14,32 @@
* limitations under the License.
*/
-package com.android.tv.util;
+package com.android.tv.util.account;
import android.accounts.Account;
import android.content.Context;
import android.content.SharedPreferences;
-import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
-import android.util.Log;
-
-import java.util.Arrays;
-
-/**
- * Helper methods for getting and selecting a user account.
- */
-public class AccountHelper {
- private static final String TAG = "AccountHelper";
- private static final boolean DEBUG = false;
+/** Helper methods for getting and selecting a user account. */
+public class AccountHelperImpl implements com.android.tv.util.account.AccountHelper {
private static final String SELECTED_ACCOUNT = "android.tv.livechannels.selected_account";
- private final Context mContext;
+ protected final Context mContext;
private final SharedPreferences mDefaultPreferences;
- @Nullable
- private Account mSelectedAccount;
+ @Nullable private Account mSelectedAccount;
- public AccountHelper(Context context) {
+ public AccountHelperImpl(Context context) {
mContext = context.getApplicationContext();
mDefaultPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
}
- /**
- * Returns the currently selected account or {@code null} if none is selected.
- */
+ /** Returns the currently selected account or {@code null} if none is selected. */
+ @Override
@Nullable
- public Account getSelectedAccount() {
+ public final Account getSelectedAccount() {
String accountId = mDefaultPreferences.getString(SELECTED_ACCOUNT, null);
if (accountId == null) {
return null;
@@ -68,9 +57,11 @@ public class AccountHelper {
}
/**
- * Returns all eligible accounts .
+ * Returns all eligible accounts.
+ *
+ * <p>Override this method to return the accounts needed.
*/
- private Account[] getEligibleAccounts() {
+ protected Account[] getEligibleAccounts() {
return new Account[0];
}
@@ -79,8 +70,9 @@ public class AccountHelper {
*
* @return selected account or {@code null} if none is selected.
*/
+ @Override
@Nullable
- public Account selectFirstAccount() {
+ public final Account selectFirstAccount() {
Account account = getFirstEligibleAccount();
if (account != null) {
selectAccount(account);
@@ -93,19 +85,17 @@ public class AccountHelper {
*
* @return first account or {@code null} if none is eligible.
*/
+ @Override
@Nullable
- public Account getFirstEligibleAccount() {
+ public final Account getFirstEligibleAccount() {
Account[] accounts = getEligibleAccounts();
return accounts.length == 0 ? null : accounts[0];
}
- /**
- * Sets the given account as the selected account.
- */
+ /** Sets the given account as the selected account. */
private void selectAccount(Account account) {
- SharedPreferences defaultPreferences = PreferenceManager
- .getDefaultSharedPreferences(mContext);
+ SharedPreferences defaultPreferences =
+ PreferenceManager.getDefaultSharedPreferences(mContext);
defaultPreferences.edit().putString(SELECTED_ACCOUNT, account.name).commit();
}
}
-
diff --git a/src/com/android/tv/util/BitmapUtils.java b/src/com/android/tv/util/images/BitmapUtils.java
index fbaab023..d6bd5a31 100644
--- a/src/com/android/tv/util/BitmapUtils.java
+++ b/src/com/android/tv/util/images/BitmapUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.tv.util;
+package com.android.tv.util.images;
import android.content.ContentResolver;
import android.content.Context;
@@ -29,7 +29,7 @@ import android.net.Uri;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
-
+import com.android.tv.common.util.NetworkTrafficTags;
import java.io.BufferedInputStream;
import java.io.Closeable;
import java.io.IOException;
@@ -45,12 +45,14 @@ public final class BitmapUtils {
// The value of 64K, for MARK_READ_LIMIT, is chosen to be eight times the default buffer size
// of BufferedInputStream (8K) allowing it to double its buffers three times. Also it is a
// fairly reasonable value, not using too much memory and being large enough for most cases.
- private static final int MARK_READ_LIMIT = 64 * 1024; // 64K
+ private static final int MARK_READ_LIMIT = 64 * 1024; // 64K
- private static final int CONNECTION_TIMEOUT_MS_FOR_URLCONNECTION = 3000; // 3 sec
- private static final int READ_TIMEOUT_MS_FOR_URLCONNECTION = 10000; // 10 sec
+ private static final int CONNECTION_TIMEOUT_MS_FOR_URLCONNECTION = 3000; // 3 sec
+ private static final int READ_TIMEOUT_MS_FOR_URLCONNECTION = 10000; // 10 sec
- private BitmapUtils() { /* cannot be instantiated */ }
+ private BitmapUtils() {
+ /* cannot be instantiated */
+ }
public static Bitmap scaleBitmap(Bitmap bm, int maxWidth, int maxHeight) {
Rect rect = calculateNewSize(bm, maxWidth, maxHeight);
@@ -59,7 +61,8 @@ public final class BitmapUtils {
public static Bitmap getScaledMutableBitmap(Bitmap bm, int maxWidth, int maxHeight) {
Bitmap scaledBitmap = scaleBitmap(bm, maxWidth, maxHeight);
- return scaledBitmap.isMutable() ? scaledBitmap
+ return scaledBitmap.isMutable()
+ ? scaledBitmap
: scaledBitmap.copy(Bitmap.Config.ARGB_8888, true);
}
@@ -77,17 +80,17 @@ public final class BitmapUtils {
return rect;
}
- public static ScaledBitmapInfo createScaledBitmapInfo(String id, Bitmap bm, int maxWidth,
- int maxHeight) {
- return new ScaledBitmapInfo(id, scaleBitmap(bm, maxWidth, maxHeight),
+ public static ScaledBitmapInfo createScaledBitmapInfo(
+ String id, Bitmap bm, int maxWidth, int maxHeight) {
+ return new ScaledBitmapInfo(
+ id,
+ scaleBitmap(bm, maxWidth, maxHeight),
calculateInSampleSize(bm.getWidth(), bm.getHeight(), maxWidth, maxHeight));
}
- /**
- * Decode large sized bitmap into requested size.
- */
- public static ScaledBitmapInfo decodeSampledBitmapFromUriString(Context context,
- String uriString, int reqWidth, int reqHeight) {
+ /** Decode large sized bitmap into requested size. */
+ public static ScaledBitmapInfo decodeSampledBitmapFromUriString(
+ Context context, String uriString, int reqWidth, int reqHeight) {
if (TextUtils.isEmpty(uriString)) {
return null;
}
@@ -162,8 +165,8 @@ public final class BitmapUtils {
return urlConnection;
}
- private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth,
- int reqHeight) {
+ private static int calculateInSampleSize(
+ BitmapFactory.Options options, int reqWidth, int reqHeight) {
return calculateInSampleSize(options.outWidth, options.outHeight, reqWidth, reqHeight);
}
@@ -187,7 +190,7 @@ public final class BitmapUtils {
closeable.close();
} catch (IOException e) {
// Log and continue.
- Log.w(TAG,"Error closing " + closeable, e);
+ Log.w(TAG, "Error closing " + closeable, e);
}
}
if (urlConnection instanceof HttpURLConnection) {
@@ -195,21 +198,13 @@ public final class BitmapUtils {
}
}
- /**
- * A wrapper class which contains the loaded bitmap and the scaling information.
- */
+ /** A wrapper class which contains the loaded bitmap and the scaling information. */
public static class ScaledBitmapInfo {
- /**
- * The id of bitmap, usually this is the URI of the original.
- */
- @NonNull
- public final String id;
+ /** The id of bitmap, usually this is the URI of the original. */
+ @NonNull public final String id;
- /**
- * The loaded bitmap object.
- */
- @NonNull
- public final Bitmap bitmap;
+ /** The loaded bitmap object. */
+ @NonNull public final Bitmap bitmap;
/**
* The scaling factor to the original bitmap. It should be an positive integer.
@@ -222,8 +217,8 @@ public final class BitmapUtils {
* A constructor.
*
* @param bitmap The loaded bitmap object.
- * @param inSampleSize The sampling size.
- * See {@link android.graphics.BitmapFactory.Options#inSampleSize}
+ * @param inSampleSize The sampling size. See {@link
+ * android.graphics.BitmapFactory.Options#inSampleSize}
*/
public ScaledBitmapInfo(@NonNull String id, @NonNull Bitmap bitmap, int inSampleSize) {
this.id = id;
@@ -232,10 +227,9 @@ public final class BitmapUtils {
}
/**
- * Checks if the bitmap needs to be reloaded. The scaling is performed by power 2.
- * The bitmap can be reloaded only if the required width or height is greater then or equal
- * to the existing bitmap.
- * If the full sized bitmap is already loaded, returns {@code false}.
+ * Checks if the bitmap needs to be reloaded. The scaling is performed by power 2. The
+ * bitmap can be reloaded only if the required width or height is greater then or equal to
+ * the existing bitmap. If the full sized bitmap is already loaded, returns {@code false}.
*
* @see android.graphics.BitmapFactory.Options#inSampleSize
*/
@@ -245,26 +239,41 @@ public final class BitmapUtils {
return false;
}
Rect size = calculateNewSize(this.bitmap, reqWidth, reqHeight);
- boolean reload = (size.right >= bitmap.getWidth() * 2
- || size.bottom >= bitmap.getHeight() * 2);
+ boolean reload =
+ (size.right >= bitmap.getWidth() * 2 || size.bottom >= bitmap.getHeight() * 2);
if (DEBUG) {
- Log.d(TAG, "needToReload(" + reqWidth + ", " + reqHeight + ")=" + reload
- + " because the new size would be " + size + " for " + this);
+ Log.d(
+ TAG,
+ "needToReload("
+ + reqWidth
+ + ", "
+ + reqHeight
+ + ")="
+ + reload
+ + " because the new size would be "
+ + size
+ + " for "
+ + this);
}
return reload;
}
- /**
- * Returns {@code true} if a request the size of {@code other} would need a reload.
- */
- public boolean needToReload(ScaledBitmapInfo other){
+ /** Returns {@code true} if a request the size of {@code other} would need a reload. */
+ public boolean needToReload(ScaledBitmapInfo other) {
return needToReload(other.bitmap.getWidth(), other.bitmap.getHeight());
}
@Override
public String toString() {
- return "ScaledBitmapInfo[" + id + "](in=" + inSampleSize + ", w=" + bitmap.getWidth()
- + ", h=" + bitmap.getHeight() + ")";
+ return "ScaledBitmapInfo["
+ + id
+ + "](in="
+ + inSampleSize
+ + ", w="
+ + bitmap.getWidth()
+ + ", h="
+ + bitmap.getHeight()
+ + ")";
}
}
diff --git a/src/com/android/tv/util/ImageCache.java b/src/com/android/tv/util/images/ImageCache.java
index b413c364..e260d67a 100644
--- a/src/com/android/tv/util/ImageCache.java
+++ b/src/com/android/tv/util/images/ImageCache.java
@@ -14,18 +14,15 @@
* limitations under the License.
*/
-package com.android.tv.util;
+package com.android.tv.util.images;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
import android.util.LruCache;
+import com.android.tv.common.memory.MemoryManageable;
+import com.android.tv.util.images.BitmapUtils.ScaledBitmapInfo;
-import com.android.tv.common.MemoryManageable;
-import com.android.tv.util.BitmapUtils.ScaledBitmapInfo;
-
-/**
- * A convenience class for caching bitmap.
- */
+/** A convenience class for caching bitmap. */
public class ImageCache implements MemoryManageable {
private static final float MAX_CACHE_SIZE_PERCENT = 0.8f;
private static final float MIN_CACHE_SIZE_PERCENT = 0.05f;
@@ -48,16 +45,17 @@ public class ImageCache implements MemoryManageable {
if (DEBUG) {
Log.d(TAG, "Memory cache created (size = " + memCacheSize + " Kbytes)");
}
- mMemoryCache = new LruCache<String, ScaledBitmapInfo>(memCacheSize) {
- /**
- * Measure item size in kilobytes rather than units which is more practical for a bitmap
- * cache
- */
- @Override
- protected int sizeOf(String key, ScaledBitmapInfo bitmapInfo) {
- return (bitmapInfo.bitmap.getByteCount() + 1023) / 1024;
- }
- };
+ mMemoryCache =
+ new LruCache<String, ScaledBitmapInfo>(memCacheSize) {
+ /**
+ * Measure item size in kilobytes rather than units which is more practical for
+ * a bitmap cache
+ */
+ @Override
+ protected int sizeOf(String key, ScaledBitmapInfo bitmapInfo) {
+ return (bitmapInfo.bitmap.getByteCount() + 1023) / 1024;
+ }
+ };
}
private static ImageCache sImageCache;
@@ -67,7 +65,7 @@ public class ImageCache implements MemoryManageable {
* param.
*
* @param memCacheSizePercent The cache size as a percent of available app memory. Should be in
- * range of MIN_CACHE_SIZE_PERCENT(0.05) ~ MAX_CACHE_SIZE_PERCENT(0.8).
+ * range of MIN_CACHE_SIZE_PERCENT(0.05) ~ MAX_CACHE_SIZE_PERCENT(0.8).
* @return An existing retained ImageCache object or a new one if one did not exist
*/
public static synchronized ImageCache getInstance(float memCacheSizePercent) {
@@ -82,7 +80,6 @@ public class ImageCache implements MemoryManageable {
return new ImageCache(memCacheSizePercent);
}
-
/**
* Returns an existing ImageCache, if it doesn't exist, a new one is created using
* DEFAULT_CACHE_SIZE_PERCENT (0.1).
@@ -96,8 +93,8 @@ public class ImageCache implements MemoryManageable {
/**
* Adds a bitmap to memory cache.
*
- * <p>If there is an existing bitmap only replace it if
- * {@link ScaledBitmapInfo#needToReload(ScaledBitmapInfo)} is true.
+ * <p>If there is an existing bitmap only replace it if {@link
+ * ScaledBitmapInfo#needToReload(ScaledBitmapInfo)} is true.
*
* @param bitmapInfo The {@link ScaledBitmapInfo} object to store
*/
@@ -112,14 +109,25 @@ public class ImageCache implements MemoryManageable {
if (old != null && !old.needToReload(bitmapInfo)) {
mMemoryCache.put(key, old);
if (DEBUG) {
- Log.d(TAG,
- "Kept original " + old + " in memory cache because it was larger than "
- + bitmapInfo + ".");
+ Log.d(
+ TAG,
+ "Kept original "
+ + old
+ + " in memory cache because it was larger than "
+ + bitmapInfo
+ + ".");
}
} else {
if (DEBUG) {
- Log.d(TAG, "Add " + bitmapInfo + " to memory cache. Current size is " +
- mMemoryCache.size() + " / " + mMemoryCache.maxSize() + " Kbytes");
+ Log.d(
+ TAG,
+ "Add "
+ + bitmapInfo
+ + " to memory cache. Current size is "
+ + mMemoryCache.size()
+ + " / "
+ + mMemoryCache.maxSize()
+ + " Kbytes");
}
}
}
@@ -158,19 +166,21 @@ public class ImageCache implements MemoryManageable {
* Calculates the memory cache size based on a percentage of the max available VM memory. Eg.
* setting percent to 0.2 would set the memory cache to one fifth of the available memory.
* Throws {@link IllegalArgumentException} if percent is < 0.05 or > .8. memCacheSize is stored
- * in kilobytes instead of bytes as this will eventually be passed to construct a LruCache
- * which takes an int in its constructor. This value should be chosen carefully based on a
- * number of factors Refer to the corresponding Android Training class for more discussion:
+ * in kilobytes instead of bytes as this will eventually be passed to construct a LruCache which
+ * takes an int in its constructor. This value should be chosen carefully based on a number of
+ * factors Refer to the corresponding Android Training class for more discussion:
* http://developer.android.com/training/displaying-bitmaps/
*
* @param percent Percent of available app memory to use to size memory cache.
*/
public static int calculateMemCacheSize(float percent) {
if (percent < MIN_CACHE_SIZE_PERCENT || percent > MAX_CACHE_SIZE_PERCENT) {
- throw new IllegalArgumentException("setMemCacheSizePercent - percent must be "
- + "between 0.05 and 0.8 (inclusive)");
+ throw new IllegalArgumentException(
+ "setMemCacheSizePercent - percent must be "
+ + "between 0.05 and 0.8 (inclusive)");
}
- return Math.max(MIN_CACHE_SIZE_KBYTES,
+ return Math.max(
+ MIN_CACHE_SIZE_KBYTES,
Math.round(percent * Runtime.getRuntime().maxMemory() / 1024));
}
diff --git a/src/com/android/tv/util/ImageLoader.java b/src/com/android/tv/util/images/ImageLoader.java
index 86bb94c1..e844e2ca 100644
--- a/src/com/android/tv/util/ImageLoader.java
+++ b/src/com/android/tv/util/images/ImageLoader.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.tv.util;
+package com.android.tv.util.images;
import android.content.Context;
import android.graphics.Bitmap;
@@ -30,10 +30,9 @@ import android.support.annotation.UiThread;
import android.support.annotation.WorkerThread;
import android.util.ArraySet;
import android.util.Log;
-
import com.android.tv.R;
-import com.android.tv.util.BitmapUtils.ScaledBitmapInfo;
-
+import com.android.tv.common.concurrent.NamedThreadFactory;
+import com.android.tv.util.images.BitmapUtils.ScaledBitmapInfo;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
@@ -47,8 +46,8 @@ import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
- * This class wraps up completing some arbitrary long running work when loading a bitmap. It
- * handles things like using a memory cache, running the work in a background thread.
+ * This class wraps up completing some arbitrary long running work when loading a bitmap. It handles
+ * things like using a memory cache, running the work in a background thread.
*/
public final class ImageLoader {
private static final String TAG = "ImageLoader";
@@ -69,19 +68,23 @@ public final class ImageLoader {
/**
* An private {@link Executor} that can be used to execute tasks in parallel.
*
- * <p>{@code IMAGE_THREAD_POOL_EXECUTOR} setting are copied from {@link AsyncTask}
- * Since we do a lot of concurrent image loading we can exhaust a thread pool.
- * ImageLoader catches the error, and just leaves the image blank.
- * However other tasks will fail and crash the application.
+ * <p>{@code IMAGE_THREAD_POOL_EXECUTOR} setting are copied from {@link AsyncTask} Since we do a
+ * lot of concurrent image loading we can exhaust a thread pool. ImageLoader catches the error,
+ * and just leaves the image blank. However other tasks will fail and crash the application.
*
* <p>Using a separate thread pool prevents image loading from causing other tasks to fail.
*/
private static final Executor IMAGE_THREAD_POOL_EXECUTOR;
static {
- ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
- MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS, sPoolWorkQueue,
- sThreadFactory);
+ ThreadPoolExecutor threadPoolExecutor =
+ new ThreadPoolExecutor(
+ CORE_POOL_SIZE,
+ MAXIMUM_POOL_SIZE,
+ KEEP_ALIVE_SECONDS,
+ TimeUnit.SECONDS,
+ sPoolWorkQueue,
+ sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
IMAGE_THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
@@ -91,28 +94,26 @@ public final class ImageLoader {
/**
* Handles when image loading is finished.
*
- * <p>Use this to prevent leaking an Activity or other Context while image loading is
- * still pending. When you extend this class you <strong>MUST NOT</strong> use a non static
- * inner class, or the containing object will still be leaked.
+ * <p>Use this to prevent leaking an Activity or other Context while image loading is still
+ * pending. When you extend this class you <strong>MUST NOT</strong> use a non static inner
+ * class, or the containing object will still be leaked.
*/
@UiThread
- public static abstract class ImageLoaderCallback<T> {
+ public abstract static class ImageLoaderCallback<T> {
private final WeakReference<T> mWeakReference;
/**
* Creates an callback keeping a weak reference to {@code referent}.
*
- * <p> If the "referent" is no longer valid, it no longer makes sense to run the
- * callback. The referent is the View, or Activity or whatever that actually needs to
- * receive the Bitmap. If the referent has been GC, then no need to run the callback.
+ * <p>If the "referent" is no longer valid, it no longer makes sense to run the callback.
+ * The referent is the View, or Activity or whatever that actually needs to receive the
+ * Bitmap. If the referent has been GC, then no need to run the callback.
*/
public ImageLoaderCallback(T referent) {
mWeakReference = new WeakReference<>(referent);
}
- /**
- * Called when bitmap is loaded.
- */
+ /** Called when bitmap is loaded. */
private void onBitmapLoaded(@Nullable Bitmap bitmap) {
T referent = mWeakReference.get();
if (referent != null) {
@@ -122,9 +123,7 @@ public final class ImageLoader {
}
}
- /**
- * Called when bitmap is loaded if the weak reference is still valid.
- */
+ /** Called when bitmap is loaded if the weak reference is still valid. */
public abstract void onBitmapLoaded(T referent, @Nullable Bitmap bitmap);
}
@@ -134,62 +133,80 @@ public final class ImageLoader {
* Preload a bitmap image into the cache.
*
* <p>Not to make heavy CPU load, AsyncTask.SERIAL_EXECUTOR is used for the image loading.
+ *
* <p>This method is thread safe.
*/
- public static void prefetchBitmap(Context context, final String uriString, final int maxWidth,
- final int maxHeight) {
+ public static void prefetchBitmap(
+ Context context, final String uriString, final int maxWidth, final int maxHeight) {
if (DEBUG) Log.d(TAG, "prefetchBitmap() " + uriString);
if (Looper.getMainLooper() == Looper.myLooper()) {
doLoadBitmap(context, uriString, maxWidth, maxHeight, null, AsyncTask.SERIAL_EXECUTOR);
} else {
final Context appContext = context.getApplicationContext();
- getMainHandler().post(new Runnable() {
- @Override
- @MainThread
- public void run() {
- // Calling from the main thread prevents a ConcurrentModificationException
- // in LoadBitmapTask.onPostExecute
- doLoadBitmap(appContext, uriString, maxWidth, maxHeight, null,
- AsyncTask.SERIAL_EXECUTOR);
- }
- });
+ getMainHandler()
+ .post(
+ new Runnable() {
+ @Override
+ @MainThread
+ public void run() {
+ // Calling from the main thread prevents a
+ // ConcurrentModificationException
+ // in LoadBitmapTask.onPostExecute
+ doLoadBitmap(
+ appContext,
+ uriString,
+ maxWidth,
+ maxHeight,
+ null,
+ AsyncTask.SERIAL_EXECUTOR);
+ }
+ });
}
}
/**
* Load a bitmap image with the cache using a ContentResolver.
*
- * <p><b>Note</b> that the callback will be called synchronously if the bitmap already is in
- * the cache.
+ * <p><b>Note</b> that the callback will be called synchronously if the bitmap already is in the
+ * cache.
*
* @return {@code true} if the load is complete and the callback is executed.
*/
@UiThread
- public static boolean loadBitmap(Context context, String uriString,
- ImageLoaderCallback callback) {
+ public static boolean loadBitmap(
+ Context context, String uriString, ImageLoaderCallback callback) {
return loadBitmap(context, uriString, Integer.MAX_VALUE, Integer.MAX_VALUE, callback);
}
/**
* Load a bitmap image with the cache and resize it with given params.
*
- * <p><b>Note</b> that the callback will be called synchronously if the bitmap already is in
- * the cache.
+ * <p><b>Note</b> that the callback will be called synchronously if the bitmap already is in the
+ * cache.
*
* @return {@code true} if the load is complete and the callback is executed.
*/
@UiThread
- public static boolean loadBitmap(Context context, String uriString, int maxWidth, int maxHeight,
+ public static boolean loadBitmap(
+ Context context,
+ String uriString,
+ int maxWidth,
+ int maxHeight,
ImageLoaderCallback callback) {
if (DEBUG) {
Log.d(TAG, "loadBitmap() " + uriString);
}
- return doLoadBitmap(context, uriString, maxWidth, maxHeight, callback,
- IMAGE_THREAD_POOL_EXECUTOR);
+ return doLoadBitmap(
+ context, uriString, maxWidth, maxHeight, callback, IMAGE_THREAD_POOL_EXECUTOR);
}
- private static boolean doLoadBitmap(Context context, String uriString,
- int maxWidth, int maxHeight, ImageLoaderCallback callback, Executor executor) {
+ private static boolean doLoadBitmap(
+ Context context,
+ String uriString,
+ int maxWidth,
+ int maxHeight,
+ ImageLoaderCallback callback,
+ Executor executor) {
// Check the cache before creating a Task. The cache will be checked again in doLoadBitmap
// but checking a cache is much cheaper than creating an new task.
ImageCache imageCache = ImageCache.getInstance();
@@ -200,7 +217,9 @@ public final class ImageLoader {
}
return true;
}
- return doLoadBitmap(callback, executor,
+ return doLoadBitmap(
+ callback,
+ executor,
new LoadBitmapFromUriTask(context, imageCache, uriString, maxWidth, maxHeight));
}
@@ -219,12 +238,10 @@ public final class ImageLoader {
return doLoadBitmap(callback, IMAGE_THREAD_POOL_EXECUTOR, loadBitmapTask);
}
- /**
- * @return {@code true} if the load is complete and the callback is executed.
- */
+ /** @return {@code true} if the load is complete and the callback is executed. */
@UiThread
- private static boolean doLoadBitmap(ImageLoaderCallback callback, Executor executor,
- LoadBitmapTask loadBitmapTask) {
+ private static boolean doLoadBitmap(
+ ImageLoaderCallback callback, Executor executor, LoadBitmapTask loadBitmapTask) {
ScaledBitmapInfo bitmapInfo = loadBitmapTask.getFromCache();
boolean needToReload = loadBitmapTask.isReloadNeeded();
if (bitmapInfo != null && !needToReload) {
@@ -259,7 +276,7 @@ public final class ImageLoader {
*
* <p>Implement {@link #doGetBitmapInBackground} to do the actual loading.
*/
- public static abstract class LoadBitmapTask extends AsyncTask<Void, Void, ScaledBitmapInfo> {
+ public abstract static class LoadBitmapTask extends AsyncTask<Void, Void, ScaledBitmapInfo> {
protected final Context mAppContext;
protected final int mMaxWidth;
protected final int mMaxHeight;
@@ -273,24 +290,28 @@ public final class ImageLoader {
*/
private boolean isReloadNeeded() {
ScaledBitmapInfo bitmapInfo = getFromCache();
- boolean needToReload = bitmapInfo != null && bitmapInfo
- .needToReload(mMaxWidth, mMaxHeight);
+ boolean needToReload =
+ bitmapInfo != null && bitmapInfo.needToReload(mMaxWidth, mMaxHeight);
if (DEBUG) {
if (needToReload) {
- Log.d(TAG, "Bitmap needs to be reloaded. {"
- + "originalWidth=" + bitmapInfo.bitmap.getWidth()
- + ", originalHeight=" + bitmapInfo.bitmap.getHeight()
- + ", reqWidth=" + mMaxWidth
- + ", reqHeight=" + mMaxHeight
- + "}");
+ Log.d(
+ TAG,
+ "Bitmap needs to be reloaded. {"
+ + "originalWidth="
+ + bitmapInfo.bitmap.getWidth()
+ + ", originalHeight="
+ + bitmapInfo.bitmap.getHeight()
+ + ", reqWidth="
+ + mMaxWidth
+ + ", reqHeight="
+ + mMaxHeight
+ + "}");
}
}
return needToReload;
}
- /**
- * Checks if a reload would be needed if the results of other was available.
- */
+ /** Checks if a reload would be needed if the results of other was available. */
private boolean isReloadNeeded(LoadBitmapTask other) {
return (other.mMaxHeight != Integer.MAX_VALUE && mMaxHeight >= other.mMaxHeight * 2)
|| (other.mMaxWidth != Integer.MAX_VALUE && mMaxWidth >= other.mMaxWidth * 2);
@@ -301,11 +322,14 @@ public final class ImageLoader {
return mImageCache.get(mKey);
}
- public LoadBitmapTask(Context context, ImageCache imageCache, String key, int maxHeight,
- int maxWidth) {
+ public LoadBitmapTask(
+ Context context, ImageCache imageCache, String key, int maxHeight, int maxWidth) {
if (maxWidth == 0 || maxHeight == 0) {
throw new IllegalArgumentException(
- "Image size should not be 0. {width=" + maxWidth + ", height=" + maxHeight
+ "Image size should not be 0. {width="
+ + maxWidth
+ + ", height="
+ + maxHeight
+ "}");
}
mAppContext = context.getApplicationContext();
@@ -315,9 +339,7 @@ public final class ImageLoader {
mMaxWidth = maxWidth;
}
- /**
- * Loads the bitmap returning a possibly scaled down version.
- */
+ /** Loads the bitmap returning a possibly scaled down version. */
@Nullable
@WorkerThread
public abstract ScaledBitmapInfo doGetBitmapInBackground();
@@ -352,40 +374,48 @@ public final class ImageLoader {
@Override
public String toString() {
- return this.getClass().getSimpleName() + "(" + mKey + " " + mMaxWidth + "x" + mMaxHeight
+ return this.getClass().getSimpleName()
+ + "("
+ + mKey
+ + " "
+ + mMaxWidth
+ + "x"
+ + mMaxHeight
+ ")";
}
}
private static final class LoadBitmapFromUriTask extends LoadBitmapTask {
- private LoadBitmapFromUriTask(Context context, ImageCache imageCache, String uriString,
- int maxWidth, int maxHeight) {
+ private LoadBitmapFromUriTask(
+ Context context,
+ ImageCache imageCache,
+ String uriString,
+ int maxWidth,
+ int maxHeight) {
super(context, imageCache, uriString, maxHeight, maxWidth);
}
@Override
@Nullable
public final ScaledBitmapInfo doGetBitmapInBackground() {
- return BitmapUtils
- .decodeSampledBitmapFromUriString(mAppContext, getKey(), mMaxWidth, mMaxHeight);
+ return BitmapUtils.decodeSampledBitmapFromUriString(
+ mAppContext, getKey(), mMaxWidth, mMaxHeight);
}
}
- /**
- * Loads and caches the logo for a given {@link TvInputInfo}
- */
+ /** Loads and caches the logo for a given {@link TvInputInfo} */
public static final class LoadTvInputLogoTask extends LoadBitmapTask {
private final TvInputInfo mInfo;
public LoadTvInputLogoTask(Context context, ImageCache cache, TvInputInfo info) {
- super(context,
+ super(
+ context,
cache,
getTvInputLogoKey(info.getId()),
context.getResources()
.getDimensionPixelSize(R.dimen.channel_banner_input_logo_size),
context.getResources()
- .getDimensionPixelSize(R.dimen.channel_banner_input_logo_size)
- );
+ .getDimensionPixelSize(R.dimen.channel_banner_input_logo_size));
mInfo = info;
}
@@ -403,9 +433,7 @@ public final class ImageLoader {
return BitmapUtils.createScaledBitmapInfo(getKey(), original, mMaxWidth, mMaxHeight);
}
- /**
- * Returns key of TV input logo.
- */
+ /** Returns key of TV input logo. */
public static String getTvInputLogoKey(String inputId) {
return inputId + "-logo";
}
@@ -418,6 +446,5 @@ public final class ImageLoader {
return sMainHandler;
}
- private ImageLoader() {
- }
+ private ImageLoader() {}
}