Commit f5319d4f by Oleksandr Barabash

init

parents
#built application files
*.apk
*.ap_
# files for the dex VM
*.dex
# Java class files
*.class
# generated files
bin/
gen/
# Local configuration file (sdk path, etc)
local.properties
# Windows thumbnail db
Thumbs.db
# OSX files
.DS_Store
# Eclipse project files
.classpath
.project
# Android Studio
.idea
*.iml
#.idea/workspace.xml - remove # and delete .idea if it better suit your needs.
.gradle
build/
tv
gradle
mobile/libs/
mobile/src/androidTest/
mobile/src/test/
# tv_mobile_hls_stream
stream app (tv, mobile modules)
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.3'
classpath 'com.jakewharton:butterknife-gradle-plugin:8.4.0'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
ext {
sdk = 25
buildTools = "25.0.2"
minSdk = 16
libraryVersion = "1.0.2"
supportVersion = "25.3.0"
}
allprojects {
repositories {
mavenCentral()
jcenter()
}
}
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
apply plugin: 'com.android.application'
apply plugin: 'com.jakewharton.butterknife'
apply plugin: 'org.greenrobot.greendao'
android {
compileSdkVersion project.sdk
buildToolsVersion project.buildTools
defaultConfig {
applicationId "com.android.mobile"
minSdkVersion project.minSdk
targetSdkVersion project.sdk
versionCode 1
versionName "1.0"
buildConfigField "String", "MOBILE_TV_URL", "\"https://stb.tv.s1z.info\""
buildConfigField "String", "USER_AGENT", "\"AndroidTV\""
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
ext {
support = "25.3.1"
glide = "3.6.1"
exoplayer = "r1.5.9"
retrofit = "2.1.0"
converter_gson = retrofit
okhttp = "3.4.1"
butterknife = "8.4.0"
easing = "2.0@aar"
android_animations = "2.2@aar"
green_dao = "3.2.0"
butterknife_compiler = butterknife
dagger = "2.13"
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile "com.android.support:appcompat-v7:$support"
compile "com.android.support:recyclerview-v7:$support"
compile "com.android.support:cardview-v7:$support"
compile "com.android.support:preference-v7:$support"
compile "com.daimajia.easing:library:$easing"
compile "com.daimajia.androidanimations:library:$android_animations"
compile "com.github.bumptech.glide:glide:$glide"
compile "com.google.android.exoplayer:exoplayer:$exoplayer"
compile "com.squareup.retrofit2:retrofit:$retrofit"
compile "com.squareup.retrofit2:converter-gson:$converter_gson"
compile "com.squareup.okhttp3:okhttp:$okhttp"
compile "com.jakewharton:butterknife:$butterknife"
compile "org.greenrobot:greendao:$green_dao"
annotationProcessor "com.jakewharton:butterknife-compiler:$butterknife_compiler"
compile "com.google.dagger:dagger:$dagger"
annotationProcessor "com.google.dagger:dagger-compiler:$dagger"
}
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /home/oem/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 *;
#}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.mobile">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:name=".ApplicationContext">
<activity
android:name=".MainActivity"
android:screenOrientation="landscape"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".PlayerActivity"
android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen"
android:screenOrientation="landscape" />
<activity android:name=".IdentifyUserActivity"
android:windowSoftInputMode="adjustPan"
android:screenOrientation="landscape" />
</application>
</manifest>
\ No newline at end of file
package com.android.mobile;
import android.app.Application;
import com.android.mobile.dependencies.component.ApplicationComponent;
import com.android.mobile.dependencies.component.DaggerApplicationComponent;
import com.android.mobile.dependencies.module.AnimationModule;
import com.android.mobile.dependencies.module.ApplicationModule;
import com.android.mobile.dependencies.module.DatabaseModule;
import com.android.mobile.dependencies.module.NetworkModule;
import com.android.mobile.dependencies.module.RetrofitModule;
import com.android.mobile.security.TelevisionTrustStore;
public class ApplicationContext extends Application {
private static ApplicationComponent component;
@Override
public void onCreate() {
super.onCreate();
component = DaggerApplicationComponent.builder()
.networkModule(new NetworkModule(new TelevisionTrustStore(this)))
.retrofitModule(new RetrofitModule(BuildConfig.MOBILE_TV_URL))
.databaseModule(new DatabaseModule())
.applicationModule(new ApplicationModule(this))
.animationModule(new AnimationModule())
.build();
}
public static ApplicationComponent getComponent() {
return component;
}
}
package com.android.mobile;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.WindowManager;
import com.android.mobile.util.Preferences;
public abstract class BaseActivity extends AppCompatActivity {
private static final String TAG = BaseActivity.class.getSimpleName();
private static final int STATE_NORMAL = -1;
private static final int STATE_UNDEFINED = 0;
private static final int STATE_NOT_REGISTERED = 1;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setApplicationRoute();
super.onCreate(savedInstanceState);
}
private void setApplicationRoute() {
int state = getApplicationState();
Log.d(TAG, "App state: " + state);
Intent intent = getRouteIntent(state);
if (intent != null) {
startActivity(intent);
finish();
}
}
private Intent getRouteIntent(int state) {
Intent intent = new Intent(this, IdentifyUserActivity.class);
switch (state) {
case STATE_UNDEFINED:
return intent.putExtra(IdentifyUserActivity.STATUS, IdentifyUserActivity.CHECK_SERIAL);
case STATE_NOT_REGISTERED:
return intent.putExtra(IdentifyUserActivity.STATUS, IdentifyUserActivity.DEVICE_NOT_REGISTERED);
}
return null;
}
private int getApplicationState() {
if (isUndefined()) {
return STATE_UNDEFINED;
} else if (!isRegistered()) {
return STATE_NOT_REGISTERED;
}
return STATE_NORMAL;
}
private boolean hasIdentifier() {
return Preferences.getUserIdentifier(this) != null
&& !Preferences.getUserIdentifier(this).equals(Build.UNKNOWN);
}
private boolean isRegistered() {
return Preferences.getUserLogin(this) != null &&
Preferences.getUserPassword(this) != null;
}
private boolean isUndefined() {
return !hasIdentifier() && !isRegistered();
}
}
package com.android.mobile;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageView;
import com.android.mobile.ui.fragments.CheckSerialFragment;
import com.android.mobile.ui.fragments.DeviceNotRegisteredFragment;
import com.android.mobile.util.APIUtil;
import com.android.mobile.util.Preferences;
import com.android.mobile.util.ViewUtil;
public class IdentifyUserActivity extends AppCompatActivity {
private static final String TAG = IdentifyUserActivity.class.getSimpleName();
public static final String STATUS = "status";
public static final int DEVICE_NOT_REGISTERED = 0;
public static final int CHECK_SERIAL = 1;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.identify_user_activity);
int status = getIntent().getIntExtra(STATUS, -1);
ViewUtil.setImageDrawable(this,
(ImageView) findViewById(R.id.logotype),
APIUtil.getISPLogo(Preferences.getUserIsp(this)));
if (status != -1) {
getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out)
.add(R.id.container, getFragment(status))
.commit();
}
}
private Fragment getFragment(int status) {
switch (status) {
case CHECK_SERIAL:
return CheckSerialFragment.newInstance(null);
case DEVICE_NOT_REGISTERED:
return DeviceNotRegisteredFragment.newInstance(null);
}
return null;
}
}
package com.android.mobile;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.view.KeyEvent;
import com.android.mobile.ui.fragments.ChannelsFragment;
import com.android.mobile.ui.fragments.MenuFragment;
import com.android.mobile.util.FocusHandler;
public class MainActivity extends BaseActivity {
private static final String TAG = MainActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onResume() {
super.onResume();
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.container, ChannelsFragment.newInstance(null))
.commit();
}
@Override
public void onBackPressed() {
if (FocusHandler.isMenuOpen()) {
getSupportFragmentManager().popBackStack(MenuFragment.class.getName(),
FragmentManager.POP_BACK_STACK_INCLUSIVE);
} else {
super.onBackPressed();
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
final boolean unique = event.getRepeatCount() == 0;
if (unique) {
if (keyCode == KeyEvent.KEYCODE_MENU) {
showMenuFragment();
return true;
} else if (keyCode == KeyEvent.KEYCODE_BACK) {
onBackPressed();
return true;
}
}
return false;
}
private void showMenuFragment() {
if (FocusHandler.isMenuOpen()) {
getSupportFragmentManager().popBackStack(MenuFragment.class.getName(),
FragmentManager.POP_BACK_STACK_INCLUSIVE);
FocusHandler.setMenuOpen(false);
} else {
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.slide_from_top, R.anim.slide_to_top,
R.anim.slide_from_top, R.anim.slide_to_top)
.add(R.id.container, MenuFragment.newInstance(null))
.addToBackStack(MenuFragment.class.getName())
.commit();
}
}
}
package com.android.mobile.api;
import com.google.gson.annotations.SerializedName;
import java.util.Map;
public final class STBResponse {
@SerializedName("status_code") private String statusCode;
@SerializedName("data") private Map<String, String> data;
@SerializedName("details") private String details;
private STBResponse(Builder builder) {
statusCode = builder.statusCode;
data = builder.data;
details = builder.details;
}
public String getStatusCode() {
return statusCode;
}
public Map<String, String> getData() {
return data;
}
public String getDetails() {
return details;
}
public boolean isSuccessful() {
return statusCode.equals("200");
}
@Override
public String toString() {
return "STBResponse{" +
"statusCode='" + statusCode + '\'' +
", data=" + data +
", details='" + details + '\'' +
'}';
}
public static final class Builder {
private String statusCode;
private Map<String, String> data;
private String details;
public Builder() {
}
public Builder statusCode(String statusCode) {
this.statusCode = statusCode;
return this;
}
public Builder data(Map<String, String> data) {
this.data = data;
return this;
}
public Builder details(String details) {
this.details = details;
return this;
}
public STBResponse build() {
return new STBResponse(this);
}
}
}
package com.android.mobile.api.controller;
import com.android.mobile.api.STBResponse;
import com.android.mobile.api.retrofit.RetrofitCallback;
import com.android.mobile.api.retrofit.service.AccountService;
import java.io.IOException;
import java.util.Map;
import retrofit2.Call;
import retrofit2.Response;
import retrofit2.Retrofit;
public class AccountController {
private static final String TAG = AccountController.class.getSimpleName();
private Callback mCallback;
private AccountService mAccountService;
public AccountController(Retrofit retrofit) {
mAccountService = retrofit.create(AccountService.class);
}
public void setCallback(Callback mCallback) {
this.mCallback = mCallback;
}
public void signIn(Map<String, String> params) {
if (mCallback != null) {
mCallback.onRun();
}
mAccountService.signIn(params).enqueue(new retrofit2.Callback<STBResponse>() {
@Override
public void onResponse(Call<STBResponse> call, Response<STBResponse> response) {
if (response.isSuccessful()) {
if (mCallback != null) {
mCallback.onSuccess(response.body());
}
} else {
if (mCallback != null) {
try {
mCallback.onFailure(new IOException(response.errorBody().string()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Override
public void onFailure(Call<STBResponse> call, Throwable t) {
if (mCallback != null) {
mCallback.onFailure(t);
}
}
});
}
public void signUp(Map<String, String> params) {
if (mCallback != null) {
mCallback.onRun();
}
mAccountService.signUp(params).enqueue(new retrofit2.Callback<STBResponse>() {
@Override
public void onResponse(Call<STBResponse> call, Response<STBResponse> response) {
if (response.isSuccessful()) {
if (mCallback != null) {
mCallback.onSuccess(response.body());
}
} else {
if (mCallback != null) {
try {
mCallback.onFailure(new IOException(response.errorBody().string()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Override
public void onFailure(Call<STBResponse> call, Throwable t) {
if (mCallback != null) {
mCallback.onFailure(t);
}
}
});
}
public void signOut() {
if (mCallback != null) {
mCallback.onRun();
}
mAccountService.signOut().enqueue(new retrofit2.Callback<STBResponse>() {
@Override
public void onResponse(Call<STBResponse> call, Response<STBResponse> response) {
if (response.isSuccessful()) {
if (mCallback != null) {
mCallback.onSuccess(response.body());
}
} else {
if (mCallback != null) {
try {
mCallback.onFailure(new IOException(response.errorBody().string()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Override
public void onFailure(Call<STBResponse> call, Throwable t) {
if (mCallback != null) {
mCallback.onFailure(t);
}
}
});
}
public void setUserIdentifier(Map<String, String> params) {
if (mCallback != null) {
mCallback.onRun();
}
mAccountService.setUserIdentifier(params).enqueue(new retrofit2.Callback<STBResponse>() {
@Override
public void onResponse(Call<STBResponse> call, Response<STBResponse> response) {
if (response.isSuccessful()) {
if (mCallback != null) {
mCallback.onSuccess(response.body());
}
} else {
if (mCallback != null) {
try {
mCallback.onFailure(new IOException(response.errorBody().string()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Override
public void onFailure(Call<STBResponse> call, Throwable t) {
if (mCallback != null) {
mCallback.onFailure(t);
}
}
});
}
public interface Callback extends RetrofitCallback {
void onRun();
void onSuccess(STBResponse response);
void onFailure(Throwable throwable);
}
}
package com.android.mobile.api.controller;
import com.android.mobile.api.STBResponse;
import com.android.mobile.api.retrofit.RetrofitCallback;
import com.android.mobile.api.retrofit.service.ChannelService;
import com.android.mobile.exception.NonSuccessfulResponseException;
import java.io.IOException;
import retrofit2.Call;
import retrofit2.Response;
import retrofit2.Retrofit;
public class ChannelController {
private ChannelService channelService;
private Callback callback;
public ChannelController(Retrofit retrofit) {
channelService = retrofit.create(ChannelService.class);
}
public void setCallback(Callback callback) {
this.callback = callback;
}
public void getChannels() {
callback.onRun();
Call<STBResponse> call = channelService.getChannels();
call.enqueue(new ChannelCallbackQueue());
}
private class ChannelCallbackQueue implements retrofit2.Callback<STBResponse> {
@Override
public void onResponse(Call<STBResponse> call, Response<STBResponse> response) {
if (response.isSuccessful()) {
callback.onSuccess(response.body());
} else {
try {
callback.onFailure(new NonSuccessfulResponseException(response.errorBody().string()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void onFailure(Call<STBResponse> call, Throwable t) {
callback.onFailure(new NonSuccessfulResponseException(t.getMessage()));
}
}
public interface Callback extends RetrofitCallback {
void onRun();
void onSuccess(STBResponse response);
void onFailure(Throwable throwable);
}
}
package com.android.mobile.api.retrofit;
public interface RetrofitCallback {
}
package com.android.mobile.api.retrofit.service;
import com.android.mobile.api.STBResponse;
import java.util.Map;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.POST;
public interface AccountService {
String EMAIL = "email", PASSWORD = "password", SERIAL = "serial";
@POST("/api/v1/signin") Call<STBResponse> signIn(@Body Map<String, String> params);
@POST("/api/v1/signup") Call<STBResponse> signUp(@Body Map<String, String> params);
@POST("/api/v1/signout") Call<STBResponse> signOut();
@POST("/api/v1/startup") Call<STBResponse> setUserIdentifier(@Body Map<String, String> params);
}
package com.android.mobile.api.retrofit.service;
import com.android.mobile.api.STBResponse;
import retrofit2.Call;
import retrofit2.http.GET;
public interface ChannelService {
@GET("/api/v1/channels") Call<STBResponse> getChannels();
}
package com.android.mobile.database;
import android.content.Context;
import com.android.mobile.database.model.DaoMaster;
public class DatabaseHelper extends DaoMaster.OpenHelper {
public DatabaseHelper(Context context) {
super(context, "channels.db");
}
}
package com.android.mobile.database.model;
import android.os.Parcel;
import android.os.Parcelable;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.Index;
import org.greenrobot.greendao.annotation.Property;
import org.greenrobot.greendao.annotation.Generated;
@Entity(nameInDb = "channels", indexes = {@Index(value = "title DESC", unique = true)})
public class ChannelRecord implements Parcelable {
@Id(autoincrement = true)
private Long id;
@SerializedName("title") @Property(nameInDb = "title")
private String title;
@SerializedName("category") @Property(nameInDb = "category")
private String category;
@SerializedName("url") @Property(nameInDb = "url")
private String url;
@SerializedName("bg_image") @Property(nameInDb = "bg_image")
private String bgImage;
public ChannelRecord() {
}
public ChannelRecord(String title, String category, String url, String bgImage) {
this.title = title;
this.category = category;
this.url = url;
this.bgImage = bgImage;
}
protected ChannelRecord(Parcel in) {
this.title = in.readString();
this.category = in.readString();
this.url = in.readString();
this.bgImage = in.readString();
}
@Generated(hash = 1905863218)
public ChannelRecord(Long id, String title, String category, String url, String bgImage) {
this.id = id;
this.title = title;
this.category = category;
this.url = url;
this.bgImage = bgImage;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(title);
dest.writeString(category);
dest.writeString(url);
dest.writeString(bgImage);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<ChannelRecord> CREATOR = new Creator<ChannelRecord>() {
@Override
public ChannelRecord createFromParcel(Parcel in) {
return new ChannelRecord(in);
}
@Override
public ChannelRecord[] newArray(int size) {
return new ChannelRecord[size];
}
};
public String getTitle() {
return title == null ? "" : title;
}
public void setTitle(String title) {
this.title = title;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getBgImage() {
return bgImage;
}
public void setBgImage(String bgImage) {
this.bgImage = bgImage;
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public String toString() {
return new Gson().toJson(this);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ChannelRecord)) return false;
ChannelRecord channel = (ChannelRecord) o;
if (getTitle() != null ? !getTitle().equals(channel.getTitle()) : channel.getTitle() != null)
return false;
if (getCategory() != null ? !getCategory().equals(channel.getCategory()) : channel.getCategory() != null)
return false;
if (getUrl() != null ? !getUrl().equals(channel.getUrl()) : channel.getUrl() != null)
return false;
return getBgImage() != null ? getBgImage().equals(channel.getBgImage()) : channel.getBgImage() == null;
}
@Override
public int hashCode() {
int result = getTitle() != null ? getTitle().hashCode() : 0;
result = 31 * result + (getCategory() != null ? getCategory().hashCode() : 0);
result = 31 * result + (getUrl() != null ? getUrl().hashCode() : 0);
result = 31 * result + (getBgImage() != null ? getBgImage().hashCode() : 0);
return result;
}
}
package com.android.mobile.dependencies;
import com.android.mobile.ApplicationContext;
import com.android.mobile.PlayerActivity;
import com.android.mobile.dependencies.component.ApplicationComponent;
import com.android.mobile.ui.ScalableCardView;
import com.android.mobile.ui.fragments.ChangeSerialFragment;
import com.android.mobile.ui.fragments.ChannelsFragment;
import com.android.mobile.ui.fragments.CheckSerialFragment;
import com.android.mobile.ui.fragments.MenuFragment;
import com.android.mobile.ui.fragments.SignInFragment;
import com.android.mobile.ui.fragments.SignUpFragment;
public final class Injector {
private static ApplicationComponent component;
static {
component = ApplicationContext.getComponent();
}
public static void inject(SignInFragment signInFragment) {
component.inject(signInFragment);
}
public static void inject(ChangeSerialFragment changeSerialFragment) {
component.inject(changeSerialFragment);
}
public static void inject(SignUpFragment signUpFragment) {
component.inject(signUpFragment);
}
public static void inject(ChannelsFragment channelsFragment) {
component.inject(channelsFragment);
}
public static void inject(PlayerActivity playerActivity) {
component.inject(playerActivity);
}
public static void inject(ScalableCardView scalableCardView) {
component.inject(scalableCardView);
}
public static void inject(MenuFragment menuFragment) {
component.inject(menuFragment);
}
public static void inject(CheckSerialFragment checkSerialFragment) {
component.inject(checkSerialFragment);
}
}
package com.android.mobile.dependencies.component;
import com.android.mobile.PlayerActivity;
import com.android.mobile.dependencies.module.AnimationModule;
import com.android.mobile.dependencies.module.ApplicationModule;
import com.android.mobile.dependencies.module.DatabaseModule;
import com.android.mobile.dependencies.module.NetworkModule;
import com.android.mobile.dependencies.module.RetrofitModule;
import com.android.mobile.ui.ScalableCardView;
import com.android.mobile.ui.fragments.ChangeSerialFragment;
import com.android.mobile.ui.fragments.ChannelsFragment;
import com.android.mobile.ui.fragments.CheckSerialFragment;
import com.android.mobile.ui.fragments.MenuFragment;
import com.android.mobile.ui.fragments.SignInFragment;
import com.android.mobile.ui.fragments.SignUpFragment;
import javax.inject.Singleton;
import dagger.Component;
@Singleton
@Component(dependencies = {}, modules = {NetworkModule.class,
RetrofitModule.class,
DatabaseModule.class,
ApplicationModule.class,
AnimationModule.class})
public interface ApplicationComponent {
void inject(SignInFragment signInFragment);
void inject(ChangeSerialFragment changeSerialFragment);
void inject(SignUpFragment signUpFragment);
void inject(ChannelsFragment channelsFragment);
void inject(PlayerActivity playerActivity);
void inject(ScalableCardView scalableCardView);
void inject(MenuFragment menuFragment);
void inject(CheckSerialFragment checkSerialFragment);
}
package com.android.mobile.dependencies.module;
import com.android.mobile.util.AnimationUtil;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class AnimationModule {
@Provides
@Singleton
AnimationUtil provideAnimationUtil() {
return new AnimationUtil();
}
}
package com.android.mobile.dependencies.module;
import android.content.Context;
import com.android.mobile.ApplicationContext;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class ApplicationModule {
private ApplicationContext application;
public ApplicationModule(ApplicationContext application) {
this.application = application;
}
@Provides
@Singleton
ApplicationContext provideApplicationContext() {
return application;
}
@Provides
@Singleton
Context provideContext() {
return application.getApplicationContext();
}
}
package com.android.mobile.dependencies.module;
import android.content.Context;
import com.android.mobile.database.DatabaseHelper;
import com.android.mobile.database.model.ChannelRecordDao;
import com.android.mobile.database.model.DaoMaster;
import com.android.mobile.database.model.DaoSession;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class DatabaseModule {
@Provides
@Singleton
DatabaseHelper provideDatabaseHelper(Context context) {
return new DatabaseHelper(context);
}
@Provides
@Singleton
DaoSession provideDatabaseSession(DatabaseHelper helper) {
return new DaoMaster(helper.getWritableDatabase()).newSession();
}
@Provides
@Singleton
ChannelRecordDao provideChannelDatabase(DaoSession session) {
return session.getChannelRecordDao();
}
}
package com.android.mobile.dependencies.module;
import com.android.mobile.security.TrustStore;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.concurrent.TimeUnit;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import dagger.Module;
import dagger.Provides;
import okhttp3.OkHttpClient;
@Module
public class NetworkModule {
private SSLSocketFactory sslSocketFactory;
private X509TrustManager trustManager;
public NetworkModule(TrustStore trustStore) {
try {
TrustManager[] trustManagers = getTrustManager(trustStore);
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, trustManagers, null);
trustManager = (X509TrustManager) trustManagers[0];
sslSocketFactory = context.getSocketFactory();
} catch (NoSuchAlgorithmException | KeyManagementException e ){
throw new AssertionError(e);
}
}
@Provides
@Singleton
@Named("TLS")
OkHttpClient provideSecureHttpClient() {
return new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.sslSocketFactory(sslSocketFactory, trustManager)
.hostnameVerifier(HttpsURLConnection.getDefaultHostnameVerifier())
.build();
}
public TrustManager[] getTrustManager(TrustStore trustStore) {
try {
InputStream keyStoreInputStream = trustStore.getKeyStoreInputStream();
KeyStore keyStore = KeyStore.getInstance("BKS");
keyStore.load(keyStoreInputStream, trustStore.getKeyStorePassword().toCharArray());
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509");
trustManagerFactory.init(keyStore);
return trustManagerFactory.getTrustManagers();
} catch (KeyStoreException | CertificateException | IOException | NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
}
}
package com.android.mobile.dependencies.module;
import com.android.mobile.api.controller.AccountController;
import com.android.mobile.api.controller.ChannelController;
import javax.inject.Named;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
@Module
public class RetrofitModule {
private String url;
public RetrofitModule(String url) {
this.url = url;
}
@Provides
@Singleton
@Named("TLSConnection")
Retrofit provideSecureRetrofit(@Named("TLS") OkHttpClient okHttpClient) {
return new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();
}
@Provides
@Singleton
AccountController provideAccountController(@Named("TLSConnection") Retrofit retrofit) {
return new AccountController(retrofit);
}
@Provides
@Singleton
ChannelController provideChannelController(@Named("TLSConnection") Retrofit retrofit) {
return new ChannelController(retrofit);
}
}
package com.android.mobile.exception;
import java.io.IOException;
public class InvalidIdentifierException extends IOException {
public InvalidIdentifierException(String message) {
super(message);
}
}
package com.android.mobile.exception;
import java.io.IOException;
public class NonSuccessfulResponseException extends IOException {
public NonSuccessfulResponseException(String detailMessage) {
super(detailMessage);
}
}
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.mobile.player;
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
import com.google.android.exoplayer.MediaCodecSelector;
import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.audio.AudioCapabilities;
import com.google.android.exoplayer.extractor.Extractor;
import com.google.android.exoplayer.extractor.ExtractorSampleSource;
import com.google.android.exoplayer.extractor.ts.PtsTimestampAdjuster;
import com.google.android.exoplayer.extractor.ts.TsExtractor;
import com.google.android.exoplayer.text.TextTrackRenderer;
import com.google.android.exoplayer.upstream.Allocator;
import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DefaultAllocator;
import com.google.android.exoplayer.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer.upstream.DefaultHttpDataSource;
import com.google.android.exoplayer.upstream.DefaultUriDataSource;
import android.content.Context;
import android.media.AudioManager;
import android.media.MediaCodec;
import android.net.Uri;
import android.os.Handler;
/**
* A {@link Player.RendererBuilder} for streams that can be read using an {@link Extractor}.
*/
public class ExtractorRendererBuilder implements Player.RendererBuilder {
private static final int BUFFER_SEGMENT_SIZE = 64 * 1024;
private static final int BUFFER_SEGMENT_COUNT = 256;
private static final int READ_TIMEOUT = 30 * 1000;
private static final int CONNECTION_TIMEOUT = 30 * 1000;
private final Context context;
private final String userAgent;
private final Uri uri;
public ExtractorRendererBuilder(Context context, String userAgent, Uri uri) {
this.context = context;
this.userAgent = userAgent;
this.uri = uri;
}
@Override
public void buildRenderers(Player player) {
Allocator allocator = new DefaultAllocator(BUFFER_SEGMENT_SIZE);
Handler mainHandler = player.getMainHandler();
// Build the video and audio renderers.
DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter(mainHandler, null);
// DataSource dataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
// change timeouts from 8000 to 30000 @equa1s
DataSource dataSource = new DefaultUriDataSource(context, bandwidthMeter,
new DefaultHttpDataSource(userAgent, null, null, CONNECTION_TIMEOUT, READ_TIMEOUT, false));
TsExtractor tsExtractor = new TsExtractor(new PtsTimestampAdjuster(0));
ExtractorSampleSource sampleSource = new ExtractorSampleSource(uri, dataSource, allocator,
BUFFER_SEGMENT_COUNT * BUFFER_SEGMENT_SIZE, mainHandler, player, 0, tsExtractor);
MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context,
sampleSource, MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000,
mainHandler, player, 50);
MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource,
MediaCodecSelector.DEFAULT, null, true, mainHandler, player,
AudioCapabilities.getCapabilities(context), AudioManager.STREAM_MUSIC);
TrackRenderer textRenderer = new TextTrackRenderer(sampleSource, player,
mainHandler.getLooper());
// Invoke the addCallback.
TrackRenderer[] renderers = new TrackRenderer[Player.RENDERER_COUNT];
renderers[Player.TYPE_VIDEO] = videoRenderer;
renderers[Player.TYPE_AUDIO] = audioRenderer;
renderers[Player.TYPE_TEXT] = textRenderer;
player.onRenderers(renderers, bandwidthMeter);
}
@Override
public void cancel() {
// Do nothing.
}
}
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.mobile.player;
import com.google.android.exoplayer.DefaultLoadControl;
import com.google.android.exoplayer.LoadControl;
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
import com.google.android.exoplayer.MediaCodecSelector;
import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.audio.AudioCapabilities;
import com.google.android.exoplayer.hls.DefaultHlsTrackSelector;
import com.google.android.exoplayer.hls.HlsChunkSource;
import com.google.android.exoplayer.hls.HlsMasterPlaylist;
import com.google.android.exoplayer.hls.HlsPlaylist;
import com.google.android.exoplayer.hls.HlsPlaylistParser;
import com.google.android.exoplayer.hls.HlsSampleSource;
import com.google.android.exoplayer.hls.PtsTimestampAdjusterProvider;
import com.google.android.exoplayer.metadata.MetadataTrackRenderer;
import com.google.android.exoplayer.metadata.id3.Id3Frame;
import com.google.android.exoplayer.metadata.id3.Id3Parser;
import com.google.android.exoplayer.text.TextTrackRenderer;
import com.google.android.exoplayer.text.eia608.Eia608TrackRenderer;
import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DefaultAllocator;
import com.google.android.exoplayer.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer.upstream.DefaultUriDataSource;
import com.google.android.exoplayer.util.ManifestFetcher;
import com.google.android.exoplayer.util.ManifestFetcher.ManifestCallback;
import android.content.Context;
import android.media.AudioManager;
import android.media.MediaCodec;
import android.os.Handler;
import java.io.IOException;
import java.util.List;
/**
* A {@link Player.RendererBuilder} for HLS.
*/
public class HlsRendererBuilder implements Player.RendererBuilder {
private static final int BUFFER_SEGMENT_SIZE = 64 * 1024;
private static final int MAIN_BUFFER_SEGMENTS = 254;
private static final int AUDIO_BUFFER_SEGMENTS = 54;
private static final int TEXT_BUFFER_SEGMENTS = 2;
private final Context context;
private final String userAgent;
private final String url;
private AsyncRendererBuilder currentAsyncBuilder;
public HlsRendererBuilder(Context context, String userAgent, String url) {
this.context = context;
this.userAgent = userAgent;
this.url = url;
}
@Override
public void buildRenderers(Player player) {
currentAsyncBuilder = new AsyncRendererBuilder(context, userAgent, url, player);
currentAsyncBuilder.init();
}
@Override
public void cancel() {
if (currentAsyncBuilder != null) {
currentAsyncBuilder.cancel();
currentAsyncBuilder = null;
}
}
private static final class AsyncRendererBuilder implements ManifestCallback<HlsPlaylist> {
private final Context context;
private final String userAgent;
private final Player player;
private final ManifestFetcher<HlsPlaylist> playlistFetcher;
private boolean canceled;
public AsyncRendererBuilder(Context context, String userAgent, String url, Player player) {
this.context = context;
this.userAgent = userAgent;
this.player = player;
HlsPlaylistParser parser = new HlsPlaylistParser();
playlistFetcher = new ManifestFetcher<>(url, new DefaultUriDataSource(context, userAgent),
parser);
}
public void init() {
playlistFetcher.singleLoad(player.getMainHandler().getLooper(), this);
}
public void cancel() {
canceled = true;
}
@Override
public void onSingleManifestError(IOException e) {
if (canceled) {
return;
}
player.onRenderersError(e);
}
@Override
public void onSingleManifest(HlsPlaylist manifest) {
if (canceled) {
return;
}
Handler mainHandler = player.getMainHandler();
LoadControl loadControl = new DefaultLoadControl(new DefaultAllocator(BUFFER_SEGMENT_SIZE));
DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
PtsTimestampAdjusterProvider timestampAdjusterProvider = new PtsTimestampAdjusterProvider();
boolean haveSubtitles = false;
boolean haveAudios = false;
if (manifest instanceof HlsMasterPlaylist) {
HlsMasterPlaylist masterPlaylist = (HlsMasterPlaylist) manifest;
haveSubtitles = !masterPlaylist.subtitles.isEmpty();
haveAudios = !masterPlaylist.audios.isEmpty();
}
// Build the video/id3 renderers.
DataSource dataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
HlsChunkSource chunkSource = new HlsChunkSource(true /* isMaster */, dataSource, manifest,
DefaultHlsTrackSelector.newDefaultInstance(context), bandwidthMeter,
timestampAdjusterProvider, HlsChunkSource.ADAPTIVE_MODE_SPLICE);
HlsSampleSource sampleSource = new HlsSampleSource(chunkSource, loadControl,
MAIN_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, Player.TYPE_VIDEO);
MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context,
sampleSource, MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT,
5000, mainHandler, player, 50);
MetadataTrackRenderer<List<Id3Frame>> id3Renderer = new MetadataTrackRenderer<>(
sampleSource, new Id3Parser(), player, mainHandler.getLooper());
// Build the audio renderer.
MediaCodecAudioTrackRenderer audioRenderer;
if (haveAudios) {
DataSource audioDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
HlsChunkSource audioChunkSource = new HlsChunkSource(false /* isMaster */, audioDataSource,
manifest, DefaultHlsTrackSelector.newAudioInstance(), bandwidthMeter,
timestampAdjusterProvider, HlsChunkSource.ADAPTIVE_MODE_SPLICE);
HlsSampleSource audioSampleSource = new HlsSampleSource(audioChunkSource, loadControl,
AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player,
Player.TYPE_AUDIO);
audioRenderer = new MediaCodecAudioTrackRenderer(
new SampleSource[] {sampleSource, audioSampleSource}, MediaCodecSelector.DEFAULT, null,
true, player.getMainHandler(), player, AudioCapabilities.getCapabilities(context),
AudioManager.STREAM_MUSIC);
} else {
audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource,
MediaCodecSelector.DEFAULT, null, true, player.getMainHandler(), player,
AudioCapabilities.getCapabilities(context), AudioManager.STREAM_MUSIC);
}
// Build the text renderer.
TrackRenderer textRenderer;
if (haveSubtitles) {
DataSource textDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
HlsChunkSource textChunkSource = new HlsChunkSource(false /* isMaster */, textDataSource,
manifest, DefaultHlsTrackSelector.newSubtitleInstance(), bandwidthMeter,
timestampAdjusterProvider, HlsChunkSource.ADAPTIVE_MODE_SPLICE);
HlsSampleSource textSampleSource = new HlsSampleSource(textChunkSource, loadControl,
TEXT_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, Player.TYPE_TEXT);
textRenderer = new TextTrackRenderer(textSampleSource, player, mainHandler.getLooper());
} else {
textRenderer = new Eia608TrackRenderer(sampleSource, player, mainHandler.getLooper());
}
TrackRenderer[] renderers = new TrackRenderer[Player.RENDERER_COUNT];
renderers[Player.TYPE_VIDEO] = videoRenderer;
renderers[Player.TYPE_AUDIO] = audioRenderer;
renderers[Player.TYPE_METADATA] = id3Renderer;
renderers[Player.TYPE_TEXT] = textRenderer;
player.onRenderers(renderers, bandwidthMeter);
}
}
}
package com.android.mobile.security;
import android.content.Context;
import com.android.mobile.R;
import java.io.InputStream;
public class TelevisionTrustStore implements TrustStore {
private final Context context;
public TelevisionTrustStore(Context context) {
this.context = context;
}
@Override
public InputStream getKeyStoreInputStream() {
return context.getResources().openRawResource(R.raw.television);
}
@Override
public String getKeyStorePassword() {
return "whisper";
}
}
package com.android.mobile.security;
import java.io.InputStream;
public interface TrustStore {
InputStream getKeyStoreInputStream();
String getKeyStorePassword();
}
package com.android.mobile.ui;
public interface AutoHideInterface {
void reset();
void show();
void hide();
}
package com.android.mobile.ui;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import java.util.TimerTask;
public class AutoHideTimerTask extends TimerTask {
private static final String TAG = AutoHideView.class.getSimpleName();
private Handler handler = new Handler(Looper.getMainLooper());
private View mView;
private boolean isAnimate = false;
private Animation animation;
public AutoHideTimerTask(View view) {
this(view, false);
}
public AutoHideTimerTask(View view, boolean isAnimate) {
this.mView = view;
if (isAnimate) {
animation = AnimationUtils.loadAnimation(view.getContext(), android.R.anim.fade_out);
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {}
@Override
public void onAnimationEnd(Animation animation) {
mView.setVisibility(View.GONE);
}
@Override
public void onAnimationRepeat(Animation animation) {}
});
}
this.isAnimate = isAnimate;
}
@Override
public void run() {
hide();
}
private void hide() {
handler.post(new Runnable() {
@Override
public void run() {
if (isAnimate) {
mView.startAnimation(animation);
} else {
mView.setVisibility(View.GONE);
}
}
});
}
}
package com.android.mobile.ui;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
import com.android.mobile.R;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class AutoHideView extends FrameLayout implements AutoHideInterface {
private final static String TAG = AutoHideView.class.getSimpleName();
private final int DEFAULT_TIME = 3000;
private ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
private AutoHideTimerTask task = null;
private boolean isAnimate = false;
private Animation mFadeIn;
private Animation mFadeOut;
private int time;
public AutoHideView(Context context) {
super(context);
task = new AutoHideTimerTask(this);
service.schedule(task, DEFAULT_TIME, TimeUnit.MILLISECONDS);
}
public AutoHideView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.AutoHideView, 0, 0);
try {
isAnimate = a.getBoolean(R.styleable.AutoHideView_isAnimate, false);
time = a.getInteger(R.styleable.AutoHideView_time, DEFAULT_TIME);
} finally {
a.recycle();
}
if (isAnimate) {
mFadeIn = AnimationUtils.loadAnimation(context, android.R.anim.fade_in);
mFadeIn.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {}
@Override
public void onAnimationEnd(Animation animation) {
setVisibility(VISIBLE);
}
@Override
public void onAnimationRepeat(Animation animation) {}
});
mFadeOut = AnimationUtils.loadAnimation(context, android.R.anim.fade_out);
mFadeOut.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
setVisibility(GONE);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
task = new AutoHideTimerTask(this, isAnimate);
service.schedule(task, time, TimeUnit.MILLISECONDS);
}
@Override
public void reset() {
if (service != null) {
service.shutdown();
service.shutdownNow();
service = null;
}
service = Executors.newSingleThreadScheduledExecutor();
task = new AutoHideTimerTask(this, isAnimate);
service.schedule(task, time, TimeUnit.MILLISECONDS);
}
@Override
public void show() {
if (isAnimate) {
startAnimation(mFadeIn);
} else {
setVisibility(VISIBLE);
}
reset();
}
@Override
public void hide() {
if (service != null) {
service.shutdown();
service.shutdownNow();
service = null;
}
if (isAnimate) {
startAnimation(mFadeOut);
} else {
setVisibility(GONE);
}
}
}
package com.android.mobile.ui;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.CardView;
import android.util.AttributeSet;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.android.mobile.R;
import com.android.mobile.database.model.ChannelRecord;
import com.android.mobile.util.ViewUtil;
import butterknife.BindView;
import butterknife.ButterKnife;
public class BaseCardView extends CardView implements BindableCardView {
private ChannelRecord channel;
@BindView(R.id.poster) public ImageView poster;
@BindView(R.id.title) public TextView title;
@BindView(R.id.description) public TextView description;
@BindView(R.id.container) public RelativeLayout container;
public BaseCardView(Context context) {
super(context);
}
public BaseCardView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
ButterKnife.bind(this);
}
@Override
public void bind(@NonNull ChannelRecord channel, boolean isSelected, int position) {
ViewUtil.loadImage(getContext(), poster, channel.getBgImage());
setBackground(isSelected);
title.setText(channel.getTitle());
description.setText(channel.getCategory());
}
@Override
public void unbind() {
if (channel != null) {
channel = null;
}
}
private void setBackground(boolean isSelected) {
if (isSelected) {
ViewUtil.setBackgroundColor(getContext(), container, R.color.blue_600);
} else {
ViewUtil.setBackgroundColor(getContext(), container, R.color.grey_600);
}
}
}
package com.android.mobile.ui;
import android.support.annotation.NonNull;
import com.android.mobile.database.model.ChannelRecord;
interface BindableCardView extends Unbindable {
void bind(@NonNull ChannelRecord channel, boolean isSelected, int position);
}
package com.android.mobile.ui;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.util.AttributeSet;
import android.widget.ProgressBar;
import com.android.mobile.R;
public class LoadingView extends ProgressBar {
private static final int DEFAULT_COLOR = Color.WHITE;
public LoadingView(Context context) {
super(context);
}
public LoadingView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.LoadingView, 0, 0);
int color;
try {
color = a.getColor(R.styleable.LoadingView_color_filter, DEFAULT_COLOR);
} finally {
a.recycle();
}
getIndeterminateDrawable().setColorFilter(color, PorterDuff.Mode.SRC_IN);
}
public void setVisibility(boolean visibility) {
if (visibility) {
show();
} else {
hide();
}
}
private void show() {
setVisibility(VISIBLE);
}
private void hide() {
setVisibility(GONE);
}
}
package com.android.mobile.ui;
import android.content.Context;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import com.android.mobile.ApplicationContext;
import com.android.mobile.database.model.ChannelRecord;
import com.android.mobile.dependencies.Injector;
import com.android.mobile.util.AnimationUtil;
import javax.inject.Inject;
public class ScalableCardView extends BaseCardView {
@Inject AnimationUtil mAnimationUtil;
public ScalableCardView(Context context) {
super(context);
}
public ScalableCardView(Context context, AttributeSet attrs) {
super(context, attrs);
Injector.inject(this);
}
@Override
public void bind(@NonNull ChannelRecord channel, boolean isSelected, int position) {
super.bind(channel, isSelected, position);
setScale(isSelected);
}
public void setScale(boolean isScale) {
if (isScale) {
mAnimationUtil.zoomIn(this);
} else {
mAnimationUtil.zoomOut(this);
}
}
}
package com.android.mobile.ui;
public interface Unbindable {
void unbind();
}
package com.android.mobile.ui.adapters;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.mobile.R;
import com.android.mobile.util.ViewUtil;
import java.util.List;
public class BaseListAdapter extends TrackSelectionAdapter<BaseListAdapter.ViewHolder> {
class ViewHolder extends TrackSelectionAdapter.ViewHolder {
private TextView mTextView;
public ViewHolder(View itemView) {
super(itemView);
this.mTextView = (TextView) itemView.findViewById(R.id.item);
}
public TextView getTextItem() {
return mTextView;
}
public LinearLayout getItem() {
return (LinearLayout) itemView;
}
}
private Context context;
private List<String> data;
private LayoutInflater inflater;
public BaseListAdapter(Context context, List<String> data) {
setHasStableIds(true);
this.context = context;
this.data = data;
this.inflater = LayoutInflater.from(context);
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(inflater.inflate(R.layout.account_menu_item, parent, false));
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
LinearLayout item = holder.getItem();
holder.getTextItem().setText(data.get(position));
if (item.isSelected()) {
ViewUtil.setBackgroundColor(context, item, R.color.amber_900);
} else {
ViewUtil.setBackgroundColor(context, item, R.color.grey_800);
}
}
@Override
public int getItemCount() {
return data != null ? data.size() : 0;
}
@Override
public int getItemViewType(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
}
package com.android.mobile.ui.adapters;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.android.mobile.R;
import com.android.mobile.database.model.ChannelRecord;
import com.android.mobile.ui.ScalableCardView;
import java.util.List;
public class GridTrackSelectionAdapter extends TrackSelectionAdapter<GridTrackSelectionAdapter.ViewHolder> {
private LayoutInflater inflater;
private List<ChannelRecord> channels;
public GridTrackSelectionAdapter(@NonNull Context context, @Nullable List<ChannelRecord> channels) {
this.inflater = LayoutInflater.from(context);
this.channels = channels;
}
class ViewHolder extends TrackSelectionAdapter.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
}
public ScalableCardView getView() {
return (ScalableCardView) itemView;
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
ScalableCardView view = (ScalableCardView)
inflater.inflate(R.layout.scaled_card_view_item, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, int index) {
super.onBindViewHolder(viewHolder, index);
ChannelRecord record = channels.get(index);
viewHolder.getView().bind(record, getFocusedItem() == index, index);
}
@Override
public int getItemCount() {
return channels != null ? channels.size() : 0;
}
@Override
public int getItemViewType(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public void onViewDetachedFromWindow(ViewHolder holder) {
super.onViewDetachedFromWindow(holder);
holder.getView().clearAnimation();
}
public void swap(List<ChannelRecord> channels) {
this.channels = channels;
notifyDataSetChanged();
}
}
package com.android.mobile.ui.adapters;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.android.mobile.R;
import com.android.mobile.database.model.ChannelRecord;
import com.android.mobile.ui.ScalableCardView;
import java.util.List;
public class LinearTrackSelectionAdapter extends TrackSelectionAdapter<LinearTrackSelectionAdapter.ViewHolder> {
private LayoutInflater mLayoutInflater;
private List<ChannelRecord> mChannels;
class ViewHolder extends TrackSelectionAdapter.ViewHolder {
ViewHolder(View itemView) {
super(itemView);
}
public ScalableCardView getView() {
return (ScalableCardView) itemView;
}
}
public LinearTrackSelectionAdapter(Context context, List<ChannelRecord> mChannels) {
this.mChannels = mChannels;
this.mLayoutInflater = LayoutInflater.from(context);
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final ScalableCardView view = (ScalableCardView) mLayoutInflater.inflate(R.layout.scaled_card_view_item, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
super.onBindViewHolder(viewHolder, position);
ScalableCardView view = viewHolder.getView();
view.bind(mChannels.get(position), view.isSelected(), position);
}
@Override
public void onViewRecycled(ViewHolder holder) {
super.onViewRecycled(holder);
holder.getView().unbind();
}
@Override
public int getItemCount() {
return mChannels != null ? mChannels.size() : 0;
}
@Override
public int getItemViewType(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
public List<ChannelRecord> getChannels() {
return mChannels;
}
public void swap(List<ChannelRecord> channels) {
this.mChannels = channels;
notifyDataSetChanged();
}
}
package com.android.mobile.ui.adapters;
import android.support.v7.widget.RecyclerView;
import android.view.View;
public abstract class TrackSelectionAdapter<VH extends TrackSelectionAdapter.ViewHolder> extends RecyclerView.Adapter<VH> {
private int focused = 0;
TrackSelectionAdapter() {
setHasStableIds(true);
}
public boolean tryMoveSelection(RecyclerView mRecyclerView, int direction) {
int tryFocusItem = focused + direction;
if (tryFocusItem >= 0 && tryFocusItem < getItemCount()) {
notifyItemChanged(focused);
focused = tryFocusItem;
mRecyclerView.smoothScrollToPosition(focused);
notifyItemChanged(focused);
return true;
}
return false;
}
@Override
public void onBindViewHolder(VH viewHolder, int i) {
viewHolder.itemView.setSelected(focused == i);
}
public int getFocusedItem() {
return focused;
}
public void setFocused(Integer focused) {
notifyItemChanged(this.focused);
this.focused = focused;
notifyItemChanged(focused);
}
public class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
notifyItemChanged(focused);
focused = getLayoutPosition();
notifyItemChanged(focused);
}
});
}
public View getView() {
return itemView;
}
}
}
package com.android.mobile.ui.animation;
import android.view.View;
import com.daimajia.androidanimations.library.YoYo;
import com.daimajia.androidanimations.library.fading_entrances.FadeInAnimator;
import com.daimajia.androidanimations.library.fading_exits.FadeOutAnimator;
public class Fade {
private long duration = 500;
private FadeInAnimator fadeIn;
private FadeOutAnimator fadeOut;
public Fade() {
this.fadeIn = new FadeInAnimator();
this.fadeOut = new FadeOutAnimator();
}
public void setDuration(long duration) {
this.duration = duration;
}
public long getDuration() {
return duration;
}
public void fadeIn(View view) {
YoYo.with(fadeIn).duration(duration).playOn(view);
}
public void fadeOut(View view) {
YoYo.with(fadeOut).duration(duration).playOn(view);
}
}
package com.android.mobile.ui.animation;
import android.support.v4.view.ViewCompat;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;
public class Zoom {
private static final float CENTER_PIVOT = .5f;
private static final float START_X_SCALE = 1f;
private static final float START_Y_SCALE = 1f;
private static final float END_X_SCALE = 1.1f;
private static final float END_Y_SCALE = 1.2f;
private static final float TRANSLATION_IN_Z = 2f;
private static final float TRANSLATION_OUT_Z = 1f;
private static final long DURATION_OUT = 250;
private static final long DURATION_IN = 350;
public Zoom() {
}
public void zoomIn(View view) {
Animation scaleIn = new ScaleAnimation(START_X_SCALE, END_X_SCALE, START_Y_SCALE, END_Y_SCALE,
Animation.RELATIVE_TO_SELF, CENTER_PIVOT, Animation.RELATIVE_TO_SELF, CENTER_PIVOT);
scaleIn.setFillAfter(true);
scaleIn.setDuration(DURATION_IN);
view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
ViewCompat.setTranslationZ(view, TRANSLATION_IN_Z);
view.startAnimation(scaleIn);
}
public void zoomOut(View view) {
Animation scaleOut = new ScaleAnimation(END_X_SCALE, START_X_SCALE, END_Y_SCALE, START_Y_SCALE,
Animation.RELATIVE_TO_SELF, CENTER_PIVOT, Animation.RELATIVE_TO_SELF, CENTER_PIVOT);
scaleOut.setFillAfter(true);
scaleOut.setDuration(DURATION_OUT);
view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
ViewCompat.setTranslationZ(view, TRANSLATION_OUT_Z);
view.startAnimation(scaleOut);
}
}
package com.android.mobile.ui.divider;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.annotation.DimenRes;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.RecyclerView;
import android.view.View;
/**
* @author yqritc on 2015/01/08.
*/
public class HorizontalDividerItemDecoration extends FlexibleDividerDecoration {
private MarginProvider mMarginProvider;
protected HorizontalDividerItemDecoration(Builder builder) {
super(builder);
mMarginProvider = builder.mMarginProvider;
}
@Override
protected Rect getDividerBound(int position, RecyclerView parent, View child) {
Rect bounds = new Rect(0, 0, 0, 0);
int transitionX = (int) ViewCompat.getTranslationX(child);
int transitionY = (int) ViewCompat.getTranslationY(child);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
bounds.left = parent.getPaddingLeft() +
mMarginProvider.dividerLeftMargin(position, parent) + transitionX;
bounds.right = parent.getWidth() - parent.getPaddingRight() -
mMarginProvider.dividerRightMargin(position, parent) + transitionX;
int dividerSize = getDividerSize(position, parent);
boolean isReverseLayout = isReverseLayout(parent);
if (mDividerType == DividerType.DRAWABLE) {
// set top and bottom position of divider
if (isReverseLayout) {
bounds.bottom = child.getTop() - params.topMargin + transitionY;
bounds.top = bounds.bottom - dividerSize;
} else {
bounds.top = child.getBottom() + params.bottomMargin + transitionY;
bounds.bottom = bounds.top + dividerSize;
}
} else {
// set center point of divider
int halfSize = dividerSize / 2;
if (isReverseLayout) {
bounds.top = child.getTop() - params.topMargin - halfSize + transitionY;
} else {
bounds.top = child.getBottom() + params.bottomMargin + halfSize + transitionY;
}
bounds.bottom = bounds.top;
}
if (mPositionInsideItem) {
if (isReverseLayout) {
bounds.top += dividerSize;
bounds.bottom += dividerSize;
} else {
bounds.top -= dividerSize;
bounds.bottom -= dividerSize;
}
}
return bounds;
}
@Override
protected void setItemOffsets(Rect outRect, int position, RecyclerView parent) {
if (mPositionInsideItem) {
outRect.set(0, 0, 0, 0);
return;
}
if (isReverseLayout(parent)) {
outRect.set(0, getDividerSize(position, parent), 0, 0);
} else {
outRect.set(0, 0, 0, getDividerSize(position, parent));
}
}
private int getDividerSize(int position, RecyclerView parent) {
if (mPaintProvider != null) {
return (int) mPaintProvider.dividerPaint(position, parent).getStrokeWidth();
} else if (mSizeProvider != null) {
return mSizeProvider.dividerSize(position, parent);
} else if (mDrawableProvider != null) {
Drawable drawable = mDrawableProvider.drawableProvider(position, parent);
return drawable.getIntrinsicHeight();
}
throw new RuntimeException("failed to get size");
}
/**
* Interface for controlling divider margin
*/
public interface MarginProvider {
/**
* Returns left margin of divider.
*
* @param position Divider position (or group index for GridLayoutManager)
* @param parent RecyclerView
* @return left margin
*/
int dividerLeftMargin(int position, RecyclerView parent);
/**
* Returns right margin of divider.
*
* @param position Divider position (or group index for GridLayoutManager)
* @param parent RecyclerView
* @return right margin
*/
int dividerRightMargin(int position, RecyclerView parent);
}
public static class Builder extends FlexibleDividerDecoration.Builder<Builder> {
private MarginProvider mMarginProvider = new MarginProvider() {
@Override
public int dividerLeftMargin(int position, RecyclerView parent) {
return 0;
}
@Override
public int dividerRightMargin(int position, RecyclerView parent) {
return 0;
}
};
public Builder(Context context) {
super(context);
}
public Builder margin(final int leftMargin, final int rightMargin) {
return marginProvider(new MarginProvider() {
@Override
public int dividerLeftMargin(int position, RecyclerView parent) {
return leftMargin;
}
@Override
public int dividerRightMargin(int position, RecyclerView parent) {
return rightMargin;
}
});
}
public Builder margin(int horizontalMargin) {
return margin(horizontalMargin, horizontalMargin);
}
public Builder marginResId(@DimenRes int leftMarginId, @DimenRes int rightMarginId) {
return margin(mResources.getDimensionPixelSize(leftMarginId),
mResources.getDimensionPixelSize(rightMarginId));
}
public Builder marginResId(@DimenRes int horizontalMarginId) {
return marginResId(horizontalMarginId, horizontalMarginId);
}
public Builder marginProvider(MarginProvider provider) {
mMarginProvider = provider;
return this;
}
public HorizontalDividerItemDecoration build() {
checkBuilderParams();
return new HorizontalDividerItemDecoration(this);
}
}
}
package com.android.mobile.ui.divider;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.annotation.DimenRes;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.RecyclerView;
import android.view.View;
/**
* @author yqritc on 2015/01/08.
*/
public class VerticalDividerItemDecoration extends FlexibleDividerDecoration {
private MarginProvider mMarginProvider;
protected VerticalDividerItemDecoration(Builder builder) {
super(builder);
mMarginProvider = builder.mMarginProvider;
}
@Override
protected Rect getDividerBound(int position, RecyclerView parent, View child) {
Rect bounds = new Rect(0, 0, 0, 0);
int transitionX = (int) ViewCompat.getTranslationX(child);
int transitionY = (int) ViewCompat.getTranslationY(child);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
bounds.top = parent.getPaddingTop() +
mMarginProvider.dividerTopMargin(position, parent) + transitionY;
bounds.bottom = parent.getHeight() - parent.getPaddingBottom() -
mMarginProvider.dividerBottomMargin(position, parent) + transitionY;
int dividerSize = getDividerSize(position, parent);
boolean isReverseLayout = isReverseLayout(parent);
if (mDividerType == DividerType.DRAWABLE) {
// set left and right position of divider
if (isReverseLayout) {
bounds.right = child.getLeft() - params.leftMargin + transitionX;
bounds.left = bounds.right - dividerSize;
} else {
bounds.left = child.getRight() + params.rightMargin + transitionX;
bounds.right = bounds.left + dividerSize;
}
} else {
// set center point of divider
int halfSize = dividerSize / 2;
if (isReverseLayout) {
bounds.left = child.getLeft() - params.leftMargin - halfSize + transitionX;
} else {
bounds.left = child.getRight() + params.rightMargin + halfSize + transitionX;
}
bounds.right = bounds.left;
}
if (mPositionInsideItem) {
if (isReverseLayout) {
bounds.left += dividerSize;
bounds.right += dividerSize;
} else {
bounds.left -= dividerSize;
bounds.right -= dividerSize;
}
}
return bounds;
}
@Override
protected void setItemOffsets(Rect outRect, int position, RecyclerView parent) {
if (mPositionInsideItem) {
outRect.set(0, 0, 0, 0);
return;
}
if (isReverseLayout(parent)) {
outRect.set(getDividerSize(position, parent), 0, 0, 0);
} else {
outRect.set(0, 0, getDividerSize(position, parent), 0);
}
}
private int getDividerSize(int position, RecyclerView parent) {
if (mPaintProvider != null) {
return (int) mPaintProvider.dividerPaint(position, parent).getStrokeWidth();
} else if (mSizeProvider != null) {
return mSizeProvider.dividerSize(position, parent);
} else if (mDrawableProvider != null) {
Drawable drawable = mDrawableProvider.drawableProvider(position, parent);
return drawable.getIntrinsicWidth();
}
throw new RuntimeException("failed to get size");
}
/**
* Interface for controlling divider margin
*/
public interface MarginProvider {
/**
* Returns top margin of divider.
*
* @param position Divider position (or group index for GridLayoutManager)
* @param parent RecyclerView
* @return top margin
*/
int dividerTopMargin(int position, RecyclerView parent);
/**
* Returns bottom margin of divider.
*
* @param position Divider position (or group index for GridLayoutManager)
* @param parent RecyclerView
* @return bottom margin
*/
int dividerBottomMargin(int position, RecyclerView parent);
}
public static class Builder extends FlexibleDividerDecoration.Builder<Builder> {
private MarginProvider mMarginProvider = new MarginProvider() {
@Override
public int dividerTopMargin(int position, RecyclerView parent) {
return 0;
}
@Override
public int dividerBottomMargin(int position, RecyclerView parent) {
return 0;
}
};
public Builder(Context context) {
super(context);
}
public Builder margin(final int topMargin, final int bottomMargin) {
return marginProvider(new MarginProvider() {
@Override
public int dividerTopMargin(int position, RecyclerView parent) {
return topMargin;
}
@Override
public int dividerBottomMargin(int position, RecyclerView parent) {
return bottomMargin;
}
});
}
public Builder margin(int verticalMargin) {
return margin(verticalMargin, verticalMargin);
}
public Builder marginResId(@DimenRes int topMarginId, @DimenRes int bottomMarginId) {
return margin(mResources.getDimensionPixelSize(topMarginId),
mResources.getDimensionPixelSize(bottomMarginId));
}
public Builder marginResId(@DimenRes int verticalMarginId) {
return marginResId(verticalMarginId, verticalMarginId);
}
public Builder marginProvider(MarginProvider provider) {
mMarginProvider = provider;
return this;
}
public VerticalDividerItemDecoration build() {
checkBuilderParams();
return new VerticalDividerItemDecoration(this);
}
}
}
package com.android.mobile.ui.fragments;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.android.mobile.R;
import com.android.mobile.ui.LoadingView;
import com.android.mobile.ui.adapters.BaseListAdapter;
import com.android.mobile.util.ApplicationProvider;
import com.android.mobile.util.FocusHandler;
import java.util.Arrays;
import butterknife.BindArray;
import butterknife.BindView;
import butterknife.ButterKnife;
public class AccountFragment extends Fragment implements View.OnKeyListener {
private static final String TAG = AccountFragment.class.getSimpleName();
public static final int ID = 6;
@BindArray(R.array.account_menu_items) public String[] mMenuItems;
@BindView(R.id.menu_recycler_view) public RecyclerView mMenuRecyclerView;
@BindView(R.id.menu_item_details) public FrameLayout mMenuItemDetails;
@BindView(R.id.loading_view) public LoadingView mLoadingView;
public static AccountFragment newInstance(Bundle bundle) {
AccountFragment fragment = new AccountFragment();
if (bundle != null) {
fragment.setArguments(bundle);
}
return fragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.account_fragment, container, false);
ButterKnife.bind(this, view);
return view;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mMenuRecyclerView.setHasFixedSize(true);
mMenuRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
mMenuRecyclerView.setAdapter(new BaseListAdapter(getActivity(), Arrays.asList(mMenuItems)));
mMenuRecyclerView.setOnKeyListener(this);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
addFragment();
}
@Override
public void onResume() {
super.onResume();
FocusHandler.setVisible(ID);
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
boolean isUnique = event.getRepeatCount() == 0;
int direction = 0;
if (isUnique) {
if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
direction = ApplicationProvider.Account.MOVE_UP;
} else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
direction = ApplicationProvider.Account.MOVE_DOWN;
}
getAdapter().tryMoveSelection(mMenuRecyclerView, direction);
replaceFragment();
}
}
return false;
}
private BaseListAdapter getAdapter() {
return (BaseListAdapter) mMenuRecyclerView.getAdapter();
}
private void replaceFragment() {
getFragmentManager().beginTransaction()
.replace(R.id.menu_item_details, DummyFragment.newInstance(getPackage()))
.setCustomAnimations(R.anim.fade_scale_in, R.anim.fade_scale_out)
.commit();
}
private void addFragment() {
getFragmentManager().beginTransaction()
.add(R.id.menu_item_details, DummyFragment.newInstance(getPackage()))
.setCustomAnimations(R.anim.fade_scale_in, R.anim.fade_scale_out)
.commit();
}
private Bundle getPackage() {
Bundle bundle = new Bundle();
bundle.putInt(DummyFragment.DUMMY_KEY, getAdapter().getFocusedItem());
return bundle;
}
}
package com.android.mobile.ui.fragments;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import com.android.mobile.ApplicationContext;
import com.android.mobile.R;
import com.android.mobile.dependencies.Injector;
import com.android.mobile.util.AnimationUtil;
import com.android.mobile.util.Preferences;
import com.android.mobile.util.Util;
import javax.inject.Inject;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class ChangeSerialFragment extends Fragment {
private static final String TAG = ChangeSerialFragment.class.getSimpleName();
public static final int ID = 2;
@BindView(R.id.serial) public EditText mSerial;
@BindView(R.id.save_serial) public Button mSaveSerial;
@Inject AnimationUtil animationUtil;
public static ChangeSerialFragment newInstance(Bundle bundle) {
ChangeSerialFragment instance = new ChangeSerialFragment();
if (bundle != null) {
instance.setArguments(bundle);
}
return instance;
}
public ChangeSerialFragment() {
Injector.inject(this);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.change_serial_fragment, container, false);
ButterKnife.bind(this, view);
return view;
}
@OnClick(R.id.save_serial) public void saveSerial() {
String serial = mSerial.getText().toString();
if (serial.isEmpty()) {
mSerial.setError(getString(R.string.change_serial_fragment__save_serial));
animationUtil.wobble(mSerial);
return;
}
if (!Util.isValidSerial(serial)) {
mSerial.setError(getString(R.string.change_serial_fragment__serial_is_not_valid));
animationUtil.wobble(mSerial);
return;
}
Preferences.setUserIdentifier(getContext(), serial);
getFragmentManager().beginTransaction()
.replace(R.id.container, CheckSerialFragment.newInstance(null))
.addToBackStack(CheckSerialFragment.class.getSimpleName())
.commit();
}
}
package com.android.mobile.ui.fragments;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.RecyclerView;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.widget.Toast;
import com.android.mobile.PlayerActivity;
import com.android.mobile.R;
import com.android.mobile.api.STBResponse;
import com.android.mobile.api.controller.ChannelController;
import com.android.mobile.database.model.ChannelRecord;
import com.android.mobile.dependencies.Injector;
import com.android.mobile.ui.adapters.GridTrackSelectionAdapter;
import com.android.mobile.ui.divider.HorizontalDividerItemDecoration;
import com.android.mobile.ui.divider.VerticalDividerItemDecoration;
import com.android.mobile.ui.snappysmoothscroller.SnapType;
import com.android.mobile.ui.snappysmoothscroller.SnappyGridLayoutManager;
import com.android.mobile.util.ApplicationProvider;
import com.android.mobile.util.FocusHandler;
import com.android.mobile.util.Util;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import butterknife.BindView;
import butterknife.ButterKnife;
public class ChannelsFragment extends Fragment implements ChannelController.Callback {
private static final String TAG = ChannelsFragment.class.getSimpleName();
public static final int ID = 5;
private ProgressDialog progressDialog;
@BindView(R.id.recycler_view) public RecyclerView recyclerView;
private GridTrackSelectionAdapter adapter;
@Inject ChannelController mChannelController;
public static ChannelsFragment newInstance(Bundle bundle) {
ChannelsFragment instance = new ChannelsFragment();
if (bundle != null) {
instance.setArguments(bundle);
}
return instance;
}
public ChannelsFragment() {
Injector.inject(this);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mChannelController.setCallback(this);
mChannelController.getChannels();
}
public void startPlayerActivity(int id) {
setCurrentPlay(id);
Intent intent = new Intent(getActivity(), PlayerActivity.class);
intent.putExtra(PlayerActivity.CHANNEL_ID_EXTRA, id);
startActivity(intent);
getActivity().overridePendingTransition(R.anim.slide_from_left, R.anim.slide_to_right);
}
private void setCurrentPlay(int id) {
ApplicationProvider.setCurrent(id);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.channels_fragment, container, false);
ButterKnife.bind(this, view);
return view;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
recyclerView.setHasFixedSize(true);
recyclerView.addItemDecoration(new VerticalDividerItemDecoration.Builder(getContext())
.sizeResId(R.dimen.divider_vertical_margin)
.colorResId(android.R.color.transparent)
.build());
recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getContext())
.sizeResId(R.dimen.divider_horizontal_margin)
.colorResId(android.R.color.transparent)
.build());
adapter = new GridTrackSelectionAdapter(getActivity(), null);
SnappyGridLayoutManager snappyGridLayoutManager = new SnappyGridLayoutManager(getContext(), ApplicationProvider.COLUMN_COUNT);
snappyGridLayoutManager.setSnapType(SnapType.CENTER);
snappyGridLayoutManager.setSnapInterpolator(new DecelerateInterpolator());
recyclerView.setLayoutManager(snappyGridLayoutManager);
recyclerView.setAdapter(adapter);
recyclerView.setItemViewCacheSize(32);
recyclerView.setDrawingCacheEnabled(true);
recyclerView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
recyclerView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
recyclerView.getItemAnimator().setChangeDuration(5);
recyclerView.getItemAnimator().setMoveDuration(100);
recyclerView.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
boolean isUnique = event.getRepeatCount() == 0;
if (isUnique) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_RIGHT:
return adapter.tryMoveSelection(recyclerView, ApplicationProvider.MOVE_RIGHT);
case KeyEvent.KEYCODE_DPAD_LEFT:
return adapter.tryMoveSelection(recyclerView, ApplicationProvider.MOVE_LEFT);
case KeyEvent.KEYCODE_DPAD_UP:
return adapter.tryMoveSelection(recyclerView, ApplicationProvider.MOVE_UP);
case KeyEvent.KEYCODE_DPAD_DOWN:
return adapter.tryMoveSelection(recyclerView, ApplicationProvider.MOVE_DOWN);
case KeyEvent.KEYCODE_DPAD_CENTER:
startPlayerActivity(adapter.getFocusedItem());
return true;
}
}
}
return false;
}
});
}
@Override
public void onResume() {
super.onResume();
FocusHandler.setVisible(ID);
}
@Override
public void onDestroy() {
super.onDestroy();
dismiss();
}
@Override
public void onRun() {
progressDialog = ProgressDialog.show(getActivity(), getString(R.string.ChannelsFragment__loading),
getString(R.string.ChannelsFragment__wait_please_while_loading_channels));
progressDialog.setCancelable(false);
}
@Override
public void onSuccess(final STBResponse response) {
// FIXME: It's not smart enough @equa1s
new AsyncTask<Void,Void,List<ChannelRecord>>() {
@Override
protected List<ChannelRecord> doInBackground(Void[] params) {
Map<String, String> data = response.getData();
if (data != null && !data.isEmpty()) {
List<ChannelRecord> remoteRecords = new Gson().fromJson(data.get("channels"), new TypeToken<ArrayList<ChannelRecord>>(){}.getType());
if (remoteRecords != null && !remoteRecords.isEmpty()) {
ApplicationProvider.fillCache(remoteRecords);
return remoteRecords;
}
}
return null;
}
@Override
protected void onPostExecute(final List<ChannelRecord> channels) {
super.onPostExecute(channels);
Util.runOnMainThread(new Runnable() {
@Override
public void run() {
if (adapter != null) {
adapter.swap(channels);
}
}
});
dismiss();
}
}.execute();
}
@Override
public void onFailure(Throwable throwable) {
dismiss();
Toast.makeText(getActivity(), throwable.getMessage().substring(0, 50) + "...", Toast.LENGTH_SHORT).show();
}
private void dismiss() {
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.dismiss();
progressDialog = null;
}
}
}
package com.android.mobile.ui.fragments;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.mobile.ApplicationContext;
import com.android.mobile.MainActivity;
import com.android.mobile.R;
import com.android.mobile.api.STBResponse;
import com.android.mobile.api.controller.AccountController;
import com.android.mobile.api.retrofit.service.AccountService;
import com.android.mobile.dependencies.Injector;
import com.android.mobile.ui.LoadingView;
import com.android.mobile.util.APIUtil;
import com.android.mobile.util.AnimationUtil;
import com.android.mobile.util.Preferences;
import com.android.mobile.util.Dialogs;
import com.android.mobile.util.Util;
import com.android.mobile.util.ViewUtil;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class CheckSerialFragment extends Fragment implements AccountController.Callback {
private static final String TAG = CheckSerialFragment.class.getSimpleName();
public static final int ID = 1;
@BindView(R.id.loading_view) public LoadingView mLoadingView;
@BindView(R.id.check_serial_button) public Button mCheckSerial;
@BindView(R.id.change_serial_button) public Button mChangeSerial;
@BindView(R.id.serial) public TextView mSerial;
@BindView(R.id.content) public LinearLayout mContent;
@Inject AccountController mAccountController;
@Inject AnimationUtil animationUtil;
public static CheckSerialFragment newInstance(Bundle bundle) {
CheckSerialFragment instance = new CheckSerialFragment();
if (bundle != null) {
instance.setArguments(bundle);
}
return instance;
}
public CheckSerialFragment() {
Injector.inject(this);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAccountController.setCallback(this);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.check_serial_fragment, container, false);
ButterKnife.bind(this, view);
return view;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mSerial.setText(Preferences.getUserIdentifier(getContext()));
}
@OnClick(R.id.check_serial_button)
public void checkSerial() {
String serial = mSerial.getText().toString();
if (serial.isEmpty()) {
mSerial.setError(getString(R.string.check_serial_fragment__save_serial));
animationUtil.wobble(mSerial);
return;
}
if (!Util.isValidSerial(serial)) {
mSerial.setError(getString(R.string.check_serial_fragment__serial_is_not_valid));
animationUtil.wobble(mSerial);
return;
}
Map<String, String> params = new HashMap<>();
params.put(AccountService.SERIAL, serial);
mAccountController.setUserIdentifier(params);
}
@OnClick(R.id.change_serial_button)
public void changeSerial() {
getFragmentManager().beginTransaction()
.replace(R.id.container, ChangeSerialFragment.newInstance(null))
.addToBackStack(ChangeSerialFragment.class.getSimpleName())
.commit();
}
@Override
public void onRun() {
setLoading(true);
}
@Override
public void onSuccess(STBResponse response) {
setLoading(false);
Log.d(TAG, "onSuccess: " + response.toString());
Map<String, String> data = response.getData();
String isp = data.get("isp");
ViewUtil.setImageDrawable(getActivity(),
(ImageView) getActivity().findViewById(R.id.logotype),
APIUtil.getISPLogo(isp != null ? isp : "0"));
Preferences.setUserIsp(getContext(), isp);
Preferences.setUserIdentifier(getContext(), mSerial.getText().toString());
Activity activity = getActivity();
startActivity(new Intent(activity, MainActivity.class));
activity.finish();
}
@Override
public void onFailure(Throwable throwable) {
setLoading(false);
Log.d(TAG, "onFailure: " + throwable.getMessage());
Dialogs.showDialog(getContext(),
getString(R.string.check_serial_fragment__something_went_wrong),
throwable.getMessage());
mCheckSerial.requestFocus();
}
private void setLoading(boolean isLoading) {
mLoadingView.setVisibility(isLoading);
mContent.setVisibility(isLoading ? View.GONE : View.VISIBLE);
}
}
package com.android.mobile.ui.fragments;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import com.android.mobile.R;
import com.android.mobile.util.Preferences;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class DeviceNotRegisteredFragment extends Fragment {
private static final String TAG = DeviceNotRegisteredFragment.class.getSimpleName();
public static final int ID = 0;
@BindView(R.id.sign_in_button) public Button mSignIn;
@BindView(R.id.sign_up_button) public Button mSignUp;
@BindView(R.id.change_serial) public Button mChangeSerial;
@BindView(R.id.serial_number) public TextView mSerial;
public static DeviceNotRegisteredFragment newInstance(Bundle bundle) {
DeviceNotRegisteredFragment instance = new DeviceNotRegisteredFragment();
if (bundle != null) {
instance.setArguments(bundle);
}
return instance;
}
public DeviceNotRegisteredFragment() {
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.device_not_registered_fragment, container, false);
ButterKnife.bind(this, view);
return view;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mSerial.setText(Preferences.getUserIdentifier(getContext()));
}
@OnClick(R.id.sign_in_button) public void signIn() {
getFragmentManager().beginTransaction()
.replace(R.id.container, SignInFragment.newInstance(null))
.addToBackStack(SignInFragment.class.getSimpleName())
.commit();
}
@OnClick(R.id.sign_up_button) public void signUp() {
getFragmentManager().beginTransaction()
.replace(R.id.container, SignUpFragment.newInstance(null))
.addToBackStack(SignUpFragment.class.getSimpleName())
.commit();
}
@OnClick(R.id.change_serial) public void changeSerial() {
getFragmentManager().beginTransaction()
.replace(R.id.container, ChangeSerialFragment.newInstance(null))
.addToBackStack(ChangeSerialFragment.class.getSimpleName())
.commit();
}
}
package com.android.mobile.ui.fragments;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.android.mobile.R;
import butterknife.BindView;
import butterknife.ButterKnife;
public class DummyFragment extends Fragment {
private static final String TAG = DummyFragment.class.getSimpleName();
public static final String DUMMY_KEY = "dummy_key";
public int mDummyId;
@BindView(R.id.dummy) public TextView mDummyTextView;
public static DummyFragment newInstance(Bundle bundle) {
DummyFragment fragment = new DummyFragment();
if (bundle != null) {
fragment.setArguments(bundle);
}
return fragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dummy_fragment, container, false);
ButterKnife.bind(this, view);
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mDummyId = getArguments().getInt(DUMMY_KEY);
String text = "Dummy";
switch (mDummyId) {
case 0: text = "One"; break;
case 1: text = "Two"; break;
case 2: text = "Three"; break;
case 3: text = "Four"; break;
case 4: text = "Five"; break;
case 5: text = "Six"; break;
}
mDummyTextView.setText(text);
}
}
package com.android.mobile.ui.fragments;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.android.mobile.ApplicationContext;
import com.android.mobile.MainActivity;
import com.android.mobile.R;
import com.android.mobile.api.STBResponse;
import com.android.mobile.api.controller.AccountController;
import com.android.mobile.dependencies.Injector;
import com.android.mobile.util.AnimationUtil;
import com.android.mobile.util.ApplicationProvider;
import com.android.mobile.util.ApplicationProvider.Menu;
import com.android.mobile.util.FocusHandler;
import com.android.mobile.util.Preferences;
import javax.inject.Inject;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class MenuFragment extends Fragment implements AccountController.Callback {
private static final String TAG = MenuFragment.class.getSimpleName();
private ProgressDialog progressDialog;
@Inject AccountController mAccountController;
@Inject AnimationUtil animation;
private MainActivity mActivity;
@BindView(R.id.channels) public ImageView mChannelsView;
@BindView(R.id.account) public ImageView mAccountView;
@BindView(R.id.preferences) public ImageView mPreferenceView;
@BindView(R.id.log_out) public ImageView mLogOutView;
@BindView(R.id.title) public TextView mMenuTitle;
private int current = 1;
public static MenuFragment newInstance(Bundle bundle) {
MenuFragment fragment = new MenuFragment();
if (bundle != null) {
fragment.setArguments(bundle);
}
return fragment;
}
public MenuFragment() {
Injector.inject(this);
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
mActivity = (MainActivity) context;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAccountController.setCallback(this);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.menu_fragment, container, false);
ButterKnife.bind(this, view);
return view;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.requestFocus();
tryMove(Menu.CHANNELS);
view.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
boolean unique = event.getRepeatCount() == 0;
boolean isDown = event.getAction() == KeyEvent.ACTION_DOWN;
if (unique && isDown) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_LEFT:
tryMove(ApplicationProvider.MOVE_LEFT);
return true;
case KeyEvent.KEYCODE_DPAD_RIGHT:
tryMove(ApplicationProvider.MOVE_RIGHT);
return true;
case KeyEvent.KEYCODE_DPAD_CENTER:
performClick();
return true;
}
}
return false;
}
});
}
private void tryMove(int direction) {
int focus = current + direction;
if (focus >= 1 && focus <= 4) {
ImageView view = getViewById(focus);
animation.zoomIn(view);
view = getViewById(current);
animation.zoomOut(view);
current = focus;
}
showMenuTitle();
}
private void showMenuTitle() {
mMenuTitle.setText(getTitleById());
animation.fadeOut(mMenuTitle);
animation.fadeIn(mMenuTitle);
}
private boolean performClick() {
switch (current) {
case Menu.CHANNELS:
onChannelsClick();
return true;
case Menu.ACCOUNT:
onAccountClick();
return true;
case Menu.PREFERENCES:
onPreferencesClick();
return true;
case Menu.LOGOUT:
onLogOutClick();
return true;
}
return false;
}
private String getTitleById() {
switch (current) {
case Menu.CHANNELS:
return getString(R.string.menu__channels);
case Menu.ACCOUNT:
return getString(R.string.menu__private_office);
case Menu.PREFERENCES:
return getString(R.string.menu__preferences);
case Menu.LOGOUT:
return getString(R.string.menu__log_out);
default:
throw new AssertionError("Unknown identifier!");
}
}
private ImageView getViewById(int id) {
switch (id) {
case Menu.CHANNELS:
return mChannelsView;
case Menu.ACCOUNT:
return mAccountView;
case Menu.PREFERENCES:
return mPreferenceView;
case Menu.LOGOUT:
return mLogOutView;
default:
throw new AssertionError("Unknown identifier!");
}
}
private FragmentTransaction getFragmentTransaction() {
FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
transaction.setCustomAnimations(R.anim.fade_scale_in, R.anim.fade_scale_out,
R.anim.fade_scale_in, R.anim.fade_scale_out);
return transaction;
}
@Override
public void onResume() {
super.onResume();
FocusHandler.setMenuOpen(true);
}
@Override
public void onDestroy() {
super.onDestroy();
getFragmentManager().popBackStack(MenuFragment.class.getName(),
FragmentManager.POP_BACK_STACK_INCLUSIVE);
FocusHandler.setMenuOpen(false);
}
@Override
public void onDetach() {
super.onDetach();
if (mActivity != null) {
mActivity = null;
}
}
@Override
public void onRun() {
progressDialog = ProgressDialog.show(getActivity(), getString(R.string.MenuFragment__logging_out),
getString(R.string.MenuFragment__wait_please_this_can_take_a_while));
progressDialog.setCancelable(false);
}
@Override
public void onSuccess(STBResponse response) {
logOut();
progressDialog.dismiss();
FocusHandler.setMenuOpen(false);
getFragmentManager().popBackStack(MenuFragment.class.getName(),
FragmentManager.POP_BACK_STACK_INCLUSIVE);
mActivity.startActivity(new Intent(getActivity(), MainActivity.class));
mActivity.overridePendingTransition(R.anim.fade_scale_in, R.anim.fade_scale_out);
}
@Override
public void onFailure(Throwable throwable) {
progressDialog.dismiss();
Toast.makeText(getContext(), R.string.MenuFragment__sorry_something_went_wrong, Toast.LENGTH_SHORT)
.show();
}
@OnClick(R.id.channels)
public void onChannelsClick() {
FocusHandler.setMenuOpen(false);
getFragmentManager().popBackStack(MenuFragment.class.getName(),
FragmentManager.POP_BACK_STACK_INCLUSIVE);
getFragmentTransaction()
.replace(R.id.container, ChannelsFragment.newInstance(null))
.commit();
}
@OnClick(R.id.account)
public void onAccountClick() {
FocusHandler.setMenuOpen(false);
getFragmentManager().popBackStack(MenuFragment.class.getName(),
FragmentManager.POP_BACK_STACK_INCLUSIVE);
getFragmentTransaction()
.replace(R.id.container, AccountFragment.newInstance(null))
.commit();
}
@OnClick(R.id.preferences)
public void onPreferencesClick() {
FocusHandler.setMenuOpen(false);
getFragmentManager().popBackStack(MenuFragment.class.getName(),
FragmentManager.POP_BACK_STACK_INCLUSIVE);
getFragmentTransaction()
.replace(R.id.container, PreferencesFragment.newInstance(null))
.commit();
}
@OnClick(R.id.log_out)
public void onLogOutClick() {
mAccountController.signOut();
}
private void logOut() {
Preferences.setUserLogin(getActivity(), null);
Preferences.setUserPassword(getActivity(), null);
}
}
package com.android.mobile.ui.fragments;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceFragmentCompat;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.android.mobile.R;
import com.android.mobile.util.FocusHandler;
public class PreferencesFragment extends PreferenceFragmentCompat {
public static final int ID = 7;
private static final String PREFERENCES_PARENTAL_CONTROL = "preferences_parental_control";
private static final String PREFERENCES_LANGUAGE = "preferences_language";
private static final String PREFERENCES_DEVICE_INFORMATION = "preferences_device_information";
public static PreferencesFragment newInstance(Bundle bundle) {
PreferencesFragment fragment = new PreferencesFragment();
if (bundle != null) {
fragment.setArguments(bundle);
}
return fragment;
}
public PreferencesFragment() {
}
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.app_preference);
findPreference(PREFERENCES_PARENTAL_CONTROL).setOnPreferenceClickListener(
new CategoryClickListener(PREFERENCES_PARENTAL_CONTROL)
);
findPreference(PREFERENCES_LANGUAGE).setOnPreferenceClickListener(
new CategoryClickListener(PREFERENCES_LANGUAGE)
);
findPreference(PREFERENCES_DEVICE_INFORMATION).setOnPreferenceClickListener(
new CategoryClickListener(PREFERENCES_DEVICE_INFORMATION)
);
}
@Override
public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
RecyclerView view = super.onCreateRecyclerView(inflater, parent, savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
view.setBackgroundColor(getResources().getColor(android.R.color.white, null));
} else {
view.setBackgroundColor(getResources().getColor(android.R.color.white));
}
return view;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}
@Override
public void onResume() {
super.onResume();
FocusHandler.setVisible(ID);
}
private class CategoryClickListener implements Preference.OnPreferenceClickListener {
private String category;
public CategoryClickListener(String category) {
this.category = category;
}
@Override
public boolean onPreferenceClick(Preference preference) {
Fragment fragment = null;
switch (category) {
case PREFERENCES_PARENTAL_CONTROL:
fragment = new AccountFragment();
break;
case PREFERENCES_LANGUAGE:
fragment = new AccountFragment();
break;
case PREFERENCES_DEVICE_INFORMATION:
fragment = new AccountFragment();
break;
default:
throw new AssertionError();
}
if (fragment != null) {
FragmentTransaction fragmentTransaction = getActivity()
.getSupportFragmentManager()
.beginTransaction();
fragmentTransaction.replace(R.id.container, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
return true;
}
}
}
package com.android.mobile.ui.fragments;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import com.android.mobile.ApplicationContext;
import com.android.mobile.MainActivity;
import com.android.mobile.R;
import com.android.mobile.api.STBResponse;
import com.android.mobile.api.controller.AccountController;
import com.android.mobile.api.retrofit.service.AccountService;
import com.android.mobile.dependencies.Injector;
import com.android.mobile.ui.LoadingView;
import com.android.mobile.util.AnimationUtil;
import com.android.mobile.util.FocusHandler;
import com.android.mobile.util.Preferences;
import com.android.mobile.util.Dialogs;
import com.android.mobile.util.Util;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class SignInFragment extends Fragment implements AccountController.Callback {
private static final String TAG = SignInFragment.class.getSimpleName();
public static final int ID = 3;
@BindView(R.id.sign_in) public Button mSignIn;
@BindView(R.id.email) public EditText mEmail;
@BindView(R.id.password) public EditText mPassword;
@BindView(R.id.content) public LinearLayout mContent;
@BindView(R.id.loading_view) public LoadingView mLoadingView;
@Inject AnimationUtil mAnimationUtil;
@Inject AccountController mAccountController;
public static SignInFragment newInstance(Bundle bundle) {
SignInFragment instance = new SignInFragment();
if (bundle != null) {
instance.setArguments(bundle);
}
return instance;
}
public SignInFragment() {
Injector.inject(this);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAccountController.setCallback(this);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.sign_in_fragment, container, false);
ButterKnife.bind(this, view);
return view;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
FocusHandler.setVisible(ID);
mEmail.requestFocus();
}
@Override
public void onRun() {
setLoading(true);
}
@Override
public void onSuccess(STBResponse response) {
setLoading(false);
Log.d(TAG, "onSuccess: " + response.toString());
if (response.isSuccessful()) {
Activity activity = getActivity();
Preferences.setUserLogin(getContext(), mEmail.getText().toString());
Preferences.setUserPassword(getContext(), mPassword.getText().toString());
startActivity(new Intent(activity, MainActivity.class));
activity.finish();
}
}
@Override
public void onFailure(Throwable throwable) {
setLoading(false);
Log.d(TAG, "onFailure: " + throwable.getMessage());
Dialogs.showDialog(getContext(),
getString(R.string.sign_in_fragment__something_went_wrong),
throwable.getMessage());
mEmail.requestFocus();
}
@OnClick(R.id.sign_in) public void signIn() {
String email = mEmail.getText().toString();
String password = mPassword.getText().toString();
if (email.isEmpty()) {
mEmail.setError(getString(R.string.sign_in_fragment__please_fill_this_field));
mAnimationUtil.wobble(mEmail);
return;
}
if (!Util.isValidEmail(email)) {
mEmail.setError(getString(R.string.sign_in_fragment__please_enter_an_email));
mAnimationUtil.wobble(mEmail);
return;
}
if (password.isEmpty()) {
mPassword.setError(getString(R.string.sign_in_fragment__please_fill_this_field));
mAnimationUtil.wobble(mPassword);
return;
}
if (!Util.isValidPassword(password)) {
mPassword.setError(getString(R.string.sign_in_fragment__please_enter_a_password));
mAnimationUtil.wobble(mPassword);
return;
}
Map<String, String> params = new HashMap<>();
params.put(AccountService.EMAIL, email);
params.put(AccountService.PASSWORD, Util.md5(password));
params.put(AccountService.SERIAL, Preferences.getUserIdentifier(getContext()));
mAccountController.signIn(params);
}
private void setLoading(boolean isLoading) {
mLoadingView.setVisibility(isLoading);
mContent.setVisibility(isLoading ? View.GONE : View.VISIBLE);
}
}
package com.android.mobile.ui.fragments;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import com.android.mobile.ApplicationContext;
import com.android.mobile.MainActivity;
import com.android.mobile.R;
import com.android.mobile.api.STBResponse;
import com.android.mobile.api.controller.AccountController;
import com.android.mobile.api.retrofit.service.AccountService;
import com.android.mobile.dependencies.Injector;
import com.android.mobile.ui.LoadingView;
import com.android.mobile.util.AnimationUtil;
import com.android.mobile.util.Preferences;
import com.android.mobile.util.Dialogs;
import com.android.mobile.util.Util;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class SignUpFragment extends Fragment implements AccountController.Callback {
private static final String TAG = SignUpFragment.class.getSimpleName();
public static final int ID = 4;
@BindView(R.id.email) public EditText mEmail;
@BindView(R.id.password) public EditText mPassword;
@BindView(R.id.password_repeat) public EditText mPasswordRepeat;
@BindView(R.id.sign_up) public Button mSignUp;
@BindView(R.id.content) public LinearLayout mContent;
@BindView(R.id.loading_view) public LoadingView mLoadingView;
@Inject AnimationUtil mAnimationUtil;
@Inject AccountController mAccountController;
public static SignUpFragment newInstance(Bundle bundle) {
SignUpFragment instance = new SignUpFragment();
if (bundle != null) {
instance.setArguments(bundle);
}
return instance;
}
public SignUpFragment() {
Injector.inject(this);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAccountController.setCallback(this);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.sign_up_fragment, container, false);
ButterKnife.bind(this, view);
return view;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mEmail.requestFocus();
}
@Override
public void onRun() {
setLoading(true);
}
@Override
public void onSuccess(STBResponse response) {
setLoading(false);
if (response.isSuccessful()) {
Activity activity = getActivity();
Preferences.setUserLogin(getContext(), mEmail.getText().toString());
Preferences.setUserPassword(getContext(), mPassword.getText().toString());
startActivity(new Intent(activity, MainActivity.class));
activity.finish();
}
}
@Override
public void onFailure(Throwable throwable) {
setLoading(false);
Dialogs.showDialog(getContext(),
getString(R.string.sign_up_fragment__something_went_wrong),
throwable.getMessage());
mEmail.requestFocus();
}
@OnClick(R.id.sign_up) public void signUp() {
String email = mEmail.getText().toString();
String password = mPassword.getText().toString();
String repeatPassword = mPasswordRepeat.getText().toString();
if (email.isEmpty()) {
mEmail.setError(getString(R.string.sign_up_fragment__please_fill_this_field));
mAnimationUtil.wobble(mEmail);
return;
}
if (!Util.isValidEmail(email)) {
mEmail.setError(getString(R.string.sign_up_fragment__please_enter_an_email));
mAnimationUtil.wobble(mEmail);
return;
}
if (password.isEmpty()) {
mPassword.setError(getString(R.string.sign_up_fragment__please_fill_this_field));
mAnimationUtil.wobble(mPassword);
return;
}
if (!Util.isValidPassword(password)) {
mPassword.setError(getString(R.string.sign_up_fragment__please_enter_a_password));
mAnimationUtil.wobble(mPassword);
return;
}
if (repeatPassword.isEmpty()) {
mPasswordRepeat.setError(getString(R.string.sign_up_fragment__please_fill_this_field));
mAnimationUtil.wobble(mPasswordRepeat);
return;
}
if (!repeatPassword.equals(password)) {
mPasswordRepeat.setError(getString(R.string.sign_up_fragment__enter_correct_password));
mAnimationUtil.wobble(mPasswordRepeat);
return;
}
Map<String, String> params = new HashMap<>();
params.put(AccountService.EMAIL, email);
params.put(AccountService.PASSWORD, Util.md5(password));
params.put(AccountService.SERIAL, Preferences.getUserIdentifier(getContext()));
mAccountController.signUp(params);
}
private void setLoading(boolean isLoading) {
mLoadingView.setVisibility(isLoading);
mContent.setVisibility(isLoading ? View.GONE : View.VISIBLE);
}
}
package com.android.mobile.ui.snappysmoothscroller;
import android.graphics.PointF;
import android.support.v7.widget.LinearLayoutManager;
public class LinearLayoutScrollVectorDetector implements SnappySmoothScroller.ScrollVectorDetector {
private LinearLayoutManager layoutManager;
public LinearLayoutScrollVectorDetector(LinearLayoutManager layoutManager) {
this.layoutManager = layoutManager;
}
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return layoutManager.computeScrollVectorForPosition(targetPosition);
}
}
package com.android.mobile.ui.snappysmoothscroller;
public enum SnapType {
START,
END,
CENTER,
VISIBLE
}
package com.android.mobile.ui.snappysmoothscroller;
import android.content.Context;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.animation.Interpolator;
public class SnappyGridLayoutManager extends GridLayoutManager implements SnappyLayoutManager {
private SnappySmoothScroller.Builder builder;
public SnappyGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
public SnappyGridLayoutManager(Context context, int spanCount) {
super(context, spanCount);
init();
}
public SnappyGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {
super(context, spanCount, orientation, reverseLayout);
init();
}
private void init() {
builder = new SnappySmoothScroller.Builder();
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
SnappySmoothScroller scroller = builder
.setPosition(position)
.setScrollVectorDetector(new LinearLayoutScrollVectorDetector(this))
.build(recyclerView.getContext());
startSmoothScroll(scroller);
}
@Override
public void setSnapType(SnapType snapType) {
builder.setSnapType(snapType);
}
@Override
public void setSnapDuration(int snapDuration) {
builder.setSnapDuration(snapDuration);
}
@Override
public void setSnapInterpolator(Interpolator snapInterpolator) {
builder.setSnapInterpolator(snapInterpolator);
}
@Override
public void setSnapPadding(int snapPadding) {
builder.setSnapPadding(snapPadding);
}
@Override
public void setSnapPaddingStart(int snapPaddingStart) {
builder.setSnapPaddingStart(snapPaddingStart);
}
@Override
public void setSnapPaddingEnd(int snapPaddingEnd) {
builder.setSnapPaddingEnd(snapPaddingEnd);
}
@Override
public void setSeekDuration(int seekDuration) {
builder.setSeekDuration(seekDuration);
}
}
package com.android.mobile.ui.snappysmoothscroller;
import android.view.animation.Interpolator;
public interface SnappyLayoutManager {
void setSnapType(SnapType snapType);
void setSnapDuration(int snapDuration);
void setSnapInterpolator(Interpolator snapInterpolator);
void setSnapPadding(int snapPadding);
void setSnapPaddingStart(int snapPaddingStart);
void setSnapPaddingEnd(int snapPaddingEnd);
void setSeekDuration(int seekDuration);
}
package com.android.mobile.ui.snappysmoothscroller;
import android.content.Context;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.animation.Interpolator;
public class SnappyLinearLayoutManager extends LinearLayoutManager implements SnappyLayoutManager {
private SnappySmoothScroller.Builder builder;
public SnappyLinearLayoutManager(Context context) {
super(context);
init();
}
public SnappyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
init();
}
public SnappyLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
builder = new SnappySmoothScroller.Builder();
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
SnappySmoothScroller scroller = builder
.setPosition(position)
.setScrollVectorDetector(new LinearLayoutScrollVectorDetector(this))
.build(recyclerView.getContext());
startSmoothScroll(scroller);
}
@Override
public void setSnapType(SnapType snapType) {
builder.setSnapType(snapType);
}
@Override
public void setSnapDuration(int snapDuration) {
builder.setSnapDuration(snapDuration);
}
@Override
public void setSnapInterpolator(Interpolator snapInterpolator) {
builder.setSnapInterpolator(snapInterpolator);
}
@Override
public void setSnapPadding(int snapPadding) {
builder.setSnapPadding(snapPadding);
}
@Override
public void setSnapPaddingStart(int snapPaddingStart) {
builder.setSnapPaddingStart(snapPaddingStart);
}
@Override
public void setSnapPaddingEnd(int snapPaddingEnd) {
builder.setSnapPaddingEnd(snapPaddingEnd);
}
@Override
public void setSeekDuration(int seekDuration) {
builder.setSeekDuration(seekDuration);
}
}
package com.android.mobile.ui.snappysmoothscroller;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.util.AttributeSet;
import android.view.animation.Interpolator;
public class SnappyStaggeredGridLayoutManager extends StaggeredGridLayoutManager implements SnappyLayoutManager {
private SnappySmoothScroller.Builder builder;
public SnappyStaggeredGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
public SnappyStaggeredGridLayoutManager(int spanCount, int orientation) {
super(spanCount, orientation);
init();
}
private void init() {
builder = new SnappySmoothScroller.Builder();
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
SnappySmoothScroller scroller = builder
.setPosition(position)
.setScrollVectorDetector(new StaggeredGridLayoutScrollVectorDetector(this))
.build(recyclerView.getContext());
startSmoothScroll(scroller);
}
@Override
public void setSnapType(SnapType snapType) {
builder.setSnapType(snapType);
}
@Override
public void setSnapDuration(int snapDuration) {
builder.setSnapDuration(snapDuration);
}
@Override
public void setSnapInterpolator(Interpolator snapInterpolator) {
builder.setSnapInterpolator(snapInterpolator);
}
@Override
public void setSnapPadding(int snapPadding) {
builder.setSnapPadding(snapPadding);
}
@Override
public void setSnapPaddingStart(int snapPaddingStart) {
builder.setSnapPaddingStart(snapPaddingStart);
}
@Override
public void setSnapPaddingEnd(int snapPaddingEnd) {
builder.setSnapPaddingEnd(snapPaddingEnd);
}
@Override
public void setSeekDuration(int seekDuration) {
builder.setSeekDuration(seekDuration);
}
}
package com.android.mobile.ui.snappysmoothscroller;
import android.graphics.PointF;
import android.support.v7.widget.StaggeredGridLayoutManager;
public class StaggeredGridLayoutScrollVectorDetector implements SnappySmoothScroller.ScrollVectorDetector {
final static int LAYOUT_START = -1;
final static int LAYOUT_END = 1;
private StaggeredGridLayoutManager layoutManager;
public StaggeredGridLayoutScrollVectorDetector(StaggeredGridLayoutManager layoutManager) {
this.layoutManager = layoutManager;
}
private int getFirstChildPosition() {
final int childCount = layoutManager.getChildCount();
return childCount == 0 ? 0 : layoutManager.getPosition(layoutManager.getChildAt(0));
}
private int calculateScrollDirectionForPosition(int position) {
if (layoutManager.getChildCount() == 0) {
return layoutManager.getReverseLayout() ? LAYOUT_END : LAYOUT_START;
}
final int firstChildPos = getFirstChildPosition();
return position < firstChildPos != layoutManager.getReverseLayout() ? LAYOUT_START : LAYOUT_END;
}
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
final int direction = calculateScrollDirectionForPosition(targetPosition);
if (direction == 0) {
return null;
}
if (layoutManager.getOrientation() == StaggeredGridLayoutManager.HORIZONTAL) {
return new PointF(direction, 0);
} else {
return new PointF(0, direction);
}
}
}
package com.android.mobile.util;
import com.android.mobile.R;
import java.util.Map;
public class APIUtil {
// TODO: test values
private static final String MICROSOFT = "0";
private static final String ORACLE = "1";
private static final String PAY_PAL = "2";
public static boolean isResponseOK(Map<String, String> response) {
String status = response.get("status_code");
return status != null && status.equalsIgnoreCase("200");
}
public static boolean hasISP(Map<String, String> response) {
String isp = response.get("isp");
return isp != null && !isp.isEmpty();
}
public static int getISPLogo(String isp) {
switch (isp) {
case MICROSOFT:
return R.drawable.microsoft;
case ORACLE:
return R.drawable.oracle;
case PAY_PAL:
return R.drawable.paypal;
}
return R.drawable.google;
}
}
package com.android.mobile.util;
import android.view.View;
import com.android.mobile.ui.animation.Fade;
import com.android.mobile.ui.animation.Zoom;
import com.daimajia.androidanimations.library.YoYo;
import com.daimajia.androidanimations.library.attention.WobbleAnimator;
public class AnimationUtil {
private Zoom zoom;
private WobbleAnimator wobble;
private Fade fade;
public AnimationUtil() {
zoom = new Zoom();
wobble = new WobbleAnimator();
fade = new Fade();
}
public void zoomIn(View view) {
zoom.zoomIn(view);
}
public void zoomOut(View view) {
zoom.zoomOut(view);
}
public void wobble(View view) {
YoYo.with(wobble).playOn(view);
}
public void fadeIn(View... views) {
for (View v : views) {
fade.fadeIn(v);
}
}
public void fadeOut(View... views) {
for (View v : views) {
fade.fadeOut(v);
}
}
public Zoom getZoom() {
return zoom;
}
public WobbleAnimator getWobble() {
return wobble;
}
public Fade getFade() {
return fade;
}
}
package com.android.mobile.util;
import com.android.mobile.database.model.ChannelRecord;
import java.util.ArrayList;
import java.util.List;
public class ApplicationProvider {
public static final int COLUMN_COUNT = 3;
public static final int MOVE_UP = -COLUMN_COUNT;
public static final int MOVE_DOWN = +COLUMN_COUNT;
public static final int MOVE_LEFT = -1;
public static final int MOVE_RIGHT = +1;
public static final int HOLD = 0;
public interface Menu {
int CHANNELS = 1;
int ACCOUNT = 2;
int PREFERENCES = 3;
int LOGOUT = 4;
}
public interface Account {
int MOVE_UP = -1;
int MOVE_DOWN = +1;
}
private static Integer CURRENT = 0;
private static List<ChannelRecord> CHANNELS = new ArrayList<>();
public static void fillCache(List<ChannelRecord> channels) {
CHANNELS = channels;
}
public static List<ChannelRecord> getChannels() {
return CHANNELS;
}
public static ChannelRecord getById(int id) throws IllegalArgumentException {
if (id < 0) {
throw new IllegalArgumentException();
}
return CHANNELS.get(id);
}
public static void setCurrent(int current) {
CURRENT = current;
}
public static Integer getCurrent() {
return CURRENT;
}
public static ChannelRecord getChannel(String title) {
for (ChannelRecord channel : CHANNELS) {
if (channel.getTitle().equals(title)) {
return channel;
}
}
return null;
}
public static ChannelRecord getChannel(ChannelRecord channel) {
for (ChannelRecord channel1 : CHANNELS) {
if (channel1.equals(channel)) {
return channel1;
}
}
return null;
}
public static int size() {
return CHANNELS.size();
}
public static int lastIndex() {
return size() - 1;
}
}
This diff is collapsed. Click to expand it.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment