From d41f0075a7d2ea826204e81fcec57d0aa57171a9 Mon Sep 17 00:00:00 2001 From: Nick Chalko Date: Wed, 26 Oct 2016 14:03:09 -0700 Subject: Sync to ub-tv-killing at 6f6e46557accb62c9548e4177d6005aa944dbf33 Change-Id: I873644d6d9d0110c981ef6075cb4019c16bbb94b --- src/com/android/tv/util/AsyncDbTask.java | 4 +- src/com/android/tv/util/CompositeComparator.java | 42 ++++++++ src/com/android/tv/util/DvrTunerStorageUtils.java | 113 ---------------------- src/com/android/tv/util/LocationUtils.java | 99 +++++++++++-------- src/com/android/tv/util/PermissionUtils.java | 7 +- src/com/android/tv/util/PipInputManager.java | 2 + src/com/android/tv/util/RecurringRunner.java | 5 +- src/com/android/tv/util/SetupUtils.java | 43 ++++++-- src/com/android/tv/util/SystemProperties.java | 6 -- src/com/android/tv/util/ToastUtils.java | 43 ++++++++ src/com/android/tv/util/TvSettings.java | 4 - src/com/android/tv/util/Utils.java | 16 ++- 12 files changed, 204 insertions(+), 180 deletions(-) create mode 100644 src/com/android/tv/util/CompositeComparator.java delete mode 100644 src/com/android/tv/util/DvrTunerStorageUtils.java create mode 100644 src/com/android/tv/util/ToastUtils.java (limited to 'src/com/android/tv/util') diff --git a/src/com/android/tv/util/AsyncDbTask.java b/src/com/android/tv/util/AsyncDbTask.java index 8bcdb294..78243642 100644 --- a/src/com/android/tv/util/AsyncDbTask.java +++ b/src/com/android/tv/util/AsyncDbTask.java @@ -29,9 +29,9 @@ import android.util.Log; import android.util.Range; import com.android.tv.common.SoftPreconditions; -import com.android.tv.dvr.RecordedProgram; import com.android.tv.data.Channel; import com.android.tv.data.Program; +import com.android.tv.dvr.RecordedProgram; import java.util.ArrayList; import java.util.List; @@ -162,7 +162,7 @@ public abstract class AsyncDbTask @Override public String toString() { - return this.getClass().getSimpleName() + "(" + mUri + ")"; + return this.getClass().getName() + "(" + mUri + ")"; } } diff --git a/src/com/android/tv/util/CompositeComparator.java b/src/com/android/tv/util/CompositeComparator.java new file mode 100644 index 00000000..47cf50fe --- /dev/null +++ b/src/com/android/tv/util/CompositeComparator.java @@ -0,0 +1,42 @@ +/* + * 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.Comparator; + +/** + * A comparator which runs multiple comparators sequentially. + */ +public class CompositeComparator implements Comparator { + private final Comparator[] mComparators; + + @SafeVarargs + public CompositeComparator(Comparator... comparators) { + mComparators = comparators; + } + + @Override + public int compare(T lhs, T rhs) { + for (Comparator comparator : mComparators) { + int result = comparator.compare(lhs, rhs); + if (result != 0) { + return result; + } + } + return 0; + } +} diff --git a/src/com/android/tv/util/DvrTunerStorageUtils.java b/src/com/android/tv/util/DvrTunerStorageUtils.java deleted file mode 100644 index 534a95ef..00000000 --- a/src/com/android/tv/util/DvrTunerStorageUtils.java +++ /dev/null @@ -1,113 +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.os.Environment; -import android.content.Context; -import android.os.StatFs; -import android.os.storage.StorageManager; -import android.os.storage.StorageVolume; - -import com.android.tv.common.feature.CommonFeatures; - -import java.io.File; - -/** - * A utility class for storage usage of DVR recording. - */ -public class DvrTunerStorageUtils { - // STOPSHIP: turn off ALLOW_REMOVABLE_STORAGE. b/30768857 - private static final boolean ALLOW_REMOVABLE_STORAGE = true; - - private static final long MIN_STORAGE_SIZE_FOR_DVR_IN_BYTES = 50 * 1024 * 1024 * 1024L; - private static final long MIN_FREE_STORAGE_SIZE_FOR_DVR_IN_BYTES = 10 * 1024 * 1024 * 1024L; - private static final String RECORDING_DATA_SUB_PATH = "/recording/"; - // Since {@link StorageVolume#getUuid} will return null for internal storage and {@code null} - // should be used for missing storage status, we need the internal storage specifier. - private static final String INTERNAL_STORAGE_UUID = "internal_storage_uuid"; - - /** - * Returns the path to DVR recording data directory. - * @param context {@link Context} - * @param recordingId unique {@link String} specifier for each recording - * @return {@link File} - */ - public static File getRecordingDataDirectory(Context context, String recordingId) { - File recordingDataRootDir = getRootDirectory(context); - if (recordingDataRootDir == null) { - return null; - } - return new File(recordingDataRootDir + RECORDING_DATA_SUB_PATH + recordingId); - } - - /** - * Returns the unique identifier for the storage which will be used to store recordings. - * @param context {@link Context} - * @return {@link String} of the unique identifier when storage exists, {@code null} otherwise - */ - public static String getRecordingStorageUuid(Context context) { - File recordingDataRootDir = getRootDirectory(context); - StorageManager manager = (StorageManager) context.getSystemService(context.STORAGE_SERVICE); - StorageVolume volume = manager.getStorageVolume(recordingDataRootDir); - if (volume == null) { - return null; - } - if (!Environment.MEDIA_MOUNTED.equals(volume.getState())) { - return null; - } - String uuid = volume.getUuid(); - return uuid == null ? INTERNAL_STORAGE_UUID : uuid; - } - - /** - * Returns whether the storage has sufficient storage. - * @param context {@link Context} - * @return {@code true} when there is sufficient storage, {@code false} otherwise - */ - public static boolean isStorageSufficient(Context context) { - File recordingDataRootDir = getRootDirectory(context); - if (recordingDataRootDir == null || !recordingDataRootDir.isDirectory()) { - return false; - } - if (CommonFeatures.FORCE_RECORDING_UNTIL_NO_SPACE.isEnabled(context)) { - return true; - } - StatFs statFs = new StatFs(recordingDataRootDir.toString()); - return statFs.getTotalBytes() >= MIN_STORAGE_SIZE_FOR_DVR_IN_BYTES - && statFs.getAvailableBytes() >= MIN_FREE_STORAGE_SIZE_FOR_DVR_IN_BYTES; - } - - private static File getRootDirectory(Context context) { - if (!ALLOW_REMOVABLE_STORAGE) { - return context.getExternalFilesDir(null); - } - File[] dirs = context.getExternalFilesDirs(null); - if (dirs == null) { - return null; - } - for (File dir : dirs) { - if (dir == null) { - continue; - } - StatFs statFs = new StatFs(dir.toString()); - if (statFs.getTotalBytes() >= MIN_STORAGE_SIZE_FOR_DVR_IN_BYTES - && statFs.getAvailableBytes() >= MIN_FREE_STORAGE_SIZE_FOR_DVR_IN_BYTES) { - return dir; - } - } - return dirs[0]; - } -} diff --git a/src/com/android/tv/util/LocationUtils.java b/src/com/android/tv/util/LocationUtils.java index 406a9d88..8e3b59e9 100644 --- a/src/com/android/tv/util/LocationUtils.java +++ b/src/com/android/tv/util/LocationUtils.java @@ -25,6 +25,7 @@ import android.location.LocationManager; import android.os.Bundle; import android.util.Log; + import java.io.IOException; import java.util.List; import java.util.Locale; @@ -36,36 +37,6 @@ public class LocationUtils { private static final String TAG = "LocationUtils"; private static final boolean DEBUG = false; - private static final LocationListener LOCATION_LISTENER = new LocationListener() { - @Override - public void onLocationChanged(Location location) { - Geocoder geocoder = new Geocoder(sApplicationContext, Locale.getDefault()); - try { - List
addresses = geocoder.getFromLocation(location.getLatitude(), - location.getLongitude(), 1); - if (addresses != null) { - sAddress = addresses.get(0); - if (DEBUG) Log.d(TAG, "returned address: " + sAddress); - } else { - if (DEBUG) Log.d(TAG, "No address returned"); - } - sError = null; - } catch (IOException e) { - Log.w(TAG, "Error in retrieving address", e); - sError = e; - } - } - - @Override - public void onStatusChanged(String provider, int status, Bundle extras) { } - - @Override - public void onProviderEnabled(String provider) { } - - @Override - public void onProviderDisabled(String provider) { } - }; - private static Context sApplicationContext; private static Address sAddress; private static IOException sError; @@ -83,19 +54,67 @@ public class LocationUtils { } if (sApplicationContext == null) { sApplicationContext = context.getApplicationContext(); - LocationManager mLocationManager = (LocationManager) context.getSystemService( - Context.LOCATION_SERVICE); - try { - mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 10, - LOCATION_LISTENER, null); - } catch (SecurityException e) { - // Enables requesting the location updates again. - sApplicationContext = null; - throw e; - } } + LocationUtilsHelper.startLocationUpdates(); return null; } + 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
addresses = geocoder.getFromLocation( + location.getLatitude(), location.getLongitude(), 1); + if (addresses != null) { + sAddress = addresses.get(0); + if (DEBUG) Log.d(TAG, "Got " + sAddress); + } 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/PermissionUtils.java b/src/com/android/tv/util/PermissionUtils.java index a443ede7..453885a4 100644 --- a/src/com/android/tv/util/PermissionUtils.java +++ b/src/com/android/tv/util/PermissionUtils.java @@ -7,6 +7,11 @@ 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; @@ -39,7 +44,7 @@ public class PermissionUtils { } public static boolean hasReadTvListings(Context context) { - return context.checkSelfPermission("android.permission.READ_TV_LISTINGS") + return context.checkSelfPermission(PERMISSION_READ_TV_LISTINGS) == PackageManager.PERMISSION_GRANTED; } } diff --git a/src/com/android/tv/util/PipInputManager.java b/src/com/android/tv/util/PipInputManager.java index 03bdc681..2c51d5a0 100644 --- a/src/com/android/tv/util/PipInputManager.java +++ b/src/com/android/tv/util/PipInputManager.java @@ -149,6 +149,7 @@ public class PipInputManager { if (mStarted) { return; } + mStarted = true; mInputManager.addCallback(mTvInputCallback); mChannelTuner.addListener(mChannelTunerListener); initializePipInputList(); @@ -161,6 +162,7 @@ public class PipInputManager { if (!mStarted) { return; } + mStarted = false; mInputManager.removeCallback(mTvInputCallback); mChannelTuner.removeListener(mChannelTunerListener); mPipInputMap.clear(); diff --git a/src/com/android/tv/util/RecurringRunner.java b/src/com/android/tv/util/RecurringRunner.java index 469170ed..4135bd4e 100644 --- a/src/com/android/tv/util/RecurringRunner.java +++ b/src/com/android/tv/util/RecurringRunner.java @@ -126,10 +126,7 @@ public final class RecurringRunner { return next; } - /** - * Resets the next run time. - */ - public long resetNextRunTime() { + private long resetNextRunTime() { long next = System.currentTimeMillis() + mIntervalMs; getSharedPreferences().edit().putLong(mName, next).apply(); return next; diff --git a/src/com/android/tv/util/SetupUtils.java b/src/com/android/tv/util/SetupUtils.java index 1213d317..8223a81c 100644 --- a/src/com/android/tv/util/SetupUtils.java +++ b/src/com/android/tv/util/SetupUtils.java @@ -20,6 +20,8 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.media.tv.TvContract; import android.media.tv.TvInputInfo; import android.media.tv.TvInputManager; @@ -35,6 +37,8 @@ import com.android.tv.TvApplication; import com.android.tv.common.SoftPreconditions; import com.android.tv.data.Channel; import com.android.tv.data.ChannelDataManager; +import com.android.tv.data.epg.EpgFetcher; +import com.android.tv.experiments.Experiments; import com.android.tv.tuner.tvinput.TunerTvInputService; import java.util.Collections; @@ -267,7 +271,8 @@ public class SetupUtils { // Find all already-verified packages. Set setUpPackages = new HashSet<>(); SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); - for (String input : sp.getStringSet(PREF_KEY_SET_UP_INPUTS, Collections.emptySet())) { + for (String input : sp.getStringSet(PREF_KEY_SET_UP_INPUTS, + Collections.emptySet())) { if (!TextUtils.isEmpty(input)) { ComponentName componentName = ComponentName.unflattenFromString(input); if (componentName != null) { @@ -330,14 +335,28 @@ public class SetupUtils { removedInputList.remove(mTunerInputId); if (!removedInputList.isEmpty()) { + boolean inputPackageDeleted = false; for (String input : removedInputList) { - mRecognizedInputs.remove(input); - mSetUpInputs.remove(input); - mKnownInputs.remove(input); + 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); + 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"); + mRecognizedInputs.remove(input); + mSetUpInputs.remove(input); + mKnownInputs.remove(input); + inputPackageDeleted = true; + } + } + if (inputPackageDeleted) { + mSharedPreferences.edit().putStringSet(PREF_KEY_SET_UP_INPUTS, mSetUpInputs) + .putStringSet(PREF_KEY_KNOWN_INPUTS, mKnownInputs) + .putStringSet(PREF_KEY_RECOGNIZED_INPUTS, mRecognizedInputs).apply(); } - mSharedPreferences.edit().putStringSet(PREF_KEY_SET_UP_INPUTS, mSetUpInputs) - .putStringSet(PREF_KEY_KNOWN_INPUTS, mKnownInputs) - .putStringSet(PREF_KEY_RECOGNIZED_INPUTS, mRecognizedInputs).apply(); } } @@ -345,7 +364,7 @@ public class SetupUtils { * Called when an setup is done. Once it is called, {@link #isSetupDone} returns {@code true} * for {@code inputId}. */ - public void onSetupDone(String inputId) { + private void onSetupDone(String inputId) { SoftPreconditions.checkState(inputId != null); if (DEBUG) Log.d(TAG, "onSetupDone: input=" + inputId); if (!mRecognizedInputs.contains(inputId)) { @@ -363,5 +382,13 @@ public class SetupUtils { mSetUpInputs.add(inputId); mSharedPreferences.edit().putStringSet(PREF_KEY_SET_UP_INPUTS, mSetUpInputs).apply(); } + // Start fetching program guide data for internal tuners. + Context context = mTvApplication.getApplicationContext(); + if (Utils.isInternalTvInput(context, inputId)) { + if (context.checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) + == PackageManager.PERMISSION_GRANTED && Experiments.CLOUD_EPG.get()) { + EpgFetcher.getInstance(context).startImmediately(); + } + } } } diff --git a/src/com/android/tv/util/SystemProperties.java b/src/com/android/tv/util/SystemProperties.java index 235161b6..e737f233 100644 --- a/src/com/android/tv/util/SystemProperties.java +++ b/src/com/android/tv/util/SystemProperties.java @@ -35,12 +35,6 @@ public final class SystemProperties { public static final BooleanSystemProperty ALLOW_STRICT_MODE = new BooleanSystemProperty( "tv_allow_strict_mode", true); - /** - * Allow Strict death penalty for eng builds. - */ - public static final BooleanSystemProperty ALLOW_DEATH_PENALTY = new BooleanSystemProperty( - "tv_allow_death_penalty", true); - /** * When true {@link android.view.KeyEvent}s are logged. Defaults to false. */ diff --git a/src/com/android/tv/util/ToastUtils.java b/src/com/android/tv/util/ToastUtils.java new file mode 100644 index 00000000..34346b2a --- /dev/null +++ b/src/com/android/tv/util/ToastUtils.java @@ -0,0 +1,43 @@ +/* + * 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.content.Context; +import android.support.annotation.MainThread; +import android.widget.Toast; + +import java.lang.ref.WeakReference; + +/** + * A utility class for the toast message. + */ +public class ToastUtils { + private static WeakReference sToast; + + /** + * 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) { + sToast.get().cancel(); + } + Toast toast = Toast.makeText(context, text, duration); + toast.show(); + sToast = new WeakReference<>(toast); + } +} diff --git a/src/com/android/tv/util/TvSettings.java b/src/com/android/tv/util/TvSettings.java index 4a65cbbe..97ff59d6 100644 --- a/src/com/android/tv/util/TvSettings.java +++ b/src/com/android/tv/util/TvSettings.java @@ -34,9 +34,6 @@ import java.util.Set; public final class TvSettings { private TvSettings() {} - public static final String PREFS_FILE = "settings"; - public static final String PREF_TV_WATCH_LOGGING_ENABLED = "tv_watch_logging_enabled"; - public static final String PREF_CLOSED_CAPTION_ENABLED = "is_cc_enabled"; // boolean value public static final String PREF_DISPLAY_MODE = "display_mode"; // int value public static final String PREF_PIP_LAYOUT = "pip_layout"; // int value public static final String PREF_PIP_SIZE = "pip_size"; // int value @@ -49,7 +46,6 @@ public final class TvSettings { public @interface PipSound {} public static final int PIP_SOUND_MAIN = 0; public static final int PIP_SOUND_PIP_WINDOW = PIP_SOUND_MAIN + 1; - public static final int PIP_SOUND_LAST = PIP_SOUND_PIP_WINDOW; // PIP layouts @Retention(RetentionPolicy.SOURCE) diff --git a/src/com/android/tv/util/Utils.java b/src/com/android/tv/util/Utils.java index 9f90c69f..99d34431 100644 --- a/src/com/android/tv/util/Utils.java +++ b/src/com/android/tv/util/Utils.java @@ -37,6 +37,7 @@ 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; @@ -77,7 +78,6 @@ public class Utils { 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_KEY_FROM_LAUNCHER = "from_launcher"; - public static final String EXTRA_KEY_RECORDING_URI = "recording_uri"; 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"; public static final String EXTRA_KEY_RECORDED_PROGRAM_PIN_CHECKED = @@ -119,7 +119,7 @@ public class Utils { // 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 BUNDLED_PACKAGE_SET = new HashSet<>(); + private static final Set BUNDLED_PACKAGE_SET = new ArraySet<>(); static { BUNDLED_PACKAGE_SET.add("com.android.tv"); @@ -802,6 +802,18 @@ public class Utils { 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}. */ -- cgit v1.2.3