aboutsummaryrefslogtreecommitdiff
path: root/src/com/android/tv/tuner/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/tv/tuner/util')
-rw-r--r--src/com/android/tv/tuner/util/PostalCodeUtils.java138
-rw-r--r--src/com/android/tv/tuner/util/StringUtils.java38
-rw-r--r--src/com/android/tv/tuner/util/SystemPropertiesProxy.java16
-rw-r--r--src/com/android/tv/tuner/util/TunerInputInfoUtils.java87
4 files changed, 205 insertions, 74 deletions
diff --git a/src/com/android/tv/tuner/util/PostalCodeUtils.java b/src/com/android/tv/tuner/util/PostalCodeUtils.java
new file mode 100644
index 00000000..9eb689a7
--- /dev/null
+++ b/src/com/android/tv/tuner/util/PostalCodeUtils.java
@@ -0,0 +1,138 @@
+/*
+ * 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.tuner.util;
+
+import android.content.Context;
+import android.location.Address;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import android.util.Log;
+import com.android.tv.tuner.TunerPreferences;
+import com.android.tv.util.LocationUtils;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+/**
+ * A utility class to update, get, and set the last known postal or zip code.
+ */
+public class PostalCodeUtils {
+ private static final String TAG = "PostalCodeUtils";
+
+ // Postcode formats, where A signifies a letter and 9 a digit:
+ // US zip code format: 99999
+ private static final String POSTCODE_REGEX_US = "^(\\d{5})";
+ // UK postcode district formats: A9, A99, AA9, AA99
+ // Full UK postcode format: Postcode District + space + 9AA
+ // Should be able to handle both postcode district and full postcode
+ private static final String POSTCODE_REGEX_GB =
+ "^([A-Z][A-Z]?[0-9][0-9A-Z]?)( ?[0-9][A-Z]{2})?$";
+ private static final String POSTCODE_REGEX_GB_GIR = "^GIR( ?0AA)?$"; // special UK postcode
+
+ private static final Map<String, Pattern> REGION_PATTERN = new HashMap<>();
+ private static final Map<String, Integer> REGION_MAX_LENGTH = new HashMap<>();
+
+ static {
+ REGION_PATTERN.put(Locale.US.getCountry(), Pattern.compile(POSTCODE_REGEX_US));
+ REGION_PATTERN.put(
+ Locale.UK.getCountry(),
+ Pattern.compile(POSTCODE_REGEX_GB + "|" + POSTCODE_REGEX_GB_GIR));
+ REGION_MAX_LENGTH.put(Locale.US.getCountry(), 5);
+ REGION_MAX_LENGTH.put(Locale.UK.getCountry(), 8);
+ }
+
+ // The longest postcode number is 10-character-long.
+ // Use a larger number to accommodate future changes.
+ private static final int DEFAULT_MAX_LENGTH = 16;
+
+ /** Returns {@code true} if postal code has been changed */
+ public static boolean updatePostalCode(Context context)
+ throws IOException, SecurityException, NoPostalCodeException {
+ String postalCode = getPostalCode(context);
+ String lastPostalCode = getLastPostalCode(context);
+ if (TextUtils.isEmpty(postalCode)) {
+ if (TextUtils.isEmpty(lastPostalCode)) {
+ throw new NoPostalCodeException();
+ }
+ } else if (!TextUtils.equals(postalCode, lastPostalCode)) {
+ setLastPostalCode(context, postalCode);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Gets the last stored postal or zip code, which might be decided by {@link LocationUtils} or
+ * input by users.
+ */
+ public static String getLastPostalCode(Context context) {
+ return TunerPreferences.getLastPostalCode(context);
+ }
+
+ /**
+ * Sets the last stored postal or zip code. This method will overwrite the value written by
+ * calling {@link #updatePostalCode(Context)}.
+ */
+ public static void setLastPostalCode(Context context, String postalCode) {
+ Log.i(TAG, "Set Postal Code:" + postalCode);
+ TunerPreferences.setLastPostalCode(context, postalCode);
+ }
+
+ @Nullable
+ private static String getPostalCode(Context context) throws IOException, SecurityException {
+ Address address = LocationUtils.getCurrentAddress(context);
+ if (address != null) {
+ Log.i(TAG, "Current country and postal code is " + address.getCountryName() + ", "
+ + address.getPostalCode());
+ return address.getPostalCode();
+ }
+ return null;
+ }
+
+ /** An {@link java.lang.Exception} class to notify no valid postal or zip code is available. */
+ public static class NoPostalCodeException extends Exception {
+ public NoPostalCodeException() {
+ }
+ }
+
+ /**
+ * Checks whether a postcode matches the format of the specific region.
+ *
+ * @return {@code false} if the region is supported and the postcode doesn't match; {@code true}
+ * otherwise
+ */
+ public static boolean matches(@NonNull CharSequence postcode, @NonNull String region) {
+ Pattern pattern = REGION_PATTERN.get(region.toUpperCase());
+ return pattern == null || pattern.matcher(postcode).matches();
+ }
+
+ /**
+ * Gets the largest possible postcode length in the region.
+ *
+ * @return maximum postcode length if the region is supported; {@link #DEFAULT_MAX_LENGTH}
+ * otherwise
+ */
+ public static int getRegionMaxLength(Context context) {
+ Integer maxLength =
+ REGION_MAX_LENGTH.get(LocationUtils.getCurrentCountry(context).toUpperCase());
+ return maxLength == null ? DEFAULT_MAX_LENGTH : maxLength;
+ }
+} \ No newline at end of file
diff --git a/src/com/android/tv/tuner/util/StringUtils.java b/src/com/android/tv/tuner/util/StringUtils.java
deleted file mode 100644
index 15571e75..00000000
--- a/src/com/android/tv/tuner/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.tuner.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/tuner/util/SystemPropertiesProxy.java b/src/com/android/tv/tuner/util/SystemPropertiesProxy.java
index 62a64361..2817ccbf 100644
--- a/src/com/android/tv/tuner/util/SystemPropertiesProxy.java
+++ b/src/com/android/tv/tuner/util/SystemPropertiesProxy.java
@@ -58,4 +58,20 @@ public class SystemPropertiesProxy {
}
return def;
}
+
+ public static String getString(String key, String def) throws IllegalArgumentException {
+ try {
+ Class SystemPropertiesClass = Class.forName("android.os.SystemProperties");
+ Method getIntMethod =
+ SystemPropertiesClass.getDeclaredMethod("get", String.class, String.class);
+ getIntMethod.setAccessible(true);
+ return (String) getIntMethod.invoke(SystemPropertiesClass, key, def);
+ } catch (InvocationTargetException
+ | IllegalAccessException
+ | NoSuchMethodException
+ | ClassNotFoundException e) {
+ Log.e(TAG, "Failed to invoke SystemProperties.get()", e);
+ }
+ return def;
+ }
}
diff --git a/src/com/android/tv/tuner/util/TunerInputInfoUtils.java b/src/com/android/tv/tuner/util/TunerInputInfoUtils.java
index 5c411f64..f421bf1a 100644
--- a/src/com/android/tv/tuner/util/TunerInputInfoUtils.java
+++ b/src/com/android/tv/tuner/util/TunerInputInfoUtils.java
@@ -21,10 +21,11 @@ import android.content.ComponentName;
import android.content.Context;
import android.media.tv.TvInputInfo;
import android.media.tv.TvInputManager;
+import android.os.AsyncTask;
import android.os.Build;
import android.support.annotation.Nullable;
-import android.support.v4.os.BuildCompat;
import android.util.Log;
+import android.util.Pair;
import com.android.tv.common.feature.CommonFeatures;
import com.android.tv.tuner.R;
@@ -43,23 +44,31 @@ public class TunerInputInfoUtils {
*/
@Nullable
@TargetApi(Build.VERSION_CODES.N)
- public static TvInputInfo buildTunerInputInfo(Context context, boolean fromBuiltInTuner) {
- int numOfDevices = TunerHal.getTunerCount(context);
- if (numOfDevices == 0) {
+ public static TvInputInfo buildTunerInputInfo(Context context) {
+ Pair<Integer, Integer> tunerTypeAndCount = TunerHal.getTunerTypeAndCount(context);
+ if (tunerTypeAndCount.first == null || tunerTypeAndCount.second == 0) {
return null;
}
- TvInputInfo.Builder builder = new TvInputInfo.Builder(context, new ComponentName(context,
- TunerTvInputService.class));
- if (fromBuiltInTuner) {
- builder.setLabel(R.string.bt_app_name);
- } else {
- builder.setLabel(R.string.ut_app_name);
+ int inputLabelId = 0;
+ switch (tunerTypeAndCount.first) {
+ case TunerHal.TUNER_TYPE_BUILT_IN:
+ inputLabelId = R.string.bt_app_name;
+ break;
+ case TunerHal.TUNER_TYPE_USB:
+ inputLabelId = R.string.ut_app_name;
+ break;
+ case TunerHal.TUNER_TYPE_NETWORK:
+ inputLabelId = R.string.nt_app_name;
+ break;
}
try {
- return builder.setCanRecord(CommonFeatures.DVR.isEnabled(context))
- .setTunerCount(numOfDevices)
+ TvInputInfo.Builder builder = new TvInputInfo.Builder(context,
+ new ComponentName(context, TunerTvInputService.class));
+ return builder.setLabel(inputLabelId)
+ .setCanRecord(CommonFeatures.DVR.isEnabled(context))
+ .setTunerCount(tunerTypeAndCount.second)
.build();
- } catch (NullPointerException e) {
+ } catch (IllegalArgumentException | NullPointerException e) {
// TunerTvInputService is not enabled.
return null;
}
@@ -71,30 +80,36 @@ public class TunerInputInfoUtils {
* @param context {@link Context} instance
*/
public static void updateTunerInputInfo(Context context) {
- if (BuildCompat.isAtLeastN()) {
- if (DEBUG) Log.d(TAG, "updateTunerInputInfo()");
- TvInputInfo info = buildTunerInputInfo(context, isBuiltInTuner(context));
- if (info != null) {
- ((TvInputManager) context.getSystemService(Context.TV_INPUT_SERVICE))
- .updateTvInputInfo(info);
- if (DEBUG) {
- Log.d(TAG, "TvInputInfo [" + info.loadLabel(context)
- + "] updated: " + info.toString());
+ final Context appContext = context.getApplicationContext();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ new AsyncTask<Void, Void, TvInputInfo>() {
+ @Override
+ protected TvInputInfo doInBackground(Void... params) {
+ if (DEBUG) Log.d(TAG, "updateTunerInputInfo()");
+ return buildTunerInputInfo(appContext);
}
- } else {
- if (DEBUG) {
- Log.d(TAG, "Updating tuner input's info failed. Input is not ready yet.");
+
+ @Override
+ @TargetApi(Build.VERSION_CODES.N)
+ protected void onPostExecute(TvInputInfo info) {
+ if (info != null) {
+ ((TvInputManager) appContext.getSystemService(Context.TV_INPUT_SERVICE))
+ .updateTvInputInfo(info);
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "TvInputInfo ["
+ + info.loadLabel(appContext)
+ + "] updated: "
+ + info.toString());
+ }
+ } else {
+ if (DEBUG) {
+ Log.d(TAG, "Updating tuner input info failed. Input is not ready yet.");
+ }
+ }
}
- }
+ }.execute();
}
}
-
- /**
- * Returns if the current tuner service is for a built-in tuner.
- *
- * @param context {@link Context} instance
- */
- public static boolean isBuiltInTuner(Context context) {
- return TunerHal.getTunerType(context) == TunerHal.TUNER_TYPE_BUILT_IN;
- }
-}
+} \ No newline at end of file