aboutsummaryrefslogtreecommitdiff
path: root/common/src/com/android/tv
diff options
context:
space:
mode:
authorNick Chalko <nchalko@google.com>2015-11-04 15:15:29 -0800
committerNick Chalko <nchalko@google.com>2015-11-10 13:59:03 -0800
commit7d67089aa1e9aa2123c3cd2f386d7019a1544db1 (patch)
tree6f90c2065a853628dd7704788dd41b787acb6fae /common/src/com/android/tv
parent07b043dc3db83d6d20f0e8513b946830ab00e37b (diff)
downloadTV-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')
-rw-r--r--common/src/com/android/tv/common/BooleanSystemProperty.java101
-rw-r--r--common/src/com/android/tv/common/TvCommonConstants.java25
-rw-r--r--common/src/com/android/tv/common/feature/Feature.java38
-rw-r--r--common/src/com/android/tv/common/feature/FeatureUtils.java86
-rw-r--r--common/src/com/android/tv/common/feature/GServiceFeature.java41
-rw-r--r--common/src/com/android/tv/common/feature/PropertyFeature.java52
-rw-r--r--common/src/com/android/tv/common/ui/setup/OnActionClickListener.java29
-rw-r--r--common/src/com/android/tv/common/ui/setup/SetupActionHelper.java33
-rw-r--r--common/src/com/android/tv/common/ui/setup/SetupFragment.java106
-rw-r--r--common/src/com/android/tv/common/ui/setup/SetupGuidedStepFragment.java50
-rw-r--r--common/src/com/android/tv/common/ui/setup/SetupMultiPaneFragment.java64
-rw-r--r--common/src/com/android/tv/common/ui/setup/SetupStep.java77
-rw-r--r--common/src/com/android/tv/common/ui/setup/SteppedSetupActivity.java113
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);
+ }
+}