Start initial framework
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/workspace.xml
|
||||
/.idea/libraries
|
||||
.DS_Store
|
||||
/build
|
3
AdbConnect.bat
Normal file
@ -0,0 +1,3 @@
|
||||
cd C:\Users\Eric\AppData\Local\Android\android-sdk\platform-tools
|
||||
adb connect 192.168.1.106:4321
|
||||
pause
|
6
MediaBrowserTv/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/workspace.xml
|
||||
/.idea/libraries
|
||||
.DS_Store
|
||||
/build
|
1
MediaBrowserTv/.idea/.name
generated
Normal file
@ -0,0 +1 @@
|
||||
MediaBrowserTv
|
23
MediaBrowserTv/.idea/compiler.xml
generated
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<option name="DEFAULT_COMPILER" value="Javac" />
|
||||
<resourceExtensions />
|
||||
<wildcardResourcePatterns>
|
||||
<entry name="!?*.java" />
|
||||
<entry name="!?*.form" />
|
||||
<entry name="!?*.class" />
|
||||
<entry name="!?*.groovy" />
|
||||
<entry name="!?*.scala" />
|
||||
<entry name="!?*.flex" />
|
||||
<entry name="!?*.kt" />
|
||||
<entry name="!?*.clj" />
|
||||
</wildcardResourcePatterns>
|
||||
<annotationProcessing>
|
||||
<profile default="true" name="Default" enabled="false">
|
||||
<processorPath useClasspath="true" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
</component>
|
||||
</project>
|
||||
|
3
MediaBrowserTv/.idea/copyright/profiles_settings.xml
generated
Normal file
@ -0,0 +1,3 @@
|
||||
<component name="CopyrightManager">
|
||||
<settings default="" />
|
||||
</component>
|
5
MediaBrowserTv/.idea/encodings.xml
generated
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
|
||||
</project>
|
||||
|
19
MediaBrowserTv/.idea/gradle.xml
generated
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="distributionType" value="LOCAL" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleHome" value="C:\Program Files (x86)\android-studio\gradle\gradle-2.2.1" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
</set>
|
||||
</option>
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
|
10
MediaBrowserTv/.idea/misc.xml
generated
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="EntryPointsManager">
|
||||
<entry_points version="2.0" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" assert-keyword="true" jdk-15="true" project-jdk-name="1.7" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
</project>
|
||||
|
10
MediaBrowserTv/.idea/modules.xml
generated
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/MediaBrowserTv.iml" filepath="$PROJECT_DIR$/MediaBrowserTv.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
|
5
MediaBrowserTv/.idea/scopes/scope_settings.xml
generated
Normal file
@ -0,0 +1,5 @@
|
||||
<component name="DependencyValidationManager">
|
||||
<state>
|
||||
<option name="SKIP_IMPORT_STATEMENTS" value="false" />
|
||||
</state>
|
||||
</component>
|
7
MediaBrowserTv/.idea/vcs.xml
generated
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="" />
|
||||
</component>
|
||||
</project>
|
||||
|
21
MediaBrowserTv/MediaBrowserTv.iml
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="java-gradle" name="Java-Gradle">
|
||||
<configuration>
|
||||
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="false">
|
||||
<output url="file://$MODULE_DIR$/build/classes/main" />
|
||||
<output-test url="file://$MODULE_DIR$/build/classes/test" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
|
1
MediaBrowserTv/app/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/build
|
102
MediaBrowserTv/app/app.iml
Normal file
@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="android-gradle" name="Android-Gradle">
|
||||
<configuration>
|
||||
<option name="GRADLE_PROJECT_PATH" value=":app" />
|
||||
</configuration>
|
||||
</facet>
|
||||
<facet type="android" name="Android">
|
||||
<configuration>
|
||||
<option name="SELECTED_BUILD_VARIANT" value="debug" />
|
||||
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
|
||||
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
|
||||
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugTest" />
|
||||
<option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" />
|
||||
<option name="TEST_SOURCE_GEN_TASK_NAME" value="generateDebugTestSources" />
|
||||
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
||||
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
|
||||
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
|
||||
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="false">
|
||||
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/debug" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/test/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/test/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/test/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/test/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/test/debug" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/test/debug" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex-cache" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jacoco" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaResources" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/libs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/ndk" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Android API 21 Platform" jdkType="Android SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" exported="" name="Java-WebSocket-1.3.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-v4-21.0.2" level="project" />
|
||||
<orderEntry type="library" exported="" name="okio-1.0.1" level="project" />
|
||||
<orderEntry type="library" exported="" name="MediaBrowser.ApiClient.Java" level="project" />
|
||||
<orderEntry type="library" exported="" name="recyclerview-v7-21.0.2" level="project" />
|
||||
<orderEntry type="library" exported="" name="picasso-2.3.2" level="project" />
|
||||
<orderEntry type="library" exported="" name="disklrucache-2.0.2" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-annotations-21.0.2" level="project" />
|
||||
<orderEntry type="library" exported="" name="okhttp-urlconnection-2.1.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="volley-2014.10.9" level="project" />
|
||||
<orderEntry type="library" exported="" name="appcompat-v7-21.0.2" level="project" />
|
||||
<orderEntry type="library" exported="" name="gson-2.3" level="project" />
|
||||
<orderEntry type="library" exported="" name="okhttp-2.1.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="leanback-v17-21.0.2" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
|
38
MediaBrowserTv/app/build.gradle
Normal file
@ -0,0 +1,38 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
|
||||
android {
|
||||
compileSdkVersion 21
|
||||
buildToolsVersion "21.1.1"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "tv.mediabrowser.mediabrowsertv"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 21
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
compile 'com.android.support:recyclerview-v7:21.0.2'
|
||||
compile 'com.android.support:leanback-v17:21.0.2'
|
||||
compile 'com.android.support:appcompat-v7:21.0.2'
|
||||
compile 'com.squareup.picasso:picasso:2.3.2'
|
||||
compile 'com.google.code.gson:gson:2.3'
|
||||
compile 'com.squareup.okhttp:okhttp:2.1.0'
|
||||
compile 'com.squareup.okhttp:okhttp-urlconnection:2.1.0'
|
||||
compile 'com.squareup.okio:okio:1.0.1'
|
||||
compile 'me.neavo:volley:2014.10.9'}
|
17
MediaBrowserTv/app/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in C:\Users\Eric\AppData\Local\Android\android-sdk/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
@ -0,0 +1,13 @@
|
||||
package tv.mediabrowser.mediabrowsertv;
|
||||
|
||||
import android.app.Application;
|
||||
import android.test.ApplicationTestCase;
|
||||
|
||||
/**
|
||||
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
|
||||
*/
|
||||
public class ApplicationTest extends ApplicationTestCase<Application> {
|
||||
public ApplicationTest() {
|
||||
super(Application.class);
|
||||
}
|
||||
}
|
50
MediaBrowserTv/app/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="tv.mediabrowser.mediabrowsertv"
|
||||
android:versionCode="1"
|
||||
android:versionName="0.0.1" >
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.touchscreen"
|
||||
android:required="false" />
|
||||
|
||||
<application
|
||||
android:name="tv.mediabrowser.mediabrowsertv.TvApp"
|
||||
android:banner="@drawable/app_icon"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Leanback" >
|
||||
<activity
|
||||
android:name="tv.mediabrowser.mediabrowsertv.MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:logo="@drawable/app_icon"
|
||||
android:screenOrientation="landscape" >
|
||||
</activity>
|
||||
<activity
|
||||
android:name="tv.mediabrowser.mediabrowsertv.PlayerActivity"
|
||||
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" />
|
||||
<activity android:name="tv.mediabrowser.mediabrowsertv.DetailsActivity" />
|
||||
<activity
|
||||
android:name="tv.mediabrowser.mediabrowsertv.StartupActivity"
|
||||
android:label="@string/app_name"
|
||||
android:logo="@drawable/app_icon"
|
||||
android:noHistory="true" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name="tv.mediabrowser.mediabrowsertv.ConnectActivity"
|
||||
android:label="@string/title_activity_connect" >
|
||||
</activity>
|
||||
<activity
|
||||
android:name="tv.mediabrowser.mediabrowsertv.SelectUserActivity"
|
||||
android:label="@string/title_activity_select_user" >
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package tv.mediabrowser.mediabrowsertv;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
/*
|
||||
* BrowseErrorActivity shows how to use ErrorFragment
|
||||
*/
|
||||
public class BrowseErrorActivity extends Activity {
|
||||
private static int TIMER_DELAY = 3000;
|
||||
private static int SPINNER_WIDTH = 100;
|
||||
private static int SPINNER_HEIGHT = 100;
|
||||
|
||||
private ErrorFragment mErrorFragment;
|
||||
private SpinnerFragment mSpinnerFragment;
|
||||
|
||||
/**
|
||||
* Called when the activity is first created.
|
||||
*/
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_home);
|
||||
|
||||
testError();
|
||||
}
|
||||
|
||||
private void testError() {
|
||||
mErrorFragment = new ErrorFragment();
|
||||
getFragmentManager().beginTransaction().add(R.id.main_browse_fragment, mErrorFragment).commit();
|
||||
|
||||
mSpinnerFragment = new SpinnerFragment();
|
||||
getFragmentManager().beginTransaction().add(R.id.main_browse_fragment, mSpinnerFragment).commit();
|
||||
|
||||
final Handler handler = new Handler();
|
||||
handler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
getFragmentManager().beginTransaction().remove(mSpinnerFragment).commit();
|
||||
mErrorFragment.setErrorContent();
|
||||
}
|
||||
}, TIMER_DELAY);
|
||||
}
|
||||
|
||||
static public class SpinnerFragment extends Fragment {
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
ProgressBar progressBar = new ProgressBar(container.getContext());
|
||||
if (container instanceof FrameLayout) {
|
||||
FrameLayout.LayoutParams layoutParams =
|
||||
new FrameLayout.LayoutParams(SPINNER_WIDTH, SPINNER_HEIGHT, Gravity.CENTER);
|
||||
progressBar.setLayoutParams(layoutParams);
|
||||
}
|
||||
return progressBar;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package tv.mediabrowser.mediabrowsertv;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import mediabrowser.model.querying.ItemQuery;
|
||||
|
||||
/**
|
||||
* Created by Eric on 12/4/2014.
|
||||
*/
|
||||
public class BrowseRowDef {
|
||||
private String headerText;
|
||||
private List<ItemQuery> itemQueries;
|
||||
|
||||
public String getHeaderText() {
|
||||
return headerText;
|
||||
}
|
||||
|
||||
public void setHeaderText(String headerText) {
|
||||
this.headerText = headerText;
|
||||
}
|
||||
|
||||
public List<ItemQuery> getItemQueries() {
|
||||
return itemQueries;
|
||||
}
|
||||
|
||||
public void setItemQueries(List<ItemQuery> itemQueries) {
|
||||
this.itemQueries = itemQueries;
|
||||
}
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
package tv.mediabrowser.mediabrowsertv;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.v17.leanback.widget.ImageCardView;
|
||||
import android.support.v17.leanback.widget.Presenter;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.squareup.picasso.Picasso;
|
||||
import com.squareup.picasso.Target;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import mediabrowser.model.dto.BaseItemDto;
|
||||
|
||||
public class CardPresenter extends Presenter {
|
||||
private static final String TAG = "CardPresenter";
|
||||
|
||||
private static Context mContext;
|
||||
private static int CARD_WIDTH = 313;
|
||||
private static int CARD_HEIGHT = 176;
|
||||
private TvApp application;
|
||||
|
||||
public CardPresenter() {
|
||||
super();
|
||||
application = TvApp.getApplication();
|
||||
|
||||
}
|
||||
|
||||
static class ViewHolder extends Presenter.ViewHolder {
|
||||
private BaseItemDto mItem;
|
||||
private ImageCardView mCardView;
|
||||
private Drawable mDefaultCardImage;
|
||||
private PicassoImageCardViewTarget mImageCardViewTarget;
|
||||
|
||||
public ViewHolder(View view) {
|
||||
super(view);
|
||||
mCardView = (ImageCardView) view;
|
||||
|
||||
mImageCardViewTarget = new PicassoImageCardViewTarget(mCardView);
|
||||
mDefaultCardImage = mContext.getResources().getDrawable(R.drawable.movie);
|
||||
}
|
||||
|
||||
public void setItem(BaseItemDto m) {
|
||||
mItem = m;
|
||||
}
|
||||
|
||||
public BaseItemDto getItem() {
|
||||
return mItem;
|
||||
}
|
||||
|
||||
public ImageCardView getCardView() {
|
||||
return mCardView;
|
||||
}
|
||||
|
||||
protected void updateCardViewImage(String url) {
|
||||
Picasso.with(mContext)
|
||||
.load(url)
|
||||
.resize(CARD_WIDTH, CARD_HEIGHT)
|
||||
.centerCrop()
|
||||
.error(mDefaultCardImage)
|
||||
.into(mImageCardViewTarget);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent) {
|
||||
//Log.d(TAG, "onCreateViewHolder");
|
||||
mContext = parent.getContext();
|
||||
|
||||
ImageCardView cardView = new ImageCardView(mContext);
|
||||
cardView.setFocusable(true);
|
||||
cardView.setFocusableInTouchMode(true);
|
||||
cardView.setBackgroundColor(mContext.getResources().getColor(R.color.fastlane_background));
|
||||
return new ViewHolder(cardView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
|
||||
BaseItemDto baseItem = (BaseItemDto) item;
|
||||
((ViewHolder) viewHolder).setItem(baseItem);
|
||||
|
||||
//Log.d(TAG, "onBindViewHolder");
|
||||
if (baseItem != null) {
|
||||
((ViewHolder) viewHolder).mCardView.setTitleText(baseItem.getName());
|
||||
((ViewHolder) viewHolder).mCardView.setContentText(baseItem.getProductionYear().toString());
|
||||
((ViewHolder) viewHolder).mCardView.setMainImageDimensions(CARD_WIDTH, CARD_HEIGHT);
|
||||
//((ViewHolder) viewHolder).mCardView.setBadgeImage(mContext.getResources().getDrawable(
|
||||
// R.drawable.videos_by_google_icon));
|
||||
|
||||
((ViewHolder) viewHolder).updateCardViewImage(Utils.getPrimaryImageUrl(baseItem, application.getConnectionManager().GetApiClient(baseItem)));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
|
||||
//Log.d(TAG, "onUnbindViewHolder");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewAttachedToWindow(Presenter.ViewHolder viewHolder) {
|
||||
//Log.d(TAG, "onViewAttachedToWindow");
|
||||
}
|
||||
|
||||
public static class PicassoImageCardViewTarget implements Target {
|
||||
private ImageCardView mImageCardView;
|
||||
|
||||
public PicassoImageCardViewTarget(ImageCardView mImageCardView) {
|
||||
this.mImageCardView = mImageCardView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom loadedFrom) {
|
||||
Drawable bitmapDrawable = new BitmapDrawable(mContext.getResources(), bitmap);
|
||||
mImageCardView.setMainImage(bitmapDrawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBitmapFailed(Drawable drawable) {
|
||||
mImageCardView.setMainImage(drawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareLoad(Drawable drawable) {
|
||||
// Do nothing, default_background manager has its own transitions
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package tv.mediabrowser.mediabrowsertv;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.os.Build;
|
||||
import android.widget.TextView;
|
||||
|
||||
import mediabrowser.apiinteraction.IConnectionManager;
|
||||
import mediabrowser.apiinteraction.connectionmanager.ConnectionManager;
|
||||
|
||||
|
||||
public class ConnectActivity extends Activity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.fragment_connect);
|
||||
|
||||
IConnectionManager connectionManager = ((TvApp) getApplicationContext()).getConnectionManager();
|
||||
|
||||
|
||||
TextView pin = (TextView) findViewById(R.id.textViewPin);
|
||||
pin.setText("34545");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A placeholder fragment containing a simple view.
|
||||
*/
|
||||
public static class PlaceholderFragment extends Fragment {
|
||||
|
||||
public PlaceholderFragment() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
View rootView = inflater.inflate(R.layout.fragment_connect, container, false);
|
||||
return rootView;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package tv.mediabrowser.mediabrowsertv;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
|
||||
import tv.mediabrowser.mediabrowsertv.R;
|
||||
|
||||
/*
|
||||
* Details activity class that loads LeanbackDetailsFragment class
|
||||
*/
|
||||
public class DetailsActivity extends Activity {
|
||||
public static final String SHARED_ELEMENT_NAME = "hero";
|
||||
public static final String MOVIE = "Movie";
|
||||
|
||||
/**
|
||||
* Called when the activity is first created.
|
||||
*/
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_details);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package tv.mediabrowser.mediabrowsertv;
|
||||
|
||||
import android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter;
|
||||
|
||||
public class DetailsDescriptionPresenter extends AbstractDetailsDescriptionPresenter {
|
||||
@Override
|
||||
protected void onBindDescription(ViewHolder viewHolder, Object item) {
|
||||
Movie movie = (Movie) item;
|
||||
|
||||
if (movie != null) {
|
||||
viewHolder.getTitle().setText(movie.getTitle());
|
||||
viewHolder.getSubtitle().setText(movie.getStudio());
|
||||
viewHolder.getBody().setText(movie.getDescription());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package tv.mediabrowser.mediabrowsertv;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
/*
|
||||
* This class demonstrates how to extend ErrorFragment
|
||||
*/
|
||||
public class ErrorFragment extends android.support.v17.leanback.app.ErrorFragment {
|
||||
private static final String TAG = "ErrorFragment";
|
||||
private static final boolean TRANSLUCENT = true;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
Log.d(TAG, "onCreate");
|
||||
super.onCreate(savedInstanceState);
|
||||
setTitle(getResources().getString(R.string.app_name));
|
||||
}
|
||||
|
||||
void setErrorContent() {
|
||||
setImageDrawable(getResources().getDrawable(R.drawable.lb_ic_sad_cloud));
|
||||
setMessage(getResources().getString(R.string.error_fragment_message));
|
||||
setDefaultBackground(TRANSLUCENT);
|
||||
|
||||
setButtonText(getResources().getString(R.string.dismiss_error));
|
||||
setButtonClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View arg0) {
|
||||
getFragmentManager().beginTransaction().remove(ErrorFragment.this).commit();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package tv.mediabrowser.mediabrowsertv;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
/**
|
||||
* Created by Eric on 12/4/2014.
|
||||
*/
|
||||
public class HomeFragment extends StdBrowseFragment {
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
MainTitle = this.getString(R.string.home_title);
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package tv.mediabrowser.mediabrowsertv;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
|
||||
public class MainActivity extends Activity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_home);
|
||||
}
|
||||
}
|
@ -0,0 +1,262 @@
|
||||
package tv.mediabrowser.mediabrowsertv;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.v17.leanback.app.BackgroundManager;
|
||||
import android.support.v17.leanback.app.BrowseFragment;
|
||||
import android.support.v17.leanback.widget.ArrayObjectAdapter;
|
||||
import android.support.v17.leanback.widget.HeaderItem;
|
||||
import android.support.v17.leanback.widget.ListRow;
|
||||
import android.support.v17.leanback.widget.ListRowPresenter;
|
||||
import android.support.v17.leanback.widget.OnItemClickedListener;
|
||||
import android.support.v17.leanback.widget.OnItemSelectedListener;
|
||||
import android.support.v17.leanback.widget.Presenter;
|
||||
import android.support.v17.leanback.widget.Row;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.squareup.picasso.Picasso;
|
||||
import com.squareup.picasso.Target;
|
||||
|
||||
import mediabrowser.apiinteraction.ApiClient;
|
||||
import mediabrowser.apiinteraction.ApiEventListener;
|
||||
import mediabrowser.apiinteraction.ConnectionResult;
|
||||
import mediabrowser.apiinteraction.IConnectionManager;
|
||||
import mediabrowser.apiinteraction.android.AndroidConnectionManager;
|
||||
import mediabrowser.apiinteraction.android.GsonJsonSerializer;
|
||||
import mediabrowser.logging.ConsoleLogger;
|
||||
import mediabrowser.apiinteraction.Response;
|
||||
import mediabrowser.apiinteraction.android.AndroidApiClient;
|
||||
import mediabrowser.apiinteraction.android.AndroidDevice;
|
||||
import mediabrowser.apiinteraction.android.VolleyHttpClient;
|
||||
import mediabrowser.apiinteraction.device.IDevice;
|
||||
import mediabrowser.apiinteraction.http.IAsyncHttpClient;
|
||||
import mediabrowser.apiinteraction.serialization.BoonJsonSerializer;
|
||||
import mediabrowser.model.logging.ILogger;
|
||||
import mediabrowser.model.serialization.IJsonSerializer;
|
||||
import mediabrowser.model.session.ClientCapabilities;
|
||||
import mediabrowser.model.users.AuthenticationResult;
|
||||
|
||||
|
||||
public class MainFragment extends BrowseFragment {
|
||||
private static final String TAG = "MainFragment";
|
||||
|
||||
private static final int NUM_ROWS = 6;
|
||||
private static final int NUM_COLS = 15;
|
||||
|
||||
private ArrayObjectAdapter mRowsAdapter;
|
||||
private Drawable mDefaultBackground;
|
||||
private Target mBackgroundTarget;
|
||||
private DisplayMetrics mMetrics;
|
||||
private Timer mBackgroundTimer;
|
||||
private final Handler mHandler = new Handler();
|
||||
private URI mBackgroundURI;
|
||||
Movie mMovie;
|
||||
CardPresenter mCardPresenter;
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
//Log.i(TAG, "onCreate");
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
prepareBackgroundManager();
|
||||
|
||||
setupUIElements();
|
||||
|
||||
loadRows();
|
||||
|
||||
setupEventListeners();
|
||||
}
|
||||
|
||||
private void loadRows() {
|
||||
List<Movie> list = MovieList.setupMovies();
|
||||
|
||||
mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
|
||||
mCardPresenter = new CardPresenter();
|
||||
|
||||
int i;
|
||||
for (i = 0; i < NUM_ROWS; i++) {
|
||||
if (i != 0) {
|
||||
Collections.shuffle(list);
|
||||
}
|
||||
ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(mCardPresenter);
|
||||
for (int j = 0; j < NUM_COLS; j++) {
|
||||
listRowAdapter.add(list.get(j % 5));
|
||||
}
|
||||
HeaderItem header = new HeaderItem(i, MovieList.MOVIE_CATEGORY[i], null);
|
||||
mRowsAdapter.add(new ListRow(header, listRowAdapter));
|
||||
}
|
||||
|
||||
HeaderItem gridHeader = new HeaderItem(i, "PREFERENCES", null);
|
||||
|
||||
GridItemPresenter mGridPresenter = new GridItemPresenter();
|
||||
ArrayObjectAdapter gridRowAdapter = new ArrayObjectAdapter(mGridPresenter);
|
||||
gridRowAdapter.add(getResources().getString(R.string.grid_view));
|
||||
gridRowAdapter.add(getResources().getString(R.string.send_feeback));
|
||||
gridRowAdapter.add(getResources().getString(R.string.personal_settings));
|
||||
mRowsAdapter.add(new ListRow(gridHeader, gridRowAdapter));
|
||||
|
||||
setAdapter(mRowsAdapter);
|
||||
|
||||
}
|
||||
|
||||
private void prepareBackgroundManager() {
|
||||
|
||||
BackgroundManager backgroundManager = BackgroundManager.getInstance(getActivity());
|
||||
backgroundManager.attach(getActivity().getWindow());
|
||||
mBackgroundTarget = new PicassoBackgroundManagerTarget(backgroundManager);
|
||||
|
||||
mDefaultBackground = getResources().getDrawable(R.drawable.default_background);
|
||||
|
||||
mMetrics = new DisplayMetrics();
|
||||
getActivity().getWindowManager().getDefaultDisplay().getMetrics(mMetrics);
|
||||
}
|
||||
|
||||
private void setupUIElements() {
|
||||
// setBadgeDrawable(getActivity().getResources().getDrawable(
|
||||
// R.drawable.videos_by_google_banner));
|
||||
setTitle(getString(R.string.browse_title)); // Badge, when set, takes precedent
|
||||
// over title
|
||||
setHeadersState(HEADERS_ENABLED);
|
||||
setHeadersTransitionOnBackEnabled(true);
|
||||
|
||||
// set fastLane (or headers) background color
|
||||
setBrandColor(getResources().getColor(R.color.fastlane_background));
|
||||
// set search icon color
|
||||
setSearchAffordanceColor(getResources().getColor(R.color.search_opaque));
|
||||
}
|
||||
|
||||
private void setupEventListeners() {
|
||||
setOnItemSelectedListener(getDefaultItemSelectedListener());
|
||||
setOnItemClickedListener(getDefaultItemClickedListener());
|
||||
setOnSearchClickedListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Toast.makeText(getActivity(), "Implement your own in-app search", Toast.LENGTH_LONG)
|
||||
.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected OnItemSelectedListener getDefaultItemSelectedListener() {
|
||||
return new OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(Object item, Row row) {
|
||||
if (item instanceof Movie) {
|
||||
mBackgroundURI = ((Movie) item).getBackgroundImageURI();
|
||||
startBackgroundTimer();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected OnItemClickedListener getDefaultItemClickedListener() {
|
||||
return new OnItemClickedListener() {
|
||||
@Override
|
||||
public void onItemClicked(Object item, Row row) {
|
||||
if (item instanceof Movie) {
|
||||
Movie movie = (Movie) item;
|
||||
Log.d(TAG, "Item: " + item.toString());
|
||||
Intent intent = new Intent(getActivity(), DetailsActivity.class);
|
||||
intent.putExtra(getString(R.string.movie), movie);
|
||||
startActivity(intent);
|
||||
} else if (item instanceof String) {
|
||||
Toast.makeText(getActivity(), (String) item, Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected void setDefaultBackground(Drawable background) {
|
||||
mDefaultBackground = background;
|
||||
}
|
||||
|
||||
protected void setDefaultBackground(int resourceId) {
|
||||
mDefaultBackground = getResources().getDrawable(resourceId);
|
||||
}
|
||||
|
||||
protected void updateBackground(URI uri) {
|
||||
Picasso.with(getActivity())
|
||||
.load(uri.toString())
|
||||
.resize(mMetrics.widthPixels, mMetrics.heightPixels)
|
||||
.centerCrop()
|
||||
.error(mDefaultBackground)
|
||||
.into(mBackgroundTarget);
|
||||
}
|
||||
|
||||
protected void updateBackground(Drawable drawable) {
|
||||
BackgroundManager.getInstance(getActivity()).setDrawable(drawable);
|
||||
}
|
||||
|
||||
protected void clearBackground() {
|
||||
BackgroundManager.getInstance(getActivity()).setDrawable(mDefaultBackground);
|
||||
}
|
||||
|
||||
private void startBackgroundTimer() {
|
||||
if (null != mBackgroundTimer) {
|
||||
mBackgroundTimer.cancel();
|
||||
}
|
||||
mBackgroundTimer = new Timer();
|
||||
mBackgroundTimer.schedule(new UpdateBackgroundTask(), 300);
|
||||
}
|
||||
|
||||
private class UpdateBackgroundTask extends TimerTask {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mBackgroundURI != null) {
|
||||
updateBackground(mBackgroundURI);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private class GridItemPresenter extends Presenter {
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent) {
|
||||
TextView view = new TextView(parent.getContext());
|
||||
view.setLayoutParams(new ViewGroup.LayoutParams(200, 200));
|
||||
view.setFocusable(true);
|
||||
view.setFocusableInTouchMode(true);
|
||||
view.setBackgroundColor(getResources().getColor(R.color.default_background));
|
||||
view.setTextColor(Color.WHITE);
|
||||
view.setGravity(Gravity.CENTER);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder viewHolder, Object item) {
|
||||
((TextView) viewHolder.view).setText((String) item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnbindViewHolder(ViewHolder viewHolder) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
package tv.mediabrowser.mediabrowsertv;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
public class Movie implements Serializable {
|
||||
static final long serialVersionUID = 727566175075960653L;
|
||||
private static long count = 0;
|
||||
private long id;
|
||||
private String title;
|
||||
private String description;
|
||||
private String bgImageUrl;
|
||||
private String cardImageUrl;
|
||||
private String videoUrl;
|
||||
private String studio;
|
||||
private String category;
|
||||
|
||||
public Movie() {
|
||||
}
|
||||
|
||||
public static long getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public static void incCount() {
|
||||
count++;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getStudio() {
|
||||
return studio;
|
||||
}
|
||||
|
||||
public void setStudio(String studio) {
|
||||
this.studio = studio;
|
||||
}
|
||||
|
||||
public String getVideoUrl() {
|
||||
return videoUrl;
|
||||
}
|
||||
|
||||
public void setVideoUrl(String videoUrl) {
|
||||
this.videoUrl = videoUrl;
|
||||
}
|
||||
|
||||
public String getBackgroundImageUrl() {
|
||||
return bgImageUrl;
|
||||
}
|
||||
|
||||
public void setBackgroundImageUrl(String bgImageUrl) {
|
||||
this.bgImageUrl = bgImageUrl;
|
||||
}
|
||||
|
||||
public String getCardImageUrl() {
|
||||
return cardImageUrl;
|
||||
}
|
||||
|
||||
public void setCardImageUrl(String cardImageUrl) {
|
||||
this.cardImageUrl = cardImageUrl;
|
||||
}
|
||||
|
||||
public String getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
public void setCategory(String category) {
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
public URI getBackgroundImageURI() {
|
||||
try {
|
||||
Log.d("BACK MOVIE: ", bgImageUrl);
|
||||
return new URI(getBackgroundImageUrl());
|
||||
} catch (URISyntaxException e) {
|
||||
Log.d("URI exception: ", bgImageUrl);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public URI getCardImageURI() {
|
||||
try {
|
||||
return new URI(getCardImageUrl());
|
||||
} catch (URISyntaxException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Movie{" +
|
||||
"id=" + id +
|
||||
", title='" + title + '\'' +
|
||||
", videoUrl='" + videoUrl + '\'' +
|
||||
", backgroundImageUrl='" + bgImageUrl + '\'' +
|
||||
", backgroundImageURI='" + getBackgroundImageURI().toString() + '\'' +
|
||||
", cardImageUrl='" + cardImageUrl + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
package tv.mediabrowser.mediabrowsertv;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class MovieList {
|
||||
public static final String MOVIE_CATEGORY[] = {
|
||||
"Category Zero",
|
||||
"Category One",
|
||||
"Category Two",
|
||||
"Category Three",
|
||||
"Category Four",
|
||||
"Category Five",
|
||||
};
|
||||
|
||||
public static List<Movie> list;
|
||||
|
||||
public static List<Movie> setupMovies() {
|
||||
list = new ArrayList<Movie>();
|
||||
String title[] = {
|
||||
"Zeitgeist 2010_ Year in Review",
|
||||
"Google Demo Slam_ 20ft Search",
|
||||
"Introducing Gmail Blue",
|
||||
"Introducing Google Fiber to the Pole",
|
||||
"Introducing Google Nose"
|
||||
};
|
||||
|
||||
String description = "Fusce id nisi turpis. Praesent viverra bibendum semper. "
|
||||
+ "Donec tristique, orci sed semper lacinia, quam erat rhoncus massa, non congue tellus est "
|
||||
+ "quis tellus. Sed mollis orci venenatis quam scelerisque accumsan. Curabitur a massa sit "
|
||||
+ "amet mi accumsan mollis sed et magna. Vivamus sed aliquam risus. Nulla eget dolor in elit "
|
||||
+ "facilisis mattis. Ut aliquet luctus lacus. Phasellus nec commodo erat. Praesent tempus id "
|
||||
+ "lectus ac scelerisque. Maecenas pretium cursus lectus id volutpat.";
|
||||
|
||||
String videoUrl[] = {
|
||||
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/Zeitgeist/Zeitgeist%202010_%20Year%20in%20Review.mp4",
|
||||
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/Demo%20Slam/Google%20Demo%20Slam_%2020ft%20Search.mp4",
|
||||
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/April%20Fool's%202013/Introducing%20Gmail%20Blue.mp4",
|
||||
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/April%20Fool's%202013/Introducing%20Google%20Fiber%20to%20the%20Pole.mp4",
|
||||
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/April%20Fool's%202013/Introducing%20Google%20Nose.mp4"
|
||||
};
|
||||
String bgImageUrl[] = {
|
||||
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/Zeitgeist/Zeitgeist%202010_%20Year%20in%20Review/bg.jpg",
|
||||
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/Demo%20Slam/Google%20Demo%20Slam_%2020ft%20Search/bg.jpg",
|
||||
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/April%20Fool's%202013/Introducing%20Gmail%20Blue/bg.jpg",
|
||||
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/April%20Fool's%202013/Introducing%20Google%20Fiber%20to%20the%20Pole/bg.jpg",
|
||||
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/April%20Fool's%202013/Introducing%20Google%20Nose/bg.jpg",
|
||||
};
|
||||
String cardImageUrl[] = {
|
||||
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/Zeitgeist/Zeitgeist%202010_%20Year%20in%20Review/card.jpg",
|
||||
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/Demo%20Slam/Google%20Demo%20Slam_%2020ft%20Search/card.jpg",
|
||||
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/April%20Fool's%202013/Introducing%20Gmail%20Blue/card.jpg",
|
||||
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/April%20Fool's%202013/Introducing%20Google%20Fiber%20to%20the%20Pole/card.jpg",
|
||||
"http://commondatastorage.googleapis.com/android-tv/Sample%20videos/April%20Fool's%202013/Introducing%20Google%20Nose/card.jpg"
|
||||
};
|
||||
|
||||
list.add(buildMovieInfo("category", title[0],
|
||||
description, "Studio Zero", videoUrl[0], cardImageUrl[0], bgImageUrl[0]));
|
||||
list.add(buildMovieInfo("category", title[1],
|
||||
description, "Studio One", videoUrl[1], cardImageUrl[1], bgImageUrl[1]));
|
||||
list.add(buildMovieInfo("category", title[2],
|
||||
description, "Studio Two", videoUrl[2], cardImageUrl[2], bgImageUrl[2]));
|
||||
list.add(buildMovieInfo("category", title[3],
|
||||
description, "Studio Three", videoUrl[3], cardImageUrl[3], bgImageUrl[3]));
|
||||
list.add(buildMovieInfo("category", title[4],
|
||||
description, "Studio Four", videoUrl[4], cardImageUrl[4], bgImageUrl[4]));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private static Movie buildMovieInfo(String category, String title,
|
||||
String description, String studio, String videoUrl, String cardImageUrl,
|
||||
String bgImageUrl) {
|
||||
Movie movie = new Movie();
|
||||
movie.setId(Movie.getCount());
|
||||
Movie.incCount();
|
||||
movie.setTitle(title);
|
||||
movie.setDescription(description);
|
||||
movie.setStudio(studio);
|
||||
movie.setCategory(category);
|
||||
movie.setCardImageUrl(cardImageUrl);
|
||||
movie.setBackgroundImageUrl(bgImageUrl);
|
||||
movie.setVideoUrl(videoUrl);
|
||||
return movie;
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package tv.mediabrowser.mediabrowsertv;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.v17.leanback.app.BackgroundManager;
|
||||
|
||||
import com.squareup.picasso.Picasso;
|
||||
import com.squareup.picasso.Target;
|
||||
|
||||
/**
|
||||
* Picasso target for updating default_background images
|
||||
*/
|
||||
public class PicassoBackgroundManagerTarget implements Target {
|
||||
BackgroundManager mBackgroundManager;
|
||||
|
||||
public PicassoBackgroundManagerTarget(BackgroundManager backgroundManager) {
|
||||
this.mBackgroundManager = backgroundManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom loadedFrom) {
|
||||
this.mBackgroundManager.setBitmap(bitmap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBitmapFailed(Drawable drawable) {
|
||||
this.mBackgroundManager.setDrawable(drawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareLoad(Drawable drawable) {
|
||||
// Do nothing, default_background manager has its own transitions
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
|
||||
PicassoBackgroundManagerTarget that = (PicassoBackgroundManagerTarget) o;
|
||||
|
||||
if (!mBackgroundManager.equals(that.mBackgroundManager))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return mBackgroundManager.hashCode();
|
||||
}
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package tv.mediabrowser.mediabrowsertv;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.media.MediaPlayer;
|
||||
import android.os.Bundle;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.VideoView;
|
||||
|
||||
/**
|
||||
* PlaybackOverlayActivity for video playback that loads PlaybackOverlayFragment
|
||||
*/
|
||||
public class PlaybackOverlayActivity extends Activity implements
|
||||
PlaybackOverlayFragment.OnPlayPauseClickedListener {
|
||||
private static final String TAG = "PlaybackOverlayActivity";
|
||||
|
||||
private static final double MEDIA_HEIGHT = 0.95;
|
||||
private static final double MEDIA_WIDTH = 0.95;
|
||||
private static final double MEDIA_TOP_MARGIN = 0.025;
|
||||
private static final double MEDIA_RIGHT_MARGIN = 0.025;
|
||||
private static final double MEDIA_BOTTOM_MARGIN = 0.025;
|
||||
private static final double MEDIA_LEFT_MARGIN = 0.025;
|
||||
|
||||
|
||||
private VideoView mVideoView;
|
||||
private PlaybackState mPlaybackState = PlaybackState.IDLE;
|
||||
|
||||
/**
|
||||
* Called when the activity is first created.
|
||||
*/
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.playback_controls);
|
||||
loadViews();
|
||||
//setupCallbacks();
|
||||
overScan();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
mVideoView.suspend();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of OnPlayPauseClickedListener
|
||||
*/
|
||||
public void onFragmentPlayPause(Movie movie, int position, Boolean playPause) {
|
||||
mVideoView.setVideoPath(movie.getVideoUrl());
|
||||
|
||||
if (position == 0 || mPlaybackState == PlaybackState.IDLE) {
|
||||
setupCallbacks();
|
||||
mPlaybackState = PlaybackState.IDLE;
|
||||
}
|
||||
|
||||
if (playPause && mPlaybackState != PlaybackState.PLAYING) {
|
||||
mPlaybackState = PlaybackState.PLAYING;
|
||||
if (position > 0) {
|
||||
mVideoView.seekTo(position);
|
||||
mVideoView.start();
|
||||
}
|
||||
} else {
|
||||
mPlaybackState = PlaybackState.PAUSED;
|
||||
mVideoView.pause();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadViews() {
|
||||
mVideoView = (VideoView) findViewById(R.id.videoView);
|
||||
}
|
||||
|
||||
private void overScan() {
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
getWindowManager().getDefaultDisplay().getMetrics(metrics);
|
||||
int w = (int) (metrics.widthPixels * MEDIA_WIDTH);
|
||||
int h = (int) (metrics.heightPixels * MEDIA_HEIGHT);
|
||||
int marginLeft = (int) (metrics.widthPixels * MEDIA_LEFT_MARGIN);
|
||||
int marginTop = (int) (metrics.heightPixels * MEDIA_TOP_MARGIN);
|
||||
int marginRight = (int) (metrics.widthPixels * MEDIA_RIGHT_MARGIN);
|
||||
int marginBottom = (int) (metrics.heightPixels * MEDIA_BOTTOM_MARGIN);
|
||||
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(w, h);
|
||||
lp.setMargins(marginLeft, marginTop, marginRight, marginBottom);
|
||||
mVideoView.setLayoutParams(lp);
|
||||
}
|
||||
|
||||
private void setupCallbacks() {
|
||||
|
||||
mVideoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
|
||||
|
||||
@Override
|
||||
public boolean onError(MediaPlayer mp, int what, int extra) {
|
||||
String msg = "";
|
||||
if (extra == MediaPlayer.MEDIA_ERROR_TIMED_OUT) {
|
||||
msg = getString(R.string.video_error_media_load_timeout);
|
||||
} else if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) {
|
||||
msg = getString(R.string.video_error_server_inaccessible);
|
||||
} else {
|
||||
msg = getString(R.string.video_error_unknown_error);
|
||||
}
|
||||
mVideoView.stopPlayback();
|
||||
mPlaybackState = PlaybackState.IDLE;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
|
||||
@Override
|
||||
public void onPrepared(MediaPlayer mp) {
|
||||
if (mPlaybackState == PlaybackState.PLAYING) {
|
||||
mVideoView.start();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
|
||||
@Override
|
||||
public void onCompletion(MediaPlayer mp) {
|
||||
mPlaybackState = PlaybackState.IDLE;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* List of various states that we can be in
|
||||
*/
|
||||
public static enum PlaybackState {
|
||||
PLAYING, PAUSED, BUFFERING, IDLE;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,424 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package tv.mediabrowser.mediabrowsertv;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.media.MediaMetadataRetriever;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter;
|
||||
import android.support.v17.leanback.widget.Action;
|
||||
import android.support.v17.leanback.widget.ArrayObjectAdapter;
|
||||
import android.support.v17.leanback.widget.ClassPresenterSelector;
|
||||
import android.support.v17.leanback.widget.ControlButtonPresenterSelector;
|
||||
import android.support.v17.leanback.widget.HeaderItem;
|
||||
import android.support.v17.leanback.widget.ListRow;
|
||||
import android.support.v17.leanback.widget.ListRowPresenter;
|
||||
import android.support.v17.leanback.widget.OnActionClickedListener;
|
||||
import android.support.v17.leanback.widget.OnItemViewClickedListener;
|
||||
import android.support.v17.leanback.widget.OnItemViewSelectedListener;
|
||||
import android.support.v17.leanback.widget.PlaybackControlsRow;
|
||||
import android.support.v17.leanback.widget.PlaybackControlsRow.FastForwardAction;
|
||||
import android.support.v17.leanback.widget.PlaybackControlsRow.PlayPauseAction;
|
||||
import android.support.v17.leanback.widget.PlaybackControlsRow.RepeatAction;
|
||||
import android.support.v17.leanback.widget.PlaybackControlsRow.RewindAction;
|
||||
import android.support.v17.leanback.widget.PlaybackControlsRow.ShuffleAction;
|
||||
import android.support.v17.leanback.widget.PlaybackControlsRow.SkipNextAction;
|
||||
import android.support.v17.leanback.widget.PlaybackControlsRow.SkipPreviousAction;
|
||||
import android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsDownAction;
|
||||
import android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsUpAction;
|
||||
import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
|
||||
import android.support.v17.leanback.widget.Presenter;
|
||||
import android.support.v17.leanback.widget.Row;
|
||||
import android.support.v17.leanback.widget.RowPresenter;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.squareup.picasso.Picasso;
|
||||
import com.squareup.picasso.Target;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* Class for video playback with media control
|
||||
*/
|
||||
public class PlaybackOverlayFragment extends android.support.v17.leanback.app.PlaybackOverlayFragment {
|
||||
private static final String TAG = "PlaybackControlsFragment";
|
||||
|
||||
private static Context sContext;
|
||||
|
||||
private static final boolean SHOW_DETAIL = true;
|
||||
private static final boolean HIDE_MORE_ACTIONS = false;
|
||||
private static final int PRIMARY_CONTROLS = 5;
|
||||
private static final boolean SHOW_IMAGE = PRIMARY_CONTROLS <= 5;
|
||||
private static final int BACKGROUND_TYPE = PlaybackOverlayFragment.BG_LIGHT;
|
||||
private static final int CARD_WIDTH = 200;
|
||||
private static final int CARD_HEIGHT = 240;
|
||||
private static final int DEFAULT_UPDATE_PERIOD = 1000;
|
||||
private static final int UPDATE_PERIOD = 16;
|
||||
private static final int SIMULATED_BUFFERED_TIME = 10000;
|
||||
|
||||
private ArrayObjectAdapter mRowsAdapter;
|
||||
private ArrayObjectAdapter mPrimaryActionsAdapter;
|
||||
private ArrayObjectAdapter mSecondaryActionsAdapter;
|
||||
private PlayPauseAction mPlayPauseAction;
|
||||
private RepeatAction mRepeatAction;
|
||||
private ThumbsUpAction mThumbsUpAction;
|
||||
private ThumbsDownAction mThumbsDownAction;
|
||||
private ShuffleAction mShuffleAction;
|
||||
private FastForwardAction mFastForwardAction;
|
||||
private RewindAction mRewindAction;
|
||||
private SkipNextAction mSkipNextAction;
|
||||
private SkipPreviousAction mSkipPreviousAction;
|
||||
private PlaybackControlsRow mPlaybackControlsRow;
|
||||
private ArrayList<Movie> mItems = new ArrayList<Movie>();
|
||||
private int mCurrentItem;
|
||||
private Handler mHandler;
|
||||
private Runnable mRunnable;
|
||||
private Movie mSelectedMovie;
|
||||
private PicassoPlaybackControlsRowTarget mPlaybackControlsRowTarget;
|
||||
|
||||
OnPlayPauseClickedListener mCallback;
|
||||
|
||||
// Container Activity must implement this interface
|
||||
public interface OnPlayPauseClickedListener {
|
||||
public void onFragmentPlayPause(Movie movie, int position, Boolean playPause);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
Log.i(TAG, "onCreate");
|
||||
super.onCreate(savedInstanceState);
|
||||
sContext = getActivity();
|
||||
|
||||
mItems = new ArrayList<Movie>();
|
||||
mSelectedMovie = (Movie) getActivity()
|
||||
.getIntent().getSerializableExtra(DetailsActivity.MOVIE);
|
||||
|
||||
List<Movie> movies = MovieList.list;
|
||||
|
||||
ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
|
||||
|
||||
for (int j = 0; j < movies.size(); j++) {
|
||||
mItems.add(movies.get(j));
|
||||
if (mSelectedMovie.getTitle().contentEquals(movies.get(j).getTitle())) {
|
||||
mCurrentItem = j;
|
||||
}
|
||||
}
|
||||
|
||||
mHandler = new Handler();
|
||||
|
||||
setBackgroundType(BACKGROUND_TYPE);
|
||||
setFadingEnabled(false);
|
||||
|
||||
setupRows();
|
||||
|
||||
setOnItemViewSelectedListener(new OnItemViewSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
|
||||
RowPresenter.ViewHolder rowViewHolder, Row row) {
|
||||
Log.i(TAG, "onItemSelected: " + item + " row " + row);
|
||||
}
|
||||
});
|
||||
setOnItemViewClickedListener(new OnItemViewClickedListener() {
|
||||
@Override
|
||||
public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
|
||||
RowPresenter.ViewHolder rowViewHolder, Row row) {
|
||||
Log.i(TAG, "onItemClicked: " + item + " row " + row);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
|
||||
// This makes sure that the container activity has implemented
|
||||
// the callback interface. If not, it throws an exception
|
||||
try {
|
||||
mCallback = (OnPlayPauseClickedListener) activity;
|
||||
} catch (ClassCastException e) {
|
||||
throw new ClassCastException(activity.toString()
|
||||
+ " must implement OnPlayPauseClickedListener");
|
||||
}
|
||||
}
|
||||
|
||||
private void setupRows() {
|
||||
|
||||
ClassPresenterSelector ps = new ClassPresenterSelector();
|
||||
|
||||
PlaybackControlsRowPresenter playbackControlsRowPresenter;
|
||||
if (SHOW_DETAIL) {
|
||||
playbackControlsRowPresenter = new PlaybackControlsRowPresenter(
|
||||
new DescriptionPresenter());
|
||||
} else {
|
||||
playbackControlsRowPresenter = new PlaybackControlsRowPresenter();
|
||||
}
|
||||
playbackControlsRowPresenter.setOnActionClickedListener(new OnActionClickedListener() {
|
||||
public void onActionClicked(Action action) {
|
||||
if (action.getId() == mPlayPauseAction.getId()) {
|
||||
if (mPlayPauseAction.getIndex() == PlayPauseAction.PLAY) {
|
||||
startProgressAutomation();
|
||||
setFadingEnabled(true);
|
||||
mCallback.onFragmentPlayPause(mItems.get(mCurrentItem),
|
||||
mPlaybackControlsRow.getCurrentTime(), true);
|
||||
} else {
|
||||
stopProgressAutomation();
|
||||
setFadingEnabled(false);
|
||||
mCallback.onFragmentPlayPause(mItems.get(mCurrentItem),
|
||||
mPlaybackControlsRow.getCurrentTime(), false);
|
||||
}
|
||||
} else if (action.getId() == mSkipNextAction.getId()) {
|
||||
next();
|
||||
} else if (action.getId() == mSkipPreviousAction.getId()) {
|
||||
prev();
|
||||
} else if (action.getId() == mFastForwardAction.getId()) {
|
||||
Toast.makeText(getActivity(), "TODO: Fast Forward", Toast.LENGTH_SHORT).show();
|
||||
} else if (action.getId() == mRewindAction.getId()) {
|
||||
Toast.makeText(getActivity(), "TODO: Rewind", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
if (action instanceof PlaybackControlsRow.MultiAction) {
|
||||
((PlaybackControlsRow.MultiAction) action).nextIndex();
|
||||
notifyChanged(action);
|
||||
}
|
||||
}
|
||||
});
|
||||
playbackControlsRowPresenter.setSecondaryActionsHidden(HIDE_MORE_ACTIONS);
|
||||
|
||||
ps.addClassPresenter(PlaybackControlsRow.class, playbackControlsRowPresenter);
|
||||
ps.addClassPresenter(ListRow.class, new ListRowPresenter());
|
||||
mRowsAdapter = new ArrayObjectAdapter(ps);
|
||||
|
||||
addPlaybackControlsRow();
|
||||
addOtherRows();
|
||||
|
||||
setAdapter(mRowsAdapter);
|
||||
}
|
||||
|
||||
private int getDuration() {
|
||||
Movie movie = mItems.get(mCurrentItem);
|
||||
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
mmr.setDataSource(movie.getVideoUrl(), new HashMap<String, String>());
|
||||
} else {
|
||||
mmr.setDataSource(movie.getVideoUrl());
|
||||
}
|
||||
String time = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
|
||||
long duration = Long.parseLong(time);
|
||||
return (int) duration;
|
||||
}
|
||||
|
||||
private void addPlaybackControlsRow() {
|
||||
if (SHOW_DETAIL) {
|
||||
mPlaybackControlsRow = new PlaybackControlsRow(mSelectedMovie);
|
||||
} else {
|
||||
mPlaybackControlsRow = new PlaybackControlsRow();
|
||||
}
|
||||
mRowsAdapter.add(mPlaybackControlsRow);
|
||||
|
||||
updatePlaybackRow(mCurrentItem);
|
||||
|
||||
ControlButtonPresenterSelector presenterSelector = new ControlButtonPresenterSelector();
|
||||
mPrimaryActionsAdapter = new ArrayObjectAdapter(presenterSelector);
|
||||
mSecondaryActionsAdapter = new ArrayObjectAdapter(presenterSelector);
|
||||
mPlaybackControlsRow.setPrimaryActionsAdapter(mPrimaryActionsAdapter);
|
||||
mPlaybackControlsRow.setSecondaryActionsAdapter(mSecondaryActionsAdapter);
|
||||
|
||||
mPlayPauseAction = new PlayPauseAction(sContext);
|
||||
mRepeatAction = new RepeatAction(sContext);
|
||||
mThumbsUpAction = new ThumbsUpAction(sContext);
|
||||
mThumbsDownAction = new ThumbsDownAction(sContext);
|
||||
mShuffleAction = new ShuffleAction(sContext);
|
||||
mSkipNextAction = new PlaybackControlsRow.SkipNextAction(sContext);
|
||||
mSkipPreviousAction = new PlaybackControlsRow.SkipPreviousAction(sContext);
|
||||
mFastForwardAction = new PlaybackControlsRow.FastForwardAction(sContext);
|
||||
mRewindAction = new PlaybackControlsRow.RewindAction(sContext);
|
||||
|
||||
if (PRIMARY_CONTROLS > 5) {
|
||||
mPrimaryActionsAdapter.add(mThumbsUpAction);
|
||||
} else {
|
||||
mSecondaryActionsAdapter.add(mThumbsUpAction);
|
||||
}
|
||||
mPrimaryActionsAdapter.add(mSkipPreviousAction);
|
||||
if (PRIMARY_CONTROLS > 3) {
|
||||
mPrimaryActionsAdapter.add(new PlaybackControlsRow.RewindAction(sContext));
|
||||
}
|
||||
mPrimaryActionsAdapter.add(mPlayPauseAction);
|
||||
if (PRIMARY_CONTROLS > 3) {
|
||||
mPrimaryActionsAdapter.add(new PlaybackControlsRow.FastForwardAction(sContext));
|
||||
}
|
||||
mPrimaryActionsAdapter.add(mSkipNextAction);
|
||||
|
||||
mSecondaryActionsAdapter.add(mRepeatAction);
|
||||
mSecondaryActionsAdapter.add(mShuffleAction);
|
||||
if (PRIMARY_CONTROLS > 5) {
|
||||
mPrimaryActionsAdapter.add(mThumbsDownAction);
|
||||
} else {
|
||||
mSecondaryActionsAdapter.add(mThumbsDownAction);
|
||||
}
|
||||
mSecondaryActionsAdapter.add(new PlaybackControlsRow.HighQualityAction(sContext));
|
||||
mSecondaryActionsAdapter.add(new PlaybackControlsRow.ClosedCaptioningAction(sContext));
|
||||
}
|
||||
|
||||
private void notifyChanged(Action action) {
|
||||
ArrayObjectAdapter adapter = mPrimaryActionsAdapter;
|
||||
if (adapter.indexOf(action) >= 0) {
|
||||
adapter.notifyArrayItemRangeChanged(adapter.indexOf(action), 1);
|
||||
return;
|
||||
}
|
||||
adapter = mSecondaryActionsAdapter;
|
||||
if (adapter.indexOf(action) >= 0) {
|
||||
adapter.notifyArrayItemRangeChanged(adapter.indexOf(action), 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void updatePlaybackRow(int index) {
|
||||
if (mPlaybackControlsRow.getItem() != null) {
|
||||
Movie item = (Movie) mPlaybackControlsRow.getItem();
|
||||
item.setTitle(mItems.get(mCurrentItem).getTitle());
|
||||
item.setStudio(mItems.get(mCurrentItem).getStudio());
|
||||
}
|
||||
if (SHOW_IMAGE) {
|
||||
mPlaybackControlsRowTarget = new PicassoPlaybackControlsRowTarget(mPlaybackControlsRow);
|
||||
updateVideoImage(mItems.get(mCurrentItem).getCardImageURI());
|
||||
}
|
||||
mRowsAdapter.notifyArrayItemRangeChanged(0, 1);
|
||||
mPlaybackControlsRow.setTotalTime(getDuration());
|
||||
mPlaybackControlsRow.setCurrentTime(0);
|
||||
mPlaybackControlsRow.setBufferedProgress(0);
|
||||
}
|
||||
|
||||
private void addOtherRows() {
|
||||
ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
|
||||
for (Movie movie : mItems) {
|
||||
listRowAdapter.add(movie);
|
||||
}
|
||||
HeaderItem header = new HeaderItem(0, getString(R.string.related_movies), null);
|
||||
mRowsAdapter.add(new ListRow(header, listRowAdapter));
|
||||
|
||||
}
|
||||
|
||||
private int getUpdatePeriod() {
|
||||
if (getView() == null || mPlaybackControlsRow.getTotalTime() <= 0) {
|
||||
return DEFAULT_UPDATE_PERIOD;
|
||||
}
|
||||
return Math.max(UPDATE_PERIOD, mPlaybackControlsRow.getTotalTime() / getView().getWidth());
|
||||
}
|
||||
|
||||
private void startProgressAutomation() {
|
||||
mRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int updatePeriod = getUpdatePeriod();
|
||||
int currentTime = mPlaybackControlsRow.getCurrentTime() + updatePeriod;
|
||||
int totalTime = mPlaybackControlsRow.getTotalTime();
|
||||
mPlaybackControlsRow.setCurrentTime(currentTime);
|
||||
mPlaybackControlsRow.setBufferedProgress(currentTime + SIMULATED_BUFFERED_TIME);
|
||||
|
||||
if (totalTime > 0 && totalTime <= currentTime) {
|
||||
next();
|
||||
}
|
||||
mHandler.postDelayed(this, updatePeriod);
|
||||
}
|
||||
};
|
||||
mHandler.postDelayed(mRunnable, getUpdatePeriod());
|
||||
}
|
||||
|
||||
private void next() {
|
||||
if (++mCurrentItem >= mItems.size()) {
|
||||
mCurrentItem = 0;
|
||||
}
|
||||
|
||||
if (mPlayPauseAction.getIndex() == PlayPauseAction.PLAY) {
|
||||
mCallback.onFragmentPlayPause(mItems.get(mCurrentItem), 0, false);
|
||||
} else {
|
||||
mCallback.onFragmentPlayPause(mItems.get(mCurrentItem), 0, true);
|
||||
}
|
||||
updatePlaybackRow(mCurrentItem);
|
||||
}
|
||||
|
||||
private void prev() {
|
||||
if (--mCurrentItem < 0) {
|
||||
mCurrentItem = mItems.size() - 1;
|
||||
}
|
||||
if (mPlayPauseAction.getIndex() == PlayPauseAction.PLAY) {
|
||||
mCallback.onFragmentPlayPause(mItems.get(mCurrentItem), 0, false);
|
||||
} else {
|
||||
mCallback.onFragmentPlayPause(mItems.get(mCurrentItem), 0, true);
|
||||
}
|
||||
updatePlaybackRow(mCurrentItem);
|
||||
}
|
||||
|
||||
private void stopProgressAutomation() {
|
||||
if (mHandler != null && mRunnable != null) {
|
||||
mHandler.removeCallbacks(mRunnable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
stopProgressAutomation();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
static class DescriptionPresenter extends AbstractDetailsDescriptionPresenter {
|
||||
@Override
|
||||
protected void onBindDescription(ViewHolder viewHolder, Object item) {
|
||||
viewHolder.getTitle().setText(((Movie) item).getTitle());
|
||||
viewHolder.getSubtitle().setText(((Movie) item).getStudio());
|
||||
}
|
||||
}
|
||||
|
||||
public static class PicassoPlaybackControlsRowTarget implements Target {
|
||||
PlaybackControlsRow mPlaybackControlsRow;
|
||||
|
||||
public PicassoPlaybackControlsRowTarget(PlaybackControlsRow playbackControlsRow) {
|
||||
mPlaybackControlsRow = playbackControlsRow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom loadedFrom) {
|
||||
Drawable bitmapDrawable = new BitmapDrawable(sContext.getResources(), bitmap);
|
||||
mPlaybackControlsRow.setImageDrawable(bitmapDrawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBitmapFailed(Drawable drawable) {
|
||||
mPlaybackControlsRow.setImageDrawable(drawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareLoad(Drawable drawable) {
|
||||
// Do nothing, default_background manager has its own transitions
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateVideoImage(URI uri) {
|
||||
Picasso.with(sContext)
|
||||
.load(uri.toString())
|
||||
.resize(Utils.convertDpToPixel(sContext, CARD_WIDTH),
|
||||
Utils.convertDpToPixel(sContext, CARD_HEIGHT))
|
||||
.into(mPlaybackControlsRowTarget);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,420 @@
|
||||
package tv.mediabrowser.mediabrowsertv;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.media.MediaPlayer;
|
||||
import android.media.MediaPlayer.OnCompletionListener;
|
||||
import android.media.MediaPlayer.OnErrorListener;
|
||||
import android.media.MediaPlayer.OnPreparedListener;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RelativeLayout.LayoutParams;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.VideoView;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
public class PlayerActivity extends Activity {
|
||||
|
||||
private static final String TAG = "PlayerActivity";
|
||||
|
||||
private static final int HIDE_CONTROLLER_TIME = 5000;
|
||||
private static final int SEEKBAR_DELAY_TIME = 100;
|
||||
private static final int SEEKBAR_INTERVAL_TIME = 1000;
|
||||
private static final int MIN_SCRUB_TIME = 3000;
|
||||
private static final int SCRUB_SEGMENT_DIVISOR = 30;
|
||||
private static final double MEDIA_BAR_TOP_MARGIN = 0.8;
|
||||
private static final double MEDIA_BAR_RIGHT_MARGIN = 0.2;
|
||||
private static final double MEDIA_BAR_BOTTOM_MARGIN = 0.0;
|
||||
private static final double MEDIA_BAR_LEFT_MARGIN = 0.2;
|
||||
private static final double MEDIA_BAR_HEIGHT = 0.1;
|
||||
private static final double MEDIA_BAR_WIDTH = 0.9;
|
||||
|
||||
private VideoView mVideoView;
|
||||
private TextView mStartText;
|
||||
private TextView mEndText;
|
||||
private SeekBar mSeekbar;
|
||||
private ImageView mPlayPause;
|
||||
private ProgressBar mLoading;
|
||||
private View mControllers;
|
||||
private View mContainer;
|
||||
private Timer mSeekbarTimer;
|
||||
private Timer mControllersTimer;
|
||||
private PlaybackState mPlaybackState;
|
||||
private final Handler mHandler = new Handler();
|
||||
private Movie mSelectedMovie;
|
||||
private boolean mShouldStartPlayback;
|
||||
private boolean mControlersVisible;
|
||||
private int mDuration;
|
||||
private DisplayMetrics mMetrics;
|
||||
|
||||
/*
|
||||
* List of various states that we can be in
|
||||
*/
|
||||
public static enum PlaybackState {
|
||||
PLAYING, PAUSED, BUFFERING, IDLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_player);
|
||||
|
||||
mMetrics = new DisplayMetrics();
|
||||
getWindowManager().getDefaultDisplay().getMetrics(mMetrics);
|
||||
|
||||
loadViews();
|
||||
setupController();
|
||||
setupControlsCallbacks();
|
||||
startVideoPlayer();
|
||||
updateMetadata(true);
|
||||
}
|
||||
|
||||
private void startVideoPlayer() {
|
||||
Bundle b = getIntent().getExtras();
|
||||
mSelectedMovie = (Movie) getIntent().getSerializableExtra(getResources().getString(R.string.movie));
|
||||
if (null != b) {
|
||||
mShouldStartPlayback = b.getBoolean(getResources().getString(R.string.should_start));
|
||||
int startPosition = b.getInt(getResources().getString(R.string.start_position), 0);
|
||||
mVideoView.setVideoPath(mSelectedMovie.getVideoUrl());
|
||||
if (mShouldStartPlayback) {
|
||||
mPlaybackState = PlaybackState.PLAYING;
|
||||
updatePlayButton(mPlaybackState);
|
||||
if (startPosition > 0) {
|
||||
mVideoView.seekTo(startPosition);
|
||||
}
|
||||
mVideoView.start();
|
||||
mPlayPause.requestFocus();
|
||||
startControllersTimer();
|
||||
} else {
|
||||
updatePlaybackLocation();
|
||||
mPlaybackState = PlaybackState.PAUSED;
|
||||
updatePlayButton(mPlaybackState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updatePlaybackLocation() {
|
||||
if (mPlaybackState == PlaybackState.PLAYING ||
|
||||
mPlaybackState == PlaybackState.BUFFERING) {
|
||||
startControllersTimer();
|
||||
} else {
|
||||
stopControllersTimer();
|
||||
}
|
||||
}
|
||||
|
||||
private void play(int position) {
|
||||
startControllersTimer();
|
||||
mVideoView.seekTo(position);
|
||||
mVideoView.start();
|
||||
restartSeekBarTimer();
|
||||
}
|
||||
|
||||
private void stopSeekBarTimer() {
|
||||
Log.d(TAG, "Stopped TrickPlay Timer");
|
||||
if (null != mSeekbarTimer) {
|
||||
mSeekbarTimer.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private void restartSeekBarTimer() {
|
||||
stopSeekBarTimer();
|
||||
mSeekbarTimer = new Timer();
|
||||
mSeekbarTimer.scheduleAtFixedRate(new UpdateSeekbarTask(), SEEKBAR_DELAY_TIME,
|
||||
SEEKBAR_INTERVAL_TIME);
|
||||
}
|
||||
|
||||
private void stopControllersTimer() {
|
||||
if (null != mControllersTimer) {
|
||||
mControllersTimer.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private void startControllersTimer() {
|
||||
if (null != mControllersTimer) {
|
||||
mControllersTimer.cancel();
|
||||
}
|
||||
mControllersTimer = new Timer();
|
||||
mControllersTimer.schedule(new HideControllersTask(), HIDE_CONTROLLER_TIME);
|
||||
}
|
||||
|
||||
private void updateControlersVisibility(boolean show) {
|
||||
if (show) {
|
||||
mControllers.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mControllers.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
Log.d(TAG, "onPause() was called");
|
||||
if (null != mSeekbarTimer) {
|
||||
mSeekbarTimer.cancel();
|
||||
mSeekbarTimer = null;
|
||||
}
|
||||
if (null != mControllersTimer) {
|
||||
mControllersTimer.cancel();
|
||||
}
|
||||
mVideoView.pause();
|
||||
mPlaybackState = PlaybackState.PAUSED;
|
||||
updatePlayButton(PlaybackState.PAUSED);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
Log.d(TAG, "onStop() was called");
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
Log.d(TAG, "onDestroy() is called");
|
||||
stopControllersTimer();
|
||||
stopSeekBarTimer();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
Log.d(TAG, "onStart was called");
|
||||
super.onStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
Log.d(TAG, "onResume() was called");
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
private class HideControllersTask extends TimerTask {
|
||||
@Override
|
||||
public void run() {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateControlersVisibility(false);
|
||||
mControlersVisible = false;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private class UpdateSeekbarTask extends TimerTask {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
mHandler.post(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
int currentPos = 0;
|
||||
currentPos = mVideoView.getCurrentPosition();
|
||||
updateSeekbar(currentPos, mDuration);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private class BackToDetailTask extends TimerTask {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Intent intent = new Intent(PlayerActivity.this, DetailsActivity.class);
|
||||
intent.putExtra(getResources().getString(R.string.movie), mSelectedMovie);
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void setupController() {
|
||||
|
||||
int w = (int) (mMetrics.widthPixels * MEDIA_BAR_WIDTH);
|
||||
int h = (int) (mMetrics.heightPixels * MEDIA_BAR_HEIGHT);
|
||||
int marginLeft = (int) (mMetrics.widthPixels * MEDIA_BAR_LEFT_MARGIN);
|
||||
int marginTop = (int) (mMetrics.heightPixels * MEDIA_BAR_TOP_MARGIN);
|
||||
int marginRight = (int) (mMetrics.widthPixels * MEDIA_BAR_RIGHT_MARGIN);
|
||||
int marginBottom = (int) (mMetrics.heightPixels * MEDIA_BAR_BOTTOM_MARGIN);
|
||||
LayoutParams lp = new LayoutParams(w, h);
|
||||
lp.setMargins(marginLeft, marginTop, marginRight, marginBottom);
|
||||
mControllers.setLayoutParams(lp);
|
||||
mStartText.setText(getResources().getString(R.string.init_text));
|
||||
mEndText.setText(getResources().getString(R.string.init_text));
|
||||
}
|
||||
|
||||
private void setupControlsCallbacks() {
|
||||
|
||||
mVideoView.setOnErrorListener(new OnErrorListener() {
|
||||
|
||||
@Override
|
||||
public boolean onError(MediaPlayer mp, int what, int extra) {
|
||||
String msg = "";
|
||||
if (extra == MediaPlayer.MEDIA_ERROR_TIMED_OUT) {
|
||||
msg = getString(R.string.video_error_media_load_timeout);
|
||||
} else if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) {
|
||||
msg = getString(R.string.video_error_server_unaccessible);
|
||||
} else {
|
||||
msg = getString(R.string.video_error_unknown_error);
|
||||
}
|
||||
mVideoView.stopPlayback();
|
||||
mPlaybackState = PlaybackState.IDLE;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
mVideoView.setOnPreparedListener(new OnPreparedListener() {
|
||||
|
||||
@Override
|
||||
public void onPrepared(MediaPlayer mp) {
|
||||
Log.d(TAG, "onPrepared is reached");
|
||||
mDuration = mp.getDuration();
|
||||
mEndText.setText(Utils.formatMillis(mDuration));
|
||||
mSeekbar.setMax(mDuration);
|
||||
restartSeekBarTimer();
|
||||
}
|
||||
});
|
||||
|
||||
mVideoView.setOnCompletionListener(new OnCompletionListener() {
|
||||
|
||||
@Override
|
||||
public void onCompletion(MediaPlayer mp) {
|
||||
stopSeekBarTimer();
|
||||
mPlaybackState = PlaybackState.IDLE;
|
||||
updatePlayButton(PlaybackState.IDLE);
|
||||
mControllersTimer = new Timer();
|
||||
mControllersTimer.schedule(new BackToDetailTask(), HIDE_CONTROLLER_TIME);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* @Override public boolean onKeyDown(int keyCode, KeyEvent event) { return
|
||||
* super.onKeyDown(keyCode, event); }
|
||||
*/
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
int currentPos = 0;
|
||||
int delta = (int) (mDuration / SCRUB_SEGMENT_DIVISOR);
|
||||
if (delta < MIN_SCRUB_TIME)
|
||||
delta = MIN_SCRUB_TIME;
|
||||
|
||||
Log.v("keycode", "duration " + mDuration + " delta:" + delta);
|
||||
if (!mControlersVisible) {
|
||||
updateControlersVisibility(true);
|
||||
}
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_DPAD_CENTER:
|
||||
return true;
|
||||
case KeyEvent.KEYCODE_DPAD_DOWN:
|
||||
return true;
|
||||
case KeyEvent.KEYCODE_DPAD_LEFT:
|
||||
currentPos = mVideoView.getCurrentPosition();
|
||||
currentPos -= delta;
|
||||
if (currentPos > 0)
|
||||
play(currentPos);
|
||||
return true;
|
||||
case KeyEvent.KEYCODE_DPAD_RIGHT:
|
||||
currentPos = mVideoView.getCurrentPosition();
|
||||
currentPos += delta;
|
||||
if (currentPos < mDuration)
|
||||
play(currentPos);
|
||||
return true;
|
||||
case KeyEvent.KEYCODE_DPAD_UP:
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
private void updateSeekbar(int position, int duration) {
|
||||
mSeekbar.setProgress(position);
|
||||
mSeekbar.setMax(duration);
|
||||
mStartText.setText(Utils.formatMillis(position));
|
||||
mEndText.setText(Utils.formatMillis(duration));
|
||||
}
|
||||
|
||||
private void updatePlayButton(PlaybackState state) {
|
||||
switch (state) {
|
||||
case PLAYING:
|
||||
mLoading.setVisibility(View.INVISIBLE);
|
||||
mPlayPause.setVisibility(View.VISIBLE);
|
||||
mPlayPause.setImageDrawable(
|
||||
getResources().getDrawable(R.drawable.ic_pause_playcontrol_normal));
|
||||
break;
|
||||
case PAUSED:
|
||||
case IDLE:
|
||||
mLoading.setVisibility(View.INVISIBLE);
|
||||
mPlayPause.setVisibility(View.VISIBLE);
|
||||
mPlayPause.setImageDrawable(
|
||||
getResources().getDrawable(R.drawable.ic_play_playcontrol_normal));
|
||||
break;
|
||||
case BUFFERING:
|
||||
mPlayPause.setVisibility(View.INVISIBLE);
|
||||
mLoading.setVisibility(View.VISIBLE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateMetadata(boolean visible) {
|
||||
mVideoView.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void loadViews() {
|
||||
mVideoView = (VideoView) findViewById(R.id.videoView);
|
||||
mStartText = (TextView) findViewById(R.id.startText);
|
||||
mEndText = (TextView) findViewById(R.id.endText);
|
||||
mSeekbar = (SeekBar) findViewById(R.id.seekBar);
|
||||
mPlayPause = (ImageView) findViewById(R.id.playpause);
|
||||
mLoading = (ProgressBar) findViewById(R.id.progressBar);
|
||||
mControllers = findViewById(R.id.controllers);
|
||||
mContainer = findViewById(R.id.container);
|
||||
|
||||
mVideoView.setOnClickListener(mPlayPauseHandler);
|
||||
}
|
||||
|
||||
View.OnClickListener mPlayPauseHandler = new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
Log.d(TAG, "clicked play pause button");
|
||||
|
||||
if (!mControlersVisible) {
|
||||
updateControlersVisibility(true);
|
||||
}
|
||||
|
||||
if (mPlaybackState == PlaybackState.PAUSED) {
|
||||
mPlaybackState = PlaybackState.PLAYING;
|
||||
updatePlayButton(mPlaybackState);
|
||||
mVideoView.start();
|
||||
startControllersTimer();
|
||||
} else {
|
||||
mVideoView.pause();
|
||||
mPlaybackState = PlaybackState.PAUSED;
|
||||
updatePlayButton(PlaybackState.PAUSED);
|
||||
stopControllersTimer();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package tv.mediabrowser.mediabrowsertv;
|
||||
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
||||
|
||||
public class SelectUserActivity extends ActionBarActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_select_user);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
getMenuInflater().inflate(R.menu.menu_select_user, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
// Handle action bar item clicks here. The action bar will
|
||||
// automatically handle clicks on the Home/Up button, so long
|
||||
// as you specify a parent activity in AndroidManifest.xml.
|
||||
int id = item.getItemId();
|
||||
|
||||
//noinspection SimplifiableIfStatement
|
||||
if (id == R.id.action_settings) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
package tv.mediabrowser.mediabrowsertv;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.os.Build;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import mediabrowser.apiinteraction.ApiEventListener;
|
||||
import mediabrowser.apiinteraction.ConnectionResult;
|
||||
import mediabrowser.apiinteraction.IConnectionManager;
|
||||
import mediabrowser.apiinteraction.Response;
|
||||
import mediabrowser.apiinteraction.android.AndroidConnectionManager;
|
||||
import mediabrowser.apiinteraction.android.GsonJsonSerializer;
|
||||
import mediabrowser.apiinteraction.android.VolleyHttpClient;
|
||||
import mediabrowser.model.dto.UserDto;
|
||||
import mediabrowser.model.logging.ILogger;
|
||||
import mediabrowser.model.serialization.IJsonSerializer;
|
||||
import mediabrowser.model.session.ClientCapabilities;
|
||||
import mediabrowser.model.users.AuthenticationResult;
|
||||
|
||||
|
||||
public class StartupActivity extends Activity {
|
||||
|
||||
private TvApp application;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.fragment_startup);
|
||||
application = (TvApp) getApplicationContext();
|
||||
final Activity activity = this;
|
||||
|
||||
connectToServer(activity);
|
||||
|
||||
}
|
||||
|
||||
private void connectToServer(final Activity activity){
|
||||
final ILogger logger = application.getLogger();
|
||||
// The underlying http stack. Developers can inject their own if desired
|
||||
VolleyHttpClient volleyHttpClient = new VolleyHttpClient(logger, application);
|
||||
ClientCapabilities capabilities = new ClientCapabilities();
|
||||
IJsonSerializer jsonSerializer = new GsonJsonSerializer();
|
||||
|
||||
|
||||
ApiEventListener apiEventListener = new ApiEventListener();
|
||||
|
||||
final IConnectionManager connectionManager = new AndroidConnectionManager(application,
|
||||
jsonSerializer,
|
||||
logger,
|
||||
volleyHttpClient,
|
||||
"MediaBrowserTv",
|
||||
BuildConfig.VERSION_NAME,
|
||||
capabilities,
|
||||
apiEventListener);
|
||||
|
||||
application.setConnectionManager(connectionManager);
|
||||
|
||||
connectionManager.Connect(new Response<ConnectionResult>() {
|
||||
@Override
|
||||
public void onResponse(ConnectionResult response) {
|
||||
switch (response.getState()) {
|
||||
case ConnectSignIn:
|
||||
logger.Debug("Sign in with connect...");
|
||||
Intent intent = new Intent(activity, ConnectActivity.class);
|
||||
startActivity(intent);
|
||||
break;
|
||||
|
||||
case Unavailable:
|
||||
logger.Debug("No server available...");
|
||||
Utils.showToast(application, "No MB Servers available...");
|
||||
break;
|
||||
case ServerSignIn:
|
||||
logger.Debug("Sign in with server "+ response.getServers().get(0).getName() + " total: " + response.getServers().size());
|
||||
connectionManager.Connect(response.getServers().get(0), new Response<ConnectionResult>() {
|
||||
@Override
|
||||
public void onResponse(ConnectionResult serverResult) {
|
||||
switch (serverResult.getState()) {
|
||||
case ServerSignIn:
|
||||
try {
|
||||
serverResult.getApiClient().AuthenticateUserAsync("Dad","1224", new Response<AuthenticationResult>() {
|
||||
@Override
|
||||
public void onResponse(AuthenticationResult authenticationResult) {
|
||||
logger.Debug("Signed in as Dad.");
|
||||
application.setCurrentUser(authenticationResult.getUser());
|
||||
Intent intent = new Intent(activity, MainActivity.class);
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
break;
|
||||
case SignedIn:
|
||||
logger.Debug("Already signed in");
|
||||
response.getApiClient().GetUserAsync(response.getApiClient().getCurrentUserId(), new Response<UserDto>() {
|
||||
@Override
|
||||
public void onResponse(UserDto response) {
|
||||
application.setCurrentUser(response);
|
||||
Intent intent = new Intent(activity, MainActivity.class);
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case ServerSelection:
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,297 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License
|
||||
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||
* or implied. See the License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
|
||||
package tv.mediabrowser.mediabrowsertv;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.v17.leanback.app.BackgroundManager;
|
||||
import android.support.v17.leanback.app.BrowseFragment;
|
||||
import android.support.v17.leanback.widget.ArrayObjectAdapter;
|
||||
import android.support.v17.leanback.widget.HeaderItem;
|
||||
import android.support.v17.leanback.widget.ImageCardView;
|
||||
import android.support.v17.leanback.widget.ListRow;
|
||||
import android.support.v17.leanback.widget.ListRowPresenter;
|
||||
import android.support.v17.leanback.widget.OnItemViewClickedListener;
|
||||
import android.support.v17.leanback.widget.OnItemViewSelectedListener;
|
||||
import android.support.v17.leanback.widget.Presenter;
|
||||
import android.support.v17.leanback.widget.Row;
|
||||
import android.support.v17.leanback.widget.RowPresenter;
|
||||
import android.support.v4.app.ActivityOptionsCompat;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.squareup.picasso.Picasso;
|
||||
import com.squareup.picasso.Target;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import mediabrowser.apiinteraction.ApiClient;
|
||||
import mediabrowser.model.dto.BaseItemDto;
|
||||
|
||||
|
||||
public class StdBrowseFragment extends BrowseFragment {
|
||||
private static final String TAG = "StdBrowseFragment";
|
||||
|
||||
private static final int BACKGROUND_UPDATE_DELAY = 300;
|
||||
private static final int GRID_ITEM_WIDTH = 200;
|
||||
private static final int GRID_ITEM_HEIGHT = 200;
|
||||
private static final int NUM_ROWS = 6;
|
||||
private static final int NUM_COLS = 15;
|
||||
|
||||
protected String MainTitle;
|
||||
protected ApiClient apiClient;
|
||||
private ArrayObjectAdapter mRowsAdapter;
|
||||
private Drawable mDefaultBackground;
|
||||
private Target mBackgroundTarget;
|
||||
private DisplayMetrics mMetrics;
|
||||
private Timer mBackgroundTimer;
|
||||
private final Handler mHandler = new Handler();
|
||||
private String mBackgroundUrl;
|
||||
protected ArrayList<BrowseRowDef> mRows = new ArrayList<>();
|
||||
CardPresenter mCardPresenter;
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
Log.i(TAG, "onCreate");
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
prepareBackgroundManager();
|
||||
|
||||
setupUIElements();
|
||||
|
||||
setupQueries();
|
||||
|
||||
loadRows();
|
||||
|
||||
setupEventListeners();
|
||||
}
|
||||
|
||||
private void setupQueries() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (null != mBackgroundTimer) {
|
||||
Log.d(TAG, "onDestroy: " + mBackgroundTimer.toString());
|
||||
mBackgroundTimer.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadRows() {
|
||||
|
||||
mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
|
||||
mCardPresenter = new CardPresenter();
|
||||
|
||||
for (BrowseRowDef def : mRows) {
|
||||
|
||||
}
|
||||
int i = 0;
|
||||
// for (i = 0; i < NUM_ROWS; i++) {
|
||||
// if (i != 0) {
|
||||
// Collections.shuffle(list);
|
||||
// }
|
||||
// ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(mCardPresenter);
|
||||
// for (int j = 0; j < NUM_COLS; j++) {
|
||||
// listRowAdapter.add(list.get(j % 5));
|
||||
// }
|
||||
// HeaderItem header = new HeaderItem(i, MovieList.MOVIE_CATEGORY[i], null);
|
||||
// mRowsAdapter.add(new ListRow(header, listRowAdapter));
|
||||
// }
|
||||
|
||||
HeaderItem gridHeader = new HeaderItem(i, "SETTINGS", null);
|
||||
|
||||
GridItemPresenter mGridPresenter = new GridItemPresenter();
|
||||
ArrayObjectAdapter gridRowAdapter = new ArrayObjectAdapter(mGridPresenter);
|
||||
gridRowAdapter.add(getResources().getString(R.string.grid_view));
|
||||
gridRowAdapter.add(getResources().getString(R.string.error_fragment));
|
||||
gridRowAdapter.add(getResources().getString(R.string.personal_settings));
|
||||
gridRowAdapter.add("Logout " + TvApp.getApplication().getCurrentUser().getName());
|
||||
mRowsAdapter.add(new ListRow(gridHeader, gridRowAdapter));
|
||||
|
||||
setAdapter(mRowsAdapter);
|
||||
|
||||
}
|
||||
|
||||
private void prepareBackgroundManager() {
|
||||
|
||||
BackgroundManager backgroundManager = BackgroundManager.getInstance(getActivity());
|
||||
backgroundManager.attach(getActivity().getWindow());
|
||||
mBackgroundTarget = new PicassoBackgroundManagerTarget(backgroundManager);
|
||||
|
||||
mDefaultBackground = getResources().getDrawable(R.drawable.default_background);
|
||||
|
||||
mMetrics = new DisplayMetrics();
|
||||
getActivity().getWindowManager().getDefaultDisplay().getMetrics(mMetrics);
|
||||
}
|
||||
|
||||
private void setupUIElements() {
|
||||
setBadgeDrawable(getActivity().getResources().getDrawable(
|
||||
R.drawable.mblogo));
|
||||
setTitle(MainTitle); // Badge, when set, takes precedent
|
||||
// over title
|
||||
setHeadersState(HEADERS_ENABLED);
|
||||
setHeadersTransitionOnBackEnabled(true);
|
||||
|
||||
// set fastLane (or headers) background color
|
||||
setBrandColor(getResources().getColor(R.color.fastlane_background));
|
||||
// set search icon color
|
||||
setSearchAffordanceColor(getResources().getColor(R.color.search_opaque));
|
||||
}
|
||||
|
||||
private void setupEventListeners() {
|
||||
setOnSearchClickedListener(new View.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Toast.makeText(getActivity(), "Implement your own in-app search", Toast.LENGTH_LONG)
|
||||
.show();
|
||||
}
|
||||
});
|
||||
|
||||
setOnItemViewClickedListener(new ItemViewClickedListener());
|
||||
setOnItemViewSelectedListener(new ItemViewSelectedListener());
|
||||
}
|
||||
|
||||
private final class ItemViewClickedListener implements OnItemViewClickedListener {
|
||||
@Override
|
||||
public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
|
||||
RowPresenter.ViewHolder rowViewHolder, Row row) {
|
||||
|
||||
if (item instanceof Movie) {
|
||||
Movie movie = (Movie) item;
|
||||
Log.d(TAG, "Item: " + item.toString());
|
||||
Intent intent = new Intent(getActivity(), DetailsActivity.class);
|
||||
intent.putExtra(DetailsActivity.MOVIE, movie);
|
||||
|
||||
Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(
|
||||
getActivity(),
|
||||
((ImageCardView) itemViewHolder.view).getMainImageView(),
|
||||
DetailsActivity.SHARED_ELEMENT_NAME).toBundle();
|
||||
getActivity().startActivity(intent, bundle);
|
||||
} else if (item instanceof String) {
|
||||
if (((String) item).indexOf(getString(R.string.error_fragment)) >= 0) {
|
||||
Intent intent = new Intent(getActivity(), BrowseErrorActivity.class);
|
||||
startActivity(intent);
|
||||
} else {
|
||||
Toast.makeText(getActivity(), ((String) item), Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final class ItemViewSelectedListener implements OnItemViewSelectedListener {
|
||||
@Override
|
||||
public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
|
||||
RowPresenter.ViewHolder rowViewHolder, Row row) {
|
||||
if (item instanceof BaseItemDto) {
|
||||
BaseItemDto baseItem = (BaseItemDto)item;
|
||||
mBackgroundUrl = Utils.getBackdropImageUrl(baseItem, TvApp.getApplication().getConnectionManager().GetApiClient(baseItem));
|
||||
startBackgroundTimer();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected void setDefaultBackground(Drawable background) {
|
||||
mDefaultBackground = background;
|
||||
}
|
||||
|
||||
protected void setDefaultBackground(int resourceId) {
|
||||
mDefaultBackground = getResources().getDrawable(resourceId);
|
||||
}
|
||||
|
||||
protected void updateBackground(String url) {
|
||||
Picasso.with(getActivity())
|
||||
.load(url)
|
||||
.resize(mMetrics.widthPixels, mMetrics.heightPixels)
|
||||
.centerCrop()
|
||||
.error(mDefaultBackground)
|
||||
.into(mBackgroundTarget);
|
||||
}
|
||||
|
||||
protected void updateBackground(Drawable drawable) {
|
||||
BackgroundManager.getInstance(getActivity()).setDrawable(drawable);
|
||||
}
|
||||
|
||||
protected void clearBackground() {
|
||||
BackgroundManager.getInstance(getActivity()).setDrawable(mDefaultBackground);
|
||||
}
|
||||
|
||||
private void startBackgroundTimer() {
|
||||
if (null != mBackgroundTimer) {
|
||||
mBackgroundTimer.cancel();
|
||||
}
|
||||
mBackgroundTimer = new Timer();
|
||||
mBackgroundTimer.schedule(new UpdateBackgroundTask(), BACKGROUND_UPDATE_DELAY);
|
||||
}
|
||||
|
||||
private class UpdateBackgroundTask extends TimerTask {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mBackgroundUrl != null) {
|
||||
updateBackground(mBackgroundUrl);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private class GridItemPresenter extends Presenter {
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent) {
|
||||
TextView view = new TextView(parent.getContext());
|
||||
view.setLayoutParams(new ViewGroup.LayoutParams(GRID_ITEM_WIDTH, GRID_ITEM_HEIGHT));
|
||||
view.setFocusable(true);
|
||||
view.setFocusableInTouchMode(true);
|
||||
view.setBackgroundColor(getResources().getColor(R.color.default_background));
|
||||
view.setTextColor(Color.WHITE);
|
||||
view.setGravity(Gravity.CENTER);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder viewHolder, Object item) {
|
||||
((TextView) viewHolder.view).setText((String) item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnbindViewHolder(ViewHolder viewHolder) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package tv.mediabrowser.mediabrowsertv;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import mediabrowser.apiinteraction.ApiClient;
|
||||
import mediabrowser.apiinteraction.IConnectionManager;
|
||||
import mediabrowser.logging.ConsoleLogger;
|
||||
import mediabrowser.model.dto.UserDto;
|
||||
import mediabrowser.model.logging.ILogger;
|
||||
|
||||
/**
|
||||
* Created by Eric on 11/24/2014.
|
||||
*/
|
||||
public class TvApp extends Application {
|
||||
|
||||
private ILogger logger;
|
||||
private IConnectionManager connectionManager;
|
||||
private static TvApp app;
|
||||
private UserDto currentUser;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
logger = new ConsoleLogger();
|
||||
app = (TvApp)getApplicationContext();
|
||||
}
|
||||
|
||||
public static TvApp getApplication() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public ILogger getLogger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
public void setLogger(ILogger value) {
|
||||
logger = value;
|
||||
}
|
||||
|
||||
public IConnectionManager getConnectionManager() {
|
||||
return connectionManager;
|
||||
}
|
||||
|
||||
public void setConnectionManager(IConnectionManager connectionManager) {
|
||||
this.connectionManager = connectionManager;
|
||||
}
|
||||
|
||||
public UserDto getCurrentUser() {
|
||||
return currentUser;
|
||||
}
|
||||
|
||||
public void setCurrentUser(UserDto currentUser) {
|
||||
this.currentUser = currentUser;
|
||||
}
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
package tv.mediabrowser.mediabrowsertv;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.graphics.Point;
|
||||
import android.view.Display;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import mediabrowser.apiinteraction.ApiClient;
|
||||
import mediabrowser.model.dto.BaseItemDto;
|
||||
import mediabrowser.model.dto.ImageOptions;
|
||||
import mediabrowser.model.entities.ImageType;
|
||||
|
||||
/**
|
||||
* A collection of utility methods, all static.
|
||||
*/
|
||||
public class Utils {
|
||||
|
||||
/*
|
||||
* Making sure public utility methods remain static
|
||||
*/
|
||||
private Utils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the screen/display size
|
||||
*
|
||||
* @param context
|
||||
* @return
|
||||
*/
|
||||
public static Point getDisplaySize(Context context) {
|
||||
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
Display display = wm.getDefaultDisplay();
|
||||
Point size = new Point();
|
||||
display.getSize(size);
|
||||
int width = size.x;
|
||||
int height = size.y;
|
||||
return new Point(width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an error dialog with a given text message.
|
||||
*
|
||||
* @param context
|
||||
* @param errorString
|
||||
*/
|
||||
|
||||
public static final void showErrorDialog(Context context, String errorString) {
|
||||
new AlertDialog.Builder(context).setTitle(R.string.error)
|
||||
.setMessage(errorString)
|
||||
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
dialog.cancel();
|
||||
}
|
||||
})
|
||||
.create()
|
||||
.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a (long) toast
|
||||
*
|
||||
* @param context
|
||||
* @param msg
|
||||
*/
|
||||
public static void showToast(Context context, String msg) {
|
||||
Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a (long) toast.
|
||||
*
|
||||
* @param context
|
||||
* @param resourceId
|
||||
*/
|
||||
public static void showToast(Context context, int resourceId) {
|
||||
Toast.makeText(context, context.getString(resourceId), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
public static byte[] encrypt(String x) throws Exception {
|
||||
java.security.MessageDigest d = null;
|
||||
d = java.security.MessageDigest.getInstance("SHA-1");
|
||||
d.reset();
|
||||
d.update(x.getBytes());
|
||||
return d.digest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats time in milliseconds to hh:mm:ss string format.
|
||||
*
|
||||
* @param millis
|
||||
* @return
|
||||
*/
|
||||
public static String formatMillis(int millis) {
|
||||
String result = "";
|
||||
int hr = millis / 3600000;
|
||||
millis %= 3600000;
|
||||
int min = millis / 60000;
|
||||
millis %= 60000;
|
||||
int sec = millis / 1000;
|
||||
if (hr > 0) {
|
||||
result += hr + ":";
|
||||
}
|
||||
if (min >= 0) {
|
||||
if (min > 9) {
|
||||
result += min + ":";
|
||||
} else {
|
||||
result += "0" + min + ":";
|
||||
}
|
||||
}
|
||||
if (sec > 9) {
|
||||
result += sec;
|
||||
} else {
|
||||
result += "0" + sec;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int convertDpToPixel(Context ctx, int dp) {
|
||||
float density = ctx.getResources().getDisplayMetrics().density;
|
||||
return Math.round((float) dp * density);
|
||||
}
|
||||
|
||||
public static int dpToPx(int dp, Context ctx) {
|
||||
float density = ctx.getResources().getDisplayMetrics().density;
|
||||
return Math.round((float) dp * density);
|
||||
}
|
||||
|
||||
public static String getPrimaryImageUrl(BaseItemDto item, ApiClient apiClient) {
|
||||
ImageOptions options = new ImageOptions();
|
||||
options.setMaxWidth(300);
|
||||
options.setImageType(ImageType.Primary);
|
||||
options.setTag(item.getImageTags().get(ImageType.Primary));
|
||||
|
||||
return apiClient.GetImageUrl(item, options);
|
||||
}
|
||||
public static String getBackdropImageUrl(BaseItemDto item, ApiClient apiClient) {
|
||||
ImageOptions options = new ImageOptions();
|
||||
options.setMaxWidth(300);
|
||||
options.setImageType(ImageType.Backdrop);
|
||||
options.setImageIndex(0);
|
||||
options.setTag(item.getImageTags().get(ImageType.Backdrop));
|
||||
|
||||
return apiClient.GetImageUrl(item, options);
|
||||
}
|
||||
}
|
@ -0,0 +1,177 @@
|
||||
package tv.mediabrowser.mediabrowsertv;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.v17.leanback.app.BackgroundManager;
|
||||
import android.support.v17.leanback.app.DetailsFragment;
|
||||
import android.support.v17.leanback.widget.Action;
|
||||
import android.support.v17.leanback.widget.ArrayObjectAdapter;
|
||||
import android.support.v17.leanback.widget.ClassPresenterSelector;
|
||||
import android.support.v17.leanback.widget.DetailsOverviewRow;
|
||||
import android.support.v17.leanback.widget.DetailsOverviewRowPresenter;
|
||||
import android.support.v17.leanback.widget.HeaderItem;
|
||||
import android.support.v17.leanback.widget.ListRow;
|
||||
import android.support.v17.leanback.widget.ListRowPresenter;
|
||||
import android.support.v17.leanback.widget.OnActionClickedListener;
|
||||
import android.support.v17.leanback.widget.OnItemClickedListener;
|
||||
import android.support.v17.leanback.widget.Row;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.squareup.picasso.Picasso;
|
||||
import com.squareup.picasso.Target;
|
||||
|
||||
public class VideoDetailsFragment extends DetailsFragment {
|
||||
private static final String TAG = "VideoDetailsFragment";
|
||||
|
||||
private static final int ACTION_WATCH_TRAILER = 1;
|
||||
private static final int ACTION_RENT = 2;
|
||||
private static final int ACTION_BUY = 3;
|
||||
|
||||
private static final int DETAIL_THUMB_WIDTH = 274;
|
||||
private static final int DETAIL_THUMB_HEIGHT = 274;
|
||||
|
||||
private static final int NUM_COLS = 10;
|
||||
|
||||
private static final String MOVIE = "Movie";
|
||||
|
||||
private Movie selectedMovie;
|
||||
|
||||
private Drawable mDefaultBackground;
|
||||
private Target mBackgroundTarget;
|
||||
private DisplayMetrics mMetrics;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
Log.i(TAG, "onCreate DetailsFragment");
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
BackgroundManager backgroundManager = BackgroundManager.getInstance(getActivity());
|
||||
backgroundManager.attach(getActivity().getWindow());
|
||||
mBackgroundTarget = new PicassoBackgroundManagerTarget(backgroundManager);
|
||||
|
||||
mDefaultBackground = getResources().getDrawable(R.drawable.default_background);
|
||||
|
||||
mMetrics = new DisplayMetrics();
|
||||
getActivity().getWindowManager().getDefaultDisplay().getMetrics(mMetrics);
|
||||
|
||||
selectedMovie = (Movie) getActivity().getIntent().getSerializableExtra(MOVIE);
|
||||
new DetailRowBuilderTask().execute(selectedMovie);
|
||||
|
||||
setOnItemClickedListener(getDefaultItemClickedListener());
|
||||
updateBackground(selectedMovie.getBackgroundImageURI());
|
||||
|
||||
}
|
||||
|
||||
private class DetailRowBuilderTask extends AsyncTask<Movie, Integer, DetailsOverviewRow> {
|
||||
@Override
|
||||
protected DetailsOverviewRow doInBackground(Movie... movies) {
|
||||
selectedMovie = movies[0];
|
||||
|
||||
DetailsOverviewRow row = new DetailsOverviewRow(selectedMovie);
|
||||
try {
|
||||
Bitmap poster = Picasso.with(getActivity())
|
||||
.load(selectedMovie.getCardImageUrl())
|
||||
.resize(dpToPx(DETAIL_THUMB_WIDTH, getActivity().getApplicationContext()),
|
||||
dpToPx(DETAIL_THUMB_HEIGHT, getActivity().getApplicationContext()))
|
||||
.centerCrop()
|
||||
.get();
|
||||
row.setImageBitmap(getActivity(), poster);
|
||||
} catch (IOException e) {
|
||||
}
|
||||
|
||||
row.addAction(new Action(ACTION_WATCH_TRAILER, getResources().getString(
|
||||
R.string.watch_trailer_1), getResources().getString(R.string.watch_trailer_2)));
|
||||
row.addAction(new Action(ACTION_RENT, getResources().getString(R.string.rent_1),
|
||||
getResources().getString(R.string.rent_2)));
|
||||
row.addAction(new Action(ACTION_BUY, getResources().getString(R.string.buy_1),
|
||||
getResources().getString(R.string.buy_2)));
|
||||
return row;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(DetailsOverviewRow detailRow) {
|
||||
ClassPresenterSelector ps = new ClassPresenterSelector();
|
||||
DetailsOverviewRowPresenter dorPresenter =
|
||||
new DetailsOverviewRowPresenter(new DetailsDescriptionPresenter());
|
||||
// set detail background and style
|
||||
dorPresenter.setBackgroundColor(getResources().getColor(R.color.detail_background));
|
||||
dorPresenter.setStyleLarge(true);
|
||||
dorPresenter.setOnActionClickedListener(new OnActionClickedListener() {
|
||||
@Override
|
||||
public void onActionClicked(Action action) {
|
||||
if (action.getId() == ACTION_WATCH_TRAILER) {
|
||||
Intent intent = new Intent(getActivity(), PlayerActivity.class);
|
||||
intent.putExtra(getResources().getString(R.string.movie), selectedMovie);
|
||||
intent.putExtra(getResources().getString(R.string.should_start), true);
|
||||
startActivity(intent);
|
||||
} else {
|
||||
Toast.makeText(getActivity(), action.toString(), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ps.addClassPresenter(DetailsOverviewRow.class, dorPresenter);
|
||||
ps.addClassPresenter(ListRow.class,
|
||||
new ListRowPresenter());
|
||||
|
||||
ArrayObjectAdapter adapter = new ArrayObjectAdapter(ps);
|
||||
adapter.add(detailRow);
|
||||
|
||||
String subcategories[] = {
|
||||
getString(R.string.related_movies)
|
||||
};
|
||||
List<Movie> list = MovieList.list;
|
||||
Collections.shuffle(list);
|
||||
ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
|
||||
for (int j = 0; j < NUM_COLS; j++) {
|
||||
listRowAdapter.add(list.get(j % 5));
|
||||
}
|
||||
|
||||
HeaderItem header = new HeaderItem(0, subcategories[0], null);
|
||||
adapter.add(new ListRow(header, listRowAdapter));
|
||||
|
||||
setAdapter(adapter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected OnItemClickedListener getDefaultItemClickedListener() {
|
||||
return new OnItemClickedListener() {
|
||||
@Override
|
||||
public void onItemClicked(Object item, Row row) {
|
||||
if (item instanceof Movie) {
|
||||
Movie movie = (Movie) item;
|
||||
Intent intent = new Intent(getActivity(), DetailsActivity.class);
|
||||
intent.putExtra(MOVIE, movie);
|
||||
startActivity(intent);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected void updateBackground(URI uri) {
|
||||
Log.d(TAG, "uri" + uri);
|
||||
Log.d(TAG, "metrics" + mMetrics.toString());
|
||||
Picasso.with(getActivity())
|
||||
.load(uri.toString())
|
||||
.resize(mMetrics.widthPixels, mMetrics.heightPixels)
|
||||
.error(mDefaultBackground)
|
||||
.into(mBackgroundTarget);
|
||||
}
|
||||
|
||||
public static int dpToPx(int dp, Context ctx) {
|
||||
float density = ctx.getResources().getDisplayMetrics().density;
|
||||
return Math.round((float) dp * density);
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 15 KiB |
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<gradient
|
||||
android:startColor="@color/background_gradient_start"
|
||||
android:endColor="@color/background_gradient_end"
|
||||
android:angle="-270" />
|
||||
</shape>
|
BIN
MediaBrowserTv/app/src/main/res/drawable-hdpi/grid_bg.png
Normal file
After Width: | Height: | Size: 391 KiB |
BIN
MediaBrowserTv/app/src/main/res/drawable-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
MediaBrowserTv/app/src/main/res/drawable-hdpi/movie.png
Normal file
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 2.4 KiB |
BIN
MediaBrowserTv/app/src/main/res/drawable-hdpi/shadow7.9.png
Normal file
After Width: | Height: | Size: 233 B |
BIN
MediaBrowserTv/app/src/main/res/drawable-hdpi/star_icon.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 882 B |
After Width: | Height: | Size: 8.6 KiB |
After Width: | Height: | Size: 750 B |
BIN
MediaBrowserTv/app/src/main/res/drawable-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 535 B |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 1.3 KiB |
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<gradient
|
||||
android:startColor="@color/background_gradient_start"
|
||||
android:endColor="@color/background_gradient_end"
|
||||
android:angle="-270" />
|
||||
</shape>
|
BIN
MediaBrowserTv/app/src/main/res/drawable-xhdpi/grid_bg.png
Normal file
After Width: | Height: | Size: 391 KiB |
BIN
MediaBrowserTv/app/src/main/res/drawable-xhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 1004 B |
After Width: | Height: | Size: 677 B |
After Width: | Height: | Size: 885 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.9 KiB |
BIN
MediaBrowserTv/app/src/main/res/drawable-xhdpi/movie.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
MediaBrowserTv/app/src/main/res/drawable-xhdpi/star_icon.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 882 B |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 1.3 KiB |
BIN
MediaBrowserTv/app/src/main/res/drawable-xxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 9.1 KiB |
After Width: | Height: | Size: 632 B |
BIN
MediaBrowserTv/app/src/main/res/drawable/app_icon.png
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
MediaBrowserTv/app/src/main/res/drawable/app_icon_quantum.png
Normal file
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 1003 B |
After Width: | Height: | Size: 12 KiB |
BIN
MediaBrowserTv/app/src/main/res/drawable/details_img.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
MediaBrowserTv/app/src/main/res/drawable/ic_action_a.png
Normal file
After Width: | Height: | Size: 720 B |
BIN
MediaBrowserTv/app/src/main/res/drawable/ic_title.png
Normal file
After Width: | Height: | Size: 243 B |
BIN
MediaBrowserTv/app/src/main/res/drawable/mbandroidtv.jpg
Normal file
After Width: | Height: | Size: 7.1 KiB |
BIN
MediaBrowserTv/app/src/main/res/drawable/mblogo.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
MediaBrowserTv/app/src/main/res/drawable/movie.png
Normal file
After Width: | Height: | Size: 13 KiB |
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
|
||||
<gradient
|
||||
android:angle="90"
|
||||
android:centerColor="#00000000"
|
||||
android:endColor="#B2000000"
|
||||
android:startColor="#B2000000"
|
||||
android:type="linear" />
|
||||
|
||||
</shape>
|
BIN
MediaBrowserTv/app/src/main/res/drawable/shadow7.9.png
Normal file
After Width: | Height: | Size: 233 B |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 707 B |
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/details_fragment"
|
||||
android:name="tv.mediabrowser.mediabrowsertv.VideoDetailsFragment"
|
||||
android:layout_width="match_parent" android:layout_height="match_parent"
|
||||
tools:context=".DetailsActivity" tools:deviceIds="tv" />
|
8
MediaBrowserTv/app/src/main/res/layout/activity_home.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/main_browse_fragment"
|
||||
android:name="tv.mediabrowser.mediabrowsertv.HomeFragment" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" tools:context=".MainActivity" tools:deviceIds="tv"
|
||||
tools:ignore="MergeRootFrame"
|
||||
tools:layout="@layout/activity_home" />
|