diff options
Diffstat (limited to 'src/com/android/tv/util')
21 files changed, 697 insertions, 280 deletions
diff --git a/src/com/android/tv/util/account/AccountHelperImpl.java b/src/com/android/tv/util/AccountHelper.java index 58fbd27e..a3e6ad58 100644 --- a/src/com/android/tv/util/account/AccountHelperImpl.java +++ b/src/com/android/tv/util/AccountHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.tv.util.account; +package com.android.tv.util; import android.accounts.Account; import android.content.Context; @@ -23,23 +23,24 @@ import android.preference.PreferenceManager; import android.support.annotation.Nullable; /** Helper methods for getting and selecting a user account. */ -public class AccountHelperImpl implements com.android.tv.util.account.AccountHelper { +public class AccountHelper { + private static final String TAG = "AccountHelper"; + private static final boolean DEBUG = false; private static final String SELECTED_ACCOUNT = "android.tv.livechannels.selected_account"; - protected final Context mContext; + private final Context mContext; private final SharedPreferences mDefaultPreferences; @Nullable private Account mSelectedAccount; - public AccountHelperImpl(Context context) { + public AccountHelper(Context context) { mContext = context.getApplicationContext(); mDefaultPreferences = PreferenceManager.getDefaultSharedPreferences(mContext); } /** Returns the currently selected account or {@code null} if none is selected. */ - @Override @Nullable - public final Account getSelectedAccount() { + public Account getSelectedAccount() { String accountId = mDefaultPreferences.getString(SELECTED_ACCOUNT, null); if (accountId == null) { return null; @@ -56,12 +57,8 @@ public class AccountHelperImpl implements com.android.tv.util.account.AccountHel return mSelectedAccount; } - /** - * Returns all eligible accounts. - * - * <p>Override this method to return the accounts needed. - */ - protected Account[] getEligibleAccounts() { + /** Returns all eligible accounts . */ + private Account[] getEligibleAccounts() { return new Account[0]; } @@ -70,9 +67,8 @@ public class AccountHelperImpl implements com.android.tv.util.account.AccountHel * * @return selected account or {@code null} if none is selected. */ - @Override @Nullable - public final Account selectFirstAccount() { + public Account selectFirstAccount() { Account account = getFirstEligibleAccount(); if (account != null) { selectAccount(account); @@ -85,9 +81,8 @@ public class AccountHelperImpl implements com.android.tv.util.account.AccountHel * * @return first account or {@code null} if none is eligible. */ - @Override @Nullable - public final Account getFirstEligibleAccount() { + public Account getFirstEligibleAccount() { Account[] accounts = getEligibleAccounts(); return accounts.length == 0 ? null : accounts[0]; } diff --git a/src/com/android/tv/util/AsyncDbTask.java b/src/com/android/tv/util/AsyncDbTask.java index b575df53..376fcc70 100644 --- a/src/com/android/tv/util/AsyncDbTask.java +++ b/src/com/android/tv/util/AsyncDbTask.java @@ -28,7 +28,6 @@ import android.support.annotation.WorkerThread; import android.util.Log; import android.util.Range; import com.android.tv.common.SoftPreconditions; -import com.android.tv.common.concurrent.NamedThreadFactory; import com.android.tv.data.Channel; import com.android.tv.data.Program; import com.android.tv.dvr.data.RecordedProgram; @@ -48,7 +47,6 @@ import java.util.concurrent.RejectedExecutionException; * @param <Progress> the type of the progress units published during the background computation. * @param <Result> the type of the result of the background computation. */ -@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed public abstract class AsyncDbTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> { private static final String TAG = "AsyncDbTask"; @@ -151,7 +149,7 @@ public abstract class AsyncDbTask<Params, Progress, Result> return null; } } catch (Exception e) { - SoftPreconditions.warn(TAG, null, e, "Error querying " + this); + SoftPreconditions.warn(TAG, null, "Error querying " + this, e); return null; } } diff --git a/src/com/android/tv/util/BitmapUtils.java b/src/com/android/tv/util/BitmapUtils.java index 4c67d934..6902a6fe 100644 --- a/src/com/android/tv/util/BitmapUtils.java +++ b/src/com/android/tv/util/BitmapUtils.java @@ -29,7 +29,6 @@ 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; diff --git a/src/com/android/tv/util/Clock.java b/src/com/android/tv/util/Clock.java new file mode 100644 index 00000000..0004a669 --- /dev/null +++ b/src/com/android/tv/util/Clock.java @@ -0,0 +1,64 @@ +/* + * 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/Debug.java b/src/com/android/tv/util/Debug.java new file mode 100644 index 00000000..422a61e3 --- /dev/null +++ b/src/com/android/tv/util/Debug.java @@ -0,0 +1,50 @@ +/* + * 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 static final 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 new file mode 100644 index 00000000..6aabf37b --- /dev/null +++ b/src/com/android/tv/util/DurationTimer.java @@ -0,0 +1,80 @@ +/* + * 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/ImageLoader.java b/src/com/android/tv/util/ImageLoader.java index 32ac89f0..9b4d2a70 100644 --- a/src/com/android/tv/util/ImageLoader.java +++ b/src/com/android/tv/util/ImageLoader.java @@ -31,7 +31,6 @@ import android.support.annotation.WorkerThread; import android.util.ArraySet; import android.util.Log; import com.android.tv.R; -import com.android.tv.common.concurrent.NamedThreadFactory; import com.android.tv.util.BitmapUtils.ScaledBitmapInfo; import java.lang.ref.WeakReference; import java.util.HashMap; diff --git a/src/com/android/tv/util/LocationUtils.java b/src/com/android/tv/util/LocationUtils.java new file mode 100644 index 00000000..a960c616 --- /dev/null +++ b/src/com/android/tv/util/LocationUtils.java @@ -0,0 +1,137 @@ +/* + * 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.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/NamedThreadFactory.java b/src/com/android/tv/util/NamedThreadFactory.java new file mode 100644 index 00000000..264b8b3f --- /dev/null +++ b/src/com/android/tv/util/NamedThreadFactory.java @@ -0,0 +1,45 @@ +/* + * 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 new file mode 100644 index 00000000..85ecde5b --- /dev/null +++ b/src/com/android/tv/util/NetworkTrafficTags.java @@ -0,0 +1,63 @@ +/* + * 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/OnboardingUtils.java b/src/com/android/tv/util/OnboardingUtils.java index 63383aab..3b72e091 100644 --- a/src/com/android/tv/util/OnboardingUtils.java +++ b/src/com/android/tv/util/OnboardingUtils.java @@ -48,8 +48,8 @@ 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 = @@ -59,8 +59,8 @@ public final class OnboardingUtils { } /** - * 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) diff --git a/src/com/android/tv/util/PermissionUtils.java b/src/com/android/tv/util/PermissionUtils.java new file mode 100644 index 00000000..b3e4e3a2 --- /dev/null +++ b/src/com/android/tv/util/PermissionUtils.java @@ -0,0 +1,53 @@ +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 764689c2..c1b724a2 100644 --- a/src/com/android/tv/util/RecurringRunner.java +++ b/src/com/android/tv/util/RecurringRunner.java @@ -22,8 +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; /** diff --git a/src/com/android/tv/util/SetupUtils.java b/src/com/android/tv/util/SetupUtils.java index ad5d5024..a1ff192b 100644 --- a/src/com/android/tv/util/SetupUtils.java +++ b/src/com/android/tv/util/SetupUtils.java @@ -28,15 +28,15 @@ 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.TvSingletons; -import com.android.tv.common.BaseApplication; +import com.android.tv.ApplicationSingletons; +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.tuner.tvinput.TunerTvInputService; import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -54,8 +54,9 @@ 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 Context mContext; + private final TvApplication mTvApplication; private final SharedPreferences mSharedPreferences; private final Set<String> mKnownInputs; private final Set<String> mSetUpInputs; @@ -63,10 +64,9 @@ public class SetupUtils { private boolean mIsFirstTune; private final String mTunerInputId; - @VisibleForTesting - protected SetupUtils(Context context) { - mContext = context; - mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); + private SetupUtils(TvApplication tvApplication) { + mTvApplication = tvApplication; + mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(tvApplication); mSetUpInputs = new ArraySet<>(); mSetUpInputs.addAll( mSharedPreferences.getStringSet(PREF_KEY_SET_UP_INPUTS, Collections.emptySet())); @@ -77,16 +77,18 @@ public class SetupUtils { mRecognizedInputs.addAll( mSharedPreferences.getStringSet(PREF_KEY_RECOGNIZED_INPUTS, mKnownInputs)); mIsFirstTune = mSharedPreferences.getBoolean(PREF_KEY_IS_FIRST_TUNE, true); - mTunerInputId = BaseApplication.getSingletons(context).getEmbeddedTunerInputId(); + mTunerInputId = + TvContract.buildInputId( + new ComponentName(tvApplication, TunerTvInputService.class)); } - /** - * Creates an instance of {@link SetupUtils}. - * - * <p><b>WARNING</b> this should only be called by the top level application. - */ - public static SetupUtils createForTvSingletons(Context context) { - return new SetupUtils(context.getApplicationContext()); + /** Gets an instance of {@link SetupUtils}. */ + public static SetupUtils getInstance(Context context) { + if (sSetupUtils != null) { + return sSetupUtils; + } + sSetupUtils = new SetupUtils((TvApplication) context.getApplicationContext()); + return sSetupUtils; } /** Additional work after the setup of TV input. */ @@ -97,15 +99,14 @@ public class SetupUtils { // 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 = - TvSingletons.getSingletons(mContext).getChannelDataManager(); + final ChannelDataManager manager = mTvApplication.getChannelDataManager(); if (!manager.isDbLoadFinished()) { manager.addListener( new ChannelDataManager.Listener() { @Override public void onLoadFinished() { manager.removeListener(this); - updateChannelsAfterSetup(mContext, inputId, postRunnable); + updateChannelsAfterSetup(mTvApplication, inputId, postRunnable); } @Override @@ -115,14 +116,14 @@ public class SetupUtils { public void onChannelBrowsableChanged() {} }); } else { - updateChannelsAfterSetup(mContext, inputId, postRunnable); + updateChannelsAfterSetup(mTvApplication, inputId, postRunnable); } } private static void updateChannelsAfterSetup( Context context, final String inputId, final Runnable postRunnable) { - TvSingletons tvSingletons = TvSingletons.getSingletons(context); - final ChannelDataManager manager = tvSingletons.getChannelDataManager(); + ApplicationSingletons appSingletons = TvApplication.getSingletons(context); + final ChannelDataManager manager = appSingletons.getChannelDataManager(); manager.updateChannels( new Runnable() { @Override @@ -158,9 +159,8 @@ public class SetupUtils { @UiThread public void markNewChannelsBrowsable() { Set<String> newInputsWithChannels = new HashSet<>(); - TvSingletons singletons = TvSingletons.getSingletons(mContext); - TvInputManagerHelper tvInputManagerHelper = singletons.getTvInputManagerHelper(); - ChannelDataManager channelDataManager = singletons.getChannelDataManager(); + TvInputManagerHelper tvInputManagerHelper = mTvApplication.getTvInputManagerHelper(); + ChannelDataManager channelDataManager = mTvApplication.getChannelDataManager(); SoftPreconditions.checkState(channelDataManager.isDbLoadFinished()); for (TvInputInfo input : tvInputManagerHelper.getTvInputInfos(true, true)) { String inputId = input.getId(); @@ -340,7 +340,8 @@ public class SetupUtils { try { // Just after booting, input list from TvInputManager are not reliable. // So we need to double-check package existence. b/29034900 - mContext.getPackageManager() + mTvApplication + .getPackageManager() .getPackageInfo( ComponentName.unflattenFromString(input).getPackageName(), PackageManager.GET_ACTIVITIES); diff --git a/src/com/android/tv/util/SqlParams.java b/src/com/android/tv/util/SqlParams.java deleted file mode 100644 index c4b803b6..00000000 --- a/src/com/android/tv/util/SqlParams.java +++ /dev/null @@ -1,74 +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.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 new file mode 100644 index 00000000..eeaf33a6 --- /dev/null +++ b/src/com/android/tv/util/StringUtils.java @@ -0,0 +1,34 @@ +/* + * 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 new file mode 100644 index 00000000..e1b8a398 --- /dev/null +++ b/src/com/android/tv/util/SystemProperties.java @@ -0,0 +1,53 @@ +/* + * 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/TvInputManagerHelper.java b/src/com/android/tv/util/TvInputManagerHelper.java index c4feafb7..e97bc4f9 100644 --- a/src/com/android/tv/util/TvInputManagerHelper.java +++ b/src/com/android/tv/util/TvInputManagerHelper.java @@ -21,19 +21,17 @@ 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.TvFeatures; +import com.android.tv.Features; import com.android.tv.common.SoftPreconditions; -import com.android.tv.common.util.CommonUtils; +import com.android.tv.common.TvCommonUtils; import com.android.tv.parental.ContentRatingsManager; import com.android.tv.parental.ParentalControlSettings; import java.util.ArrayList; @@ -49,58 +47,6 @@ public class TvInputManagerHelper { private static final String TAG = "TvInputManagerHelper"; private static final boolean DEBUG = false; - 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; @@ -111,8 +57,7 @@ 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. */ @@ -136,8 +81,7 @@ public class TvInputManagerHelper { DEFAULT_TV_INPUT_PRIORITY.add(TvInputInfo.TYPE_OTHER); } - private static final String[] PARTNER_TUNER_INPUT_PREFIX_BLACKLIST = { - }; + private static final String[] PARTNER_TUNER_INPUT_PREFIX_BLACKLIST = {}; private static final String[] TESTABLE_INPUTS = { "com.android.tv.testinput/.TestTvInputService" @@ -145,7 +89,7 @@ public class TvInputManagerHelper { private final Context mContext; private final PackageManager mPackageManager; - protected final TvInputManagerInterface mTvInputManager; + private final TvInputManager 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<>(); @@ -262,23 +206,10 @@ 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; - mContentRatingsManager = new ContentRatingsManager(context, tvInputManager); + mTvInputManager = (TvInputManager) context.getSystemService(Context.TV_INPUT_SERVICE); + mContentRatingsManager = new ContentRatingsManager(context); mParentalControlSettings = new ParentalControlSettings(context); mTvInputInfoComparator = new InputComparatorInternal(this); } @@ -389,7 +320,7 @@ public class TvInputManagerHelper { /** Is the input one known bundled inputs not written by OEM/SOCs. */ public boolean isBundledInput(TvInputInfo inputInfo) { return inputInfo != null - && CommonUtils.isInBundledPackageSet( + && Utils.isInBundledPackageSet( inputInfo.getServiceInfo().applicationInfo.packageName); } @@ -497,17 +428,9 @@ public class TvInputManagerHelper { } return size; } - /** - * 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(TvInputInfo inputInfo) { + return getInputState(inputInfo.getId()); } public int getInputState(String inputId) { @@ -578,15 +501,14 @@ public class TvInputManagerHelper { } private boolean isInBlackList(String inputId) { - if (TvFeatures.USE_PARTNER_INPUT_BLACKLIST.isEnabled(mContext)) { + if (Features.USE_PARTNER_INPUT_BLACKLIST.isEnabled(mContext)) { for (String disabledTunerInputPrefix : PARTNER_TUNER_INPUT_PREFIX_BLACKLIST) { if (inputId.contains(disabledTunerInputPrefix)) { return true; } } } - if (CommonUtils.isRoboTest()) return false; - if (CommonUtils.isRunningInTest()) { + if (TvCommonUtils.isRunningInTest()) { for (String testableInput : TESTABLE_INPUTS) { if (testableInput.equals(inputId)) { return false; diff --git a/src/com/android/tv/util/Utils.java b/src/com/android/tv/util/Utils.java index 1c8ccd5b..ac3be643 100644 --- a/src/com/android/tv/util/Utils.java +++ b/src/com/android/tv/util/Utils.java @@ -38,15 +38,20 @@ 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.TvSingletons; +import com.android.tv.TvApplication; +import com.android.tv.common.BuildConfig; import com.android.tv.common.SoftPreconditions; import com.android.tv.data.Channel; 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 java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; @@ -63,11 +68,13 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; /** A class that includes convenience methods for accessing TvProvider database. */ -@SuppressWarnings("TryWithResources") // TODO(b/62143348): remove when error prone check fixed 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_KEY_FROM_LAUNCHER = "from_launcher"; @@ -109,6 +116,15 @@ 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), @@ -645,7 +661,7 @@ public class Utils { return null; } TvInputManagerHelper inputManager = - TvSingletons.getSingletons(context).getTvInputManagerHelper(); + TvApplication.getSingletons(context).getTvInputManagerHelper(); CharSequence customLabel = inputManager.loadCustomLabel(input); String label = (customLabel == null) ? null : customLabel.toString(); if (TextUtils.isEmpty(label)) { @@ -688,6 +704,11 @@ public class Utils { 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}. */ @@ -754,7 +775,7 @@ public class Utils { /** Checks where there is any internal TV input. */ public static boolean hasInternalTvInputs(Context context, boolean tunerInputOnly) { for (TvInputInfo input : - TvSingletons.getSingletons(context) + TvApplication.getSingletons(context) .getTvInputManagerHelper() .getTvInputInfos(true, tunerInputOnly)) { if (isInternalTvInput(context, input.getId())) { @@ -768,7 +789,7 @@ public class Utils { public static List<TvInputInfo> getInternalTvInputs(Context context, boolean tunerInputOnly) { List<TvInputInfo> inputs = new ArrayList<>(); for (TvInputInfo input : - TvSingletons.getSingletons(context) + TvApplication.getSingletons(context) .getTvInputManagerHelper() .getTvInputInfos(true, tunerInputOnly)) { if (isInternalTvInput(context, input.getId())) { @@ -796,22 +817,47 @@ public class Utils { /** Returns the TV input for the given channel ID. */ @Nullable public static TvInputInfo getTvInputInfoForChannelId(Context context, long channelId) { - TvSingletons tvSingletons = TvSingletons.getSingletons(context); - Channel channel = tvSingletons.getChannelDataManager().getChannel(channelId); + ApplicationSingletons appSingletons = TvApplication.getSingletons(context); + Channel channel = appSingletons.getChannelDataManager().getChannel(channelId); if (channel == null) { return null; } - return tvSingletons.getTvInputManagerHelper().getTvInputInfo(channel.getInputId()); + return appSingletons.getTvInputManagerHelper().getTvInputInfo(channel.getInputId()); } /** Returns the {@link TvInputInfo} for the given input ID. */ @Nullable public static TvInputInfo getTvInputInfoForInputId(Context context, String inputId) { - return TvSingletons.getSingletons(context) + return TvApplication.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}. */ public static int[] getCanonicalGenreIds(String genres) { if (TextUtils.isEmpty(genres)) { @@ -853,6 +899,11 @@ public class Utils { return Genres.encode(genres); } + /** 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. diff --git a/src/com/android/tv/util/ViewCache.java b/src/com/android/tv/util/ViewCache.java index b8bdb6b8..2d5ecfe6 100644 --- a/src/com/android/tv/util/ViewCache.java +++ b/src/com/android/tv/util/ViewCache.java @@ -1,18 +1,3 @@ -/* - * 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; diff --git a/src/com/android/tv/util/account/AccountHelper.java b/src/com/android/tv/util/account/AccountHelper.java deleted file mode 100644 index e98b42ec..00000000 --- a/src/com/android/tv/util/account/AccountHelper.java +++ /dev/null @@ -1,38 +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.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(); -} |