diff options
author | Nick Chalko <nchalko@google.com> | 2015-11-04 15:15:29 -0800 |
---|---|---|
committer | Nick Chalko <nchalko@google.com> | 2015-11-10 13:59:03 -0800 |
commit | 7d67089aa1e9aa2123c3cd2f386d7019a1544db1 (patch) | |
tree | 6f90c2065a853628dd7704788dd41b787acb6fae /common/src/com/android/tv | |
parent | 07b043dc3db83d6d20f0e8513b946830ab00e37b (diff) | |
download | TV-7d67089aa1e9aa2123c3cd2f386d7019a1544db1.tar.gz |
Sync to ub-tv-glee at 1.07.007
hash dce17da9f45fc4304787b1898d9915511b1df954
Change-Id: I08ac6fc0123a6653644281155e35c11b71bc5fa0
Diffstat (limited to 'common/src/com/android/tv')
13 files changed, 815 insertions, 0 deletions
diff --git a/common/src/com/android/tv/common/BooleanSystemProperty.java b/common/src/com/android/tv/common/BooleanSystemProperty.java new file mode 100644 index 00000000..77a6023c --- /dev/null +++ b/common/src/com/android/tv/common/BooleanSystemProperty.java @@ -0,0 +1,101 @@ +/* + * 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.common; + +import android.util.Log; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +/** + * Lazy loaded boolean system property. + * + * <p>Set with <code>adb shell setprop <em>key</em> <em>value</em></code> where: + * Values 'n', 'no', '0', 'false' or 'off' are considered false. + * Values 'y', 'yes', '1', 'true' or 'on' are considered true. + * (case sensitive). See <a href= + * "https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/SystemProperties.java" + * >android.os.SystemProperties.getBoolean</a>. + */ +public class BooleanSystemProperty { + private final static String TAG = "BooleanSystemProperty"; + private final static boolean DEBUG = false; + private static final List<BooleanSystemProperty> ALL_PROPERTIES = new ArrayList<>(); + private final boolean mDefaultValue; + private final String mKey; + private Boolean mValue = null; + + /** + * Create a boolean system property. + * + * @param key the system property key. + * @param defaultValue the value to return if the property is undefined or empty. + */ + public BooleanSystemProperty(String key, boolean defaultValue) { + mDefaultValue = defaultValue; + mKey = key; + ALL_PROPERTIES.add(this); + } + + public static void resetAll() { + for (BooleanSystemProperty prop : ALL_PROPERTIES) { + prop.reset(); + } + } + + /** + * Gets system properties set by <code>adb shell setprop <em>key</em> <em>value</em></code> + * + * @param key the property key. + * @param defaultValue the value to return if the property is undefined or empty. + * @return the system property value or the default value. + */ + private static boolean getBoolean(String key, boolean defaultValue) { + try { + final Class<?> systemProperties = Class.forName("android.os.SystemProperties"); + final Method get = systemProperties.getMethod("getBoolean", String.class, Boolean.TYPE); + return (boolean) get.invoke(null, key, defaultValue); + } catch (Exception e) { + Log.e(TAG, "Error getting boolean for " + key, e); + // This should never happen + return defaultValue; + } + } + + /** + * Clears the cached value. The next call to getValue will check {@code + * android.os.SystemProperties}. + */ + public void reset() { + mValue = null; + } + + /** + * Returns the value of the system property. + * + * <p>If the value is cached get the value from {@code android.os.SystemProperties} with the + * default set in the constructor. + */ + public boolean getValue() { + if (mValue == null) { + mValue = getBoolean(mKey, mDefaultValue); + if (DEBUG) Log.d(TAG, mKey + "=" + mValue); + } + return mValue; + } +} diff --git a/common/src/com/android/tv/common/TvCommonConstants.java b/common/src/com/android/tv/common/TvCommonConstants.java index 6b2cf14a..e01eb52f 100644 --- a/common/src/com/android/tv/common/TvCommonConstants.java +++ b/common/src/com/android/tv/common/TvCommonConstants.java @@ -32,6 +32,31 @@ public final class TvCommonConstants { */ public static final boolean HAS_TIME_SHIFT_API = Build.VERSION.SDK_INT >= 23; + /** + * An intent action to launch setup activity of a TV input. The intent should include + * TV input ID in the value of {@link EXTRA_INPUT_ID}. Optionally, given the value of + * {@link EXTRA_ACTIVITY_AFTER_COMPLETION}, the activity will be launched after the setup + * activity successfully finishes. + */ + public static final String INTENT_ACTION_INPUT_SETUP = + "com.android.tv.intent.action.INPUT_SETUP"; + /** + * A constant for the key to indicate a TV input ID for the intent action + * {@link INTENT_ACTION_INPUT_SETUP}. + * + * <p>Value type: String + */ + public static final String EXTRA_INPUT_ID = + "com.android.tv.intent.extra.INPUT_ID"; + /** + * A constant for the key to indicate an Activity launch intent for the intent action + * {@link INTENT_ACTION_INPUT_SETUP}. + * + * <p>Value type: Intent (Parcelable) + */ + public static final String EXTRA_ACTIVITY_AFTER_COMPLETION = + "com.android.tv.intent.extra.ACTIVITY_AFTER_COMPLETION"; + private TvCommonConstants() { } } diff --git a/common/src/com/android/tv/common/feature/Feature.java b/common/src/com/android/tv/common/feature/Feature.java new file mode 100644 index 00000000..b3a8336c --- /dev/null +++ b/common/src/com/android/tv/common/feature/Feature.java @@ -0,0 +1,38 @@ +/* + * 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.common.feature; + +import android.content.Context; + +/** + * A feature is elements of code that are turned off for most users until a feature is fully + * launched. + * + * <p>Expected usage is: + * <pre>{@code + * if (MY_FEATURE.isEnabled(context) { + * showNewCoolUi(); + * } else{ + * showOldBoringUi(); + * } + * }</pre> + */ +public interface Feature { + boolean isEnabled(Context context); + + +} diff --git a/common/src/com/android/tv/common/feature/FeatureUtils.java b/common/src/com/android/tv/common/feature/FeatureUtils.java new file mode 100644 index 00000000..2a676948 --- /dev/null +++ b/common/src/com/android/tv/common/feature/FeatureUtils.java @@ -0,0 +1,86 @@ +/* + * 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.common.feature; + +import android.content.Context; + +/** + * Static utilities for features. + */ +public class FeatureUtils { + + /** + * Returns a feature that is enabled if any of {@code features} is enabled. + * + * @param features the features to or + */ + public static Feature OR(final Feature... features) { + return new Feature() { + @Override + public boolean isEnabled(Context context) { + for (Feature f : features) { + if (f.isEnabled(context)) { + return true; + } + } + return false; + } + }; + } + + /** + * Returns a feature that is enabled if all of {@code features} is enabled. + * + * @param features the features to and + */ + public static Feature AND(final Feature... features) { + return new Feature() { + @Override + public boolean isEnabled(Context context) { + for (Feature f : features) { + if (!f.isEnabled(context)) { + return false; + } + } + return true; + } + }; + } + + /** + * A feature that is always enabled. + */ + public static final Feature ON = new Feature() { + @Override + public boolean isEnabled(Context context) { + return true; + } + }; + + /** + * A feature that is always disabled. + */ + public static final Feature OFF = new Feature() { + @Override + public boolean isEnabled(Context context) { + return false; + } + }; + + private FeatureUtils() { + } +} diff --git a/common/src/com/android/tv/common/feature/GServiceFeature.java b/common/src/com/android/tv/common/feature/GServiceFeature.java new file mode 100644 index 00000000..10b369f1 --- /dev/null +++ b/common/src/com/android/tv/common/feature/GServiceFeature.java @@ -0,0 +1,41 @@ +/* + * 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.common.feature; + +import android.content.Context; + + +/** + * A feature controlled by a GServices flag. + */ +public class GServiceFeature implements Feature { + private static final String LIVECHANNELS_PREFIX = "livechannels:"; + private final String mKey; + private final boolean mDefaultValue; + + public GServiceFeature(String key, boolean defaultValue) { + mKey = LIVECHANNELS_PREFIX + key; + mDefaultValue = defaultValue; + } + + @Override + public boolean isEnabled(Context context) { + + // GServices is not available outside of Google. + return mDefaultValue; + } +} diff --git a/common/src/com/android/tv/common/feature/PropertyFeature.java b/common/src/com/android/tv/common/feature/PropertyFeature.java new file mode 100644 index 00000000..27bccda1 --- /dev/null +++ b/common/src/com/android/tv/common/feature/PropertyFeature.java @@ -0,0 +1,52 @@ +/* + * 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.common.feature; + +import android.content.Context; + +import com.android.tv.common.BooleanSystemProperty; + +/** + * Feature controlled by system property. + * + * <p>See {@link BooleanSystemProperty} for instructions on how to set using adb. + */ +public final class PropertyFeature implements Feature { + private final BooleanSystemProperty mProperty; + + /** + * Create System Property backed feature. + * + * @param key the system property key. Length must be <= 31 characters. + * @param defaultValue the value to return if the property is undefined or empty. + */ + public PropertyFeature(String key, boolean defaultValue) { + if (key.length() > 31) { + // Since Features are initialized at startup and the keys are static go ahead and kill + // the application. + throw new IllegalArgumentException( + "Property keys have a max length of 31 characters but '" + key + "' is " + key + .length() + " characters."); + } + mProperty = new BooleanSystemProperty(key, defaultValue); + } + + @Override + public boolean isEnabled(Context context) { + return mProperty.getValue(); + } +} diff --git a/common/src/com/android/tv/common/ui/setup/OnActionClickListener.java b/common/src/com/android/tv/common/ui/setup/OnActionClickListener.java new file mode 100644 index 00000000..39af2d83 --- /dev/null +++ b/common/src/com/android/tv/common/ui/setup/OnActionClickListener.java @@ -0,0 +1,29 @@ +/* + * 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.common.ui.setup; + +/** + * A listener for the action click. + */ +public interface OnActionClickListener { + /** + * Called when the action is clicked. + * + * @param id action id. + */ + void onActionClick(int id); +} diff --git a/common/src/com/android/tv/common/ui/setup/SetupActionHelper.java b/common/src/com/android/tv/common/ui/setup/SetupActionHelper.java new file mode 100644 index 00000000..ed999990 --- /dev/null +++ b/common/src/com/android/tv/common/ui/setup/SetupActionHelper.java @@ -0,0 +1,33 @@ +/* + * 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.common.ui.setup; + +import android.app.Fragment; + +/** + * Helper class for the execution in the fragment. + */ +public class SetupActionHelper { + /** + * Executes the action of the given {@code actionId}. + */ + public static void onActionClick(Fragment fragment, int actionId) { + if (fragment.getActivity() instanceof OnActionClickListener) { + ((OnActionClickListener) fragment.getActivity()).onActionClick(actionId); + } + } +} diff --git a/common/src/com/android/tv/common/ui/setup/SetupFragment.java b/common/src/com/android/tv/common/ui/setup/SetupFragment.java new file mode 100644 index 00000000..46501652 --- /dev/null +++ b/common/src/com/android/tv/common/ui/setup/SetupFragment.java @@ -0,0 +1,106 @@ +/* + * 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.common.ui.setup; + +import android.animation.Animator; +import android.animation.ObjectAnimator; +import android.app.Fragment; +import android.content.Context; +import android.graphics.Point; +import android.hardware.display.DisplayManager; +import android.os.Bundle; +import android.support.v4.view.animation.LinearOutSlowInInterpolator; +import android.view.Display; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; + +import com.android.tv.common.R; + +/** + * A fragment which slides when it is entering/exiting. + */ +public abstract class SetupFragment extends Fragment { + public static final int ANIM_ENTER = 1; + public static final int ANIM_EXIT = 2; + public static final int ANIM_POP_ENTER = 3; + public static final int ANIM_POP_EXIT = 4; + + private static int sScreenWidth; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(getLayoutResourceId(), container, false); + // After the transition animation, we need to request the focus. If not, this fragment + // doesn't have the focus. + view.requestFocus(); + return view; + } + + /** + * Returns the layout resource ID for this fragment. + */ + protected abstract int getLayoutResourceId(); + + @Override + public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) { + if (sScreenWidth == 0) { + DisplayManager displayManager = + (DisplayManager) getActivity().getSystemService(Context.DISPLAY_SERVICE); + Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY); + Point size = new Point(); + display.getSize(size); + sScreenWidth = size.x; + } + + switch (nextAnim) { + case ANIM_ENTER: + return createTranslateAnimator(sScreenWidth, 0); + case ANIM_EXIT: + return createTranslateAnimator(0, -sScreenWidth); + case ANIM_POP_ENTER: + return createTranslateAnimator(-sScreenWidth, 0); + case ANIM_POP_EXIT: + return createTranslateAnimator(0, sScreenWidth); + } + return super.onCreateAnimator(transit, enter, nextAnim); + } + + private Animator createTranslateAnimator(int start, int end) { + ObjectAnimator animator = new ObjectAnimator(); + animator.setProperty(View.TRANSLATION_X); + animator.setFloatValues(start, end); + animator.setDuration(getResources().getInteger(R.integer.setup_slide_anim_duration)); + animator.setInterpolator(new LinearOutSlowInInterpolator()); + return animator; + } + + protected void setOnClickAction(View view, final int actionId) { + view.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + onActionClick(actionId); + } + }); + } + + protected void onActionClick(int actionId) { + SetupActionHelper.onActionClick(this, actionId); + } +} diff --git a/common/src/com/android/tv/common/ui/setup/SetupGuidedStepFragment.java b/common/src/com/android/tv/common/ui/setup/SetupGuidedStepFragment.java new file mode 100644 index 00000000..c744a4ab --- /dev/null +++ b/common/src/com/android/tv/common/ui/setup/SetupGuidedStepFragment.java @@ -0,0 +1,50 @@ +/* + * 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.common.ui.setup; + +import android.support.v17.leanback.app.GuidedStepFragment; +import android.support.v17.leanback.widget.GuidanceStylist; +import android.support.v17.leanback.widget.GuidedAction; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +/** + * A fragment for channel source info/setup. + */ +public abstract class SetupGuidedStepFragment extends GuidedStepFragment { + @Override + public GuidanceStylist onCreateGuidanceStylist() { + return new GuidanceStylist() { + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Guidance guidance) { + View view = super.onCreateView(inflater, container, guidance); + if (guidance.getIconDrawable() == null) { + // Icon view should not take up space when we don't use image. + getIconView().setVisibility(View.GONE); + } + return view; + } + }; + } + + @Override + public void onGuidedActionClicked(GuidedAction action) { + SetupActionHelper.onActionClick(this, (int) action.getId()); + } +} diff --git a/common/src/com/android/tv/common/ui/setup/SetupMultiPaneFragment.java b/common/src/com/android/tv/common/ui/setup/SetupMultiPaneFragment.java new file mode 100644 index 00000000..59416eff --- /dev/null +++ b/common/src/com/android/tv/common/ui/setup/SetupMultiPaneFragment.java @@ -0,0 +1,64 @@ +/* + * 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.common.ui.setup; + +import android.app.Fragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; + +import com.android.tv.common.R; + +/** + * A fragment for channel source info/setup. + */ +public abstract class SetupMultiPaneFragment extends SetupFragment { + public static final int ACTION_DONE = 1; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = super.onCreateView(inflater, container, savedInstanceState); + getFragmentManager().beginTransaction() + .replace(R.id.guided_step_fragment_container, getContentFragment()).commit(); + View doneButton = view.findViewById(R.id.button_done); + if (needsDoneButton()) { + doneButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View paramView) { + SetupActionHelper.onActionClick(SetupMultiPaneFragment.this, ACTION_DONE); + } + }); + } else { + doneButton.setVisibility(View.GONE); + } + return view; + } + + @Override + protected int getLayoutResourceId() { + return R.layout.fragment_setup_multi_pane; + } + + abstract protected Fragment getContentFragment(); + + protected boolean needsDoneButton() { + return true; + } +} diff --git a/common/src/com/android/tv/common/ui/setup/SetupStep.java b/common/src/com/android/tv/common/ui/setup/SetupStep.java new file mode 100644 index 00000000..b91ed6e2 --- /dev/null +++ b/common/src/com/android/tv/common/ui/setup/SetupStep.java @@ -0,0 +1,77 @@ +/* + * 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.common.ui.setup; + +import android.app.Fragment; +import android.app.FragmentManager; +import android.support.annotation.Nullable; + +/** + * An interface for the setup step. + */ +public abstract class SetupStep { + private final SetupStep mPreviousStep; + private final int mPreviousBackStackRecordCount; + + public SetupStep(FragmentManager fragmentManager, @Nullable SetupStep previousStep) { + mPreviousStep = previousStep; + mPreviousBackStackRecordCount = fragmentManager.getBackStackEntryCount(); + } + + /** + * Returns fragment to represent this step. + */ + protected abstract Fragment onCreateFragment(); + + /** + * Returns whether this step needs to be added to the back stack or not. + * + * <p>The default behavior is to add the fragment to the back stack. + */ + protected boolean needsToBeAddedToBackStack() { + return true; + } + + /** + * Returns whether this step needs fragment transition animations or not. + * + * <p>The default value is {@code} true. + */ + protected boolean needsFragmentTransitionAnimation() { + return true; + } + + /** + * Executes the given action. + */ + public abstract void executeAction(int actionId); + + /** + * Returns the back stack record count at the moment when this step starts. + */ + public int getPreviousBackStackRecordCount() { + return mPreviousBackStackRecordCount; + } + + /** + * Returns the previous step. + */ + @Nullable + public SetupStep getPreviousStep() { + return mPreviousStep; + } +} diff --git a/common/src/com/android/tv/common/ui/setup/SteppedSetupActivity.java b/common/src/com/android/tv/common/ui/setup/SteppedSetupActivity.java new file mode 100644 index 00000000..e454dc49 --- /dev/null +++ b/common/src/com/android/tv/common/ui/setup/SteppedSetupActivity.java @@ -0,0 +1,113 @@ +/* + * 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.common.ui.setup; + +import android.app.Activity; +import android.app.Fragment; +import android.app.FragmentManager.OnBackStackChangedListener; +import android.app.FragmentTransaction; +import android.os.Bundle; + +import com.android.tv.common.R; + +/** + * Stepped setup activity for onboarding screens or setup activity for TIS. + */ +public abstract class SteppedSetupActivity extends Activity implements OnActionClickListener { + private boolean mStartedInitialStep = false; + private SetupStep mStep; + + @Override + protected void onCreate(Bundle savedInstanceState) { + setTheme(R.style.Theme_Setup_GuidedStep); + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_stepped_setup); + startInitialStep(); + getFragmentManager().addOnBackStackChangedListener(new OnBackStackChangedListener() { + @Override + public void onBackStackChanged() { + if (mStep != null) { + // Need to change step to the previous one if the current step is popped from + // the back stack. + if (mStep.needsToBeAddedToBackStack() + && getFragmentManager().getBackStackEntryCount() + <= mStep.getPreviousBackStackRecordCount()) { + mStep = mStep.getPreviousStep(); + } + } + } + }); + } + + /** + * Returns the current step. + */ + public SetupStep getCurrentStep() { + return mStep; + } + + /** + * The inherited class should provide the initial step. + * + * <p>If this method returns {@code null} during {@link #onCreate}, then call + * {@link #startInitialStep} explicitly later with non null initial setup step. + * + * @see SetupStep + */ + protected abstract SetupStep onCreateInitialStep(); + + /** + * Starts the initial step. + * + * <p>The inherited class can call this method later explicitly if it doesn't want the initial + * step to be started in onCreate(). + * + * @see SetupStep + */ + protected void startInitialStep() { + if (mStartedInitialStep) { + return; + } + SetupStep step = onCreateInitialStep(); + if (step != null) { + startStep(step); + mStartedInitialStep = true; + } + } + + /** + * Starts next step. + */ + protected void startStep(SetupStep step) { + mStep = step; + Fragment fragment = step.onCreateFragment(); + FragmentTransaction ft = getFragmentManager().beginTransaction(); + if (step.needsFragmentTransitionAnimation()) { + ft.setCustomAnimations(SetupFragment.ANIM_ENTER, SetupFragment.ANIM_EXIT, + SetupFragment.ANIM_POP_ENTER, SetupFragment.ANIM_POP_EXIT); + } + if (step.needsToBeAddedToBackStack()) { + ft.addToBackStack(null); + } + ft.replace(R.id.fragment_container, fragment).commit(); + } + + @Override + public void onActionClick(int actionId) { + mStep.executeAction(actionId); + } +} |