diff options
Diffstat (limited to 'common/src/com')
18 files changed, 235 insertions, 832 deletions
diff --git a/common/src/com/android/tv/common/CollectionUtils.java b/common/src/com/android/tv/common/CollectionUtils.java index f81e51a5..300ad8f2 100644 --- a/common/src/com/android/tv/common/CollectionUtils.java +++ b/common/src/com/android/tv/common/CollectionUtils.java @@ -16,7 +16,12 @@ package com.android.tv.common; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; /** * Static utilities for collections @@ -42,4 +47,55 @@ public class CollectionUtils { } return result; } + + /** + * Unions the two collections and returns the unified list. + * <p> + * The elements is not compared with hashcode() or equals(). Comparator is used for the equality + * check. + */ + public static <T> List<T> union(Collection<T> originals, Collection<T> toAdds, + Comparator<T> comparator) { + List<T> result = new ArrayList<>(originals); + Collections.sort(result, comparator); + List<T> resultToAdd = new ArrayList<>(); + for (T toAdd : toAdds) { + if (Collections.binarySearch(result, toAdd, comparator) < 0) { + resultToAdd.add(toAdd); + } + } + result.addAll(resultToAdd); + return result; + } + + /** + * Subtracts the elements from the original collection. + */ + public static <T> List<T> subtract(Collection<T> originals, T[] toSubtracts, + Comparator<T> comparator) { + List<T> result = new ArrayList<>(originals); + Collections.sort(result, comparator); + for (T toSubtract : toSubtracts) { + int index = Collections.binarySearch(result, toSubtract, comparator); + if (index >= 0) { + result.remove(index); + } + } + return result; + } + + /** + * Returns {@code true} if the two specified collections have common elements. + */ + public static <T> boolean containsAny(Collection<T> c1, Collection<T> c2, + Comparator<T> comparator) { + List<T> contains = new ArrayList<>(c1); + Collections.sort(contains, comparator); + for (T iterate : c2) { + if (Collections.binarySearch(contains, iterate, comparator) >= 0) { + return true; + } + } + return false; + } } diff --git a/common/src/com/android/tv/common/SharedPreferencesUtils.java b/common/src/com/android/tv/common/SharedPreferencesUtils.java index 38daa963..fb3d9b56 100644 --- a/common/src/com/android/tv/common/SharedPreferencesUtils.java +++ b/common/src/com/android/tv/common/SharedPreferencesUtils.java @@ -28,9 +28,13 @@ public final class SharedPreferencesUtils { public static final String SHARED_PREF_FEATURES = "sharePreferencesFeatures"; public static final String SHARED_PREF_BROWSABLE = "browsable_shared_preference"; public static final String SHARED_PREF_WATCHED_HISTORY = "watched_history_shared_preference"; + public static final String SHARED_PREF_DVR_WATCHED_POSITION = + "dvr_watched_position_shared_preference"; public static final String SHARED_PREF_AUDIO_CAPABILITIES = "com.android.tv.audio_capabilities"; public static final String SHARED_PREF_RECURRING_RUNNER = "sharedPreferencesRecurringRunner"; + public static final String SHARED_PREF_EPG = "epg_preferences"; + public static final String SHARED_PREF_SERIES_RECORDINGS = "seriesRecordings"; private static boolean sInitializeCalled; @@ -40,7 +44,7 @@ public final class SharedPreferencesUtils { * Call {@link Context#getSharedPreferences(String, int)} as early as possible to avoid the ANR * due to the file loading. */ - public static synchronized void initialize(final Context context) { + public static synchronized void initialize(final Context context, final Runnable postTask) { if (!sInitializeCalled) { sInitializeCalled = true; new AsyncTask<Void, Void, Void>() { @@ -50,12 +54,22 @@ public final class SharedPreferencesUtils { context.getSharedPreferences(SHARED_PREF_FEATURES, Context.MODE_PRIVATE); context.getSharedPreferences(SHARED_PREF_BROWSABLE, Context.MODE_PRIVATE); context.getSharedPreferences(SHARED_PREF_WATCHED_HISTORY, Context.MODE_PRIVATE); + context.getSharedPreferences(SHARED_PREF_DVR_WATCHED_POSITION, + Context.MODE_PRIVATE); context.getSharedPreferences(SHARED_PREF_AUDIO_CAPABILITIES, Context.MODE_PRIVATE); context.getSharedPreferences(SHARED_PREF_RECURRING_RUNNER, Context.MODE_PRIVATE); + context.getSharedPreferences(SHARED_PREF_EPG, Context.MODE_PRIVATE); + context.getSharedPreferences(SHARED_PREF_SERIES_RECORDINGS, + Context.MODE_PRIVATE); return null; } + + @Override + protected void onPostExecute(Void result) { + postTask.run(); + } }.execute(); } } diff --git a/common/src/com/android/tv/common/SoftPreconditions.java b/common/src/com/android/tv/common/SoftPreconditions.java index 9b7713f6..823c42ff 100644 --- a/common/src/com/android/tv/common/SoftPreconditions.java +++ b/common/src/com/android/tv/common/SoftPreconditions.java @@ -20,7 +20,6 @@ import android.content.Context; import android.text.TextUtils; import android.util.Log; -import com.android.tv.common.BuildConfig; import com.android.tv.common.feature.Feature; /** @@ -43,12 +42,14 @@ public final class SoftPreconditions { * @param tag Used to identify the source of a log message. It usually * identifies the class or activity where the log call occurs. * @param msg The message you would like logged. + * @return the evaluation result of the boolean expression * @throws IllegalArgumentException if {@code expression} is true */ - public static void checkArgument(final boolean expression, String tag, String msg) { + public static boolean checkArgument(final boolean expression, String tag, String msg) { if (!expression) { warn(tag, "Illegal argument", msg, new IllegalArgumentException(msg)); } + return expression; } /** @@ -56,10 +57,12 @@ public final class SoftPreconditions { * method is not true. * * @param expression a boolean expression + * @return the evaluation result of the boolean expression * @throws IllegalArgumentException if {@code expression} is true */ - public static void checkArgument(final boolean expression) { + public static boolean checkArgument(final boolean expression) { checkArgument(expression, null, null); + return expression; } /** @@ -98,12 +101,14 @@ public final class SoftPreconditions { * @param tag Used to identify the source of a log message. It usually * identifies the class or activity where the log call occurs. * @param msg The message you would like logged. + * @return the evaluation result of the boolean expression * @throws IllegalStateException if {@code expression} is true */ - public static void checkState(final boolean expression, String tag, String msg) { + public static boolean checkState(final boolean expression, String tag, String msg) { if (!expression) { warn(tag, "Illegal State", msg, new IllegalStateException(msg)); } + return expression; } /** @@ -111,10 +116,12 @@ public final class SoftPreconditions { * instance, but not involving any parameters to the calling method is not true. * * @param expression a boolean expression + * @return the evaluation result of the boolean expression * @throws IllegalStateException if {@code expression} is true */ - public static void checkState(final boolean expression) { + public static boolean checkState(final boolean expression) { checkState(expression, null, null); + return expression; } /** diff --git a/common/src/com/android/tv/common/TvContentRatingCache.java b/common/src/com/android/tv/common/TvContentRatingCache.java index 7ea86287..5694cda7 100644 --- a/common/src/com/android/tv/common/TvContentRatingCache.java +++ b/common/src/com/android/tv/common/TvContentRatingCache.java @@ -39,7 +39,7 @@ public final class TvContentRatingCache implements MemoryManageable { private final static TvContentRatingCache INSTANCE = new TvContentRatingCache(); - public final static TvContentRatingCache getInstance() { + public static TvContentRatingCache getInstance() { return INSTANCE; } diff --git a/common/src/com/android/tv/common/feature/CommonFeatures.java b/common/src/com/android/tv/common/feature/CommonFeatures.java index 9925833f..d47aa603 100644 --- a/common/src/com/android/tv/common/feature/CommonFeatures.java +++ b/common/src/com/android/tv/common/feature/CommonFeatures.java @@ -16,7 +16,7 @@ package com.android.tv.common.feature; -import static com.android.tv.common.feature.EngOnlyFeature.ENG_ONLY_FEATURE; +import static com.android.tv.common.feature.FeatureUtils.AND; import static com.android.tv.common.feature.FeatureUtils.OR; import static com.android.tv.common.feature.TestableFeature.createTestableFeature; @@ -30,14 +30,26 @@ public class CommonFeatures { * DVR * * <p>See <a href="https://goto.google.com/atv-dvr-onepager">go/atv-dvr-onepager</a> + * + * DVR API is introduced in N, it only works when app runs as a system app. + */ + public static final TestableFeature DVR = createTestableFeature( + AND(OR(Sdk.N_PRE_2_OR_HIGHER, Sdk.AT_LEAST_N), SystemAppFeature.SYSTEM_APP_FEATURE)); + + /** + * ENABLE_RECORDING_REGARDLESS_OF_STORAGE_STATUS + * + * Enables dvr recording regardless of storage status. */ - public static TestableFeature DVR = createTestableFeature( - OR(ENG_ONLY_FEATURE, Sdk.N_PRE_2_OR_HIGHER)); + public static final Feature FORCE_RECORDING_UNTIL_NO_SPACE = + new PropertyFeature("force_recording_until_no_space", false); /** * USE_SW_CODEC_FOR_SD * * Prefer software based codec for SD channels. */ - public static Feature USE_SW_CODEC_FOR_SD = new PropertyFeature("use_sw_codec_for_sd", true); + public static final Feature USE_SW_CODEC_FOR_SD = + new PropertyFeature("use_sw_codec_for_sd", false + ); } diff --git a/common/src/com/android/tv/common/feature/EngOnlyFeature.java b/common/src/com/android/tv/common/feature/EngOnlyFeature.java index 14d2b49b..9fc39d9f 100644 --- a/common/src/com/android/tv/common/feature/EngOnlyFeature.java +++ b/common/src/com/android/tv/common/feature/EngOnlyFeature.java @@ -24,7 +24,7 @@ import com.android.tv.common.BuildConfig; * A feature that is only available on {@link BuildConfig#ENG} builds. */ public final class EngOnlyFeature implements Feature { - public static Feature ENG_ONLY_FEATURE = new EngOnlyFeature(); + public static final Feature ENG_ONLY_FEATURE = new EngOnlyFeature(); private EngOnlyFeature() { } diff --git a/common/src/com/android/tv/common/feature/Sdk.java b/common/src/com/android/tv/common/feature/Sdk.java index 268eaea7..46a681f8 100644 --- a/common/src/com/android/tv/common/feature/Sdk.java +++ b/common/src/com/android/tv/common/feature/Sdk.java @@ -25,7 +25,7 @@ import android.support.v4.os.BuildCompat; */ public class Sdk { - public static Feature N_PRE_2_OR_HIGHER = + public static final Feature N_PRE_2_OR_HIGHER = new SdkPreviewVersionFeature(Build.VERSION_CODES.M, 2, true); private static class SdkPreviewVersionFeature implements Feature { @@ -56,7 +56,7 @@ public class Sdk { } } - public static Feature AT_LEAST_N = new Feature() { + public static final Feature AT_LEAST_N = new Feature() { @Override public boolean isEnabled(Context context) { return BuildCompat.isAtLeastN(); diff --git a/common/src/com/android/tv/common/feature/SharedPreferencesFeature.java b/common/src/com/android/tv/common/feature/SharedPreferencesFeature.java index 4d3a70a8..a4a79b38 100644 --- a/common/src/com/android/tv/common/feature/SharedPreferencesFeature.java +++ b/common/src/com/android/tv/common/feature/SharedPreferencesFeature.java @@ -29,9 +29,9 @@ public final class SharedPreferencesFeature implements Feature { private static final String TAG = "SharedPrefFeature"; private static final boolean DEBUG = false; - private String mKey; + private final String mKey; private boolean mEnabled; - private boolean mDefaultValue; + private final boolean mDefaultValue; private SharedPreferences mSharedPreferences; private final Feature mBaseFeature; diff --git a/common/src/com/android/tv/common/feature/SystemAppFeature.java b/common/src/com/android/tv/common/feature/SystemAppFeature.java new file mode 100644 index 00000000..79fd32f3 --- /dev/null +++ b/common/src/com/android/tv/common/feature/SystemAppFeature.java @@ -0,0 +1,34 @@ +/* + * 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.common.feature; + +import android.content.Context; +import android.content.pm.ApplicationInfo; + +/** + * A feature that is for system App. + */ +public final class SystemAppFeature implements Feature { + public static final Feature SYSTEM_APP_FEATURE = new SystemAppFeature(); + + private SystemAppFeature() { } + + @Override + public boolean isEnabled(Context context) { + return (context.getApplicationInfo().flags & ApplicationInfo.FLAG_SYSTEM) != 0; + } +} diff --git a/common/src/com/android/tv/common/recording/RecordedProgram.java b/common/src/com/android/tv/common/recording/RecordedProgram.java deleted file mode 100644 index 63ce6ff9..00000000 --- a/common/src/com/android/tv/common/recording/RecordedProgram.java +++ /dev/null @@ -1,760 +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.common.recording; - -import static android.media.tv.TvContract.RecordedPrograms; - -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.media.tv.TvContract; -import android.net.Uri; -import android.support.annotation.Nullable; -import android.text.TextUtils; - -import com.android.tv.common.R; - -import java.util.Arrays; -import java.util.Comparator; -import java.util.Objects; - -/** - * Immutable instance of {@link android.media.tv.TvContract.RecordedPrograms}. - */ -public class RecordedProgram { - public static final int ID_NOT_SET = -1; - - public final static String[] PROJECTION = { - // These are in exactly the order listed in RecordedPrograms - RecordedPrograms._ID, - RecordedPrograms.COLUMN_INPUT_ID, - RecordedPrograms.COLUMN_CHANNEL_ID, - RecordedPrograms.COLUMN_TITLE, - RecordedPrograms.COLUMN_SEASON_DISPLAY_NUMBER, - RecordedPrograms.COLUMN_SEASON_TITLE, - RecordedPrograms.COLUMN_EPISODE_DISPLAY_NUMBER, - RecordedPrograms.COLUMN_EPISODE_TITLE, - RecordedPrograms.COLUMN_START_TIME_UTC_MILLIS, - RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS, - RecordedPrograms.COLUMN_BROADCAST_GENRE, - RecordedPrograms.COLUMN_CANONICAL_GENRE, - RecordedPrograms.COLUMN_SHORT_DESCRIPTION, - RecordedPrograms.COLUMN_LONG_DESCRIPTION, - RecordedPrograms.COLUMN_VIDEO_WIDTH, - RecordedPrograms.COLUMN_VIDEO_HEIGHT, - RecordedPrograms.COLUMN_AUDIO_LANGUAGE, - RecordedPrograms.COLUMN_CONTENT_RATING, - RecordedPrograms.COLUMN_POSTER_ART_URI, - RecordedPrograms.COLUMN_THUMBNAIL_URI, - RecordedPrograms.COLUMN_SEARCHABLE, - RecordedPrograms.COLUMN_RECORDING_DATA_URI, - RecordedPrograms.COLUMN_RECORDING_DATA_BYTES, - RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS, - RecordedPrograms.COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS, - RecordedPrograms.COLUMN_INTERNAL_PROVIDER_DATA, - RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1, - RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2, - RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3, - RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4, - RecordedPrograms.COLUMN_VERSION_NUMBER, - }; - - public static final RecordedProgram fromCursor(Cursor cursor) { - int index = 0; - return builder() - .setId(cursor.getLong(index++)) - .setInputId(cursor.getString(index++)) - .setChannelId(cursor.getLong(index++)) - .setTitle(cursor.getString(index++)) - .setSeasonNumber(cursor.getString(index++)) - .setSeasonTitle(cursor.getString(index++)) - .setEpisodeNumber(cursor.getString(index++)) - .setEpisodeTitle(cursor.getString(index++)) - .setStartTimeUtcMillis(cursor.getLong(index++)) - .setEndTimeUtcMillis(cursor.getLong(index++)) - .setBroadcastGenres(cursor.getString(index++)) - .setCanonicalGenres(cursor.getString(index++)) - .setShortDescription(cursor.getString(index++)) - .setLongDescription(cursor.getString(index++)) - .setVideoWidth(cursor.getInt(index++)) - .setVideoHeight(cursor.getInt(index++)) - .setAudioLanguage(cursor.getString(index++)) - .setContentRating(cursor.getString(index++)) - .setPosterArt(cursor.getString(index++)) - .setThumbnail(cursor.getString(index++)) - .setSearchable(cursor.getInt(index++) == 1) - .setDataUri(cursor.getString(index++)) - .setDataBytes(cursor.getLong(index++)) - .setDurationMillis(cursor.getLong(index++)) - .setExpireTimeUtcMillis(cursor.getLong(index++)) - .setInternalProviderData(cursor.getBlob(index++)) - .setInternalProviderFlag1(cursor.getInt(index++)) - .setInternalProviderFlag2(cursor.getInt(index++)) - .setInternalProviderFlag3(cursor.getInt(index++)) - .setInternalProviderFlag4(cursor.getInt(index++)) - .setVersionNumber(cursor.getInt(index++)) - .build(); - } - - public static ContentValues toValues(RecordedProgram recordedProgram) { - ContentValues values = new ContentValues(); - if (recordedProgram.mId != ID_NOT_SET) { - values.put(RecordedPrograms._ID, recordedProgram.mId); - } - values.put(RecordedPrograms.COLUMN_INPUT_ID, recordedProgram.mInputId); - values.put(RecordedPrograms.COLUMN_CHANNEL_ID, recordedProgram.mChannelId); - values.put(RecordedPrograms.COLUMN_TITLE, recordedProgram.mTitle); - values.put(RecordedPrograms.COLUMN_SEASON_DISPLAY_NUMBER, recordedProgram.mSeasonNumber); - values.put(RecordedPrograms.COLUMN_SEASON_TITLE, recordedProgram.mSeasonTitle); - values.put(RecordedPrograms.COLUMN_EPISODE_DISPLAY_NUMBER, recordedProgram.mEpisodeNumber); - values.put(RecordedPrograms.COLUMN_EPISODE_TITLE, recordedProgram.mTitle); - values.put(RecordedPrograms.COLUMN_START_TIME_UTC_MILLIS, - recordedProgram.mStartTimeUtcMillis); - values.put(RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS, recordedProgram.mEndTimeUtcMillis); - values.put(RecordedPrograms.COLUMN_BROADCAST_GENRE, - safeEncode(recordedProgram.mBroadcastGenres)); - values.put(RecordedPrograms.COLUMN_CANONICAL_GENRE, - safeEncode(recordedProgram.mCanonicalGenres)); - values.put(RecordedPrograms.COLUMN_SHORT_DESCRIPTION, recordedProgram.mShortDescription); - values.put(RecordedPrograms.COLUMN_LONG_DESCRIPTION, recordedProgram.mLongDescription); - if (recordedProgram.mVideoWidth == 0) { - values.putNull(RecordedPrograms.COLUMN_VIDEO_WIDTH); - } else { - values.put(RecordedPrograms.COLUMN_VIDEO_WIDTH, recordedProgram.mVideoWidth); - } - if (recordedProgram.mVideoHeight == 0) { - values.putNull(RecordedPrograms.COLUMN_VIDEO_HEIGHT); - } else { - values.put(RecordedPrograms.COLUMN_VIDEO_HEIGHT, recordedProgram.mVideoHeight); - } - values.put(RecordedPrograms.COLUMN_AUDIO_LANGUAGE, recordedProgram.mAudioLanguage); - values.put(RecordedPrograms.COLUMN_CONTENT_RATING, recordedProgram.mContentRating); - values.put(RecordedPrograms.COLUMN_POSTER_ART_URI, - safeToString(recordedProgram.mPosterArt)); - values.put(RecordedPrograms.COLUMN_THUMBNAIL_URI, safeToString(recordedProgram.mThumbnail)); - values.put(RecordedPrograms.COLUMN_SEARCHABLE, recordedProgram.mSearchable ? 1 : 0); - values.put(RecordedPrograms.COLUMN_RECORDING_DATA_URI, - safeToString(recordedProgram.mDataUri)); - values.put(RecordedPrograms.COLUMN_RECORDING_DATA_BYTES, recordedProgram.mDataBytes); - values.put(RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS, - recordedProgram.mDurationMillis); - values.put(RecordedPrograms.COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS, - recordedProgram.mExpireTimeUtcMillis); - values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_DATA, - recordedProgram.mInternalProviderData); - values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1, - recordedProgram.mInternalProviderFlag1); - values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2, - recordedProgram.mInternalProviderFlag2); - values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3, - recordedProgram.mInternalProviderFlag3); - values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4, - recordedProgram.mInternalProviderFlag4); - values.put(RecordedPrograms.COLUMN_VERSION_NUMBER, recordedProgram.mVersionNumber); - return values; - } - - public static class Builder{ - private long mId = ID_NOT_SET; - private String mInputId; - private long mChannelId; - private String mTitle; - private String mSeasonNumber; - private String mSeasonTitle; - private String mEpisodeNumber; - private String mEpisodeTitle; - private long mStartTimeUtcMillis; - private long mEndTimeUtcMillis; - private String[] mBroadcastGenres; - private String[] mCanonicalGenres; - private String mShortDescription; - private String mLongDescription; - private int mVideoWidth; - private int mVideoHeight; - private String mAudioLanguage; - private String mContentRating; - private Uri mPosterArt; - private Uri mThumbnail; - private boolean mSearchable = true; - private Uri mDataUri; - private long mDataBytes; - private long mDurationMillis; - private long mExpireTimeUtcMillis; - private byte[] mInternalProviderData; - private int mInternalProviderFlag1; - private int mInternalProviderFlag2; - private int mInternalProviderFlag3; - private int mInternalProviderFlag4; - private int mVersionNumber; - - public Builder setId(long id) { - mId = id; - return this; - } - - public Builder setInputId(String inputId) { - mInputId = inputId; - return this; - } - - public Builder setChannelId(long channelId) { - mChannelId = channelId; - return this; - } - - public Builder setTitle(String title) { - mTitle = title; - return this; - } - - public Builder setSeasonNumber(String seasonNumber) { - mSeasonNumber = seasonNumber; - return this; - } - - public Builder setSeasonTitle(String seasonTitle) { - mSeasonTitle = seasonTitle; - return this; - } - - public Builder setEpisodeNumber(String episodeNumber) { - mEpisodeNumber = episodeNumber; - return this; - } - - public Builder setEpisodeTitle(String episodeTitle) { - mEpisodeTitle = episodeTitle; - return this; - } - - public Builder setStartTimeUtcMillis(long startTimeUtcMillis) { - mStartTimeUtcMillis = startTimeUtcMillis; - return this; - } - - public Builder setEndTimeUtcMillis(long endTimeUtcMillis) { - mEndTimeUtcMillis = endTimeUtcMillis; - return this; - } - - public Builder setBroadcastGenres(String broadcastGenres) { - if (TextUtils.isEmpty(broadcastGenres)) { - mBroadcastGenres = null; - return this; - } - return setBroadcastGenres(TvContract.Programs.Genres.decode(broadcastGenres)); - } - - private Builder setBroadcastGenres(String[] broadcastGenres) { - mBroadcastGenres = broadcastGenres; - return this; - } - - public Builder setCanonicalGenres(String canonicalGenres) { - if (TextUtils.isEmpty(canonicalGenres)) { - mCanonicalGenres = null; - return this; - } - return setCanonicalGenres(TvContract.Programs.Genres.decode(canonicalGenres)); - } - - private Builder setCanonicalGenres(String[] canonicalGenres) { - mCanonicalGenres = canonicalGenres; - return this; - } - - public Builder setShortDescription(String shortDescription) { - mShortDescription = shortDescription; - return this; - } - - public Builder setLongDescription(String longDescription) { - mLongDescription = longDescription; - return this; - } - - public Builder setVideoWidth(int videoWidth) { - mVideoWidth = videoWidth; - return this; - } - - public Builder setVideoHeight(int videoHeight) { - mVideoHeight = videoHeight; - return this; - } - - public Builder setAudioLanguage(String audioLanguage) { - mAudioLanguage = audioLanguage; - return this; - } - - public Builder setContentRating(String contentRating) { - mContentRating = contentRating; - return this; - } - - private Uri toUri(String uriString) { - try { - return uriString == null ? null : Uri.parse(uriString); - } catch (Exception e) { - return null; - } - } - - public Builder setPosterArt(String posterArtUri) { - return setPosterArt(toUri(posterArtUri)); - } - - public Builder setPosterArt(Uri posterArt) { - mPosterArt = posterArt; - return this; - } - - public Builder setThumbnail(String thumbnailUri) { - return setThumbnail(toUri(thumbnailUri)); - } - - public Builder setThumbnail(Uri thumbnail) { - mThumbnail = thumbnail; - return this; - } - - public Builder setSearchable(boolean searchable) { - mSearchable = searchable; - return this; - } - - public Builder setDataUri(String dataUri) { - return setDataUri(toUri(dataUri)); - } - - public Builder setDataUri(Uri dataUri) { - mDataUri = dataUri; - return this; - } - - public Builder setDataBytes(long dataBytes) { - mDataBytes = dataBytes; - return this; - } - - public Builder setDurationMillis(long durationMillis) { - mDurationMillis = durationMillis; - return this; - } - - public Builder setExpireTimeUtcMillis(long expireTimeUtcMillis) { - mExpireTimeUtcMillis = expireTimeUtcMillis; - return this; - } - - public Builder setInternalProviderData(byte[] internalProviderData) { - mInternalProviderData = internalProviderData; - return this; - } - - public Builder setInternalProviderFlag1(int internalProviderFlag1) { - mInternalProviderFlag1 = internalProviderFlag1; - return this; - } - - public Builder setInternalProviderFlag2(int internalProviderFlag2) { - mInternalProviderFlag2 = internalProviderFlag2; - return this; - } - - public Builder setInternalProviderFlag3(int internalProviderFlag3) { - mInternalProviderFlag3 = internalProviderFlag3; - return this; - } - - public Builder setInternalProviderFlag4(int internalProviderFlag4) { - mInternalProviderFlag4 = internalProviderFlag4; - return this; - } - - public Builder setVersionNumber(int versionNumber) { - mVersionNumber = versionNumber; - return this; - } - - public RecordedProgram build() { - return new RecordedProgram(mId, mInputId, mChannelId, mTitle, mSeasonNumber, - mSeasonTitle, mEpisodeNumber, mEpisodeTitle, mStartTimeUtcMillis, - mEndTimeUtcMillis, mBroadcastGenres, mCanonicalGenres, mShortDescription, - mLongDescription, mVideoWidth, mVideoHeight, mAudioLanguage, mContentRating, - mPosterArt, mThumbnail, mSearchable, mDataUri, mDataBytes, mDurationMillis, - mExpireTimeUtcMillis, mInternalProviderData, mInternalProviderFlag1, - mInternalProviderFlag2, mInternalProviderFlag3, mInternalProviderFlag4, - mVersionNumber); - } - } - - public static Builder builder() { return new Builder(); } - - public static Builder buildFrom(RecordedProgram orig) { - return builder() - .setId(orig.getId()) - .setInputId(orig.getInputId()) - .setChannelId(orig.getChannelId()) - .setTitle(orig.getTitle()) - .setSeasonNumber(orig.getSeasonNumber()) - .setSeasonTitle(orig.getSeasonTitle()) - .setEpisodeNumber(orig.getEpisodeNumber()) - .setEpisodeTitle(orig.getEpisodeTitle()) - .setStartTimeUtcMillis(orig.getStartTimeUtcMillis()) - .setEndTimeUtcMillis(orig.getEndTimeUtcMillis()) - .setBroadcastGenres(orig.getBroadcastGenres()) - .setCanonicalGenres(orig.getCanonicalGenres()) - .setShortDescription(orig.getShortDescription()) - .setLongDescription(orig.getLongDescription()) - .setVideoWidth(orig.getVideoWidth()) - .setVideoHeight(orig.getVideoHeight()) - .setAudioLanguage(orig.getAudioLanguage()) - .setContentRating(orig.getContentRating()) - .setPosterArt(orig.getPosterArt()) - .setThumbnail(orig.getThumbnail()) - .setSearchable(orig.isSearchable()) - .setInternalProviderData(orig.getInternalProviderData()) - .setInternalProviderFlag1(orig.getInternalProviderFlag1()) - .setInternalProviderFlag2(orig.getInternalProviderFlag2()) - .setInternalProviderFlag3(orig.getInternalProviderFlag3()) - .setInternalProviderFlag4(orig.getInternalProviderFlag4()) - .setVersionNumber(orig.getVersionNumber()); - } - - public static final Comparator<RecordedProgram> START_TIME_THEN_ID_COMPARATOR - = new Comparator<RecordedProgram>() { - @Override - public int compare(RecordedProgram lhs, RecordedProgram rhs) { - int res = Long.compare(lhs.getStartTimeUtcMillis(), rhs.getStartTimeUtcMillis()); - if (res != 0) { - return res; - } - return Long.compare(lhs.mId, rhs.mId); - } - }; - - private final long mId; - private final String mInputId; - private final long mChannelId; - private final String mTitle; - private final String mSeasonNumber; - private final String mSeasonTitle; - private final String mEpisodeNumber; - private final String mEpisodeTitle; - private final long mStartTimeUtcMillis; - private final long mEndTimeUtcMillis; - private final String[] mBroadcastGenres; - private final String[] mCanonicalGenres; - private final String mShortDescription; - private final String mLongDescription; - private final int mVideoWidth; - private final int mVideoHeight; - private final String mAudioLanguage; - private final String mContentRating; - private final Uri mPosterArt; - private final Uri mThumbnail; - private final boolean mSearchable; - private final Uri mDataUri; - private final long mDataBytes; - private final long mDurationMillis; - private final long mExpireTimeUtcMillis; - private final byte[] mInternalProviderData; - private final int mInternalProviderFlag1; - private final int mInternalProviderFlag2; - private final int mInternalProviderFlag3; - private final int mInternalProviderFlag4; - private final int mVersionNumber; - - private RecordedProgram(long id, String inputId, long channelId, String title, - String seasonNumber, String seasonTitle, String episodeNumber, String episodeTitle, - long startTimeUtcMillis, long endTimeUtcMillis, String[] broadcastGenres, - String[] canonicalGenres, String shortDescription, String longDescription, - int videoWidth, int videoHeight, String audioLanguage, String contentRating, - Uri posterArt, Uri thumbnail, boolean searchable, Uri dataUri, long dataBytes, - long durationMillis, long expireTimeUtcMillis, byte[] internalProviderData, - int internalProviderFlag1, int internalProviderFlag2, int internalProviderFlag3, - int internalProviderFlag4, int versionNumber) { - mId = id; - mInputId = inputId; - mChannelId = channelId; - mTitle = title; - mSeasonNumber = seasonNumber; - mSeasonTitle = seasonTitle; - mEpisodeNumber = episodeNumber; - mEpisodeTitle = episodeTitle; - mStartTimeUtcMillis = startTimeUtcMillis; - mEndTimeUtcMillis = endTimeUtcMillis; - mBroadcastGenres = broadcastGenres; - mCanonicalGenres = canonicalGenres; - mShortDescription = shortDescription; - mLongDescription = longDescription; - mVideoWidth = videoWidth; - mVideoHeight = videoHeight; - - mAudioLanguage = audioLanguage; - mContentRating = contentRating; - mPosterArt = posterArt; - mThumbnail = thumbnail; - mSearchable = searchable; - mDataUri = dataUri; - mDataBytes = dataBytes; - mDurationMillis = durationMillis; - mExpireTimeUtcMillis = expireTimeUtcMillis; - mInternalProviderData = internalProviderData; - mInternalProviderFlag1 = internalProviderFlag1; - mInternalProviderFlag2 = internalProviderFlag2; - mInternalProviderFlag3 = internalProviderFlag3; - mInternalProviderFlag4 = internalProviderFlag4; - mVersionNumber = versionNumber; - } - - public String getAudioLanguage() { - return mAudioLanguage; - } - - public String[] getBroadcastGenres() { - return mBroadcastGenres; - } - - public String[] getCanonicalGenres() { - return mCanonicalGenres; - } - - public long getChannelId() { - return mChannelId; - } - - public String getContentRating() { - return mContentRating; - } - - public Uri getDataUri() { - return mDataUri; - } - - public long getDataBytes() { - return mDataBytes; - } - - public long getDurationMillis() { - return mDurationMillis; - } - - public long getEndTimeUtcMillis() { - return mEndTimeUtcMillis; - } - - public String getEpisodeNumber() { - return mEpisodeNumber; - } - - public String getEpisodeTitle() { - return mEpisodeTitle; - } - - public String getEpisodeDisplayTitle(Context context) { - if (!TextUtils.isEmpty(mSeasonNumber) && !TextUtils.isEmpty(mEpisodeNumber) - && !TextUtils.isEmpty(mEpisodeTitle)) { - return String.format(context.getResources().getString(R.string.episode_format), - mSeasonNumber, mEpisodeNumber, mEpisodeTitle); - } - return mEpisodeTitle; - } - - public long getExpireTimeUtcMillis() { - return mExpireTimeUtcMillis; - } - - public long getId() { - return mId; - } - - public String getInputId() { - return mInputId; - } - - public byte[] getInternalProviderData() { - return mInternalProviderData; - } - - public int getInternalProviderFlag1() { - return mInternalProviderFlag1; - } - - public int getInternalProviderFlag2() { - return mInternalProviderFlag2; - } - - public int getInternalProviderFlag3() { - return mInternalProviderFlag3; - } - - public int getInternalProviderFlag4() { - return mInternalProviderFlag4; - } - - public String getLongDescription() { - return mLongDescription; - } - - public Uri getPosterArt() { - return mPosterArt; - } - - public boolean isSearchable() { - return mSearchable; - } - - public String getSeasonNumber() { - return mSeasonNumber; - } - - public String getSeasonTitle() { - return mSeasonTitle; - } - - public String getShortDescription() { - return mShortDescription; - } - - public long getStartTimeUtcMillis() { - return mStartTimeUtcMillis; - } - - public Uri getThumbnail() { - return mThumbnail; - } - - public String getTitle() { - return mTitle; - } - - public Uri getUri() { - return ContentUris.withAppendedId(RecordedPrograms.CONTENT_URI, mId); - } - - public int getVersionNumber() { - return mVersionNumber; - } - - public int getVideoHeight() { - return mVideoHeight; - } - - public int getVideoWidth() { - return mVideoWidth; - } - - /** - * Compares everything except {@link #getInternalProviderData()} - */ - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - RecordedProgram that = (RecordedProgram) o; - return Objects.equals(mId, that.mId) && - Objects.equals(mChannelId, that.mChannelId) && - Objects.equals(mSeasonNumber, that.mSeasonNumber) && - Objects.equals(mSeasonTitle, that.mSeasonTitle) && - Objects.equals(mEpisodeNumber, that.mEpisodeNumber) && - Objects.equals(mStartTimeUtcMillis, that.mStartTimeUtcMillis) && - Objects.equals(mEndTimeUtcMillis, that.mEndTimeUtcMillis) && - Objects.equals(mVideoWidth, that.mVideoWidth) && - Objects.equals(mVideoHeight, that.mVideoHeight) && - Objects.equals(mSearchable, that.mSearchable) && - Objects.equals(mDataBytes, that.mDataBytes) && - Objects.equals(mDurationMillis, that.mDurationMillis) && - Objects.equals(mExpireTimeUtcMillis, that.mExpireTimeUtcMillis) && - Objects.equals(mInternalProviderFlag1, that.mInternalProviderFlag1) && - Objects.equals(mInternalProviderFlag2, that.mInternalProviderFlag2) && - Objects.equals(mInternalProviderFlag3, that.mInternalProviderFlag3) && - Objects.equals(mInternalProviderFlag4, that.mInternalProviderFlag4) && - Objects.equals(mVersionNumber, that.mVersionNumber) && - Objects.equals(mTitle, that.mTitle) && - Objects.equals(mEpisodeTitle, that.mEpisodeTitle) && - Arrays.equals(mBroadcastGenres, that.mBroadcastGenres) && - Arrays.equals(mCanonicalGenres, that.mCanonicalGenres) && - Objects.equals(mShortDescription, that.mShortDescription) && - Objects.equals(mLongDescription, that.mLongDescription) && - Objects.equals(mAudioLanguage, that.mAudioLanguage) && - Objects.equals(mContentRating, that.mContentRating) && - Objects.equals(mPosterArt, that.mPosterArt) && - Objects.equals(mThumbnail, that.mThumbnail); - } - - /** - * Hashes based on the ID. - */ - @Override - public int hashCode() { - return Objects.hash(mId); - } - - @Override - public String toString() { - return "RecordedProgram" - + "[" + mId + - "]{ mInputId=" + mInputId + - ", mChannelId='" + mChannelId + '\'' + - ", mTitle='" + mTitle + '\'' + - ", mEpisodeNumber=" + mEpisodeNumber + - ", mEpisodeTitle='" + mEpisodeTitle + '\'' + - ", mStartTimeUtcMillis=" + mStartTimeUtcMillis + - ", mEndTimeUtcMillis=" + mEndTimeUtcMillis + - ", mBroadcastGenres=" + - (mBroadcastGenres != null ? Arrays.toString(mBroadcastGenres) : "null") + - ", mCanonicalGenres=" + - (mCanonicalGenres != null ? Arrays.toString(mCanonicalGenres) : "null") + - ", mShortDescription='" + mShortDescription + '\'' + - ", mLongDescription='" + mLongDescription + '\'' + - ", mVideoHeight=" + mVideoHeight + - ", mVideoWidth=" + mVideoWidth + - ", mAudioLanguage='" + mAudioLanguage + '\'' + - ", mContentRating='" + mContentRating + '\'' + - ", mPosterArt=" + mPosterArt + - ", mThumbnail=" + mThumbnail + - ", mSearchable=" + mSearchable + - ", mDataUri=" + mDataUri + - ", mDataBytes=" + mDataBytes + - ", mDurationMillis=" + mDurationMillis + - ", mExpireTimeUtcMillis=" + mExpireTimeUtcMillis + - ", mInternalProviderData.length=" + - (mInternalProviderData == null ? "null" : mInternalProviderData.length) + - ", mInternalProviderFlag1=" + mInternalProviderFlag1 + - ", mInternalProviderFlag2=" + mInternalProviderFlag2 + - ", mInternalProviderFlag3=" + mInternalProviderFlag3 + - ", mInternalProviderFlag4=" + mInternalProviderFlag4 + - ", mSeasonNumber=" + mSeasonNumber + - ", mSeasonTitle=" + mSeasonTitle + - ", mVersionNumber=" + mVersionNumber + - '}'; - } - - @Nullable - private static String safeToString(@Nullable Object o) { - return o == null ? null : o.toString(); - } - - @Nullable - private static String safeEncode(@Nullable String[] genres) { - return genres == null ? null : TvContract.Programs.Genres.encode(genres); - } -} diff --git a/common/src/com/android/tv/common/ui/setup/OnActionClickListener.java b/common/src/com/android/tv/common/ui/setup/OnActionClickListener.java index 15b38f02..392d489f 100644 --- a/common/src/com/android/tv/common/ui/setup/OnActionClickListener.java +++ b/common/src/com/android/tv/common/ui/setup/OnActionClickListener.java @@ -16,15 +16,20 @@ package com.android.tv.common.ui.setup; +import android.os.Bundle; + /** * A listener for the action click. */ public interface OnActionClickListener { /** * Called when the action is clicked. + * <p> + * The method should return {@code true} if the action is handled, otherwise {@code false}. * - * @param category action category. - * @param id action id. + * @param category The action category. + * @param id The action id. + * @param params The parameter for the action. */ - void onActionClick(String category, int id); + boolean onActionClick(String category, int id, Bundle params); } diff --git a/common/src/com/android/tv/common/ui/setup/SetupActionHelper.java b/common/src/com/android/tv/common/ui/setup/SetupActionHelper.java index 0f44ce06..7ee06faf 100644 --- a/common/src/com/android/tv/common/ui/setup/SetupActionHelper.java +++ b/common/src/com/android/tv/common/ui/setup/SetupActionHelper.java @@ -17,6 +17,8 @@ package com.android.tv.common.ui.setup; import android.app.Fragment; +import android.os.Bundle; +import android.util.Log; import android.view.View; import android.view.View.OnClickListener; @@ -24,47 +26,60 @@ import android.view.View.OnClickListener; * Helper class for the execution in the fragment. */ public class SetupActionHelper { + private static final String TAG = "SetupActionHelper"; + /** - * Executes the action of the given {@code actionId}. + * Executes the action. */ - public static void onActionClick(Fragment fragment, String category, int actionId) { - OnActionClickListener listener = null; - if (fragment instanceof SetupFragment) { - listener = ((SetupFragment) fragment).getOnActionClickListener(); - } - if (listener == null && fragment.getActivity() instanceof OnActionClickListener) { - listener = (OnActionClickListener) fragment.getActivity(); - } - if (listener != null) { - listener.onActionClick(category, actionId); + public static boolean onActionClick(Fragment fragment, String category, int actionId) { + return onActionClick(fragment, category, actionId, null); + } + + /** + * Executes the action. + */ + public static boolean onActionClick(Fragment fragment, String category, int actionId, + Bundle params) { + if (fragment.getActivity() instanceof OnActionClickListener) { + return ((OnActionClickListener) fragment.getActivity()).onActionClick(category, + actionId, params); } + Log.e(TAG, "Activity can't handle the action: {category=" + category + ", actionId=" + + actionId + ", params=" + params + "}"); + return false; } /** * Creates an {@link OnClickListener} to handle the action. */ - public static OnClickListener createOnClickListenerForAction(OnActionClickListener listener, - String category, int actionId) { - return new OnActionClickListenerForAction(listener, category, actionId); + public static OnClickListener createOnClickListenerForAction(Fragment fragment, String category, + int actionId, Bundle params) { + return new OnActionClickListenerForAction(fragment, category, actionId, params); } + /** + * The {@link OnClickListener} for the view. + * <p> + * Note that this class should be used only for the views in the {@code mFragment} to avoid the + * leak of mFragment. + */ private static class OnActionClickListenerForAction implements OnClickListener { - private final OnActionClickListener mListener; + private final Fragment mFragment; private final String mCategory; private final int mActionId; + private final Bundle mParams; - OnActionClickListenerForAction(OnActionClickListener listener, String category, - int actionId) { - mListener = listener; + OnActionClickListenerForAction(Fragment fragment, String category, int actionId, + Bundle params) { + mFragment = fragment; mCategory = category; mActionId = actionId; + mParams = params; } @Override public void onClick(View v) { - if (mListener != null) { - mListener.onActionClick(mCategory, mActionId); - } + SetupActionHelper.onActionClick(mFragment, mCategory, mActionId, mParams); } } diff --git a/common/src/com/android/tv/common/ui/setup/SetupActivity.java b/common/src/com/android/tv/common/ui/setup/SetupActivity.java index 8c7b1b8e..2b381a6e 100644 --- a/common/src/com/android/tv/common/ui/setup/SetupActivity.java +++ b/common/src/com/android/tv/common/ui/setup/SetupActivity.java @@ -49,6 +49,7 @@ public abstract class SetupActivity extends Activity implements OnActionClickLis @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + SetupAnimationHelper.initialize(this); setContentView(R.layout.activity_setup); mFragmentTransitionDuration = getResources().getInteger( R.integer.setup_fragment_transition_duration); @@ -129,19 +130,26 @@ public abstract class SetupActivity extends Activity implements OnActionClickLis } @Override - public void onActionClick(String category, int actionId) { + public boolean onActionClick(String category, int actionId, Bundle params) { if (mHandler.hasMessages(MSG_EXECUTE_ACTION)) { - return; + return false; } - executeAction(category, actionId); + return executeAction(category, actionId, params); } protected void executeActionWithDelay(Runnable action, int delayMs) { mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_EXECUTE_ACTION, action), delayMs); } - // Override this method if the inherited class wants to handle the action. - protected void executeAction(String category, int actionId) { } + /** + * Override this method if the inherited class wants to handle the action. + * <p> + * The override method should return {@code true} if the action is handled, otherwise + * {@code false}. + */ + protected boolean executeAction(String category, int actionId, Bundle params) { + return false; + } /** * Returns the duration of the shared element transition. diff --git a/common/src/com/android/tv/common/ui/setup/SetupFragment.java b/common/src/com/android/tv/common/ui/setup/SetupFragment.java index df7256d3..d2b9d7c8 100644 --- a/common/src/com/android/tv/common/ui/setup/SetupFragment.java +++ b/common/src/com/android/tv/common/ui/setup/SetupFragment.java @@ -47,11 +47,9 @@ public abstract class SetupFragment extends Fragment { public static final int FRAGMENT_REENTER_TRANSITION = FRAGMENT_ENTER_TRANSITION << 2; public static final int FRAGMENT_RETURN_TRANSITION = FRAGMENT_ENTER_TRANSITION << 3; - private OnActionClickListener mOnActionClickListener; - private boolean mEnterTransitionRunning; - private TransitionListener mTransitionListener = new TransitionListener() { + private final TransitionListener mTransitionListener = new TransitionListener() { @Override public void onTransitionStart(Transition transition) { mEnterTransitionRunning = true; @@ -103,20 +101,6 @@ public abstract class SetupFragment extends Fragment { } /** - * Returns action click listener. - */ - public OnActionClickListener getOnActionClickListener() { - return mOnActionClickListener; - } - - /** - * Sets action click listener. - */ - public void setOnActionClickListener(OnActionClickListener onActionClickListener) { - mOnActionClickListener = onActionClickListener; - } - - /** * Returns the layout resource ID for this fragment. */ abstract protected int getLayoutResourceId(); @@ -130,8 +114,12 @@ public abstract class SetupFragment extends Fragment { }); } - protected void onActionClick(String category, int actionId) { - SetupActionHelper.onActionClick(this, category, actionId); + protected boolean onActionClick(String category, int actionId) { + return SetupActionHelper.onActionClick(this, category, actionId); + } + + protected boolean onActionClick(String category, int actionId, Bundle params) { + return SetupActionHelper.onActionClick(this, category, actionId, params); } @Override diff --git a/common/src/com/android/tv/common/ui/setup/SetupGuidedStepFragment.java b/common/src/com/android/tv/common/ui/setup/SetupGuidedStepFragment.java index aa912a97..bcaefec9 100644 --- a/common/src/com/android/tv/common/ui/setup/SetupGuidedStepFragment.java +++ b/common/src/com/android/tv/common/ui/setup/SetupGuidedStepFragment.java @@ -57,9 +57,7 @@ public abstract class SetupGuidedStepFragment extends GuidedStepFragment { R.dimen.setup_done_button_container_width); // Guided actions list View list = view.findViewById(R.id.guidedactions_list); - View list2 = view.findViewById(R.id.guidedactions_list2); - MarginLayoutParams marginLayoutParams = (MarginLayoutParams) view.findViewById( - R.id.guidedactions_list).getLayoutParams(); + MarginLayoutParams marginLayoutParams = (MarginLayoutParams) list.getLayoutParams(); // Use content view to check layout direction while view is being created. if (getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_LTR) { @@ -74,6 +72,9 @@ public abstract class SetupGuidedStepFragment extends GuidedStepFragment { } // gridView Alignment VerticalGridView gridView = getGuidedActionsStylist().getActionsGridView(); + // Workaround of b/28274171 + // TODO: Remove the following line once b/28274171 is resolved. + gridView.setFocusable(true); int offset = getResources().getDimensionPixelOffset( R.dimen.setup_guidedactions_selector_margin_top); gridView.setWindowAlignmentOffset(offset); diff --git a/common/src/com/android/tv/common/ui/setup/SetupMultiPaneFragment.java b/common/src/com/android/tv/common/ui/setup/SetupMultiPaneFragment.java index fea9bf4a..63247481 100644 --- a/common/src/com/android/tv/common/ui/setup/SetupMultiPaneFragment.java +++ b/common/src/com/android/tv/common/ui/setup/SetupMultiPaneFragment.java @@ -17,6 +17,8 @@ package com.android.tv.common.ui.setup; import android.os.Bundle; +import android.support.annotation.Nullable; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -28,15 +30,27 @@ import com.android.tv.common.R; * A fragment for channel source info/setup. */ public abstract class SetupMultiPaneFragment extends SetupFragment { + private static final String TAG = "SetupMultiPaneFragment"; + private static final boolean DEBUG = false; + public static final int ACTION_DONE = Integer.MAX_VALUE; + private static final String CONTENT_FRAGMENT_TAG = "content_fragment"; + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + if (DEBUG) { + Log.d(TAG, "onCreateView(" + inflater + ", " + container + ", " + savedInstanceState + + ")"); + } View view = super.onCreateView(inflater, container, savedInstanceState); - SetupGuidedStepFragment contentFragment = onCreateContentFragment(); - getChildFragmentManager().beginTransaction() - .replace(R.id.guided_step_fragment_container, contentFragment).commit(); + if (savedInstanceState == null) { + SetupGuidedStepFragment contentFragment = onCreateContentFragment(); + getChildFragmentManager().beginTransaction() + .replace(R.id.guided_step_fragment_container, contentFragment, + CONTENT_FRAGMENT_TAG).commit(); + } if (needsDoneButton()) { setOnClickAction(view.findViewById(R.id.button_done), getActionCategory(), ACTION_DONE); } else { @@ -64,6 +78,12 @@ public abstract class SetupMultiPaneFragment extends SetupFragment { abstract protected SetupGuidedStepFragment onCreateContentFragment(); + @Nullable + protected SetupGuidedStepFragment getContentFragment() { + return (SetupGuidedStepFragment) getChildFragmentManager() + .findFragmentByTag(CONTENT_FRAGMENT_TAG); + } + abstract protected String getActionCategory(); protected boolean needsDoneButton() { diff --git a/common/src/com/android/tv/common/ui/setup/animation/FadeAndShortSlide.java b/common/src/com/android/tv/common/ui/setup/animation/FadeAndShortSlide.java index 5c57d84d..e1a8e60c 100644 --- a/common/src/com/android/tv/common/ui/setup/animation/FadeAndShortSlide.java +++ b/common/src/com/android/tv/common/ui/setup/animation/FadeAndShortSlide.java @@ -90,7 +90,7 @@ public class FadeAndShortSlide extends Visibility { private Visibility mFade = new Fade(); // TODO: Consider using TransitionPropagation. - private int[] mParentIdsForDelay; + private final int[] mParentIdsForDelay; private int mDistance = DEFAULT_DISTANCE; public FadeAndShortSlide() { diff --git a/common/src/com/android/tv/common/ui/setup/animation/SetupAnimationHelper.java b/common/src/com/android/tv/common/ui/setup/animation/SetupAnimationHelper.java index 0c5849ea..d98138a2 100644 --- a/common/src/com/android/tv/common/ui/setup/animation/SetupAnimationHelper.java +++ b/common/src/com/android/tv/common/ui/setup/animation/SetupAnimationHelper.java @@ -49,6 +49,9 @@ public final class SetupAnimationHelper { * Load initial parameters. This method should be called before using this class. */ public static void initialize(Context context) { + if (sInitialized) { + return; + } sFragmentTransitionDuration = context.getResources() .getInteger(R.integer.setup_fragment_transition_duration); sFragmentTransitionLongDistance = context.getResources() @@ -66,7 +69,7 @@ public final class SetupAnimationHelper { public static class TransitionBuilder { private int mSlideEdge = Gravity.START; - private int mDistance = sFragmentTransitionLongDistance; + private final int mDistance = sFragmentTransitionLongDistance; private long mDuration = sFragmentTransitionDuration; private int[] mParentIdForDelay; private int[] mExcludeIds; |