diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..3cdbecb97 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + +[*] + +# Change these settings to your own preference +indent_style = space +indent_size = 4 + +# It's recommended to keep these unchanged +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/fakeApi.properties b/fakeApi.properties index 6ee986e3f..5d0473ebe 100644 --- a/fakeApi.properties +++ b/fakeApi.properties @@ -1,9 +1,8 @@ # Set API information in api.properties. # This is something to keep private and you obtain it by asking in the Amahi IRC channel or # send a message to support at Amahi dot org - url.amahi=https://amahi.org url.proxy=https://amahi.org client.id=1234567890 client.secret=abcdefghijklmnopqrstuvwxyz -chromecast.app.id=CC1AD845 \ No newline at end of file +chromecast.app.id=CC1AD845 diff --git a/fakeSigning.properties b/fakeSigning.properties index 8ad82e1af..86d6879d8 100644 --- a/fakeSigning.properties +++ b/fakeSigning.properties @@ -1,7 +1,6 @@ # Set API information in api.properties. # This is something to keep private and you obtain it by asking in the Amahi IRC channel or # send a message to support at Amahi dot org - keystore.file=debug.keystore keystore.password=android key.alias=androiddebugkey diff --git a/src/androidTest/java/org/amahi/anywhere/activity/AuthenticationActivityTest.java b/src/androidTest/java/org/amahi/anywhere/activity/AuthenticationActivityTest.java index 5794e9c6a..aa8fd79f0 100644 --- a/src/androidTest/java/org/amahi/anywhere/activity/AuthenticationActivityTest.java +++ b/src/androidTest/java/org/amahi/anywhere/activity/AuthenticationActivityTest.java @@ -20,7 +20,7 @@ public class AuthenticationActivityTest { @Rule public ActivityTestRule authenticationActivityTestRule = - new ActivityTestRule(AuthenticationActivity.class); + new ActivityTestRule(AuthenticationActivity.class); @Test public void testIsErrorMessageDisplayed_UsernameOrPasswordIsEmpty() { @@ -28,10 +28,10 @@ public void testIsErrorMessageDisplayed_UsernameOrPasswordIsEmpty() { onView(withId(R.id.password_layout)).check(matches(isDisplayed())); onView(withId(R.id.button_authentication)) - .check(matches(isDisplayed())) - .perform(click()); + .check(matches(isDisplayed())) + .perform(click()); onView(withId(R.id.text_message_authentication_empty)) - .check(matches(isDisplayed())); + .check(matches(isDisplayed())); } } diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 7662b0897..216dc8735 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -16,22 +16,21 @@ ~ You should have received a copy of the GNU General Public License ~ along with Amahi. If not, see . --> - - - - - - - - - - - - + + + + + + + + + + + @@ -48,7 +47,7 @@ + android:required="false" /> + android:theme="@style/Theme.Amahi"> + android:resource="@xml/file_paths" /> - + - - - + + - - + + + android:theme="@style/Theme.Amahi.Fullscreen" /> + android:theme="@style/Theme.Amahi.Fullscreen" /> + android:theme="@style/Theme.Amahi.Fullscreen" /> + android:screenOrientation="portrait" + android:theme="@style/Theme.CastVideosDark"> - + - + android:configChanges="orientation|keyboard|keyboardHidden|screenSize|screenLayout|uiMode" + android:theme="@style/Theme.Amahi.Fullscreen" /> + - + + android:theme="@style/Theme.AppCompat.NoActionBar" /> + android:windowSoftInputMode="adjustResize" /> - + + android:resource="@xml/authenticator" /> - + - - + + - - + + - - + + - + @@ -197,29 +198,35 @@ + android:value="d7b65346d3cf0028328f006bff447501d70f8996" /> + android:label="@string/title_version_settings" /> - + - + - + - + - + - + = Build.VERSION_CODES.N) { - setUpJobs(); - } - } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + setUpJobs(); + } + } - private void setUpLogging() { + private void setUpLogging() { if (isDebugging()) { Timber.plant(new Timber.DebugTree()); } @@ -90,18 +90,18 @@ public void inject(Object injectionsConsumer) { injector.inject(injectionsConsumer); } + @RequiresApi(api = Build.VERSION_CODES.N) + private void setUpJobs() { + if (!PhotosContentJob.isScheduled(this)) { + PhotosContentJob.scheduleJob(this); + } + if (!NetConnectivityJob.isScheduled(this)) { + NetConnectivityJob.scheduleJob(this); + } + } + public static class JobIds { public static final int PHOTOS_CONTENT_JOB = 125; - public static final int NET_CONNECTIVITY_JOB = 126; + public static final int NET_CONNECTIVITY_JOB = 126; } - - @RequiresApi(api = Build.VERSION_CODES.N) - private void setUpJobs() { - if (!PhotosContentJob.isScheduled(this)) { - PhotosContentJob.scheduleJob(this); - } - if (!NetConnectivityJob.isScheduled(this)) { - NetConnectivityJob.scheduleJob(this); - } - } } diff --git a/src/main/java/org/amahi/anywhere/AmahiModule.java b/src/main/java/org/amahi/anywhere/AmahiModule.java index 942f5a79a..d6999e732 100644 --- a/src/main/java/org/amahi/anywhere/AmahiModule.java +++ b/src/main/java/org/amahi/anywhere/AmahiModule.java @@ -48,9 +48,9 @@ import org.amahi.anywhere.tv.activity.TvPlaybackVideoActivity; import org.amahi.anywhere.tv.fragment.MainTVFragment; import org.amahi.anywhere.tv.fragment.ServerFileTvFragment; -import org.amahi.anywhere.util.UploadManager; import org.amahi.anywhere.tv.fragment.TvPlaybackAudioFragment; import org.amahi.anywhere.tv.fragment.TvPlaybackVideoFragment; +import org.amahi.anywhere.util.UploadManager; import javax.inject.Singleton; @@ -62,39 +62,39 @@ * provides application's {@link android.content.Context} for possible consumers. */ @Module( - includes = { - ApiModule.class - }, - injects = { - AuthenticationActivity.class, - NavigationActivity.class, - ServerAppActivity.class, - ServerFilesActivity.class, - ServerFileAudioActivity.class, - ServerFileImageActivity.class, - ServerFileVideoActivity.class, - NativeVideoActivity.class, - ServerFileWebActivity.class, - NavigationFragment.class, - ServerSharesFragment.class, - ServerAppsFragment.class, - ServerFilesFragment.class, - ServerFileImageFragment.class, - ServerFileDownloadingFragment.class, - SettingsFragment.class, - UploadSettingsFragment.class, - AudioService.class, - VideoService.class, - MainTVFragment.class, - TVWebViewActivity.class, - ServerFileTvFragment.class, - UploadService.class, - UploadManager.class, - TvPlaybackVideoFragment.class, - TvPlaybackVideoActivity.class, - TvPlaybackAudioActivity.class, - TvPlaybackAudioFragment.class - } + includes = { + ApiModule.class + }, + injects = { + AuthenticationActivity.class, + NavigationActivity.class, + ServerAppActivity.class, + ServerFilesActivity.class, + ServerFileAudioActivity.class, + ServerFileImageActivity.class, + ServerFileVideoActivity.class, + NativeVideoActivity.class, + ServerFileWebActivity.class, + NavigationFragment.class, + ServerSharesFragment.class, + ServerAppsFragment.class, + ServerFilesFragment.class, + ServerFileImageFragment.class, + ServerFileDownloadingFragment.class, + SettingsFragment.class, + UploadSettingsFragment.class, + AudioService.class, + VideoService.class, + MainTVFragment.class, + TVWebViewActivity.class, + ServerFileTvFragment.class, + UploadService.class, + UploadManager.class, + TvPlaybackVideoFragment.class, + TvPlaybackVideoActivity.class, + TvPlaybackAudioActivity.class, + TvPlaybackAudioFragment.class + } ) class AmahiModule { private final Application application; diff --git a/src/main/java/org/amahi/anywhere/account/AmahiAccount.java b/src/main/java/org/amahi/anywhere/account/AmahiAccount.java index 0588edc5e..cb940e13e 100644 --- a/src/main/java/org/amahi/anywhere/account/AmahiAccount.java +++ b/src/main/java/org/amahi/anywhere/account/AmahiAccount.java @@ -24,13 +24,12 @@ /** * Amahi account declaration. */ -public class AmahiAccount extends Account -{ - public static final String TYPE = "org.amahi"; +public class AmahiAccount extends Account { + public static final String TYPE = "org.amahi"; - public static final String TYPE_TOKEN = String.format("%s.FULL", TYPE); + public static final String TYPE_TOKEN = String.format("%s.FULL", TYPE); - public AmahiAccount(String name) { - super(name, TYPE); - } + public AmahiAccount(String name) { + super(name, TYPE); + } } diff --git a/src/main/java/org/amahi/anywhere/account/AmahiAuthenticator.java b/src/main/java/org/amahi/anywhere/account/AmahiAuthenticator.java index 6b2124901..5eba04d23 100644 --- a/src/main/java/org/amahi/anywhere/account/AmahiAuthenticator.java +++ b/src/main/java/org/amahi/anywhere/account/AmahiAuthenticator.java @@ -37,82 +37,81 @@ /** * Amahi authenticator. Performs basic account and auth token manipulations. - * + *

* The current implementation allows only single account exist on a device. */ -class AmahiAuthenticator extends AbstractAccountAuthenticator -{ - private final Context context; - - public AmahiAuthenticator(Context context) { - super(context); - - this.context = context; - } - - @Override - public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException { - Bundle accountBundle = new Bundle(); - - if (getAccounts().isEmpty()) { - Intent accountIntent = new Intent(context, AuthenticationActivity.class); - accountIntent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); - - accountBundle.putParcelable(AccountManager.KEY_INTENT, accountIntent); - } else { - accountBundle.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_CANCELED); - accountBundle.putString(AccountManager.KEY_ERROR_MESSAGE, context.getString(R.string.message_error_account_exists)); - } - - return accountBundle; - } - - private List getAccounts() { - return Arrays.asList(AccountManager.get(context).getAccountsByType(AmahiAccount.TYPE)); - } - - @Override - public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { - Bundle authBundle = new Bundle(); - - String authToken = AccountManager.get(context).peekAuthToken(account, authTokenType); - - if (!TextUtils.isEmpty(authToken)) { - authBundle.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); - authBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type); - authBundle.putString(AccountManager.KEY_AUTHTOKEN, authToken); - } else { - Intent authIntent = new Intent(context, AuthenticationActivity.class); - authIntent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); - - authBundle.putParcelable(AccountManager.KEY_INTENT, authIntent); - } - - return authBundle; - } - - @Override - public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) { - return null; - } - - @Override - public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException { - return null; - } - - @Override - public String getAuthTokenLabel(String authTokenType) { - return null; - } - - @Override - public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { - return null; - } - - @Override - public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException { - return null; - } +class AmahiAuthenticator extends AbstractAccountAuthenticator { + private final Context context; + + public AmahiAuthenticator(Context context) { + super(context); + + this.context = context; + } + + @Override + public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException { + Bundle accountBundle = new Bundle(); + + if (getAccounts().isEmpty()) { + Intent accountIntent = new Intent(context, AuthenticationActivity.class); + accountIntent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); + + accountBundle.putParcelable(AccountManager.KEY_INTENT, accountIntent); + } else { + accountBundle.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_CANCELED); + accountBundle.putString(AccountManager.KEY_ERROR_MESSAGE, context.getString(R.string.message_error_account_exists)); + } + + return accountBundle; + } + + private List getAccounts() { + return Arrays.asList(AccountManager.get(context).getAccountsByType(AmahiAccount.TYPE)); + } + + @Override + public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { + Bundle authBundle = new Bundle(); + + String authToken = AccountManager.get(context).peekAuthToken(account, authTokenType); + + if (!TextUtils.isEmpty(authToken)) { + authBundle.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); + authBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type); + authBundle.putString(AccountManager.KEY_AUTHTOKEN, authToken); + } else { + Intent authIntent = new Intent(context, AuthenticationActivity.class); + authIntent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); + + authBundle.putParcelable(AccountManager.KEY_INTENT, authIntent); + } + + return authBundle; + } + + @Override + public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) { + return null; + } + + @Override + public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException { + return null; + } + + @Override + public String getAuthTokenLabel(String authTokenType) { + return null; + } + + @Override + public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { + return null; + } + + @Override + public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException { + return null; + } } diff --git a/src/main/java/org/amahi/anywhere/account/AmahiAuthenticatorService.java b/src/main/java/org/amahi/anywhere/account/AmahiAuthenticatorService.java index 66371307e..aa7a4e5ed 100644 --- a/src/main/java/org/amahi/anywhere/account/AmahiAuthenticatorService.java +++ b/src/main/java/org/amahi/anywhere/account/AmahiAuthenticatorService.java @@ -27,19 +27,18 @@ * Amahi authenticator service. * Allows {@link android.accounts.AccountManager} to interact with{@link AmahiAuthenticator}. */ -public class AmahiAuthenticatorService extends Service -{ - private AmahiAuthenticator authenticator; +public class AmahiAuthenticatorService extends Service { + private AmahiAuthenticator authenticator; - @Override - public void onCreate() { - super.onCreate(); + @Override + public void onCreate() { + super.onCreate(); - authenticator = new AmahiAuthenticator(getApplicationContext()); - } + authenticator = new AmahiAuthenticator(getApplicationContext()); + } - @Override - public IBinder onBind(Intent intent) { - return authenticator.getIBinder(); - } + @Override + public IBinder onBind(Intent intent) { + return authenticator.getIBinder(); + } } diff --git a/src/main/java/org/amahi/anywhere/activity/AuthenticationActivity.java b/src/main/java/org/amahi/anywhere/activity/AuthenticationActivity.java index c807a753e..bf0f18e8e 100644 --- a/src/main/java/org/amahi/anywhere/activity/AuthenticationActivity.java +++ b/src/main/java/org/amahi/anywhere/activity/AuthenticationActivity.java @@ -55,259 +55,257 @@ * Authentication activity. Allows user authentication. If operation succeed * the authentication token is saved at the {@link android.accounts.AccountManager}. */ -public class AuthenticationActivity extends AccountAuthenticatorActivity implements TextWatcher, View.OnClickListener -{ - @Inject - AmahiClient amahiClient; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_authentication); - - setUpInjections(); - - setUpAuthentication(); - } - - private void setUpInjections() { - AmahiApplication.from(this).inject(this); - } - - private void setUpAuthentication() { - setUpAuthenticationMessages(); - setUpAuthenticationListeners(); - } - - private String getUsername() { - return getUsernameEdit().getText().toString(); - } - - private EditText getUsernameEdit() { - TextInputLayout username_layout = (TextInputLayout) findViewById(R.id.username_layout); - return username_layout.getEditText(); - } - - private String getPassword() { - return getPasswordEdit().getText().toString(); - } - - private EditText getPasswordEdit() { - TextInputLayout password_layout = (TextInputLayout) findViewById(R.id.password_layout); - return password_layout.getEditText(); - } - - private ActionProcessButton getAuthenticationButton() { - return (ActionProcessButton) findViewById(R.id.button_authentication); - } - - private void setUpAuthenticationMessages() { - TextView authenticationFailureMessage = (TextView) findViewById(R.id.text_message_authentication); - TextView authenticationConnectionFailureMessage = (TextView) findViewById(R.id.text_message_authentication_connection); - - authenticationFailureMessage.setMovementMethod(LinkMovementMethod.getInstance()); - authenticationConnectionFailureMessage.setMovementMethod(LinkMovementMethod.getInstance()); - } - - private void setUpAuthenticationListeners() { - setUpAuthenticationTextListener(); - setUpAuthenticationActionListener(); - } - - private void setUpAuthenticationTextListener() { - getUsernameEdit().addTextChangedListener(this); - getPasswordEdit().addTextChangedListener(this); - getPasswordEdit().setOnEditorActionListener(new EditText.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - boolean handled = false; - if (actionId == EditorInfo.IME_ACTION_GO) { - onClick(getAuthenticationButton()); - handled = true; - } - return handled; - } - }); - } - - @Override - public void onTextChanged(CharSequence text, int after, int before, int count) { - hideAuthenticationFailureMessage(); - } - - private void hideAuthenticationFailureMessage() { - ViewDirector.of(this, R.id.animator_message).show(R.id.view_message_empty); - } - - @Override - public void afterTextChanged(Editable text) { - } - - @Override - public void beforeTextChanged(CharSequence text, int start, int count, int before) { - } - - private void setUpAuthenticationActionListener() { - getAuthenticationButton().setOnClickListener(this); - } - - @Override - public void onClick(View view) { - if(getUsername().trim().isEmpty() || getPassword().trim().isEmpty()){ - ViewDirector.of(this,R.id.animator_message).show(R.id.text_message_authentication_empty); - - if(getUsername().trim().isEmpty()) - getUsernameEdit().getBackground().setColorFilter(ContextCompat.getColor(AuthenticationActivity.this, android.R.color.holo_red_light), PorterDuff.Mode.SRC_ATOP); - if(getPassword().trim().isEmpty()) - getPasswordEdit().getBackground().setColorFilter(ContextCompat.getColor(AuthenticationActivity.this, android.R.color.holo_red_light), PorterDuff.Mode.SRC_ATOP); - - getUsernameEdit().addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { - - } - - @Override - public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { - if(!getUsername().trim().isEmpty()) - getUsernameEdit().getBackground().setColorFilter(ContextCompat.getColor(AuthenticationActivity.this, R.color.blue_normal),PorterDuff.Mode.SRC_ATOP); - else - getUsernameEdit().getBackground().setColorFilter(ContextCompat.getColor(AuthenticationActivity.this, R.color.holo_red_light), PorterDuff.Mode.SRC_ATOP); - } - - @Override - public void afterTextChanged(Editable editable) { - - } - }); - - getPasswordEdit().addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { - - } - - @Override - public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { - if(!getPassword().trim().isEmpty()) - getPasswordEdit().getBackground().setColorFilter(ContextCompat.getColor(AuthenticationActivity.this, R.color.blue_normal),PorterDuff.Mode.SRC_ATOP); - else - getPasswordEdit().getBackground().setColorFilter(ContextCompat.getColor(AuthenticationActivity.this, android.R.color.holo_red_light), PorterDuff.Mode.SRC_ATOP); - } +public class AuthenticationActivity extends AccountAuthenticatorActivity implements TextWatcher, View.OnClickListener { + @Inject + AmahiClient amahiClient; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_authentication); + + setUpInjections(); + + setUpAuthentication(); + } + + private void setUpInjections() { + AmahiApplication.from(this).inject(this); + } + + private void setUpAuthentication() { + setUpAuthenticationMessages(); + setUpAuthenticationListeners(); + } + + private String getUsername() { + return getUsernameEdit().getText().toString(); + } + + private EditText getUsernameEdit() { + TextInputLayout username_layout = (TextInputLayout) findViewById(R.id.username_layout); + return username_layout.getEditText(); + } + + private String getPassword() { + return getPasswordEdit().getText().toString(); + } + + private EditText getPasswordEdit() { + TextInputLayout password_layout = (TextInputLayout) findViewById(R.id.password_layout); + return password_layout.getEditText(); + } + + private ActionProcessButton getAuthenticationButton() { + return (ActionProcessButton) findViewById(R.id.button_authentication); + } + + private void setUpAuthenticationMessages() { + TextView authenticationFailureMessage = (TextView) findViewById(R.id.text_message_authentication); + TextView authenticationConnectionFailureMessage = (TextView) findViewById(R.id.text_message_authentication_connection); + + authenticationFailureMessage.setMovementMethod(LinkMovementMethod.getInstance()); + authenticationConnectionFailureMessage.setMovementMethod(LinkMovementMethod.getInstance()); + } + + private void setUpAuthenticationListeners() { + setUpAuthenticationTextListener(); + setUpAuthenticationActionListener(); + } + + private void setUpAuthenticationTextListener() { + getUsernameEdit().addTextChangedListener(this); + getPasswordEdit().addTextChangedListener(this); + getPasswordEdit().setOnEditorActionListener(new EditText.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + boolean handled = false; + if (actionId == EditorInfo.IME_ACTION_GO) { + onClick(getAuthenticationButton()); + handled = true; + } + return handled; + } + }); + } + + @Override + public void onTextChanged(CharSequence text, int after, int before, int count) { + hideAuthenticationFailureMessage(); + } + + private void hideAuthenticationFailureMessage() { + ViewDirector.of(this, R.id.animator_message).show(R.id.view_message_empty); + } + + @Override + public void afterTextChanged(Editable text) { + } + + @Override + public void beforeTextChanged(CharSequence text, int start, int count, int before) { + } + + private void setUpAuthenticationActionListener() { + getAuthenticationButton().setOnClickListener(this); + } + + @Override + public void onClick(View view) { + if (getUsername().trim().isEmpty() || getPassword().trim().isEmpty()) { + ViewDirector.of(this, R.id.animator_message).show(R.id.text_message_authentication_empty); + + if (getUsername().trim().isEmpty()) + getUsernameEdit().getBackground().setColorFilter(ContextCompat.getColor(AuthenticationActivity.this, android.R.color.holo_red_light), PorterDuff.Mode.SRC_ATOP); + if (getPassword().trim().isEmpty()) + getPasswordEdit().getBackground().setColorFilter(ContextCompat.getColor(AuthenticationActivity.this, android.R.color.holo_red_light), PorterDuff.Mode.SRC_ATOP); + + getUsernameEdit().addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { + + } + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { + if (!getUsername().trim().isEmpty()) + getUsernameEdit().getBackground().setColorFilter(ContextCompat.getColor(AuthenticationActivity.this, R.color.blue_normal), PorterDuff.Mode.SRC_ATOP); + else + getUsernameEdit().getBackground().setColorFilter(ContextCompat.getColor(AuthenticationActivity.this, R.color.holo_red_light), PorterDuff.Mode.SRC_ATOP); + } + + @Override + public void afterTextChanged(Editable editable) { + + } + }); + + getPasswordEdit().addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { + + } + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { + if (!getPassword().trim().isEmpty()) + getPasswordEdit().getBackground().setColorFilter(ContextCompat.getColor(AuthenticationActivity.this, R.color.blue_normal), PorterDuff.Mode.SRC_ATOP); + else + getPasswordEdit().getBackground().setColorFilter(ContextCompat.getColor(AuthenticationActivity.this, android.R.color.holo_red_light), PorterDuff.Mode.SRC_ATOP); + } - @Override - public void afterTextChanged(Editable editable) { + @Override + public void afterTextChanged(Editable editable) { - } - }); + } + }); - } - else { - startAuthentication(); + } else { + startAuthentication(); - authenticate(); - } - } + authenticate(); + } + } - private void startAuthentication() { - hideAuthenticationText(); + private void startAuthentication() { + hideAuthenticationText(); - showProgress(); + showProgress(); - hideAuthenticationFailureMessage(); - } + hideAuthenticationFailureMessage(); + } - private void hideAuthenticationText() { - getUsernameEdit().setEnabled(false); - getPasswordEdit().setEnabled(false); - } + private void hideAuthenticationText() { + getUsernameEdit().setEnabled(false); + getPasswordEdit().setEnabled(false); + } - private void showProgress() { - ActionProcessButton authenticationButton = getAuthenticationButton(); + private void showProgress() { + ActionProcessButton authenticationButton = getAuthenticationButton(); - authenticationButton.setMode(ActionProcessButton.Mode.ENDLESS); - authenticationButton.setProgress(1); - } + authenticationButton.setMode(ActionProcessButton.Mode.ENDLESS); + authenticationButton.setProgress(1); + } - private void authenticate() { - amahiClient.authenticate(getUsername(), getPassword()); - } + private void authenticate() { + amahiClient.authenticate(getUsername(), getPassword()); + } - @Subscribe - public void onAuthenticationFailed(AuthenticationFailedEvent event) { - finishAuthentication(); + @Subscribe + public void onAuthenticationFailed(AuthenticationFailedEvent event) { + finishAuthentication(); - showAuthenticationFailureMessage(); - } + showAuthenticationFailureMessage(); + } - private void finishAuthentication() { - showAuthenticationText(); + private void finishAuthentication() { + showAuthenticationText(); - hideProgress(); - } + hideProgress(); + } - private void showAuthenticationText() { - getUsernameEdit().setEnabled(true); - getPasswordEdit().setEnabled(true); - } + private void showAuthenticationText() { + getUsernameEdit().setEnabled(true); + getPasswordEdit().setEnabled(true); + } - private void hideProgress() { - getAuthenticationButton().setProgress(0); - } + private void hideProgress() { + getAuthenticationButton().setProgress(0); + } - private void showAuthenticationFailureMessage() { - ViewDirector.of(this, R.id.animator_message).show(R.id.text_message_authentication); - } + private void showAuthenticationFailureMessage() { + ViewDirector.of(this, R.id.animator_message).show(R.id.text_message_authentication); + } - @Subscribe - public void onAuthenticationConnectionFailed(AuthenticationConnectionFailedEvent event) { - finishAuthentication(); + @Subscribe + public void onAuthenticationConnectionFailed(AuthenticationConnectionFailedEvent event) { + finishAuthentication(); - showAuthenticationConnectionFailureMessage(); - } + showAuthenticationConnectionFailureMessage(); + } - private void showAuthenticationConnectionFailureMessage() { - ViewDirector.of(this, R.id.animator_message).show(R.id.text_message_authentication_connection); - } + private void showAuthenticationConnectionFailureMessage() { + ViewDirector.of(this, R.id.animator_message).show(R.id.text_message_authentication_connection); + } - @Subscribe - public void onAuthenticationSucceed(AuthenticationSucceedEvent event) { - finishAuthentication(event.getAuthentication().getToken()); - } + @Subscribe + public void onAuthenticationSucceed(AuthenticationSucceedEvent event) { + finishAuthentication(event.getAuthentication().getToken()); + } - private void finishAuthentication(String authenticationToken) { - AccountManager accountManager = AccountManager.get(this); + private void finishAuthentication(String authenticationToken) { + AccountManager accountManager = AccountManager.get(this); - Bundle authenticationBundle = new Bundle(); + Bundle authenticationBundle = new Bundle(); - Account account = new AmahiAccount(getUsername()); + Account account = new AmahiAccount(getUsername()); - if (accountManager.addAccountExplicitly(account, getPassword(), null)) { - authenticationBundle.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); - authenticationBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type); - authenticationBundle.putString(AccountManager.KEY_AUTHTOKEN, authenticationToken); + if (accountManager.addAccountExplicitly(account, getPassword(), null)) { + authenticationBundle.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); + authenticationBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type); + authenticationBundle.putString(AccountManager.KEY_AUTHTOKEN, authenticationToken); - accountManager.setAuthToken(account, account.type, authenticationToken); - } + accountManager.setAuthToken(account, account.type, authenticationToken); + } - setAccountAuthenticatorResult(authenticationBundle); + setAccountAuthenticatorResult(authenticationBundle); - setResult(Activity.RESULT_OK); + setResult(Activity.RESULT_OK); - finish(); - } + finish(); + } - @Override - protected void onResume() { - super.onResume(); + @Override + protected void onResume() { + super.onResume(); - BusProvider.getBus().register(this); - } + BusProvider.getBus().register(this); + } - @Override - protected void onPause() { - super.onPause(); + @Override + protected void onPause() { + super.onPause(); - BusProvider.getBus().unregister(this); - } + BusProvider.getBus().unregister(this); + } } diff --git a/src/main/java/org/amahi/anywhere/activity/NativeVideoActivity.java b/src/main/java/org/amahi/anywhere/activity/NativeVideoActivity.java index 1f70a5557..0be9cf09d 100644 --- a/src/main/java/org/amahi/anywhere/activity/NativeVideoActivity.java +++ b/src/main/java/org/amahi/anywhere/activity/NativeVideoActivity.java @@ -60,36 +60,33 @@ * Backed up by {@link android.media.MediaPlayer}. */ public class NativeVideoActivity extends AppCompatActivity implements - MediaPlayer.OnPreparedListener, - MediaPlayer.OnCompletionListener, - SessionManagerListener -{ + MediaPlayer.OnPreparedListener, + MediaPlayer.OnCompletionListener, + SessionManagerListener { private static final Set SUPPORTED_FORMATS; private static final String VIDEO_POSITION = "video_position"; static { SUPPORTED_FORMATS = new HashSet<>(Arrays.asList( - "video/3gp", - "video/mp4", - "video/ts", - "video/webm", - "video/x-matroska" + "video/3gp", + "video/mp4", + "video/ts", + "video/webm", + "video/x-matroska" )); } - public static boolean supports(String mime_type) { - return SUPPORTED_FORMATS.contains(mime_type); - } - @Inject ServerClient serverClient; - private MediaControls videoControls; private VideoView videoView; - private CastContext mCastContext; - private CastSession mCastSession; + private CastSession mCastSession; + + public static boolean supports(String mime_type) { + return SUPPORTED_FORMATS.contains(mime_type); + } @Override protected void onCreate(Bundle savedInstanceState) { @@ -121,18 +118,18 @@ private void setUpHomeNavigation() { private void setUpCast() { mCastContext = CastContext.getSharedInstance(this); - mCastSession = mCastContext.getSessionManager().getCurrentCastSession(); + mCastSession = mCastContext.getSessionManager().getCurrentCastSession(); } private void setUpVideo() { - if (mCastSession != null && mCastSession.isConnected()) { - loadRemoteMedia(0, true); - finish(); - } else { - setUpVideoTitle(); - setUpVideoView(); - startVideo(); - } + if (mCastSession != null && mCastSession.isConnected()) { + loadRemoteMedia(0, true); + finish(); + } else { + setUpVideoTitle(); + setUpVideoView(); + startVideo(); + } } private ServerShare getVideoShare() { @@ -159,26 +156,26 @@ private ProgressBar getProgressBar() { return (ProgressBar) findViewById(android.R.id.progress); } - private void setUpVideoView() { - videoView = (VideoView) findViewById(R.id.video_view); - setUpVideoControls(); - videoView.setOnPreparedListener(this); - videoView.setOnCompletionListener(this); - videoView.setVideoURI(getVideoUri()); - videoView.setMediaController(videoControls); - } - - private void startVideo() { - Bundle bundle = getIntent().getExtras(); - boolean shouldStartPlayback = bundle.getBoolean("shouldStart", true); - int startPosition = bundle.getInt("startPosition", 0); - if (startPosition > 0) { - videoView.seekTo(startPosition); - } - if (shouldStartPlayback) { - videoView.start(); - } - } + private void setUpVideoView() { + videoView = (VideoView) findViewById(R.id.video_view); + setUpVideoControls(); + videoView.setOnPreparedListener(this); + videoView.setOnCompletionListener(this); + videoView.setVideoURI(getVideoUri()); + videoView.setMediaController(videoControls); + } + + private void startVideo() { + Bundle bundle = getIntent().getExtras(); + boolean shouldStartPlayback = bundle.getBoolean("shouldStart", true); + int startPosition = bundle.getInt("startPosition", 0); + if (startPosition > 0) { + videoView.seekTo(startPosition); + } + if (shouldStartPlayback) { + videoView.start(); + } + } private boolean areVideoControlsAvailable() { return videoControls != null; @@ -199,16 +196,16 @@ private void setUpFullScreen() { fullScreen.init(); } - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - getMenuInflater().inflate(R.menu.action_bar_cast_button, menu); - CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), menu, - R.id.media_route_menu_item); - return true; - } + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + getMenuInflater().inflate(R.menu.action_bar_cast_button, menu); + CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), menu, + R.id.media_route_menu_item); + return true; + } - @Override + @Override public boolean onOptionsItemSelected(MenuItem menuItem) { switch (menuItem.getItemId()) { case android.R.id.home: @@ -220,31 +217,31 @@ public boolean onOptionsItemSelected(MenuItem menuItem) { } } - @Override - protected void onResume() { - mCastContext.getSessionManager().addSessionManagerListener(this, CastSession.class); - super.onResume(); - } + @Override + protected void onResume() { + mCastContext.getSessionManager().addSessionManagerListener(this, CastSession.class); + super.onResume(); + } - @Override + @Override public void onPause() { super.onPause(); - mCastContext.getSessionManager().removeSessionManagerListener(this, CastSession.class); + mCastContext.getSessionManager().removeSessionManagerListener(this, CastSession.class); - if (videoControls != null && videoControls.isShowing()) { - videoControls.hide(); - } + if (videoControls != null && videoControls.isShowing()) { + videoControls.hide(); + } - if (videoView != null) { - if (!isChangingConfigurations()) { - videoView.pause(); - } + if (videoView != null) { + if (!isChangingConfigurations()) { + videoView.pause(); + } - if (isFinishing()) { - videoView.stopPlayback(); - } - } + if (isFinishing()) { + videoView.stopPlayback(); + } + } } @Override @@ -256,9 +253,9 @@ public void onPrepared(MediaPlayer mp) { @Override protected void onSaveInstanceState(Bundle outState) { - if (videoView != null) { - outState.putInt(VIDEO_POSITION, videoView.getCurrentPosition()); - } + if (videoView != null) { + outState.putInt(VIDEO_POSITION, videoView.getCurrentPosition()); + } super.onSaveInstanceState(outState); } @@ -276,98 +273,105 @@ public void onCompletion(MediaPlayer mp) { finish(); } - @Override - public void onSessionEnded(CastSession session, int error) {} - - @Override - public void onSessionResumed(CastSession session, boolean wasSuspended) { - onApplicationConnected(session); - } - - @Override - public void onSessionResumeFailed(CastSession session, int error) {} - - @Override - public void onSessionStarted(CastSession session, String sessionId) { - onApplicationConnected(session); - } - - @Override - public void onSessionStartFailed(CastSession session, int error) {} - - @Override - public void onSessionStarting(CastSession session) {} - - @Override - public void onSessionEnding(CastSession session) {} - - @Override - public void onSessionResuming(CastSession session, String sessionId) {} - - @Override - public void onSessionSuspended(CastSession session, int reason) {} - - private void onApplicationConnected(CastSession castSession) { - mCastSession = castSession; - boolean isVideoPlaying = videoView.isPlaying(); - if (isVideoPlaying) - videoView.pause(); - loadRemoteMedia(videoView.getCurrentPosition(), isVideoPlaying); - finish(); - } - - private void loadRemoteMedia(int position, boolean autoPlay) { - if (mCastSession == null) { - return; - } - final RemoteMediaClient remoteMediaClient = mCastSession.getRemoteMediaClient(); - if (remoteMediaClient == null) { - return; - } - remoteMediaClient.addListener(new RemoteMediaClient.Listener() { - @Override - public void onStatusUpdated() { - Intent intent = new Intent(NativeVideoActivity.this, ExpandedControlsActivity.class); - startActivity(intent); - remoteMediaClient.removeListener(this); - } - - @Override - public void onMetadataUpdated() { - } - - @Override - public void onQueueStatusUpdated() { - } - - @Override - public void onPreloadStatusUpdated() { - } - - @Override - public void onSendingRemoteMediaRequest() { - } - - @Override - public void onAdBreakStatusUpdated() { - - } - }); - remoteMediaClient.load(buildMediaInfo(), autoPlay, position); - } - - private MediaInfo buildMediaInfo() { - MediaMetadata movieMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE); - - movieMetadata.putString(MediaMetadata.KEY_TITLE, getVideoFile().getNameOnly()); - - MediaInfo.Builder builder = new MediaInfo.Builder(getVideoUri().toString()) - .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) - .setContentType(getVideoFile().getMime()) - .setMetadata(movieMetadata); - if (videoView != null) { - builder.setStreamDuration(videoView.getDuration()); - } - return builder.build(); - } + @Override + public void onSessionEnded(CastSession session, int error) { + } + + @Override + public void onSessionResumed(CastSession session, boolean wasSuspended) { + onApplicationConnected(session); + } + + @Override + public void onSessionResumeFailed(CastSession session, int error) { + } + + @Override + public void onSessionStarted(CastSession session, String sessionId) { + onApplicationConnected(session); + } + + @Override + public void onSessionStartFailed(CastSession session, int error) { + } + + @Override + public void onSessionStarting(CastSession session) { + } + + @Override + public void onSessionEnding(CastSession session) { + } + + @Override + public void onSessionResuming(CastSession session, String sessionId) { + } + + @Override + public void onSessionSuspended(CastSession session, int reason) { + } + + private void onApplicationConnected(CastSession castSession) { + mCastSession = castSession; + boolean isVideoPlaying = videoView.isPlaying(); + if (isVideoPlaying) + videoView.pause(); + loadRemoteMedia(videoView.getCurrentPosition(), isVideoPlaying); + finish(); + } + + private void loadRemoteMedia(int position, boolean autoPlay) { + if (mCastSession == null) { + return; + } + final RemoteMediaClient remoteMediaClient = mCastSession.getRemoteMediaClient(); + if (remoteMediaClient == null) { + return; + } + remoteMediaClient.addListener(new RemoteMediaClient.Listener() { + @Override + public void onStatusUpdated() { + Intent intent = new Intent(NativeVideoActivity.this, ExpandedControlsActivity.class); + startActivity(intent); + remoteMediaClient.removeListener(this); + } + + @Override + public void onMetadataUpdated() { + } + + @Override + public void onQueueStatusUpdated() { + } + + @Override + public void onPreloadStatusUpdated() { + } + + @Override + public void onSendingRemoteMediaRequest() { + } + + @Override + public void onAdBreakStatusUpdated() { + + } + }); + remoteMediaClient.load(buildMediaInfo(), autoPlay, position); + } + + private MediaInfo buildMediaInfo() { + MediaMetadata movieMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE); + + movieMetadata.putString(MediaMetadata.KEY_TITLE, getVideoFile().getNameOnly()); + + MediaInfo.Builder builder = new MediaInfo.Builder(getVideoUri().toString()) + .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) + .setContentType(getVideoFile().getMime()) + .setMetadata(movieMetadata); + if (videoView != null) { + builder.setStreamDuration(videoView.getDuration()); + } + return builder.build(); + } } diff --git a/src/main/java/org/amahi/anywhere/activity/NavigationActivity.java b/src/main/java/org/amahi/anywhere/activity/NavigationActivity.java index 85475a0a2..7e3064e72 100644 --- a/src/main/java/org/amahi/anywhere/activity/NavigationActivity.java +++ b/src/main/java/org/amahi/anywhere/activity/NavigationActivity.java @@ -47,7 +47,6 @@ import org.amahi.anywhere.server.model.ServerApp; import org.amahi.anywhere.server.model.ServerShare; import org.amahi.anywhere.tv.activity.IntroActivity; -import org.amahi.anywhere.tv.activity.MainTVActivity; import org.amahi.anywhere.util.Android; import org.amahi.anywhere.util.CheckTV; import org.amahi.anywhere.util.Fragments; @@ -64,17 +63,8 @@ * {@link org.amahi.anywhere.fragment.ServerSharesFragment} and {@link org.amahi.anywhere.fragment.ServerAppsFragment}. */ public class NavigationActivity extends AppCompatActivity implements DrawerLayout.DrawerListener { - private static final class State { - private State() { - } - - public static final String NAVIGATION_TITLE = "navigation_title"; - public static final String NAVIGATION_DRAWER_VISIBLE = "navigation_drawer_visible"; - } - @Inject ServerClient serverClient; - private ActionBarDrawerToggle navigationDrawerToggle; private String navigationTitle; @@ -117,8 +107,8 @@ private void showTvLoading() { setUpShares(); } - private void inflateStubs(){ - ViewStub tvLoadingStub = (ViewStub)findViewById(R.id.view_stub_tv_loading); + private void inflateStubs() { + ViewStub tvLoadingStub = (ViewStub) findViewById(R.id.view_stub_tv_loading); tvLoadingStub.inflate(); } @@ -398,4 +388,11 @@ protected void onPause() { BusProvider.getBus().unregister(this); } + + private static final class State { + public static final String NAVIGATION_TITLE = "navigation_title"; + public static final String NAVIGATION_DRAWER_VISIBLE = "navigation_drawer_visible"; + private State() { + } + } } diff --git a/src/main/java/org/amahi/anywhere/activity/ServerAppActivity.java b/src/main/java/org/amahi/anywhere/activity/ServerAppActivity.java index dc6ec00ee..9e20bfc99 100644 --- a/src/main/java/org/amahi/anywhere/activity/ServerAppActivity.java +++ b/src/main/java/org/amahi/anywhere/activity/ServerAppActivity.java @@ -48,213 +48,210 @@ * App activity. Shows web apps contents and allows basic navigation inside them. * Backed up by {@link android.webkit.WebView}. */ -public class ServerAppActivity extends AppCompatActivity -{ - private static final class AppWebAgentField - { - private AppWebAgentField() { - } +public class ServerAppActivity extends AppCompatActivity { + @Inject + ServerClient serverClient; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_server_app); + + setUpInjections(); + + setUpApp(savedInstanceState); + + getSupportActionBar().setIcon(R.drawable.ic_launcher); + } + + private void setUpInjections() { + AmahiApplication.from(this).inject(this); + } + + private void setUpApp(Bundle state) { + setUpAppWebCookie(); + setUpAppWebAgent(); + setUpAppWebClient(); + setUpAppWebSettings(); + setUpAppWebTitle(); + setUpAppWebContent(state); + } + + private void setUpAppWebCookie() { + String appHost = getApp().getHost(); + String appCookies = Preferences.ofCookie(this).getAppCookies(appHost); + + for (String appCookie : TextUtils.split(appCookies, ";")) { + CookieManager.getInstance().setCookie(getAppUrl(), appCookie); + } + } + + private ServerApp getApp() { + return getIntent().getParcelableExtra(Intents.Extras.SERVER_APP); + } + + private String getAppUrl() { + return serverClient.getServerAddress(); + } + + private void setUpAppWebAgent() { + getWebView().getSettings().setUserAgentString(getAppWebAgent()); + } + + private WebView getWebView() { + return (WebView) findViewById(R.id.web_content); + } - public static final String HOST = "Vhost"; - } + private String getAppWebAgent() { + Map agentFields = new HashMap(); + agentFields.put(AppWebAgentField.HOST, getApp().getHost()); + + return Identifier.getUserAgent(this, agentFields); + } + + private void setUpAppWebClient() { + getWebView().setWebViewClient(new AppWebClient(this)); + } - @Inject - ServerClient serverClient; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_server_app); - - setUpInjections(); - - setUpApp(savedInstanceState); - - getSupportActionBar().setIcon(R.drawable.ic_launcher); - } - - private void setUpInjections() { - AmahiApplication.from(this).inject(this); - } - - private void setUpApp(Bundle state) { - setUpAppWebCookie(); - setUpAppWebAgent(); - setUpAppWebClient(); - setUpAppWebSettings(); - setUpAppWebTitle(); - setUpAppWebContent(state); - } - - private void setUpAppWebCookie() { - String appHost = getApp().getHost(); - String appCookies = Preferences.ofCookie(this).getAppCookies(appHost); - - for (String appCookie : TextUtils.split(appCookies, ";")) { - CookieManager.getInstance().setCookie(getAppUrl(), appCookie); - } - } - - private ServerApp getApp() { - return getIntent().getParcelableExtra(Intents.Extras.SERVER_APP); - } - - private String getAppUrl() { - return serverClient.getServerAddress(); - } - - private void setUpAppWebAgent() { - getWebView().getSettings().setUserAgentString(getAppWebAgent()); - } - - private WebView getWebView() { - return (WebView) findViewById(R.id.web_content); - } + private void setUpAppWebSettings() { + WebSettings settings = getWebView().getSettings(); + + settings.setJavaScriptEnabled(true); - private String getAppWebAgent() { - Map agentFields = new HashMap(); - agentFields.put(AppWebAgentField.HOST, getApp().getHost()); - - return Identifier.getUserAgent(this, agentFields); - } - - private void setUpAppWebClient() { - getWebView().setWebViewClient(new AppWebClient(this)); - } + settings.setUseWideViewPort(true); + + settings.setSupportZoom(true); + settings.setBuiltInZoomControls(true); + settings.setDisplayZoomControls(false); + } + + private void setUpAppWebTitle() { + getSupportActionBar().setTitle(getApp().getName()); + } - private void setUpAppWebSettings() { - WebSettings settings = getWebView().getSettings(); - - settings.setJavaScriptEnabled(true); + private void setUpAppWebContent(Bundle state) { + if (state == null) { + getWebView().loadUrl(getAppUrl()); + } + } - settings.setUseWideViewPort(true); - - settings.setSupportZoom(true); - settings.setBuiltInZoomControls(true); - settings.setDisplayZoomControls(false); - } - - private void setUpAppWebTitle() { - getSupportActionBar().setTitle(getApp().getName()); - } - - private void setUpAppWebContent(Bundle state) { - if (state == null) { - getWebView().loadUrl(getAppUrl()); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.action_bar_server_app, menu); - - return super.onCreateOptionsMenu(menu); - } + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.action_bar_server_app, menu); - @Override - public boolean onOptionsItemSelected(MenuItem menuItem) { - switch (menuItem.getItemId()) { - case android.R.id.home: - finish(); - return true; + return super.onCreateOptionsMenu(menu); + } - case R.id.menu_back: - if (getWebView().canGoBack()) { - getWebView().goBack(); - } - return true; + @Override + public boolean onOptionsItemSelected(MenuItem menuItem) { + switch (menuItem.getItemId()) { + case android.R.id.home: + finish(); + return true; - case R.id.menu_forward: - if (getWebView().canGoForward()) { - getWebView().goForward(); - } - return true; - - default: - return super.onOptionsItemSelected(menuItem); - } - } - - @Override - protected void onRestoreInstanceState(Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); - - getWebView().restoreState(savedInstanceState); - } - - @Override - protected void onResume() { - super.onResume(); + case R.id.menu_back: + if (getWebView().canGoBack()) { + getWebView().goBack(); + } + return true; - getWebView().onResume(); - getWebView().resumeTimers(); - } + case R.id.menu_forward: + if (getWebView().canGoForward()) { + getWebView().goForward(); + } + return true; - @Override - protected void onPause() { - super.onPause(); + default: + return super.onOptionsItemSelected(menuItem); + } + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + + getWebView().restoreState(savedInstanceState); + } - getWebView().onPause(); - getWebView().pauseTimers(); - } + @Override + protected void onResume() { + super.onResume(); - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); + getWebView().onResume(); + getWebView().resumeTimers(); + } - getWebView().saveState(outState); - } + @Override + protected void onPause() { + super.onPause(); - @Override - protected void onDestroy() { - super.onDestroy(); + getWebView().onPause(); + getWebView().pauseTimers(); + } - getWebView().destroy(); + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); - if (isFinishing()) { - tearDownAppWebCookie(); - } - } + getWebView().saveState(outState); + } - private void tearDownAppWebCookie() { - String appHost = getApp().getHost(); - String appCookies = CookieManager.getInstance().getCookie(getAppUrl()); + @Override + protected void onDestroy() { + super.onDestroy(); - Preferences.ofCookie(this).setAppCookies(appHost, appCookies); + getWebView().destroy(); - if (CookieManager.getInstance().hasCookies()) { - CookieManager.getInstance().removeAllCookie(); - } - } + if (isFinishing()) { + tearDownAppWebCookie(); + } + } - private static final class AppWebClient extends WebViewClient - { - private final ServerAppActivity activity; - - public AppWebClient(ServerAppActivity activity) { - this.activity = activity; - } - - @Override - public void onPageStarted(WebView appWebView, String appUrl, Bitmap appFavicon) { - super.onPageStarted(appWebView, appUrl, appFavicon); - - activity.showProgress(); - } - - @Override - public void onPageFinished(WebView appWebView, String appUrl) { - super.onPageFinished(appWebView, appUrl); - - activity.showApp(); - } - } - - private void showProgress() { - ViewDirector.of(this, R.id.animator).show(android.R.id.progress); - } - - private void showApp() { - ViewDirector.of(this, R.id.animator).show(R.id.web_content); - } + private void tearDownAppWebCookie() { + String appHost = getApp().getHost(); + String appCookies = CookieManager.getInstance().getCookie(getAppUrl()); + + Preferences.ofCookie(this).setAppCookies(appHost, appCookies); + + if (CookieManager.getInstance().hasCookies()) { + CookieManager.getInstance().removeAllCookie(); + } + } + + private void showProgress() { + ViewDirector.of(this, R.id.animator).show(android.R.id.progress); + } + + private void showApp() { + ViewDirector.of(this, R.id.animator).show(R.id.web_content); + } + + private static final class AppWebAgentField { + public static final String HOST = "Vhost"; + + private AppWebAgentField() { + } + } + + private static final class AppWebClient extends WebViewClient { + private final ServerAppActivity activity; + + public AppWebClient(ServerAppActivity activity) { + this.activity = activity; + } + + @Override + public void onPageStarted(WebView appWebView, String appUrl, Bitmap appFavicon) { + super.onPageStarted(appWebView, appUrl, appFavicon); + + activity.showProgress(); + } + + @Override + public void onPageFinished(WebView appWebView, String appUrl) { + super.onPageFinished(appWebView, appUrl); + + activity.showApp(); + } + } } diff --git a/src/main/java/org/amahi/anywhere/activity/ServerFileAudioActivity.java b/src/main/java/org/amahi/anywhere/activity/ServerFileAudioActivity.java index e054267dd..80c85f3e4 100644 --- a/src/main/java/org/amahi/anywhere/activity/ServerFileAudioActivity.java +++ b/src/main/java/org/amahi/anywhere/activity/ServerFileAudioActivity.java @@ -77,599 +77,595 @@ * Backed up by {@link android.media.MediaPlayer}. */ public class ServerFileAudioActivity extends AppCompatActivity implements - ServiceConnection, - MediaController.MediaPlayerControl, - SessionManagerListener { - private CastContext mCastContext; - private CastSession mCastSession; - private AudioMetadataFormatter metadataFormatter; - - private static final Set SUPPORTED_FORMATS; - - static { - SUPPORTED_FORMATS = new HashSet<>(Arrays.asList( - "audio/flac", - "audio/mp4", - "audio/mpeg", - "audio/ogg" - )); - } - - private PlaybackLocation mLocation = PlaybackLocation.LOCAL; - - private enum PlaybackLocation { - LOCAL, - REMOTE - } - - public static boolean supports(String mime_type) { - return SUPPORTED_FORMATS.contains(mime_type); - } - - @Inject - ServerClient serverClient; - - private AudioService audioService; - private MediaControls audioControls; - - private ServerFile audioFile; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_server_file_audio); - - setUpInjections(); - - setUpHomeNavigation(); - - setUpCast(); - - setUpAudio(); - } - - private void setUpInjections() { - AmahiApplication.from(this).inject(this); - } - - private void setUpHomeNavigation() { - getSupportActionBar().setHomeButtonEnabled(true); - getSupportActionBar().setIcon(R.drawable.ic_launcher); - } - - private void setUpCast() { - mCastContext = CastContext.getSharedInstance(this); - mCastSession = mCastContext.getSessionManager().getCurrentCastSession(); - if (mCastSession != null && mCastSession.isConnected()) { - mLocation = PlaybackLocation.REMOTE; - } - } - - private void setUpAudio() { - setUpAudioFile(); - setUpAudioTitle(); - } - - private void setUpAudioFile() { - this.audioFile = getFile(); - } - - private ServerFile getFile() { - return getIntent().getParcelableExtra(Intents.Extras.SERVER_FILE); - } - - private void setUpAudioTitle() { - getSupportActionBar().setTitle(audioFile.getName()); - } - - private TextView getAudioTitleView() { - return (TextView) findViewById(R.id.text_title); - } - - private TextView getAudioSubtitleView() { - return (TextView) findViewById(R.id.text_subtitle); - } - - private ImageView getAudioAlbumArtView() { - return (ImageView) findViewById(R.id.image_album_art); - } - - private void showAudioMetadata() { - ViewDirector.of(this, R.id.animator).show(R.id.layout_content); - } - - @Subscribe - public void onAudioMetadataRetrieved(AudioMetadataRetrievedEvent event) { - metadataFormatter = new AudioMetadataFormatter( - event.getAudioTitle(), event.getAudioArtist(), event.getAudioAlbum()); - metadataFormatter.setDuration(event.getDuration()); - if (mLocation == PlaybackLocation.LOCAL) { - setUpAudioMetadata(metadataFormatter, event.getAudioAlbumArt()); - } else if (mLocation == PlaybackLocation.REMOTE) { - loadRemoteMedia(0, true); - finish(); - } - } - - private void setUpAudioMetadata(AudioMetadataFormatter audioMetadataFormatter, Bitmap audioAlbumArt) { - getAudioTitleView().setText(audioMetadataFormatter.getAudioTitle(audioFile)); - getAudioSubtitleView().setText(audioMetadataFormatter.getAudioSubtitle(getShare())); - if (audioAlbumArt == null) { - audioAlbumArt = BitmapFactory.decodeResource(getResources(), R.drawable.default_audiotrack); - getAudioAlbumArtView().setScaleType(ImageView.ScaleType.CENTER_INSIDE); - } else { - getAudioAlbumArtView().setScaleType(ImageView.ScaleType.CENTER_CROP); - } - getAudioAlbumArtView().setImageBitmap(audioAlbumArt); - } - - private ServerShare getShare() { - return getIntent().getParcelableExtra(Intents.Extras.SERVER_SHARE); - } - - private Uri getAudioUri() { - return serverClient.getFileUri(getShare(), getFile()); - } - - @Override - protected void onStart() { - super.onStart(); - - if (mLocation == PlaybackLocation.LOCAL) { - setUpAudioService(); - setUpAudioServiceBind(); - } else if (mLocation == PlaybackLocation.REMOTE) { - AudioMetadataRetrievingTask.execute(getAudioUri(), audioFile); - } - } - - private void setUpAudioService() { - Intent intent = new Intent(this, AudioService.class); - startService(intent); - } - - private void setUpAudioServiceBind() { - Intent intent = new Intent(this, AudioService.class); - bindService(intent, this, Context.BIND_AUTO_CREATE); - } - - @Override - public void onServiceDisconnected(ComponentName serviceName) { - } - - @Override - public void onServiceConnected(ComponentName serviceName, IBinder serviceBinder) { - setUpAudioServiceBind(serviceBinder); - - setUpAudioControls(); - setUpAudioPlayback(); - } - - private void setUpAudioServiceBind(IBinder serviceBinder) { - AudioService.AudioServiceBinder audioServiceBinder = (AudioService.AudioServiceBinder) serviceBinder; - audioService = audioServiceBinder.getAudioService(); - } - - private void setUpAudioControls() { - if (!areAudioControlsAvailable()) { - audioControls = new MediaControls(this); - - audioControls.setMediaPlayer(this); - audioControls.setPrevNextListeners(new AudioControlsNextListener(), new AudioControlsPreviousListener()); - audioControls.setAnchorView(findViewById(R.id.animator)); - } - } - - private boolean areAudioControlsAvailable() { - return audioControls != null; - } - - private void setUpAudioPlayback() { - if (audioService.isAudioStarted()) { - showAudio(); - setUpAudioMetadata(); - } else { - audioService.startAudio(getShare(), getAudioFiles(), getFile()); - } - } - - private List getAudioFiles() { - List audioFiles = new ArrayList(); - - for (ServerFile file : getFiles()) { - if (SUPPORTED_FORMATS.contains(file.getMime())) { - audioFiles.add(file); - } - } - - return audioFiles; - } - - private List getFiles() { - return getIntent().getParcelableArrayListExtra(Intents.Extras.SERVER_FILES); - } - - @Subscribe - public void onAudioPrepared(AudioPreparedEvent event) { - this.audioFile = audioService.getAudioFile(); - - start(); - - setUpAudioTitle(); - - showAudio(); - } - - private void showAudio() { - showAudioMetadata(); - showAudioControls(); - } - - private void showAudioControls() { - if (areAudioControlsAvailable() && !audioControls.isShowing()) { - audioControls.show(0); - } - } - - @Subscribe - public void onNextAudio(AudioControlNextEvent event) { - tearDownAudioTitle(); - tearDownAudioMetadata(); - - hideAudio(); - } - - @Subscribe - public void onPreviousAudio(AudioControlPreviousEvent event) { - tearDownAudioTitle(); - tearDownAudioMetadata(); - - hideAudio(); - } - - @Subscribe - public void onAudioCompleted(AudioCompletedEvent event) { - tearDownAudioTitle(); - tearDownAudioMetadata(); - - hideAudio(); - } - - private void tearDownAudioTitle() { - getSupportActionBar().setTitle(null); - } - - private void tearDownAudioMetadata() { - getAudioTitleView().setText(null); - getAudioSubtitleView().setText(null); - getAudioAlbumArtView().setImageBitmap(null); - } - - private void hideAudio() { - hideAudioMetadata(); - hideAudioControls(); - } - - private void hideAudioMetadata() { - ViewDirector.of(this, R.id.animator).show(android.R.id.progress); - } - - private void hideAudioControls() { - if (areAudioControlsAvailable() && audioControls.isShowing()) { - audioControls.hide(); - } - } - - @Override - public void start() { - audioService.playAudio(); - } - - @Override - public boolean canPause() { - return true; - } - - @Override - public void pause() { - audioService.pauseAudio(); - } - - @Override - public boolean canSeekBackward() { - return true; - } - - @Override - public boolean canSeekForward() { - return true; - } - - @Override - public void seekTo(int time) { - audioService.getAudioPlayer().seekTo(time); - } - - @Override - public int getDuration() { - return audioService.getAudioPlayer().getDuration(); - } - - @Override - public int getCurrentPosition() { - return audioService.getAudioPlayer().getCurrentPosition(); - } - - @Override - public boolean isPlaying() { - return audioService.getAudioPlayer().isPlaying(); - } - - @Override - public int getBufferPercentage() { - return 0; - } - - @Override - public int getAudioSessionId() { - return audioService.getAudioPlayer().getAudioSessionId(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - getMenuInflater().inflate(R.menu.action_bar_cast_button, menu); - CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), menu, - R.id.media_route_menu_item); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem menuItem) { - switch (menuItem.getItemId()) { - case android.R.id.home: - finish(); - return true; - - default: - return super.onOptionsItemSelected(menuItem); - } - } - - @Override - protected void onResume() { - super.onResume(); - - mCastContext.getSessionManager().addSessionManagerListener(this, CastSession.class); - - showAudioControlsForced(); - - BusProvider.getBus().register(this); - - if (hasAudioFileChanged()) { - setUpAudioMetadata(); - } - } - - private void showAudioControlsForced() { - if (areAudioControlsAvailable() && !audioControls.isShowing()) { - audioControls.show(0); - } - } - - private boolean hasAudioFileChanged() { - return isAudioServiceAvailable() && !this.audioFile.equals(audioService.getAudioFile()); - } - - private void setUpAudioMetadata() { - if (!isAudioServiceAvailable()) { - return; - } - - metadataFormatter = audioService.getAudioMetadataFormatter(); - this.audioFile = audioService.getAudioFile(); - - tearDownAudioTitle(); - tearDownAudioMetadata(); - - setUpAudioTitle(); - setUpAudioMetadata(audioService.getAudioMetadataFormatter(), audioService.getAudioAlbumArt()); - } - - private boolean isAudioServiceAvailable() { - return audioService != null; - } - - @Override - protected void onPause() { - super.onPause(); - - mCastContext.getSessionManager().removeSessionManagerListener(this, CastSession.class); - - hideAudioControlsForced(); - - BusProvider.getBus().unregister(this); - - if (isAudioServiceAvailable() && isFinishing()) { - tearDownAudioPlayback(); - } - } - - private void hideAudioControlsForced() { - if (areAudioControlsAvailable() && audioControls.isShowing()) { - audioControls.hide(); - } - } - - private void tearDownAudioPlayback() { - audioService.pauseAudio(); - } - - @Override - protected void onStop() { - super.onStop(); - - if (isAudioServiceAvailable()) { - tearDownAudioServiceBind(); - } - } - - private void tearDownAudioServiceBind() { - unbindService(this); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - - if (isAudioServiceAvailable() && isFinishing()) { - tearDownAudioService(); - } - } - - private void tearDownAudioService() { - Intent intent = new Intent(this, AudioService.class); - stopService(intent); - } - - private static final class AudioControlsNextListener implements View.OnClickListener { - @Override - public void onClick(View view) { - BusProvider.getBus().post(new AudioControlNextEvent()); - } - } - - private static final class AudioControlsPreviousListener implements View.OnClickListener { - @Override - public void onClick(View view) { - BusProvider.getBus().post(new AudioControlPreviousEvent()); - } - } - - @Override - public void onSessionEnded(CastSession session, int error) { - onApplicationDisconnected(); - } - - @Override - public void onSessionResumed(CastSession session, boolean wasSuspended) { - onApplicationConnected(session); - } - - @Override - public void onSessionResumeFailed(CastSession session, int error) { - onApplicationDisconnected(); - } - - @Override - public void onSessionStarted(CastSession session, String sessionId) { - onApplicationConnected(session); - } - - @Override - public void onSessionStartFailed(CastSession session, int error) { - onApplicationDisconnected(); - } - - @Override - public void onSessionStarting(CastSession session) { - } - - @Override - public void onSessionEnding(CastSession session) { - } - - @Override - public void onSessionResuming(CastSession session, String sessionId) { - } - - @Override - public void onSessionSuspended(CastSession session, int reason) { - } - - private void onApplicationConnected(CastSession castSession) { - mCastSession = castSession; - boolean isPlaying = false; - int position = 0; - if (audioService != null) { - isPlaying = audioService.isAudioStarted(); - if (isPlaying) { - audioService.pauseAudio(); - position = audioService.getAudioPlayer().getCurrentPosition(); - } - } - loadRemoteMedia(position, isPlaying); - finish(); - } - - private void onApplicationDisconnected() { - mCastSession = null; - mLocation = PlaybackLocation.LOCAL; - invalidateOptionsMenu(); - if (!isAudioServiceAvailable()) { - setUpAudioService(); - setUpAudioServiceBind(); - } - } - - private void loadRemoteMedia(int position, boolean autoPlay) { - if (mCastSession == null) { - return; - } - final RemoteMediaClient remoteMediaClient = mCastSession.getRemoteMediaClient(); - if (remoteMediaClient == null) { - return; - } - remoteMediaClient.addListener(new RemoteMediaClient.Listener() { - @Override - public void onStatusUpdated() { - Intent intent = new Intent(ServerFileAudioActivity.this, ExpandedControlsActivity.class); - startActivity(intent); - remoteMediaClient.removeListener(this); - } - - @Override - public void onMetadataUpdated() { - } - - @Override - public void onQueueStatusUpdated() { - } - - @Override - public void onPreloadStatusUpdated() { - } - - @Override - public void onSendingRemoteMediaRequest() { - } - - @Override - public void onAdBreakStatusUpdated() { - } - }); - remoteMediaClient.load(buildMediaInfo(), autoPlay, position); - } - - private MediaInfo buildMediaInfo() { - MediaMetadata audioMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MUSIC_TRACK); - - if (metadataFormatter != null) { - audioMetadata.putString(MediaMetadata.KEY_TITLE, metadataFormatter.getAudioTitle(getFile())); - audioMetadata.putString(MediaMetadata.KEY_ARTIST, metadataFormatter.getAudioArtist()); - audioMetadata.putString(MediaMetadata.KEY_ALBUM_TITLE, metadataFormatter.getAudioAlbum()); - } else { - audioMetadata.putString(MediaMetadata.KEY_TITLE, getFile().getNameOnly()); - } - - String audioSource = serverClient.getFileUri(getShare(), getFile()).toString(); - MediaInfo.Builder builder = new MediaInfo.Builder(audioSource) - .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) - .setContentType(getFile().getMime()) - .setMetadata(audioMetadata); - if (metadataFormatter != null) { - builder.setStreamDuration(metadataFormatter.getDuration()); - } - return builder.build(); - } + ServiceConnection, + MediaController.MediaPlayerControl, + SessionManagerListener { + private static final Set SUPPORTED_FORMATS; + + static { + SUPPORTED_FORMATS = new HashSet<>(Arrays.asList( + "audio/flac", + "audio/mp4", + "audio/mpeg", + "audio/ogg" + )); + } + + @Inject + ServerClient serverClient; + private CastContext mCastContext; + private CastSession mCastSession; + private AudioMetadataFormatter metadataFormatter; + private PlaybackLocation mLocation = PlaybackLocation.LOCAL; + private AudioService audioService; + private MediaControls audioControls; + private ServerFile audioFile; + + public static boolean supports(String mime_type) { + return SUPPORTED_FORMATS.contains(mime_type); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_server_file_audio); + + setUpInjections(); + + setUpHomeNavigation(); + + setUpCast(); + + setUpAudio(); + } + + private void setUpInjections() { + AmahiApplication.from(this).inject(this); + } + + private void setUpHomeNavigation() { + getSupportActionBar().setHomeButtonEnabled(true); + getSupportActionBar().setIcon(R.drawable.ic_launcher); + } + + private void setUpCast() { + mCastContext = CastContext.getSharedInstance(this); + mCastSession = mCastContext.getSessionManager().getCurrentCastSession(); + if (mCastSession != null && mCastSession.isConnected()) { + mLocation = PlaybackLocation.REMOTE; + } + } + + private void setUpAudio() { + setUpAudioFile(); + setUpAudioTitle(); + } + + private void setUpAudioFile() { + this.audioFile = getFile(); + } + + private ServerFile getFile() { + return getIntent().getParcelableExtra(Intents.Extras.SERVER_FILE); + } + + private void setUpAudioTitle() { + getSupportActionBar().setTitle(audioFile.getName()); + } + + private TextView getAudioTitleView() { + return (TextView) findViewById(R.id.text_title); + } + + private TextView getAudioSubtitleView() { + return (TextView) findViewById(R.id.text_subtitle); + } + + private ImageView getAudioAlbumArtView() { + return (ImageView) findViewById(R.id.image_album_art); + } + + private void showAudioMetadata() { + ViewDirector.of(this, R.id.animator).show(R.id.layout_content); + } + + @Subscribe + public void onAudioMetadataRetrieved(AudioMetadataRetrievedEvent event) { + metadataFormatter = new AudioMetadataFormatter( + event.getAudioTitle(), event.getAudioArtist(), event.getAudioAlbum()); + metadataFormatter.setDuration(event.getDuration()); + if (mLocation == PlaybackLocation.LOCAL) { + setUpAudioMetadata(metadataFormatter, event.getAudioAlbumArt()); + } else if (mLocation == PlaybackLocation.REMOTE) { + loadRemoteMedia(0, true); + finish(); + } + } + + private void setUpAudioMetadata(AudioMetadataFormatter audioMetadataFormatter, Bitmap audioAlbumArt) { + getAudioTitleView().setText(audioMetadataFormatter.getAudioTitle(audioFile)); + getAudioSubtitleView().setText(audioMetadataFormatter.getAudioSubtitle(getShare())); + if (audioAlbumArt == null) { + audioAlbumArt = BitmapFactory.decodeResource(getResources(), R.drawable.default_audiotrack); + getAudioAlbumArtView().setScaleType(ImageView.ScaleType.CENTER_INSIDE); + } else { + getAudioAlbumArtView().setScaleType(ImageView.ScaleType.CENTER_CROP); + } + getAudioAlbumArtView().setImageBitmap(audioAlbumArt); + } + + private ServerShare getShare() { + return getIntent().getParcelableExtra(Intents.Extras.SERVER_SHARE); + } + + private Uri getAudioUri() { + return serverClient.getFileUri(getShare(), getFile()); + } + + @Override + protected void onStart() { + super.onStart(); + + if (mLocation == PlaybackLocation.LOCAL) { + setUpAudioService(); + setUpAudioServiceBind(); + } else if (mLocation == PlaybackLocation.REMOTE) { + AudioMetadataRetrievingTask.execute(getAudioUri(), audioFile); + } + } + + private void setUpAudioService() { + Intent intent = new Intent(this, AudioService.class); + startService(intent); + } + + private void setUpAudioServiceBind() { + Intent intent = new Intent(this, AudioService.class); + bindService(intent, this, Context.BIND_AUTO_CREATE); + } + + @Override + public void onServiceDisconnected(ComponentName serviceName) { + } + + @Override + public void onServiceConnected(ComponentName serviceName, IBinder serviceBinder) { + setUpAudioServiceBind(serviceBinder); + + setUpAudioControls(); + setUpAudioPlayback(); + } + + private void setUpAudioServiceBind(IBinder serviceBinder) { + AudioService.AudioServiceBinder audioServiceBinder = (AudioService.AudioServiceBinder) serviceBinder; + audioService = audioServiceBinder.getAudioService(); + } + + private void setUpAudioControls() { + if (!areAudioControlsAvailable()) { + audioControls = new MediaControls(this); + + audioControls.setMediaPlayer(this); + audioControls.setPrevNextListeners(new AudioControlsNextListener(), new AudioControlsPreviousListener()); + audioControls.setAnchorView(findViewById(R.id.animator)); + } + } + + private boolean areAudioControlsAvailable() { + return audioControls != null; + } + + private void setUpAudioPlayback() { + if (audioService.isAudioStarted()) { + showAudio(); + setUpAudioMetadata(); + } else { + audioService.startAudio(getShare(), getAudioFiles(), getFile()); + } + } + + private List getAudioFiles() { + List audioFiles = new ArrayList(); + + for (ServerFile file : getFiles()) { + if (SUPPORTED_FORMATS.contains(file.getMime())) { + audioFiles.add(file); + } + } + + return audioFiles; + } + + private List getFiles() { + return getIntent().getParcelableArrayListExtra(Intents.Extras.SERVER_FILES); + } + + @Subscribe + public void onAudioPrepared(AudioPreparedEvent event) { + this.audioFile = audioService.getAudioFile(); + + start(); + + setUpAudioTitle(); + + showAudio(); + } + + private void showAudio() { + showAudioMetadata(); + showAudioControls(); + } + + private void showAudioControls() { + if (areAudioControlsAvailable() && !audioControls.isShowing()) { + audioControls.show(0); + } + } + + @Subscribe + public void onNextAudio(AudioControlNextEvent event) { + tearDownAudioTitle(); + tearDownAudioMetadata(); + + hideAudio(); + } + + @Subscribe + public void onPreviousAudio(AudioControlPreviousEvent event) { + tearDownAudioTitle(); + tearDownAudioMetadata(); + + hideAudio(); + } + + @Subscribe + public void onAudioCompleted(AudioCompletedEvent event) { + tearDownAudioTitle(); + tearDownAudioMetadata(); + + hideAudio(); + } + + private void tearDownAudioTitle() { + getSupportActionBar().setTitle(null); + } + + private void tearDownAudioMetadata() { + getAudioTitleView().setText(null); + getAudioSubtitleView().setText(null); + getAudioAlbumArtView().setImageBitmap(null); + } + + private void hideAudio() { + hideAudioMetadata(); + hideAudioControls(); + } + + private void hideAudioMetadata() { + ViewDirector.of(this, R.id.animator).show(android.R.id.progress); + } + + private void hideAudioControls() { + if (areAudioControlsAvailable() && audioControls.isShowing()) { + audioControls.hide(); + } + } + + @Override + public void start() { + audioService.playAudio(); + } + + @Override + public boolean canPause() { + return true; + } + + @Override + public void pause() { + audioService.pauseAudio(); + } + + @Override + public boolean canSeekBackward() { + return true; + } + + @Override + public boolean canSeekForward() { + return true; + } + + @Override + public void seekTo(int time) { + audioService.getAudioPlayer().seekTo(time); + } + + @Override + public int getDuration() { + return audioService.getAudioPlayer().getDuration(); + } + + @Override + public int getCurrentPosition() { + return audioService.getAudioPlayer().getCurrentPosition(); + } + + @Override + public boolean isPlaying() { + return audioService.getAudioPlayer().isPlaying(); + } + + @Override + public int getBufferPercentage() { + return 0; + } + + @Override + public int getAudioSessionId() { + return audioService.getAudioPlayer().getAudioSessionId(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + getMenuInflater().inflate(R.menu.action_bar_cast_button, menu); + CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), menu, + R.id.media_route_menu_item); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem menuItem) { + switch (menuItem.getItemId()) { + case android.R.id.home: + finish(); + return true; + + default: + return super.onOptionsItemSelected(menuItem); + } + } + + @Override + protected void onResume() { + super.onResume(); + + mCastContext.getSessionManager().addSessionManagerListener(this, CastSession.class); + + showAudioControlsForced(); + + BusProvider.getBus().register(this); + + if (hasAudioFileChanged()) { + setUpAudioMetadata(); + } + } + + private void showAudioControlsForced() { + if (areAudioControlsAvailable() && !audioControls.isShowing()) { + audioControls.show(0); + } + } + + private boolean hasAudioFileChanged() { + return isAudioServiceAvailable() && !this.audioFile.equals(audioService.getAudioFile()); + } + + private void setUpAudioMetadata() { + if (!isAudioServiceAvailable()) { + return; + } + + metadataFormatter = audioService.getAudioMetadataFormatter(); + this.audioFile = audioService.getAudioFile(); + + tearDownAudioTitle(); + tearDownAudioMetadata(); + + setUpAudioTitle(); + setUpAudioMetadata(audioService.getAudioMetadataFormatter(), audioService.getAudioAlbumArt()); + } + + private boolean isAudioServiceAvailable() { + return audioService != null; + } + + @Override + protected void onPause() { + super.onPause(); + + mCastContext.getSessionManager().removeSessionManagerListener(this, CastSession.class); + + hideAudioControlsForced(); + + BusProvider.getBus().unregister(this); + + if (isAudioServiceAvailable() && isFinishing()) { + tearDownAudioPlayback(); + } + } + + private void hideAudioControlsForced() { + if (areAudioControlsAvailable() && audioControls.isShowing()) { + audioControls.hide(); + } + } + + private void tearDownAudioPlayback() { + audioService.pauseAudio(); + } + + @Override + protected void onStop() { + super.onStop(); + + if (isAudioServiceAvailable()) { + tearDownAudioServiceBind(); + } + } + + private void tearDownAudioServiceBind() { + unbindService(this); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + if (isAudioServiceAvailable() && isFinishing()) { + tearDownAudioService(); + } + } + + private void tearDownAudioService() { + Intent intent = new Intent(this, AudioService.class); + stopService(intent); + } + + @Override + public void onSessionEnded(CastSession session, int error) { + onApplicationDisconnected(); + } + + @Override + public void onSessionResumed(CastSession session, boolean wasSuspended) { + onApplicationConnected(session); + } + + @Override + public void onSessionResumeFailed(CastSession session, int error) { + onApplicationDisconnected(); + } + + @Override + public void onSessionStarted(CastSession session, String sessionId) { + onApplicationConnected(session); + } + + @Override + public void onSessionStartFailed(CastSession session, int error) { + onApplicationDisconnected(); + } + + @Override + public void onSessionStarting(CastSession session) { + } + + @Override + public void onSessionEnding(CastSession session) { + } + + @Override + public void onSessionResuming(CastSession session, String sessionId) { + } + + @Override + public void onSessionSuspended(CastSession session, int reason) { + } + + private void onApplicationConnected(CastSession castSession) { + mCastSession = castSession; + boolean isPlaying = false; + int position = 0; + if (audioService != null) { + isPlaying = audioService.isAudioStarted(); + if (isPlaying) { + audioService.pauseAudio(); + position = audioService.getAudioPlayer().getCurrentPosition(); + } + } + loadRemoteMedia(position, isPlaying); + finish(); + } + + private void onApplicationDisconnected() { + mCastSession = null; + mLocation = PlaybackLocation.LOCAL; + invalidateOptionsMenu(); + if (!isAudioServiceAvailable()) { + setUpAudioService(); + setUpAudioServiceBind(); + } + } + + private void loadRemoteMedia(int position, boolean autoPlay) { + if (mCastSession == null) { + return; + } + final RemoteMediaClient remoteMediaClient = mCastSession.getRemoteMediaClient(); + if (remoteMediaClient == null) { + return; + } + remoteMediaClient.addListener(new RemoteMediaClient.Listener() { + @Override + public void onStatusUpdated() { + Intent intent = new Intent(ServerFileAudioActivity.this, ExpandedControlsActivity.class); + startActivity(intent); + remoteMediaClient.removeListener(this); + } + + @Override + public void onMetadataUpdated() { + } + + @Override + public void onQueueStatusUpdated() { + } + + @Override + public void onPreloadStatusUpdated() { + } + + @Override + public void onSendingRemoteMediaRequest() { + } + + @Override + public void onAdBreakStatusUpdated() { + } + }); + remoteMediaClient.load(buildMediaInfo(), autoPlay, position); + } + + private MediaInfo buildMediaInfo() { + MediaMetadata audioMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MUSIC_TRACK); + + if (metadataFormatter != null) { + audioMetadata.putString(MediaMetadata.KEY_TITLE, metadataFormatter.getAudioTitle(getFile())); + audioMetadata.putString(MediaMetadata.KEY_ARTIST, metadataFormatter.getAudioArtist()); + audioMetadata.putString(MediaMetadata.KEY_ALBUM_TITLE, metadataFormatter.getAudioAlbum()); + } else { + audioMetadata.putString(MediaMetadata.KEY_TITLE, getFile().getNameOnly()); + } + + String audioSource = serverClient.getFileUri(getShare(), getFile()).toString(); + MediaInfo.Builder builder = new MediaInfo.Builder(audioSource) + .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) + .setContentType(getFile().getMime()) + .setMetadata(audioMetadata); + if (metadataFormatter != null) { + builder.setStreamDuration(metadataFormatter.getDuration()); + } + return builder.build(); + } + + private enum PlaybackLocation { + LOCAL, + REMOTE + } + + private static final class AudioControlsNextListener implements View.OnClickListener { + @Override + public void onClick(View view) { + BusProvider.getBus().post(new AudioControlNextEvent()); + } + } + + private static final class AudioControlsPreviousListener implements View.OnClickListener { + @Override + public void onClick(View view) { + BusProvider.getBus().post(new AudioControlPreviousEvent()); + } + } } diff --git a/src/main/java/org/amahi/anywhere/activity/ServerFileImageActivity.java b/src/main/java/org/amahi/anywhere/activity/ServerFileImageActivity.java index fc97d7b31..60faf7970 100644 --- a/src/main/java/org/amahi/anywhere/activity/ServerFileImageActivity.java +++ b/src/main/java/org/amahi/anywhere/activity/ServerFileImageActivity.java @@ -63,288 +63,291 @@ * Backed up by {@link org.amahi.anywhere.view.TouchImageView}. */ public class ServerFileImageActivity extends AppCompatActivity implements - ViewPager.OnPageChangeListener, - SessionManagerListener -{ - private static final Set SUPPORTED_FORMATS; - - static { - SUPPORTED_FORMATS = new HashSet<>(Arrays.asList( - "image/bmp", - "image/jpeg", - "image/gif", - "image/png", - "image/webp" - )); - } - - @Inject - ServerClient serverClient; - private CastSession mCastSession; - private CastContext mCastContext; - private int imagePosition; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_server_file_image); - - setUpInjections(); - - setUpHomeNavigation(); - - setUpImage(); - - setUpCast(); - - setUpFullScreen(); - } - - private void setUpInjections() { - AmahiApplication.from(this).inject(this); - } - - private void setUpFullScreen() { - final FullScreenHelper fullScreen = new FullScreenHelper(getSupportActionBar(), getImagePager()); - fullScreen.enableOnClickToggle(false); - getImagePager().setOnViewPagerClickListener(new ClickableViewPager.OnClickListener() { - @Override - public void onViewPagerClick(ViewPager viewPager) { - fullScreen.toggle(); - } - }); - fullScreen.init(); - } - - private void setUpHomeNavigation() { - getSupportActionBar().setHomeButtonEnabled(true); - getSupportActionBar().setIcon(R.drawable.ic_launcher); - } - - private void setUpImage() { - setUpImageTitle(); - setUpImageAdapter(); - setUpImagePosition(); - setUpImageListener(); - } - - private boolean isCastConnected() { - return mCastSession != null && mCastSession.isConnected(); - } - - private void setUpCast() { - mCastContext = CastContext.getSharedInstance(this); - mCastSession = mCastContext.getSessionManager().getCurrentCastSession(); - if (isCastConnected()) { - loadRemoteMedia(); - } - } - - private void setUpImageTitle() { - setUpImageTitle(getFile()); - } - - private void setUpImageTitle(ServerFile file) { - getSupportActionBar().setTitle(file.getName()); - } - - private ServerFile getFile() { - return getIntent().getParcelableExtra(Intents.Extras.SERVER_FILE); - } - - private void setUpImageAdapter() { - getImagePager().setAdapter(new ServerFilesImagePagerAdapter(getSupportFragmentManager(), getShare(), getImageFiles())); - } - - private ClickableViewPager getImagePager() { - return (ClickableViewPager) findViewById(R.id.pager_images); - } - - private ServerShare getShare() { - return getIntent().getParcelableExtra(Intents.Extras.SERVER_SHARE); - } - - private List getImageFiles() { - List imageFiles = new ArrayList<>(); - - for (ServerFile file : getFiles()) { - if (SUPPORTED_FORMATS.contains(file.getMime())) { - imageFiles.add(file); - } - } - - return imageFiles; - } - - private List getFiles() { - return getIntent().getParcelableArrayListExtra(Intents.Extras.SERVER_FILES); - } - - private void setUpImagePosition() { - imagePosition = getImageFiles().indexOf(getFile()); - getImagePager().setCurrentItem(imagePosition); - } - - private void setUpImageListener() { - getImagePager().addOnPageChangeListener(this); - } - - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - } - - @Override - public void onPageScrollStateChanged(int state) { - } - - @Override - public void onPageSelected(int position) { - this.imagePosition = position; - setUpImageTitle(getImageFiles().get(position)); - if (isCastConnected()) { - loadRemoteMedia(); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.action_bar_server_file_image, menu); - CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), menu, - R.id.media_route_menu_item); - return super.onCreateOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem menuItem) { - switch (menuItem.getItemId()) { - case android.R.id.home: - finish(); - return true; - - case R.id.menu_share: - startFileSharingActivity(); - return true; - - default: - return super.onOptionsItemSelected(menuItem); - } - } - - private void startFileSharingActivity() { - startFileDownloading(getShare(), getCurrentFile()); - } - - private ServerFile getCurrentFile() { - return getImageFiles().get(getImagePager().getCurrentItem()); - } - - private void startFileDownloading(ServerShare share, ServerFile file) { - showFileDownloadingFragment(share, file); - } - - private void showFileDownloadingFragment(ServerShare share, ServerFile file) { - DialogFragment fragment = ServerFileDownloadingFragment.newInstance(share, file); - fragment.show(getFragmentManager(), ServerFileDownloadingFragment.TAG); - } - - @Subscribe - public void onFileDownloaded(FileDownloadedEvent event) { - finishFileDownloading(event.getFileUri()); - } - - private void finishFileDownloading(Uri fileUri) { - startFileSharingActivity(getCurrentFile(), fileUri); - } - - private void startFileSharingActivity(ServerFile file, Uri fileUri) { - Intent intent = Intents.Builder.with(this).buildServerFileSharingIntent(file, fileUri); - startActivity(intent); - } - - @Override - protected void onResume() { - super.onResume(); - - mCastContext.getSessionManager().addSessionManagerListener(this, CastSession.class); - BusProvider.getBus().register(this); - } - - @Override - protected void onPause() { - super.onPause(); - - mCastContext.getSessionManager().removeSessionManagerListener(this, CastSession.class); - BusProvider.getBus().unregister(this); - } - - public static boolean supports(String mime_type) { - return SUPPORTED_FORMATS.contains(mime_type); - } - - @Override - public void onSessionEnded(CastSession session, int error) { - onApplicationDisconnected(); - } - - @Override - public void onSessionResumed(CastSession session, boolean wasSuspended) { - onApplicationConnected(session); - } - - @Override - public void onSessionResumeFailed(CastSession session, int error) { - onApplicationDisconnected(); - } - - @Override - public void onSessionStarted(CastSession session, String sessionId) { - onApplicationConnected(session); - } - - @Override - public void onSessionStartFailed(CastSession session, int error) { - onApplicationDisconnected(); - } - - @Override - public void onSessionStarting(CastSession session) {} - - @Override - public void onSessionEnding(CastSession session) {} - - @Override - public void onSessionResuming(CastSession session, String sessionId) {} - - @Override - public void onSessionSuspended(CastSession session, int reason) {} - - private void onApplicationConnected(CastSession castSession) { - mCastSession = castSession; - invalidateOptionsMenu(); - loadRemoteMedia(); - } - - private void onApplicationDisconnected() { - mCastSession = null; - invalidateOptionsMenu(); - } - - private void loadRemoteMedia() { - final RemoteMediaClient remoteMediaClient = mCastSession.getRemoteMediaClient(); - if (remoteMediaClient != null) { - remoteMediaClient.load(buildMediaInfo()); - } - } - - private MediaInfo buildMediaInfo() { - ServerFile file = getImageFiles().get(imagePosition); - MediaMetadata imageMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_PHOTO); - imageMetadata.putString(MediaMetadata.KEY_TITLE, file.getNameOnly()); - String imageUrl = serverClient.getFileUri(getShare(), file).toString(); - return new MediaInfo.Builder(imageUrl) - .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) - .setContentType(file.getMime()) - .setMetadata(imageMetadata) - .build(); - } + ViewPager.OnPageChangeListener, + SessionManagerListener { + private static final Set SUPPORTED_FORMATS; + + static { + SUPPORTED_FORMATS = new HashSet<>(Arrays.asList( + "image/bmp", + "image/jpeg", + "image/gif", + "image/png", + "image/webp" + )); + } + + @Inject + ServerClient serverClient; + private CastSession mCastSession; + private CastContext mCastContext; + private int imagePosition; + + public static boolean supports(String mime_type) { + return SUPPORTED_FORMATS.contains(mime_type); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_server_file_image); + + setUpInjections(); + + setUpHomeNavigation(); + + setUpImage(); + + setUpCast(); + + setUpFullScreen(); + } + + private void setUpInjections() { + AmahiApplication.from(this).inject(this); + } + + private void setUpFullScreen() { + final FullScreenHelper fullScreen = new FullScreenHelper(getSupportActionBar(), getImagePager()); + fullScreen.enableOnClickToggle(false); + getImagePager().setOnViewPagerClickListener(new ClickableViewPager.OnClickListener() { + @Override + public void onViewPagerClick(ViewPager viewPager) { + fullScreen.toggle(); + } + }); + fullScreen.init(); + } + + private void setUpHomeNavigation() { + getSupportActionBar().setHomeButtonEnabled(true); + getSupportActionBar().setIcon(R.drawable.ic_launcher); + } + + private void setUpImage() { + setUpImageTitle(); + setUpImageAdapter(); + setUpImagePosition(); + setUpImageListener(); + } + + private boolean isCastConnected() { + return mCastSession != null && mCastSession.isConnected(); + } + + private void setUpCast() { + mCastContext = CastContext.getSharedInstance(this); + mCastSession = mCastContext.getSessionManager().getCurrentCastSession(); + if (isCastConnected()) { + loadRemoteMedia(); + } + } + + private void setUpImageTitle() { + setUpImageTitle(getFile()); + } + + private void setUpImageTitle(ServerFile file) { + getSupportActionBar().setTitle(file.getName()); + } + + private ServerFile getFile() { + return getIntent().getParcelableExtra(Intents.Extras.SERVER_FILE); + } + + private void setUpImageAdapter() { + getImagePager().setAdapter(new ServerFilesImagePagerAdapter(getSupportFragmentManager(), getShare(), getImageFiles())); + } + + private ClickableViewPager getImagePager() { + return (ClickableViewPager) findViewById(R.id.pager_images); + } + + private ServerShare getShare() { + return getIntent().getParcelableExtra(Intents.Extras.SERVER_SHARE); + } + + private List getImageFiles() { + List imageFiles = new ArrayList<>(); + + for (ServerFile file : getFiles()) { + if (SUPPORTED_FORMATS.contains(file.getMime())) { + imageFiles.add(file); + } + } + + return imageFiles; + } + + private List getFiles() { + return getIntent().getParcelableArrayListExtra(Intents.Extras.SERVER_FILES); + } + + private void setUpImagePosition() { + imagePosition = getImageFiles().indexOf(getFile()); + getImagePager().setCurrentItem(imagePosition); + } + + private void setUpImageListener() { + getImagePager().addOnPageChangeListener(this); + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + } + + @Override + public void onPageScrollStateChanged(int state) { + } + + @Override + public void onPageSelected(int position) { + this.imagePosition = position; + setUpImageTitle(getImageFiles().get(position)); + if (isCastConnected()) { + loadRemoteMedia(); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.action_bar_server_file_image, menu); + CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), menu, + R.id.media_route_menu_item); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem menuItem) { + switch (menuItem.getItemId()) { + case android.R.id.home: + finish(); + return true; + + case R.id.menu_share: + startFileSharingActivity(); + return true; + + default: + return super.onOptionsItemSelected(menuItem); + } + } + + private void startFileSharingActivity() { + startFileDownloading(getShare(), getCurrentFile()); + } + + private ServerFile getCurrentFile() { + return getImageFiles().get(getImagePager().getCurrentItem()); + } + + private void startFileDownloading(ServerShare share, ServerFile file) { + showFileDownloadingFragment(share, file); + } + + private void showFileDownloadingFragment(ServerShare share, ServerFile file) { + DialogFragment fragment = ServerFileDownloadingFragment.newInstance(share, file); + fragment.show(getFragmentManager(), ServerFileDownloadingFragment.TAG); + } + + @Subscribe + public void onFileDownloaded(FileDownloadedEvent event) { + finishFileDownloading(event.getFileUri()); + } + + private void finishFileDownloading(Uri fileUri) { + startFileSharingActivity(getCurrentFile(), fileUri); + } + + private void startFileSharingActivity(ServerFile file, Uri fileUri) { + Intent intent = Intents.Builder.with(this).buildServerFileSharingIntent(file, fileUri); + startActivity(intent); + } + + @Override + protected void onResume() { + super.onResume(); + + mCastContext.getSessionManager().addSessionManagerListener(this, CastSession.class); + BusProvider.getBus().register(this); + } + + @Override + protected void onPause() { + super.onPause(); + + mCastContext.getSessionManager().removeSessionManagerListener(this, CastSession.class); + BusProvider.getBus().unregister(this); + } + + @Override + public void onSessionEnded(CastSession session, int error) { + onApplicationDisconnected(); + } + + @Override + public void onSessionResumed(CastSession session, boolean wasSuspended) { + onApplicationConnected(session); + } + + @Override + public void onSessionResumeFailed(CastSession session, int error) { + onApplicationDisconnected(); + } + + @Override + public void onSessionStarted(CastSession session, String sessionId) { + onApplicationConnected(session); + } + + @Override + public void onSessionStartFailed(CastSession session, int error) { + onApplicationDisconnected(); + } + + @Override + public void onSessionStarting(CastSession session) { + } + + @Override + public void onSessionEnding(CastSession session) { + } + + @Override + public void onSessionResuming(CastSession session, String sessionId) { + } + + @Override + public void onSessionSuspended(CastSession session, int reason) { + } + + private void onApplicationConnected(CastSession castSession) { + mCastSession = castSession; + invalidateOptionsMenu(); + loadRemoteMedia(); + } + + private void onApplicationDisconnected() { + mCastSession = null; + invalidateOptionsMenu(); + } + + private void loadRemoteMedia() { + final RemoteMediaClient remoteMediaClient = mCastSession.getRemoteMediaClient(); + if (remoteMediaClient != null) { + remoteMediaClient.load(buildMediaInfo()); + } + } + + private MediaInfo buildMediaInfo() { + ServerFile file = getImageFiles().get(imagePosition); + MediaMetadata imageMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_PHOTO); + imageMetadata.putString(MediaMetadata.KEY_TITLE, file.getNameOnly()); + String imageUrl = serverClient.getFileUri(getShare(), file).toString(); + return new MediaInfo.Builder(imageUrl) + .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) + .setContentType(file.getMime()) + .setMetadata(imageMetadata) + .build(); + } } diff --git a/src/main/java/org/amahi/anywhere/activity/ServerFileVideoActivity.java b/src/main/java/org/amahi/anywhere/activity/ServerFileVideoActivity.java index 32c30ce19..f87a21cc0 100644 --- a/src/main/java/org/amahi/anywhere/activity/ServerFileVideoActivity.java +++ b/src/main/java/org/amahi/anywhere/activity/ServerFileVideoActivity.java @@ -56,50 +56,47 @@ import org.videolan.libvlc.Media; import org.videolan.libvlc.MediaPlayer; -import java.util.Locale; - /** * Video activity. Shows videos, supports basic operations such as pausing, resuming, scrolling. * The playback itself is done via {@link org.amahi.anywhere.service.VideoService}. * Backed up by {@link android.view.SurfaceView} and {@link org.videolan.libvlc.LibVLC}. */ public class ServerFileVideoActivity extends AppCompatActivity implements - ServiceConnection, - MediaController.MediaPlayerControl, - IVLCVout.OnNewVideoLayoutListener, - MediaPlayer.EventListener, - View.OnLayoutChangeListener, - VideoSwipeGestures.SeekControl { + ServiceConnection, + MediaController.MediaPlayerControl, + IVLCVout.OnNewVideoLayoutListener, + MediaPlayer.EventListener, + View.OnLayoutChangeListener, + VideoSwipeGestures.SeekControl { private static final boolean ENABLE_SUBTITLES = false; - + private static SurfaceSizes CURRENT_SIZE = SurfaceSizes.SURFACE_BEST_FIT; private VideoService videoService; private MediaControls videoControls; private FullScreenHelper fullScreen; private Handler layoutChangeHandler; - private int mVideoHeight = 0; private int mVideoWidth = 0; private int mVideoVisibleHeight = 0; private int mVideoVisibleWidth = 0; private int mVideoSarNum = 0; private int mVideoSarDen = 0; - private SurfaceView mSubtitlesSurface = null; + private final Runnable mRunnable = new Runnable() { + @Override + public void run() { + updateVideoSurfaces(); + } + }; private float bufferPercent = 0.0f; - private enum SurfaceSizes { - SURFACE_BEST_FIT, - SURFACE_FIT_SCREEN, - SURFACE_FILL, - SURFACE_16_9, - SURFACE_4_3, - SURFACE_ORIGINAL; - } + //TODO Add feature for changing the screen size - private static SurfaceSizes CURRENT_SIZE = SurfaceSizes.SURFACE_BEST_FIT; + public static boolean supports(String mime_type) { + String type = mime_type.split("/")[0]; - //TODO Add feature for changing the screen size + return "video".equals(type); + } @Override protected void onCreate(Bundle savedInstanceState) { @@ -302,13 +299,6 @@ public void onLayoutChange(View v, int left, int top, int right, } } - private final Runnable mRunnable = new Runnable() { - @Override - public void run() { - updateVideoSurfaces(); - } - }; - @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) @Override public void onNewVideoLayout(IVLCVout vout, int width, int height, int visibleWidth, int visibleHeight, int sarNum, int sarDen) { @@ -441,7 +431,7 @@ private void changeMediaPlayerLayout(int displayW, int displayH) { if (vtrack == null) return; final boolean videoSwapped = vtrack.orientation == Media.VideoTrack.Orientation.LeftBottom - || vtrack.orientation == Media.VideoTrack.Orientation.RightTop; + || vtrack.orientation == Media.VideoTrack.Orientation.RightTop; if (CURRENT_SIZE == SurfaceSizes.SURFACE_FIT_SCREEN) { int videoW = vtrack.width; int videoH = vtrack.height; @@ -464,7 +454,7 @@ private void changeMediaPlayerLayout(int displayW, int displayH) { } else { getMediaPlayer().setScale(0); getMediaPlayer().setAspectRatio(!videoSwapped ? "" + displayW + ":" + displayH - : "" + displayH + ":" + displayW); + : "" + displayH + ":" + displayW); } break; } @@ -621,9 +611,12 @@ private void tearDownVideoService() { stopService(intent); } - public static boolean supports(String mime_type) { - String type = mime_type.split("/")[0]; - - return "video".equals(type); + private enum SurfaceSizes { + SURFACE_BEST_FIT, + SURFACE_FIT_SCREEN, + SURFACE_FILL, + SURFACE_16_9, + SURFACE_4_3, + SURFACE_ORIGINAL; } } diff --git a/src/main/java/org/amahi/anywhere/activity/ServerFileWebActivity.java b/src/main/java/org/amahi/anywhere/activity/ServerFileWebActivity.java index 15af33ae0..5ad21614e 100644 --- a/src/main/java/org/amahi/anywhere/activity/ServerFileWebActivity.java +++ b/src/main/java/org/amahi/anywhere/activity/ServerFileWebActivity.java @@ -20,8 +20,6 @@ package org.amahi.anywhere.activity; import android.content.ComponentName; -import android.content.Intent; -import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; import android.support.customtabs.CustomTabsClient; @@ -29,9 +27,6 @@ import android.support.customtabs.CustomTabsServiceConnection; import android.support.customtabs.CustomTabsSession; import android.support.v7.app.AppCompatActivity; -import android.view.MenuItem; -import android.webkit.WebView; -import android.webkit.WebViewClient; import org.amahi.anywhere.AmahiApplication; import org.amahi.anywhere.R; @@ -39,7 +34,6 @@ import org.amahi.anywhere.server.model.ServerFile; import org.amahi.anywhere.server.model.ServerShare; import org.amahi.anywhere.util.Intents; -import org.amahi.anywhere.util.ViewDirector; import java.util.Arrays; import java.util.HashSet; @@ -51,97 +45,96 @@ * Web activity. Shows web resources such as SVG and HTML files. * Backed up by {@link android.webkit.WebView}. */ -public class ServerFileWebActivity extends AppCompatActivity -{ - private static final Set SUPPORTED_FORMATS; - CustomTabsClient mCustomTabsClient; - CustomTabsSession mCustomTabsSession; - CustomTabsServiceConnection mCustomTabsServiceConnection; - CustomTabsIntent mCustomTabsIntent; - - static { - SUPPORTED_FORMATS = new HashSet(Arrays.asList( - "image/svg+xml", - "text/html", - "text/plain" - )); - } - - @Inject - ServerClient serverClient; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_server_file_web); - - setUpInjections(); - - setUpWebResource(savedInstanceState); - } - - private void setUpInjections() { - AmahiApplication.from(this).inject(this); - } - - private void setUpWebResource(Bundle state) { - setUpWebResourceContent(state); - } - - private void setUpWebResourceContent(Bundle state) { - if (!isWebResourceStateValid(state)){ - setUpCustomTabs(); - } - } - - private void setUpCustomTabs(){ - - mCustomTabsServiceConnection = new CustomTabsServiceConnection() { - @Override - public void onCustomTabsServiceConnected(ComponentName componentName, CustomTabsClient customTabsClient) { - mCustomTabsClient= customTabsClient; - mCustomTabsClient.warmup(0L); - mCustomTabsSession = mCustomTabsClient.newSession(null); - } - - @Override - public void onServiceDisconnected(ComponentName name) { - mCustomTabsClient= null; - } - }; - - CustomTabsClient.bindCustomTabsService(this, getPackageName(), mCustomTabsServiceConnection); - - mCustomTabsIntent = new CustomTabsIntent.Builder(mCustomTabsSession) - .setShowTitle(true) - .build(); - - mCustomTabsIntent.launchUrl(this,getWebResourceUri()); - } - - private boolean isWebResourceStateValid(Bundle state) { - return state != null; - } - - private Uri getWebResourceUri() { - return serverClient.getFileUri(getShare(), getFile()); - } - - private ServerShare getShare() { - return getIntent().getParcelableExtra(Intents.Extras.SERVER_SHARE); - } - - private ServerFile getFile() { - return getIntent().getParcelableExtra(Intents.Extras.SERVER_FILE); - } - - public static boolean supports(String mime_type) { - return SUPPORTED_FORMATS.contains(mime_type); - } - - @Override - protected void onResume() { - super.onResume(); - onBackPressed(); - } +public class ServerFileWebActivity extends AppCompatActivity { + private static final Set SUPPORTED_FORMATS; + + static { + SUPPORTED_FORMATS = new HashSet(Arrays.asList( + "image/svg+xml", + "text/html", + "text/plain" + )); + } + + CustomTabsClient mCustomTabsClient; + CustomTabsSession mCustomTabsSession; + CustomTabsServiceConnection mCustomTabsServiceConnection; + CustomTabsIntent mCustomTabsIntent; + @Inject + ServerClient serverClient; + + public static boolean supports(String mime_type) { + return SUPPORTED_FORMATS.contains(mime_type); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_server_file_web); + + setUpInjections(); + + setUpWebResource(savedInstanceState); + } + + private void setUpInjections() { + AmahiApplication.from(this).inject(this); + } + + private void setUpWebResource(Bundle state) { + setUpWebResourceContent(state); + } + + private void setUpWebResourceContent(Bundle state) { + if (!isWebResourceStateValid(state)) { + setUpCustomTabs(); + } + } + + private void setUpCustomTabs() { + + mCustomTabsServiceConnection = new CustomTabsServiceConnection() { + @Override + public void onCustomTabsServiceConnected(ComponentName componentName, CustomTabsClient customTabsClient) { + mCustomTabsClient = customTabsClient; + mCustomTabsClient.warmup(0L); + mCustomTabsSession = mCustomTabsClient.newSession(null); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + mCustomTabsClient = null; + } + }; + + CustomTabsClient.bindCustomTabsService(this, getPackageName(), mCustomTabsServiceConnection); + + mCustomTabsIntent = new CustomTabsIntent.Builder(mCustomTabsSession) + .setShowTitle(true) + .build(); + + mCustomTabsIntent.launchUrl(this, getWebResourceUri()); + } + + private boolean isWebResourceStateValid(Bundle state) { + return state != null; + } + + private Uri getWebResourceUri() { + return serverClient.getFileUri(getShare(), getFile()); + } + + private ServerShare getShare() { + return getIntent().getParcelableExtra(Intents.Extras.SERVER_SHARE); + } + + private ServerFile getFile() { + return getIntent().getParcelableExtra(Intents.Extras.SERVER_FILE); + } + + @Override + protected void onResume() { + super.onResume(); + onBackPressed(); + } } diff --git a/src/main/java/org/amahi/anywhere/activity/ServerFilesActivity.java b/src/main/java/org/amahi/anywhere/activity/ServerFilesActivity.java index 5ef4f488c..0d6cf7179 100644 --- a/src/main/java/org/amahi/anywhere/activity/ServerFilesActivity.java +++ b/src/main/java/org/amahi/anywhere/activity/ServerFilesActivity.java @@ -37,7 +37,6 @@ import android.support.v4.app.Fragment; import android.support.v4.content.FileProvider; import android.support.v7.app.AlertDialog; -import android.support.v4.app.Fragment; import android.support.v7.app.AppCompatActivity; import android.view.MenuItem; import android.view.View; @@ -58,8 +57,6 @@ import org.amahi.anywhere.fragment.ServerFilesFragment; import org.amahi.anywhere.fragment.UploadBottomSheet; import org.amahi.anywhere.model.UploadOption; -import org.amahi.anywhere.fragment.GooglePlaySearchFragment; -import org.amahi.anywhere.fragment.ServerFileDownloadingFragment; import org.amahi.anywhere.server.client.ServerClient; import org.amahi.anywhere.server.model.ServerFile; import org.amahi.anywhere.server.model.ServerShare; @@ -86,484 +83,476 @@ */ public class ServerFilesActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks { - private static final class State { - - private State() { - } - - public static final String FILE = "file"; - - public static final String FILE_ACTION = "file_action"; - } - - - private enum FileAction { - OPEN, SHARE; - } - - @Inject - ServerClient serverClient; - - private ServerFile file; - - private FileAction fileAction; - private ProgressDialog uploadProgressDialog; - - private static final int FILE_UPLOAD_PERMISSION = 102; - private static final int CAMERA_PERMISSION = 103; - private static final int REQUEST_UPLOAD_IMAGE = 201; - private static final int REQUEST_CAMERA_IMAGE = 202; - - private File cameraImage; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_server_files); - - setUpInjections(); - - setUpHomeNavigation(); - - setUpFiles(savedInstanceState); - } - - private void setUpInjections() { - AmahiApplication.from(this).inject(this); - } - - private void setUpHomeNavigation() { - getSupportActionBar().setHomeButtonEnabled(true); - getSupportActionBar().setIcon(R.drawable.ic_launcher); - } - - private void setUpFiles(Bundle state) { - setUpFilesTitle(); - setUpUploadFAB(); - setUpUploadDialog(); - setUpFilesFragment(); - setUpFilesState(state); - } - - private void setUpFilesTitle() { - getSupportActionBar().setTitle(getShare().getName()); - } - - - private void setUpUploadFAB() { - final FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab_upload); - fab.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - new UploadBottomSheet().show(getSupportFragmentManager(), "upload_dialog"); - } - }); - } - - private void setUpUploadDialog() { - uploadProgressDialog = new ProgressDialog(this); - uploadProgressDialog.setTitle(getString(R.string.message_file_upload_title)); - uploadProgressDialog.setCancelable(false); - uploadProgressDialog.setIndeterminate(false); - uploadProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); - } - - @Override - public void onBackPressed() { - super.onBackPressed(); - setUpFilesTitle(); - } - - private ServerShare getShare() { - return getIntent().getParcelableExtra(Intents.Extras.SERVER_SHARE); - } - - private void setUpFilesFragment() { - Fragments.Operator.at(this).set(buildFilesFragment(getShare(), null), R.id.container_files); - } - - private Fragment buildFilesFragment(ServerShare share, ServerFile directory) { - return Fragments.Builder.buildServerFilesFragment(share, directory); - } - - private void setUpFilesState(Bundle state) { - if (isFilesStateValid(state)) { - this.file = state.getParcelable(State.FILE); - this.fileAction = (FileAction) state.getSerializable(State.FILE_ACTION); - } - } - - private boolean isFilesStateValid(Bundle state) { - return (state != null) && state.containsKey(State.FILE) && state.containsKey(State.FILE_ACTION); - } - - @Subscribe - public void onFileOpening(FileOpeningEvent event) { - this.file = event.getFile(); - this.fileAction = FileAction.OPEN; - - setUpFile(event.getShare(), event.getFiles(), event.getFile()); - } - - private void setUpFile(ServerShare share, List files, ServerFile file) { - if (isDirectory(file)) { - setUpFilesFragment(share, file); - } else { - setUpFileActivity(share, files, file); - } - } - - private boolean isDirectory(ServerFile file) { - return Mimes.match(file.getMime()) == Mimes.Type.DIRECTORY; - } - - private void setUpFilesFragment(ServerShare share, ServerFile directory) { - Fragments.Operator.at(this).replaceBackstacked(buildFilesFragment(share, directory), R.id.container_files); - } - - private void setUpFileActivity(ServerShare share, List files, ServerFile file) { - if (Intents.Builder.with(this).isServerFileSupported(file)) { - startFileActivity(share, files, file); - return; - } - - if (Intents.Builder.with(this).isServerFileOpeningSupported(file)) { - startFileOpeningActivity(share, file); - return; - } - - showGooglePlaySearchFragment(file); - } - - private void startFileActivity(ServerShare share, List files, ServerFile file) { - Intent intent = Intents.Builder.with(this).buildServerFileIntent(share, files, file); - startActivity(intent); - } - - private void startFileOpeningActivity(ServerShare share, ServerFile file) { - startFileDownloading(share, file); - } - - private void startFileDownloading(ServerShare share, ServerFile file) { - showFileDownloadingFragment(share, file); - } - - private void showFileDownloadingFragment(ServerShare share, ServerFile file) { - DialogFragment fragment = ServerFileDownloadingFragment.newInstance(share, file); - fragment.show(getFragmentManager(), ServerFileDownloadingFragment.TAG); - } - - @Subscribe - public void onFileDownloaded(FileDownloadedEvent event) { - finishFileDownloading(event.getFileUri()); - } - - private void finishFileDownloading(Uri fileUri) { - switch (fileAction) { - case OPEN: - startFileOpeningActivity(file, fileUri); - break; - - case SHARE: - startFileSharingActivity(file, fileUri); - break; - - default: - break; - } - } - - private void startFileOpeningActivity(ServerFile file, Uri fileUri) { - Intent intent = Intents.Builder.with(this).buildServerFileOpeningIntent(file, fileUri); - startActivity(intent); - } - - private void startFileSharingActivity(ServerFile file, Uri fileUri) { - Intent intent = Intents.Builder.with(this).buildServerFileSharingIntent(file, fileUri); - startActivity(intent); - } - - private void showGooglePlaySearchFragment(ServerFile file) { - GooglePlaySearchFragment fragment = GooglePlaySearchFragment.newInstance(file); - fragment.show(getFragmentManager(), GooglePlaySearchFragment.TAG); - } - - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - - // Forward results to EasyPermissions - EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); - } - - @Override - public void onPermissionsGranted(int requestCode, List perms) { - if (requestCode == FILE_UPLOAD_PERMISSION) { - showFileChooser(); - } else if (requestCode == CAMERA_PERMISSION) { - openCamera(); - } - } - - @Override - public void onPermissionsDenied(int requestCode, List perms) { - if (requestCode == FILE_UPLOAD_PERMISSION) { - showPermissionSnackBar(getString(R.string.file_upload_permission_denied)); - } else if (requestCode == CAMERA_PERMISSION) { - showPermissionSnackBar(getString(R.string.file_upload_permission_denied)); - } - } - - private View getParentView() { - return findViewById(R.id.coordinator_files); - } - - private void showPermissionSnackBar(String message) { - Snackbar.make(getParentView(), message, Snackbar.LENGTH_LONG) - .setAction(R.string.menu_settings, new View.OnClickListener() { - @Override - public void onClick(View v) { - new AppSettingsDialog.Builder(ServerFilesActivity.this).build().show(); - } - }) - .show(); - } - - @Subscribe - public void onUploadOptionClick(UploadClickEvent event) { - int option = event.getUploadOption(); - switch (option) { - case UploadOption.CAMERA: - if (Android.isPermissionRequired()) { - checkCameraPermissions(); - } else { - openCamera(); - } - break; - case UploadOption.FILE: - if (Android.isPermissionRequired()) { - checkFileReadPermissions(); - } else { - showFileChooser(); - } - break; - } - } - - @RequiresApi(api = Build.VERSION_CODES.M) - private void checkCameraPermissions() { - String[] perms = {Manifest.permission.WRITE_EXTERNAL_STORAGE}; - if (EasyPermissions.hasPermissions(this, perms)) { - openCamera(); - } else { - EasyPermissions.requestPermissions(this, getString(R.string.camera_permission), - CAMERA_PERMISSION, perms); - } - } - - private void openCamera() { - Intent cameraIntent = Intents.Builder.with(this).buildCameraIntent(); - if (cameraIntent.resolveActivity(getPackageManager()) != null) { - cameraImage = null; - try { - cameraImage = createImageFile(); - Uri photoURI = FileProvider.getUriForFile(this, - "org.amahi.anywhere.fileprovider", cameraImage); - cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); - startActivityForResult(cameraIntent, REQUEST_CAMERA_IMAGE); - } catch (IOException ex) { - Timber.d(ex); - } - } - } - - private File createImageFile() throws IOException { - String timeStamp = String.valueOf(new Date().getTime()); - String imageFileName = "photo-" + timeStamp; - File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); - return File.createTempFile(imageFileName, ".jpg", storageDir); - } - - @RequiresApi(api = Build.VERSION_CODES.M) - private void checkFileReadPermissions() { - String[] perms = {Manifest.permission.READ_EXTERNAL_STORAGE}; - if (EasyPermissions.hasPermissions(this, perms)) { - showFileChooser(); - } else { - EasyPermissions.requestPermissions(this, getString(R.string.file_upload_permission), - FILE_UPLOAD_PERMISSION, perms); - } - } - - private void showFileChooser() { - Intent intent = Intents.Builder.with(this).buildMediaPickerIntent(); - this.startActivityForResult(intent, REQUEST_UPLOAD_IMAGE); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (resultCode == RESULT_OK) { - switch (requestCode) { - case REQUEST_UPLOAD_IMAGE: - if (data != null) { - Uri selectedImageUri = data.getData(); - String filePath = querySelectedImagePath(selectedImageUri); - if (filePath != null) { - File file = new File(filePath); - if (file.exists()) { - ServerFilesFragment fragment = (ServerFilesFragment) - getSupportFragmentManager() - .findFragmentById(R.id.container_files); - if (fragment.checkForDuplicateFile(file.getName())) { - showDuplicateFileUploadDialog(file); - } else { - uploadFile(file); - } - } - } - } - break; - case REQUEST_CAMERA_IMAGE: - if (cameraImage.exists()) { - uploadFile(cameraImage); - } - break; - } - } - } - - private String querySelectedImagePath(Uri selectedImageUri) { - String filePath = null; - if ("content".equals(selectedImageUri.getScheme())) { - String[] filePathColumn = {MediaStore.Images.Media.DATA}; - Cursor cursor = this.getContentResolver() - .query(selectedImageUri, filePathColumn, null, null, null); - if (cursor != null) { - cursor.moveToFirst(); - int columnIndex = cursor.getColumnIndex(filePathColumn[0]); - filePath = cursor.getString(columnIndex); - cursor.close(); - } - } else { - filePath = selectedImageUri.toString(); - } - return filePath; - } - - private void showDuplicateFileUploadDialog(final File file) { - new AlertDialog.Builder(this) - .setTitle(R.string.message_duplicate_file_upload) - .setMessage(getString(R.string.message_duplicate_file_upload_body, file.getName())) - .setPositiveButton(R.string.button_yes, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - uploadFile(file); - } - }) - .setNegativeButton(R.string.button_no, null) - .show(); - } - - private void uploadFile(File uploadFile) { - serverClient.uploadFile(0, uploadFile, getShare(), file); - uploadProgressDialog.show(); - } - - - @Subscribe - public void onFileUploadProgressEvent(ServerFileUploadProgressEvent fileUploadProgressEvent) { - if (uploadProgressDialog.isShowing()) { - uploadProgressDialog.setProgress(fileUploadProgressEvent.getProgress()); - } - } - - @Subscribe - public void onFileUploadCompleteEvent(ServerFileUploadCompleteEvent event) { - uploadProgressDialog.dismiss(); - if (event.wasUploadSuccessful()) { - Fragments.Operator.at(this).replace(buildFilesFragment(getShare(), file), R.id.container_files); - Snackbar.make(getParentView(), R.string.message_file_upload_complete, Snackbar.LENGTH_LONG).show(); - if (cameraImage != null && cameraImage.exists()) { - clearCameraImage(); - } - } else { - Snackbar snackbar = Snackbar.make(getParentView(), R.string.message_file_upload_error, Snackbar.LENGTH_LONG); - if (cameraImage != null && cameraImage.exists()) { - snackbar - .setAction(R.string.button_retry, new View.OnClickListener() { - @Override - public void onClick(View v) { - uploadFile(cameraImage); - } - }) - .addCallback(new Snackbar.Callback() { - @Override - public void onDismissed(Snackbar transientBottomBar, int event) { - super.onDismissed(transientBottomBar, event); - if (event != DISMISS_EVENT_ACTION) { - clearCameraImage(); - } - } - }); - } - snackbar.show(); - } - } - - private void clearCameraImage() { - //noinspection ResultOfMethodCallIgnored - cameraImage.delete(); - cameraImage = null; - } - - @Subscribe - public void onFileSharing(ServerFileSharingEvent event) { - this.file = event.getFile(); - this.fileAction = FileAction.SHARE; - - startFileSharingActivity(event.getShare(), event.getFile()); - } - - private void startFileSharingActivity(ServerShare share, ServerFile file) { - startFileDownloading(share, file); - } - - @Override - public boolean onOptionsItemSelected(MenuItem menuItem) { - switch (menuItem.getItemId()) { - case android.R.id.home: - onBackPressed(); - return true; - - default: - return super.onOptionsItemSelected(menuItem); - } - } - - @Override - protected void onResume() { - super.onResume(); - - BusProvider.getBus().register(this); - } - - @Override - protected void onPause() { - super.onPause(); - - BusProvider.getBus().unregister(this); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - - tearDownFilesState(outState); - } - - private void tearDownFilesState(Bundle state) { - state.putParcelable(State.FILE, file); - state.putSerializable(State.FILE_ACTION, fileAction); - } + private static final int FILE_UPLOAD_PERMISSION = 102; + private static final int CAMERA_PERMISSION = 103; + private static final int REQUEST_UPLOAD_IMAGE = 201; + private static final int REQUEST_CAMERA_IMAGE = 202; + @Inject + ServerClient serverClient; + private ServerFile file; + private FileAction fileAction; + private ProgressDialog uploadProgressDialog; + private File cameraImage; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_server_files); + + setUpInjections(); + + setUpHomeNavigation(); + + setUpFiles(savedInstanceState); + } + + private void setUpInjections() { + AmahiApplication.from(this).inject(this); + } + + private void setUpHomeNavigation() { + getSupportActionBar().setHomeButtonEnabled(true); + getSupportActionBar().setIcon(R.drawable.ic_launcher); + } + + private void setUpFiles(Bundle state) { + setUpFilesTitle(); + setUpUploadFAB(); + setUpUploadDialog(); + setUpFilesFragment(); + setUpFilesState(state); + } + + private void setUpFilesTitle() { + getSupportActionBar().setTitle(getShare().getName()); + } + + private void setUpUploadFAB() { + final FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab_upload); + fab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + new UploadBottomSheet().show(getSupportFragmentManager(), "upload_dialog"); + } + }); + } + + private void setUpUploadDialog() { + uploadProgressDialog = new ProgressDialog(this); + uploadProgressDialog.setTitle(getString(R.string.message_file_upload_title)); + uploadProgressDialog.setCancelable(false); + uploadProgressDialog.setIndeterminate(false); + uploadProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); + } + + @Override + public void onBackPressed() { + super.onBackPressed(); + setUpFilesTitle(); + } + + private ServerShare getShare() { + return getIntent().getParcelableExtra(Intents.Extras.SERVER_SHARE); + } + + private void setUpFilesFragment() { + Fragments.Operator.at(this).set(buildFilesFragment(getShare(), null), R.id.container_files); + } + + private Fragment buildFilesFragment(ServerShare share, ServerFile directory) { + return Fragments.Builder.buildServerFilesFragment(share, directory); + } + + private void setUpFilesState(Bundle state) { + if (isFilesStateValid(state)) { + this.file = state.getParcelable(State.FILE); + this.fileAction = (FileAction) state.getSerializable(State.FILE_ACTION); + } + } + + private boolean isFilesStateValid(Bundle state) { + return (state != null) && state.containsKey(State.FILE) && state.containsKey(State.FILE_ACTION); + } + + @Subscribe + public void onFileOpening(FileOpeningEvent event) { + this.file = event.getFile(); + this.fileAction = FileAction.OPEN; + + setUpFile(event.getShare(), event.getFiles(), event.getFile()); + } + + private void setUpFile(ServerShare share, List files, ServerFile file) { + if (isDirectory(file)) { + setUpFilesFragment(share, file); + } else { + setUpFileActivity(share, files, file); + } + } + + private boolean isDirectory(ServerFile file) { + return Mimes.match(file.getMime()) == Mimes.Type.DIRECTORY; + } + + private void setUpFilesFragment(ServerShare share, ServerFile directory) { + Fragments.Operator.at(this).replaceBackstacked(buildFilesFragment(share, directory), R.id.container_files); + } + + private void setUpFileActivity(ServerShare share, List files, ServerFile file) { + if (Intents.Builder.with(this).isServerFileSupported(file)) { + startFileActivity(share, files, file); + return; + } + + if (Intents.Builder.with(this).isServerFileOpeningSupported(file)) { + startFileOpeningActivity(share, file); + return; + } + + showGooglePlaySearchFragment(file); + } + + private void startFileActivity(ServerShare share, List files, ServerFile file) { + Intent intent = Intents.Builder.with(this).buildServerFileIntent(share, files, file); + startActivity(intent); + } + + private void startFileOpeningActivity(ServerShare share, ServerFile file) { + startFileDownloading(share, file); + } + + private void startFileDownloading(ServerShare share, ServerFile file) { + showFileDownloadingFragment(share, file); + } + + private void showFileDownloadingFragment(ServerShare share, ServerFile file) { + DialogFragment fragment = ServerFileDownloadingFragment.newInstance(share, file); + fragment.show(getFragmentManager(), ServerFileDownloadingFragment.TAG); + } + + @Subscribe + public void onFileDownloaded(FileDownloadedEvent event) { + finishFileDownloading(event.getFileUri()); + } + + private void finishFileDownloading(Uri fileUri) { + switch (fileAction) { + case OPEN: + startFileOpeningActivity(file, fileUri); + break; + + case SHARE: + startFileSharingActivity(file, fileUri); + break; + + default: + break; + } + } + + private void startFileOpeningActivity(ServerFile file, Uri fileUri) { + Intent intent = Intents.Builder.with(this).buildServerFileOpeningIntent(file, fileUri); + startActivity(intent); + } + + private void startFileSharingActivity(ServerFile file, Uri fileUri) { + Intent intent = Intents.Builder.with(this).buildServerFileSharingIntent(file, fileUri); + startActivity(intent); + } + + private void showGooglePlaySearchFragment(ServerFile file) { + GooglePlaySearchFragment fragment = GooglePlaySearchFragment.newInstance(file); + fragment.show(getFragmentManager(), GooglePlaySearchFragment.TAG); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + + // Forward results to EasyPermissions + EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); + } + + @Override + public void onPermissionsGranted(int requestCode, List perms) { + if (requestCode == FILE_UPLOAD_PERMISSION) { + showFileChooser(); + } else if (requestCode == CAMERA_PERMISSION) { + openCamera(); + } + } + + @Override + public void onPermissionsDenied(int requestCode, List perms) { + if (requestCode == FILE_UPLOAD_PERMISSION) { + showPermissionSnackBar(getString(R.string.file_upload_permission_denied)); + } else if (requestCode == CAMERA_PERMISSION) { + showPermissionSnackBar(getString(R.string.file_upload_permission_denied)); + } + } + + private View getParentView() { + return findViewById(R.id.coordinator_files); + } + + private void showPermissionSnackBar(String message) { + Snackbar.make(getParentView(), message, Snackbar.LENGTH_LONG) + .setAction(R.string.menu_settings, new View.OnClickListener() { + @Override + public void onClick(View v) { + new AppSettingsDialog.Builder(ServerFilesActivity.this).build().show(); + } + }) + .show(); + } + + @Subscribe + public void onUploadOptionClick(UploadClickEvent event) { + int option = event.getUploadOption(); + switch (option) { + case UploadOption.CAMERA: + if (Android.isPermissionRequired()) { + checkCameraPermissions(); + } else { + openCamera(); + } + break; + case UploadOption.FILE: + if (Android.isPermissionRequired()) { + checkFileReadPermissions(); + } else { + showFileChooser(); + } + break; + } + } + + @RequiresApi(api = Build.VERSION_CODES.M) + private void checkCameraPermissions() { + String[] perms = {Manifest.permission.WRITE_EXTERNAL_STORAGE}; + if (EasyPermissions.hasPermissions(this, perms)) { + openCamera(); + } else { + EasyPermissions.requestPermissions(this, getString(R.string.camera_permission), + CAMERA_PERMISSION, perms); + } + } + + private void openCamera() { + Intent cameraIntent = Intents.Builder.with(this).buildCameraIntent(); + if (cameraIntent.resolveActivity(getPackageManager()) != null) { + cameraImage = null; + try { + cameraImage = createImageFile(); + Uri photoURI = FileProvider.getUriForFile(this, + "org.amahi.anywhere.fileprovider", cameraImage); + cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); + startActivityForResult(cameraIntent, REQUEST_CAMERA_IMAGE); + } catch (IOException ex) { + Timber.d(ex); + } + } + } + + private File createImageFile() throws IOException { + String timeStamp = String.valueOf(new Date().getTime()); + String imageFileName = "photo-" + timeStamp; + File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); + return File.createTempFile(imageFileName, ".jpg", storageDir); + } + + @RequiresApi(api = Build.VERSION_CODES.M) + private void checkFileReadPermissions() { + String[] perms = {Manifest.permission.READ_EXTERNAL_STORAGE}; + if (EasyPermissions.hasPermissions(this, perms)) { + showFileChooser(); + } else { + EasyPermissions.requestPermissions(this, getString(R.string.file_upload_permission), + FILE_UPLOAD_PERMISSION, perms); + } + } + + private void showFileChooser() { + Intent intent = Intents.Builder.with(this).buildMediaPickerIntent(); + this.startActivityForResult(intent, REQUEST_UPLOAD_IMAGE); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == RESULT_OK) { + switch (requestCode) { + case REQUEST_UPLOAD_IMAGE: + if (data != null) { + Uri selectedImageUri = data.getData(); + String filePath = querySelectedImagePath(selectedImageUri); + if (filePath != null) { + File file = new File(filePath); + if (file.exists()) { + ServerFilesFragment fragment = (ServerFilesFragment) + getSupportFragmentManager() + .findFragmentById(R.id.container_files); + if (fragment.checkForDuplicateFile(file.getName())) { + showDuplicateFileUploadDialog(file); + } else { + uploadFile(file); + } + } + } + } + break; + case REQUEST_CAMERA_IMAGE: + if (cameraImage.exists()) { + uploadFile(cameraImage); + } + break; + } + } + } + + private String querySelectedImagePath(Uri selectedImageUri) { + String filePath = null; + if ("content".equals(selectedImageUri.getScheme())) { + String[] filePathColumn = {MediaStore.Images.Media.DATA}; + Cursor cursor = this.getContentResolver() + .query(selectedImageUri, filePathColumn, null, null, null); + if (cursor != null) { + cursor.moveToFirst(); + int columnIndex = cursor.getColumnIndex(filePathColumn[0]); + filePath = cursor.getString(columnIndex); + cursor.close(); + } + } else { + filePath = selectedImageUri.toString(); + } + return filePath; + } + + private void showDuplicateFileUploadDialog(final File file) { + new AlertDialog.Builder(this) + .setTitle(R.string.message_duplicate_file_upload) + .setMessage(getString(R.string.message_duplicate_file_upload_body, file.getName())) + .setPositiveButton(R.string.button_yes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + uploadFile(file); + } + }) + .setNegativeButton(R.string.button_no, null) + .show(); + } + + private void uploadFile(File uploadFile) { + serverClient.uploadFile(0, uploadFile, getShare(), file); + uploadProgressDialog.show(); + } + + @Subscribe + public void onFileUploadProgressEvent(ServerFileUploadProgressEvent fileUploadProgressEvent) { + if (uploadProgressDialog.isShowing()) { + uploadProgressDialog.setProgress(fileUploadProgressEvent.getProgress()); + } + } + + @Subscribe + public void onFileUploadCompleteEvent(ServerFileUploadCompleteEvent event) { + uploadProgressDialog.dismiss(); + if (event.wasUploadSuccessful()) { + Fragments.Operator.at(this).replace(buildFilesFragment(getShare(), file), R.id.container_files); + Snackbar.make(getParentView(), R.string.message_file_upload_complete, Snackbar.LENGTH_LONG).show(); + if (cameraImage != null && cameraImage.exists()) { + clearCameraImage(); + } + } else { + Snackbar snackbar = Snackbar.make(getParentView(), R.string.message_file_upload_error, Snackbar.LENGTH_LONG); + if (cameraImage != null && cameraImage.exists()) { + snackbar + .setAction(R.string.button_retry, new View.OnClickListener() { + @Override + public void onClick(View v) { + uploadFile(cameraImage); + } + }) + .addCallback(new Snackbar.Callback() { + @Override + public void onDismissed(Snackbar transientBottomBar, int event) { + super.onDismissed(transientBottomBar, event); + if (event != DISMISS_EVENT_ACTION) { + clearCameraImage(); + } + } + }); + } + snackbar.show(); + } + } + + private void clearCameraImage() { + //noinspection ResultOfMethodCallIgnored + cameraImage.delete(); + cameraImage = null; + } + + @Subscribe + public void onFileSharing(ServerFileSharingEvent event) { + this.file = event.getFile(); + this.fileAction = FileAction.SHARE; + + startFileSharingActivity(event.getShare(), event.getFile()); + } + + private void startFileSharingActivity(ServerShare share, ServerFile file) { + startFileDownloading(share, file); + } + + @Override + public boolean onOptionsItemSelected(MenuItem menuItem) { + switch (menuItem.getItemId()) { + case android.R.id.home: + onBackPressed(); + return true; + + default: + return super.onOptionsItemSelected(menuItem); + } + } + + @Override + protected void onResume() { + super.onResume(); + + BusProvider.getBus().register(this); + } + + @Override + protected void onPause() { + super.onPause(); + + BusProvider.getBus().unregister(this); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + + tearDownFilesState(outState); + } + + private void tearDownFilesState(Bundle state) { + state.putParcelable(State.FILE, file); + state.putSerializable(State.FILE_ACTION, fileAction); + } + + private enum FileAction { + OPEN, SHARE; + } + + private static final class State { + + public static final String FILE = "file"; + public static final String FILE_ACTION = "file_action"; + + private State() { + } + } } diff --git a/src/main/java/org/amahi/anywhere/activity/SettingsActivity.java b/src/main/java/org/amahi/anywhere/activity/SettingsActivity.java index 1139b1774..f7537f14f 100644 --- a/src/main/java/org/amahi/anywhere/activity/SettingsActivity.java +++ b/src/main/java/org/amahi/anywhere/activity/SettingsActivity.java @@ -38,60 +38,60 @@ * Settings itself are provided via {@link org.amahi.anywhere.fragment.SettingsFragment}. */ public class SettingsActivity extends AppCompatActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setUpHomeNavigation(); - - setContentView(R.layout.activity_settings); - - setUpSettingsFragment(); - } - - private void setUpHomeNavigation() { - getSupportActionBar().setHomeButtonEnabled(true); - getSupportActionBar().setIcon(R.drawable.ic_launcher); - } - - private void setUpSettingsFragment() { - FragmentManager fragmentManager = getFragmentManager(); - fragmentManager.beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) - .replace(R.id.settings_container, new SettingsFragment()).commit(); - } - - @Override - public boolean onOptionsItemSelected(MenuItem menuItem) { - switch (menuItem.getItemId()) { - case android.R.id.home: - onBackPressed(); - return true; - - default: - return super.onOptionsItemSelected(menuItem); - } - } - - @Subscribe - public void onUploadSettingsOpenEvent(UploadSettingsOpeningEvent event) { - getFragmentManager().beginTransaction() - .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) - .replace(R.id.settings_container, new UploadSettingsFragment()) - .addToBackStack(null) - .commit(); - } - - @Override - protected void onResume() { - super.onResume(); - - BusProvider.getBus().register(this); - } - - @Override - protected void onPause() { - super.onPause(); - - BusProvider.getBus().unregister(this); - } + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setUpHomeNavigation(); + + setContentView(R.layout.activity_settings); + + setUpSettingsFragment(); + } + + private void setUpHomeNavigation() { + getSupportActionBar().setHomeButtonEnabled(true); + getSupportActionBar().setIcon(R.drawable.ic_launcher); + } + + private void setUpSettingsFragment() { + FragmentManager fragmentManager = getFragmentManager(); + fragmentManager.beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) + .replace(R.id.settings_container, new SettingsFragment()).commit(); + } + + @Override + public boolean onOptionsItemSelected(MenuItem menuItem) { + switch (menuItem.getItemId()) { + case android.R.id.home: + onBackPressed(); + return true; + + default: + return super.onOptionsItemSelected(menuItem); + } + } + + @Subscribe + public void onUploadSettingsOpenEvent(UploadSettingsOpeningEvent event) { + getFragmentManager().beginTransaction() + .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) + .replace(R.id.settings_container, new UploadSettingsFragment()) + .addToBackStack(null) + .commit(); + } + + @Override + protected void onResume() { + super.onResume(); + + BusProvider.getBus().register(this); + } + + @Override + protected void onPause() { + super.onPause(); + + BusProvider.getBus().unregister(this); + } } diff --git a/src/main/java/org/amahi/anywhere/activity/WebViewActivity.java b/src/main/java/org/amahi/anywhere/activity/WebViewActivity.java index 379b92090..2316271bb 100644 --- a/src/main/java/org/amahi/anywhere/activity/WebViewActivity.java +++ b/src/main/java/org/amahi/anywhere/activity/WebViewActivity.java @@ -19,16 +19,16 @@ protected void onCreate(Bundle savedInstanceState) { setUpHomeNavigation(); setContentView(R.layout.activity_web_view); - webView=(WebView)findViewById(R.id.webview); + webView = (WebView) findViewById(R.id.webview); loadWebView("https://www.amahi.org/android"); } - private void loadWebView(String url){ + private void loadWebView(String url) { webView.setWebViewClient(new WebViewClient()); - WebSettings settings=webView.getSettings(); + WebSettings settings = webView.getSettings(); settings.setLoadWithOverviewMode(true); settings.setBuiltInZoomControls(true); @@ -54,4 +54,4 @@ public boolean onOptionsItemSelected(MenuItem menuItem) { return super.onOptionsItemSelected(menuItem); } } -} \ No newline at end of file +} diff --git a/src/main/java/org/amahi/anywhere/adapter/FilesFilterBaseAdapter.java b/src/main/java/org/amahi/anywhere/adapter/FilesFilterBaseAdapter.java index 22be4806d..42f29d784 100644 --- a/src/main/java/org/amahi/anywhere/adapter/FilesFilterBaseAdapter.java +++ b/src/main/java/org/amahi/anywhere/adapter/FilesFilterBaseAdapter.java @@ -54,17 +54,13 @@ public abstract class FilesFilterBaseAdapter extends BaseAdapter implements Filterable { + static final ForegroundColorSpan fcs = new ForegroundColorSpan(Color.parseColor("#be5e00")); + static String queryString; LayoutInflater layoutInflater; ServerClient serverClient; - ServerShare serverShare; - List files; List filteredFiles; - - static String queryString; - static final ForegroundColorSpan fcs = new ForegroundColorSpan(Color.parseColor("#be5e00")); - private FilesFilter filesFilter; private onFilterListChange onFilterListChange; @@ -72,10 +68,6 @@ public abstract class FilesFilterBaseAdapter extends BaseAdapter implements Filt abstract View newView(ViewGroup container); - public interface onFilterListChange { - void isListEmpty(boolean empty); - } - public void setFilterListChangeListener(T t) { this.onFilterListChange = t; } @@ -133,6 +125,23 @@ public List getItems() { return files; } + void setUpImageIcon(ServerFile file, ImageView fileIconView) { + Glide.with(fileIconView.getContext()) + .load(getImageUri(file)) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .centerCrop() + .placeholder(Mimes.getFileIcon(file)) + .into(fileIconView); + } + + private Uri getImageUri(ServerFile file) { + return serverClient.getFileUri(serverShare, file); + } + + public interface onFilterListChange { + void isListEmpty(boolean empty); + } + private class FilesFilter extends Filter { @Override protected FilterResults performFiltering(CharSequence constraint) { @@ -165,19 +174,6 @@ protected void publishResults(CharSequence charSequence, FilterResults filterRes } } - void setUpImageIcon(ServerFile file, ImageView fileIconView) { - Glide.with(fileIconView.getContext()) - .load(getImageUri(file)) - .diskCacheStrategy(DiskCacheStrategy.ALL) - .centerCrop() - .placeholder(Mimes.getFileIcon(file)) - .into(fileIconView); - } - - private Uri getImageUri(ServerFile file) { - return serverClient.getFileUri(serverShare, file); - } - class AlbumArtFetcher extends AsyncTask { private final ImageView imageView; private final Uri audioUri; @@ -203,12 +199,12 @@ private byte[] extractAlbumArt(MediaMetadataRetriever audioMetadataRetriever) { @Override protected void onPostExecute(byte[] bitmap) { Glide.with(applicationContext) - .load(bitmap) - .asBitmap() - .diskCacheStrategy(DiskCacheStrategy.ALL) - .centerCrop() - .placeholder(R.drawable.ic_file_audio) - .into(imageView); + .load(bitmap) + .asBitmap() + .diskCacheStrategy(DiskCacheStrategy.ALL) + .centerCrop() + .placeholder(R.drawable.ic_file_audio) + .into(imageView); } } } diff --git a/src/main/java/org/amahi/anywhere/adapter/NavigationDrawerAdapter.java b/src/main/java/org/amahi/anywhere/adapter/NavigationDrawerAdapter.java index 313dcafdb..9fb9745d4 100644 --- a/src/main/java/org/amahi/anywhere/adapter/NavigationDrawerAdapter.java +++ b/src/main/java/org/amahi/anywhere/adapter/NavigationDrawerAdapter.java @@ -19,17 +19,12 @@ public class NavigationDrawerAdapter extends RecyclerView.Adapter { - public static final class NavigationItems - { - private NavigationItems() { - } - - public static final int SHARES = 0; - public static final int APPS = 1; - } - private final List navigationItems; private Context mContext; + public NavigationDrawerAdapter(Context context, List navigationItems) { + this.navigationItems = navigationItems; + mContext = context; + } public static NavigationDrawerAdapter newLocalAdapter(Context context) { return new NavigationDrawerAdapter(context, Arrays.asList(NavigationDrawerAdapter.NavigationItems.SHARES, NavigationDrawerAdapter.NavigationItems.APPS)); @@ -39,27 +34,14 @@ public static NavigationDrawerAdapter newRemoteAdapter(Context context) { return new NavigationDrawerAdapter(context, Arrays.asList(NavigationDrawerAdapter.NavigationItems.SHARES)); } - public NavigationDrawerAdapter(Context context, List navigationItems){ - this.navigationItems = navigationItems; - mContext = context; - } - - class NavigationDrawerViewHolder extends RecyclerView.ViewHolder{ - TextView titleShare; - NavigationDrawerViewHolder(View itemView) { - super(itemView); - titleShare = (TextView)itemView.findViewById(R.id.text_share_title); - } - } - @Override public NavigationDrawerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - return new NavigationDrawerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.view_navigation_item,parent,false)); + return new NavigationDrawerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.view_navigation_item, parent, false)); } @Override public void onBindViewHolder(NavigationDrawerViewHolder holder, int position) { - holder.titleShare.setText(getNavigationName(mContext,position)); + holder.titleShare.setText(getNavigationName(mContext, position)); } @Override @@ -80,4 +62,20 @@ private String getNavigationName(Context context, int navigationItem) { } } + public static final class NavigationItems { + public static final int SHARES = 0; + public static final int APPS = 1; + private NavigationItems() { + } + } + + class NavigationDrawerViewHolder extends RecyclerView.ViewHolder { + TextView titleShare; + + NavigationDrawerViewHolder(View itemView) { + super(itemView); + titleShare = (TextView) itemView.findViewById(R.id.text_share_title); + } + } + } diff --git a/src/main/java/org/amahi/anywhere/adapter/ServerAppsAdapter.java b/src/main/java/org/amahi/anywhere/adapter/ServerAppsAdapter.java index 484a0f979..ec1bee2a5 100644 --- a/src/main/java/org/amahi/anywhere/adapter/ServerAppsAdapter.java +++ b/src/main/java/org/amahi/anywhere/adapter/ServerAppsAdapter.java @@ -43,75 +43,75 @@ * Apps adapter. Visualizes web apps * for the {@link org.amahi.anywhere.fragment.ServerAppsFragment}. */ -public class ServerAppsAdapter extends RecyclerView.Adapter -{ - private List apps; - private Context mContext; - - public ServerAppsAdapter(Context context) { - mContext = context; - this.apps = Collections.emptyList(); - } - - class ServerAppsViewHolder extends RecyclerView.ViewHolder{ - TextView text; - ImageView logo; - ServerAppsViewHolder(View itemView) { - super(itemView); - text = (TextView)itemView.findViewById(R.id.text); - logo = (ImageView)itemView.findViewById(R.id.logo); - } - } - - @Override - public ServerAppsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - return new ServerAppsViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.view_server_app_item, parent, false)); - } - - @Override - public void onBindViewHolder(final ServerAppsViewHolder holder, int position) { - holder.text.setText(apps.get(position).getName()); - if(TextUtils.isEmpty(apps.get(position).getLogoUrl())) - holder.logo.setImageResource(R.drawable.ic_app_logo); - else { - Glide - .with(mContext) - .load(apps.get(position).getLogoUrl()) - .diskCacheStrategy(DiskCacheStrategy.ALL) - .fitCenter() - .placeholder(R.drawable.ic_app_logo) - .error(R.drawable.ic_app_logo) - .into(holder.logo); - } - holder.itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - BusProvider.getBus().post(new AppSelectedEvent(apps.get(holder.getAdapterPosition()))); - } - }); - } - - @Override - public int getItemCount() { - return apps.size(); - } - - public void replaceWith(List apps) { - this.apps = apps; - - notifyDataSetChanged(); - } - - public List getItems() { - return apps; - } - - public ServerApp getItem(int position) { - return apps.get(position); - } - - @Override - public long getItemId(int position) { - return position; - } +public class ServerAppsAdapter extends RecyclerView.Adapter { + private List apps; + private Context mContext; + + public ServerAppsAdapter(Context context) { + mContext = context; + this.apps = Collections.emptyList(); + } + + @Override + public ServerAppsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new ServerAppsViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.view_server_app_item, parent, false)); + } + + @Override + public void onBindViewHolder(final ServerAppsViewHolder holder, int position) { + holder.text.setText(apps.get(position).getName()); + if (TextUtils.isEmpty(apps.get(position).getLogoUrl())) + holder.logo.setImageResource(R.drawable.ic_app_logo); + else { + Glide + .with(mContext) + .load(apps.get(position).getLogoUrl()) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .fitCenter() + .placeholder(R.drawable.ic_app_logo) + .error(R.drawable.ic_app_logo) + .into(holder.logo); + } + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + BusProvider.getBus().post(new AppSelectedEvent(apps.get(holder.getAdapterPosition()))); + } + }); + } + + @Override + public int getItemCount() { + return apps.size(); + } + + public void replaceWith(List apps) { + this.apps = apps; + + notifyDataSetChanged(); + } + + public List getItems() { + return apps; + } + + public ServerApp getItem(int position) { + return apps.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + class ServerAppsViewHolder extends RecyclerView.ViewHolder { + TextView text; + ImageView logo; + + ServerAppsViewHolder(View itemView) { + super(itemView); + text = (TextView) itemView.findViewById(R.id.text); + logo = (ImageView) itemView.findViewById(R.id.logo); + } + } } diff --git a/src/main/java/org/amahi/anywhere/adapter/ServerFilesAdapter.java b/src/main/java/org/amahi/anywhere/adapter/ServerFilesAdapter.java index 4735b611e..a86fc29b4 100644 --- a/src/main/java/org/amahi/anywhere/adapter/ServerFilesAdapter.java +++ b/src/main/java/org/amahi/anywhere/adapter/ServerFilesAdapter.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2014 Amahi * @@ -21,10 +20,6 @@ package org.amahi.anywhere.adapter; import android.content.Context; -import android.graphics.Bitmap; -import android.media.MediaMetadataRetriever; -import android.net.Uri; -import android.os.AsyncTask; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.TextUtils; @@ -36,12 +31,6 @@ import android.widget.LinearLayout; import android.widget.TextView; -import com.bumptech.glide.Glide; -import com.bumptech.glide.load.engine.DiskCacheStrategy; -import com.bumptech.glide.load.resource.drawable.GlideDrawable; -import com.bumptech.glide.request.animation.GlideAnimation; -import com.bumptech.glide.request.target.SimpleTarget; - import org.amahi.anywhere.R; import org.amahi.anywhere.server.client.ServerClient; import org.amahi.anywhere.server.model.ServerFile; @@ -50,7 +39,6 @@ import java.text.SimpleDateFormat; import java.util.Collections; import java.util.Date; -import java.util.HashMap; /** * Files adapter. Visualizes files diff --git a/src/main/java/org/amahi/anywhere/adapter/ServerFilesImagePagerAdapter.java b/src/main/java/org/amahi/anywhere/adapter/ServerFilesImagePagerAdapter.java index 3fa4680f3..67cd2795a 100644 --- a/src/main/java/org/amahi/anywhere/adapter/ServerFilesImagePagerAdapter.java +++ b/src/main/java/org/amahi/anywhere/adapter/ServerFilesImagePagerAdapter.java @@ -33,25 +33,24 @@ * Image files adapter. Maps {@link org.amahi.anywhere.fragment.ServerFileImageFragment} * for the {@link org.amahi.anywhere.activity.ServerFileImageActivity}. */ -public class ServerFilesImagePagerAdapter extends FragmentStatePagerAdapter -{ - private final ServerShare share; - private final List files; - - public ServerFilesImagePagerAdapter(FragmentManager fragmentManager, ServerShare share, List files) { - super(fragmentManager); - - this.share = share; - this.files = files; - } - - @Override - public int getCount() { - return files.size(); - } - - @Override - public Fragment getItem(int position) { - return Fragments.Builder.buildServerFileImageFragment(share, files.get(position)); - } +public class ServerFilesImagePagerAdapter extends FragmentStatePagerAdapter { + private final ServerShare share; + private final List files; + + public ServerFilesImagePagerAdapter(FragmentManager fragmentManager, ServerShare share, List files) { + super(fragmentManager); + + this.share = share; + this.files = files; + } + + @Override + public int getCount() { + return files.size(); + } + + @Override + public Fragment getItem(int position) { + return Fragments.Builder.buildServerFileImageFragment(share, files.get(position)); + } } diff --git a/src/main/java/org/amahi/anywhere/adapter/ServerFilesMetadataAdapter.java b/src/main/java/org/amahi/anywhere/adapter/ServerFilesMetadataAdapter.java index ae364164b..1d649f024 100644 --- a/src/main/java/org/amahi/anywhere/adapter/ServerFilesMetadataAdapter.java +++ b/src/main/java/org/amahi/anywhere/adapter/ServerFilesMetadataAdapter.java @@ -44,126 +44,122 @@ import java.util.Collections; -public class ServerFilesMetadataAdapter extends FilesFilterBaseAdapter -{ - public static final class Tags - { - private Tags() { - } - - public static final int SHARE = R.id.container_files; - public static final int FILE = R.attr.server_share; - - public static final int FILE_TITLE = R.id.text; - public static final int FILE_ICON = R.id.icon; - } - - public ServerFilesMetadataAdapter(Context context, ServerClient serverClient) { - this.layoutInflater = LayoutInflater.from(context); - - this.serverClient = serverClient; - - this.files = Collections.emptyList(); - this.filteredFiles = Collections.emptyList(); - - BusProvider.getBus().register(this); - } - - protected View newView(ViewGroup container) { - View fileView = layoutInflater.inflate(R.layout.view_server_file_metadata_item, container, false); - - fileView.setTag(Tags.FILE_TITLE, fileView.findViewById(R.id.text)); - fileView.setTag(Tags.FILE_ICON, fileView.findViewById(R.id.icon)); - - return fileView; - } - - protected void bindView(ServerFile file, View fileView) { - unbindFileView(file, fileView); - - ImageView fileIcon = (ImageView) fileView.getTag(Tags.FILE_ICON); - if (Mimes.match(file.getMime()) != Mimes.Type.VIDEO) { - bindFileView(file, fileView); - } else { - if(!file.isMetaDataFetched()) { - bindFileMetadataView(file, fileView); - } else { - bindView(file, file.getFileMetadata(), fileView); - } - } - if (Mimes.match(file.getMime()) == Mimes.Type.IMAGE) { - setUpImageIcon(file, fileIcon); - } - } - - private void unbindFileView(ServerFile file, View fileView) { - TextView fileTitle = (TextView) fileView.getTag(Tags.FILE_TITLE); - ImageView fileIcon = (ImageView) fileView.getTag(Tags.FILE_ICON); - - fileTitle.setText(null); - fileTitle.setBackgroundResource(android.R.color.transparent); - - fileIcon.setImageResource(Mimes.getFileIcon(file)); - fileIcon.setBackgroundResource(R.color.background_secondary); - } - - private void bindFileView(ServerFile file, View fileView) { - TextView fileTitle = (TextView) fileView.getTag(Tags.FILE_TITLE); - ImageView fileIcon = (ImageView) fileView.getTag(Tags.FILE_ICON); - - SpannableStringBuilder sb = new SpannableStringBuilder(file.getName()); - if(queryString != null && !TextUtils.isEmpty(queryString)) { - int searchMatchPosition = file.getName().toLowerCase().indexOf(queryString.toLowerCase()); - if (searchMatchPosition != -1) - sb.setSpan(fcs, searchMatchPosition, searchMatchPosition + queryString.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); - } - fileTitle.setText(sb); - fileTitle.setBackgroundResource(R.color.background_transparent_secondary); - - fileIcon.setImageResource(Mimes.getFileIcon(file)); - fileIcon.setBackgroundResource(R.color.background_secondary); - } - - private void bindFileMetadataView(ServerFile file, View fileView) { - fileView.setTag(Tags.SHARE, serverShare); - fileView.setTag(Tags.FILE, file); - - new FileMetadataRetrievingTask(serverClient, fileView).execute(); - } - - @Subscribe - public void onFileMetadataRetrieved(FileMetadataRetrievedEvent event) { - event.getFile().setMetaDataFetched(true); - bindView(event.getFile(), event.getFileMetadata(), event.getFileView()); - } - - private void bindView(ServerFile file, ServerFileMetadata fileMetadata, View fileView) { - if (fileMetadata == null) { - bindFileView(file, fileView); - } else { - file.setFileMetadata(fileMetadata); - bindFileMetadataView(file, fileMetadata, fileView); - } - } - - private void bindFileMetadataView(ServerFile file, ServerFileMetadata fileMetadata, View fileView) { - TextView fileTitle = (TextView) fileView.getTag(Tags.FILE_TITLE); - ImageView fileIcon = (ImageView) fileView.getTag(Tags.FILE_ICON); - - fileTitle.setText(null); - fileTitle.setBackgroundResource(android.R.color.transparent); - - Glide.with(fileView.getContext()) - .load(fileMetadata.getArtworkUrl()) - .diskCacheStrategy(DiskCacheStrategy.ALL) - .centerCrop() - .fitCenter() - .placeholder(Mimes.getFileIcon(file)) - .error(Mimes.getFileIcon(file)) - .into(fileIcon); - } - - public void tearDownCallbacks() { - BusProvider.getBus().unregister(this); - } +public class ServerFilesMetadataAdapter extends FilesFilterBaseAdapter { + public ServerFilesMetadataAdapter(Context context, ServerClient serverClient) { + this.layoutInflater = LayoutInflater.from(context); + + this.serverClient = serverClient; + + this.files = Collections.emptyList(); + this.filteredFiles = Collections.emptyList(); + + BusProvider.getBus().register(this); + } + + protected View newView(ViewGroup container) { + View fileView = layoutInflater.inflate(R.layout.view_server_file_metadata_item, container, false); + + fileView.setTag(Tags.FILE_TITLE, fileView.findViewById(R.id.text)); + fileView.setTag(Tags.FILE_ICON, fileView.findViewById(R.id.icon)); + + return fileView; + } + + protected void bindView(ServerFile file, View fileView) { + unbindFileView(file, fileView); + + ImageView fileIcon = (ImageView) fileView.getTag(Tags.FILE_ICON); + if (Mimes.match(file.getMime()) != Mimes.Type.VIDEO) { + bindFileView(file, fileView); + } else { + if (!file.isMetaDataFetched()) { + bindFileMetadataView(file, fileView); + } else { + bindView(file, file.getFileMetadata(), fileView); + } + } + if (Mimes.match(file.getMime()) == Mimes.Type.IMAGE) { + setUpImageIcon(file, fileIcon); + } + } + + private void unbindFileView(ServerFile file, View fileView) { + TextView fileTitle = (TextView) fileView.getTag(Tags.FILE_TITLE); + ImageView fileIcon = (ImageView) fileView.getTag(Tags.FILE_ICON); + + fileTitle.setText(null); + fileTitle.setBackgroundResource(android.R.color.transparent); + + fileIcon.setImageResource(Mimes.getFileIcon(file)); + fileIcon.setBackgroundResource(R.color.background_secondary); + } + + private void bindFileView(ServerFile file, View fileView) { + TextView fileTitle = (TextView) fileView.getTag(Tags.FILE_TITLE); + ImageView fileIcon = (ImageView) fileView.getTag(Tags.FILE_ICON); + + SpannableStringBuilder sb = new SpannableStringBuilder(file.getName()); + if (queryString != null && !TextUtils.isEmpty(queryString)) { + int searchMatchPosition = file.getName().toLowerCase().indexOf(queryString.toLowerCase()); + if (searchMatchPosition != -1) + sb.setSpan(fcs, searchMatchPosition, searchMatchPosition + queryString.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); + } + fileTitle.setText(sb); + fileTitle.setBackgroundResource(R.color.background_transparent_secondary); + + fileIcon.setImageResource(Mimes.getFileIcon(file)); + fileIcon.setBackgroundResource(R.color.background_secondary); + } + + private void bindFileMetadataView(ServerFile file, View fileView) { + fileView.setTag(Tags.SHARE, serverShare); + fileView.setTag(Tags.FILE, file); + + new FileMetadataRetrievingTask(serverClient, fileView).execute(); + } + + @Subscribe + public void onFileMetadataRetrieved(FileMetadataRetrievedEvent event) { + event.getFile().setMetaDataFetched(true); + bindView(event.getFile(), event.getFileMetadata(), event.getFileView()); + } + + private void bindView(ServerFile file, ServerFileMetadata fileMetadata, View fileView) { + if (fileMetadata == null) { + bindFileView(file, fileView); + } else { + file.setFileMetadata(fileMetadata); + bindFileMetadataView(file, fileMetadata, fileView); + } + } + + private void bindFileMetadataView(ServerFile file, ServerFileMetadata fileMetadata, View fileView) { + TextView fileTitle = (TextView) fileView.getTag(Tags.FILE_TITLE); + ImageView fileIcon = (ImageView) fileView.getTag(Tags.FILE_ICON); + + fileTitle.setText(null); + fileTitle.setBackgroundResource(android.R.color.transparent); + + Glide.with(fileView.getContext()) + .load(fileMetadata.getArtworkUrl()) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .centerCrop() + .fitCenter() + .placeholder(Mimes.getFileIcon(file)) + .error(Mimes.getFileIcon(file)) + .into(fileIcon); + } + + public void tearDownCallbacks() { + BusProvider.getBus().unregister(this); + } + + public static final class Tags { + public static final int SHARE = R.id.container_files; + public static final int FILE = R.attr.server_share; + public static final int FILE_TITLE = R.id.text; + public static final int FILE_ICON = R.id.icon; + private Tags() { + } + } } diff --git a/src/main/java/org/amahi/anywhere/adapter/ServerSharesAdapter.java b/src/main/java/org/amahi/anywhere/adapter/ServerSharesAdapter.java index f0ed08feb..b16dbc737 100644 --- a/src/main/java/org/amahi/anywhere/adapter/ServerSharesAdapter.java +++ b/src/main/java/org/amahi/anywhere/adapter/ServerSharesAdapter.java @@ -38,59 +38,59 @@ * Shares adapter. Visualizes shares * for the {@link org.amahi.anywhere.fragment.ServerSharesFragment}. */ -public class ServerSharesAdapter extends RecyclerView.Adapter -{ - private List shares; - - class ServerShareViewHolder extends RecyclerView.ViewHolder{ - TextView textView; - ServerShareViewHolder(View itemView) { - super(itemView); - textView = (TextView)itemView.findViewById(R.id.text); - } - } - - @Override - public ServerShareViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - return new ServerShareViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.view_server_share_item, parent, false)); - } - - @Override - public void onBindViewHolder(final ServerShareViewHolder holder, int position) { - holder.textView.setText(shares.get(position).getName()); - holder.itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - BusProvider.getBus().post(new ShareSelectedEvent(shares.get(holder.getAdapterPosition()))); - } - }); - } - - @Override - public int getItemCount() { - return shares.size(); - } - - public ServerSharesAdapter(Context context) { - this.shares = Collections.emptyList(); - } - - public void replaceWith(List shares) { - this.shares = shares; - - notifyDataSetChanged(); - } - - public List getItems() { - return shares; - } - - public ServerShare getItem(int position) { - return shares.get(position); - } - - @Override - public long getItemId(int position) { - return position; - } +public class ServerSharesAdapter extends RecyclerView.Adapter { + private List shares; + + public ServerSharesAdapter(Context context) { + this.shares = Collections.emptyList(); + } + + @Override + public ServerShareViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new ServerShareViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.view_server_share_item, parent, false)); + } + + @Override + public void onBindViewHolder(final ServerShareViewHolder holder, int position) { + holder.textView.setText(shares.get(position).getName()); + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + BusProvider.getBus().post(new ShareSelectedEvent(shares.get(holder.getAdapterPosition()))); + } + }); + } + + @Override + public int getItemCount() { + return shares.size(); + } + + public void replaceWith(List shares) { + this.shares = shares; + + notifyDataSetChanged(); + } + + public List getItems() { + return shares; + } + + public ServerShare getItem(int position) { + return shares.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + class ServerShareViewHolder extends RecyclerView.ViewHolder { + TextView textView; + + ServerShareViewHolder(View itemView) { + super(itemView); + textView = (TextView) itemView.findViewById(R.id.text); + } + } } diff --git a/src/main/java/org/amahi/anywhere/adapter/ServersAdapter.java b/src/main/java/org/amahi/anywhere/adapter/ServersAdapter.java index 2c64f501c..482bcc5b5 100644 --- a/src/main/java/org/amahi/anywhere/adapter/ServersAdapter.java +++ b/src/main/java/org/amahi/anywhere/adapter/ServersAdapter.java @@ -35,90 +35,89 @@ * Servers adapter. Visualizes servers * for the {@link org.amahi.anywhere.fragment.NavigationFragment}. */ -public class ServersAdapter extends BaseAdapter -{ - private final LayoutInflater layoutInflater; +public class ServersAdapter extends BaseAdapter { + private final LayoutInflater layoutInflater; - private List servers; + private List servers; - public ServersAdapter(Context context) { - this.layoutInflater = LayoutInflater.from(context); + public ServersAdapter(Context context) { + this.layoutInflater = LayoutInflater.from(context); - this.servers = Collections.emptyList(); - } + this.servers = Collections.emptyList(); + } - public void replaceWith(List servers) { - this.servers = servers; + public void replaceWith(List servers) { + this.servers = servers; - notifyDataSetChanged(); - } + notifyDataSetChanged(); + } - @Override - public int getCount() { - return servers.size(); - } + @Override + public int getCount() { + return servers.size(); + } - public List getItems() { - return servers; - } + public List getItems() { + return servers; + } - @Override - public Server getItem(int position) { - return servers.get(position); - } + @Override + public Server getItem(int position) { + return servers.get(position); + } - @Override - public long getItemId(int position) { - return position; - } + @Override + public long getItemId(int position) { + return position; + } - @Override - public View getView(int position, View view, ViewGroup container) { - Server server = getItem(position); + @Override + public View getView(int position, View view, ViewGroup container) { + Server server = getItem(position); - if (view == null) { - view = newView(container); - } + if (view == null) { + view = newView(container); + } - bindView(server, view); + bindView(server, view); - return view; - } + return view; + } - private View newView(ViewGroup container) { - return layoutInflater.inflate(android.R.layout.simple_spinner_item, container, false); - } + private View newView(ViewGroup container) { + return layoutInflater.inflate(android.R.layout.simple_spinner_item, container, false); + } - private void bindView(Server server, View view) { - TextView serverView = (TextView) view; + private void bindView(Server server, View view) { + TextView serverView = (TextView) view; - serverView.setText(getServerName(server)); - } + serverView.setText(getServerName(server)); + } - private String getServerName(Server server) { - return server.getName(); - } + private String getServerName(Server server) { + return server.getName(); + } - @Override - public View getDropDownView(int position, View view, ViewGroup container) { - Server server = getItem(position); + @Override + public View getDropDownView(int position, View view, ViewGroup container) { + Server server = getItem(position); - if (view == null) { - view = newDropDownView(container); - } + if (view == null) { + view = newDropDownView(container); + } - bindDropDownView(server, view); + bindDropDownView(server, view); - return view; - } + return view; + } - private View newDropDownView(ViewGroup container) { - return layoutInflater.inflate(android.R.layout.simple_spinner_dropdown_item, container, false); - } + private View newDropDownView(ViewGroup container) { + return layoutInflater.inflate(android.R.layout.simple_spinner_dropdown_item, container, false); + } - private void bindDropDownView(Server server, View view) { - TextView serverView = (TextView) view; + private void bindDropDownView(Server server, View view) { + TextView serverView = (TextView) view; - serverView.setText(getServerName(server)); - } + serverView.setText(getServerName(server)); + } } diff --git a/src/main/java/org/amahi/anywhere/adapter/UploadOptionsAdapter.java b/src/main/java/org/amahi/anywhere/adapter/UploadOptionsAdapter.java index c36f49e41..58058a947 100644 --- a/src/main/java/org/amahi/anywhere/adapter/UploadOptionsAdapter.java +++ b/src/main/java/org/amahi/anywhere/adapter/UploadOptionsAdapter.java @@ -38,53 +38,53 @@ * for the {@link UploadBottomSheet}. */ public class UploadOptionsAdapter extends BaseAdapter { - private ArrayList uploadOptions; - private LayoutInflater inflater; + private ArrayList uploadOptions; + private LayoutInflater inflater; - static class ViewHolder { - ImageView image; - TextView text; - } + public UploadOptionsAdapter(Context context, ArrayList uploadOptions) { + this.uploadOptions = uploadOptions; + this.inflater = LayoutInflater.from(context); + } - public UploadOptionsAdapter(Context context, ArrayList uploadOptions) { - this.uploadOptions = uploadOptions; - this.inflater = LayoutInflater.from(context); - } + @Override + public int getCount() { + return uploadOptions.size(); + } - @Override - public int getCount() { - return uploadOptions.size(); - } + @Override + public Object getItem(int position) { + return uploadOptions.get(position); + } - @Override - public Object getItem(int position) { - return uploadOptions.get(position); - } + @Override + public long getItemId(int position) { + return position; + } - @Override - public long getItemId(int position) { - return position; - } + @Override + public View getView(int position, View convertView, ViewGroup parent) { + ViewHolder holder; + UploadOption uploadOption = uploadOptions.get(position); - @Override - public View getView(int position, View convertView, ViewGroup parent) { - ViewHolder holder; - UploadOption uploadOption = uploadOptions.get(position); + if (convertView == null) { + holder = new ViewHolder(); + convertView = inflater.inflate(R.layout.upload_list_item, parent, false); + convertView.setTag(holder); - if (convertView == null) { - holder = new ViewHolder(); - convertView = inflater.inflate(R.layout.upload_list_item, parent, false); - convertView.setTag(holder); + holder.image = (ImageView) convertView.findViewById(R.id.option_icon); + holder.text = (TextView) convertView.findViewById(R.id.option_text); + } else { + holder = (ViewHolder) convertView.getTag(); + } - holder.image = (ImageView) convertView.findViewById(R.id.option_icon); - holder.text = (TextView) convertView.findViewById(R.id.option_text); - } else { - holder = (ViewHolder) convertView.getTag(); - } + holder.image.setImageResource(uploadOption.getIcon()); + holder.text.setText(uploadOption.getName()); - holder.image.setImageResource(uploadOption.getIcon()); - holder.text.setText(uploadOption.getName()); + return convertView; + } - return convertView; - } + static class ViewHolder { + ImageView image; + TextView text; + } } diff --git a/src/main/java/org/amahi/anywhere/bus/AudioMetadataRetrievedEvent.java b/src/main/java/org/amahi/anywhere/bus/AudioMetadataRetrievedEvent.java index 3febcdd27..b98c5e24e 100644 --- a/src/main/java/org/amahi/anywhere/bus/AudioMetadataRetrievedEvent.java +++ b/src/main/java/org/amahi/anywhere/bus/AudioMetadataRetrievedEvent.java @@ -70,7 +70,7 @@ public ServerFile getServerFile() { return serverFile; } - public long getDuration() { - return duration; - } + public long getDuration() { + return duration; + } } diff --git a/src/main/java/org/amahi/anywhere/bus/ServerConnectedEvent.java b/src/main/java/org/amahi/anywhere/bus/ServerConnectedEvent.java index 729a7e734..aa7c6f78f 100644 --- a/src/main/java/org/amahi/anywhere/bus/ServerConnectedEvent.java +++ b/src/main/java/org/amahi/anywhere/bus/ServerConnectedEvent.java @@ -24,7 +24,7 @@ public class ServerConnectedEvent implements BusEvent { public Server server; - public ServerConnectedEvent(Server server){ + public ServerConnectedEvent(Server server) { this.server = server; } diff --git a/src/main/java/org/amahi/anywhere/bus/ServerFileUploadCompleteEvent.java b/src/main/java/org/amahi/anywhere/bus/ServerFileUploadCompleteEvent.java index 23f934743..a0a0f1751 100644 --- a/src/main/java/org/amahi/anywhere/bus/ServerFileUploadCompleteEvent.java +++ b/src/main/java/org/amahi/anywhere/bus/ServerFileUploadCompleteEvent.java @@ -20,19 +20,19 @@ package org.amahi.anywhere.bus; public class ServerFileUploadCompleteEvent implements BusEvent { - private int id; - private boolean wasUploadSuccessful; + private int id; + private boolean wasUploadSuccessful; - public ServerFileUploadCompleteEvent(int id, boolean wasUploadSuccessful) { - this.id = id; - this.wasUploadSuccessful = wasUploadSuccessful; - } + public ServerFileUploadCompleteEvent(int id, boolean wasUploadSuccessful) { + this.id = id; + this.wasUploadSuccessful = wasUploadSuccessful; + } - public int getId() { - return id; - } + public int getId() { + return id; + } - public boolean wasUploadSuccessful() { - return wasUploadSuccessful; - } + public boolean wasUploadSuccessful() { + return wasUploadSuccessful; + } } diff --git a/src/main/java/org/amahi/anywhere/bus/ServerFileUploadProgressEvent.java b/src/main/java/org/amahi/anywhere/bus/ServerFileUploadProgressEvent.java index d183935c1..16f8896bc 100644 --- a/src/main/java/org/amahi/anywhere/bus/ServerFileUploadProgressEvent.java +++ b/src/main/java/org/amahi/anywhere/bus/ServerFileUploadProgressEvent.java @@ -20,19 +20,19 @@ package org.amahi.anywhere.bus; public class ServerFileUploadProgressEvent implements BusEvent { - private int id; - private int progress; + private int id; + private int progress; - public ServerFileUploadProgressEvent(int id, int progress) { - this.id = id; - this.progress = progress; - } + public ServerFileUploadProgressEvent(int id, int progress) { + this.id = id; + this.progress = progress; + } - public int getId() { - return this.id; - } + public int getId() { + return this.id; + } - public int getProgress() { - return this.progress; - } + public int getProgress() { + return this.progress; + } } diff --git a/src/main/java/org/amahi/anywhere/bus/UploadClickEvent.java b/src/main/java/org/amahi/anywhere/bus/UploadClickEvent.java index 193e8d08c..e3e242a09 100644 --- a/src/main/java/org/amahi/anywhere/bus/UploadClickEvent.java +++ b/src/main/java/org/amahi/anywhere/bus/UploadClickEvent.java @@ -22,14 +22,14 @@ import org.amahi.anywhere.model.UploadOption; public class UploadClickEvent implements BusEvent { - private int uploadOption; + private int uploadOption; - public UploadClickEvent(@UploadOption.Types int uploadOption) { - this.uploadOption = uploadOption; - } + public UploadClickEvent(@UploadOption.Types int uploadOption) { + this.uploadOption = uploadOption; + } - @UploadOption.Types - public int getUploadOption() { - return uploadOption; - } + @UploadOption.Types + public int getUploadOption() { + return uploadOption; + } } diff --git a/src/main/java/org/amahi/anywhere/db/UploadQueueDb.java b/src/main/java/org/amahi/anywhere/db/UploadQueueDb.java index db3246544..679762c39 100644 --- a/src/main/java/org/amahi/anywhere/db/UploadQueueDb.java +++ b/src/main/java/org/amahi/anywhere/db/UploadQueueDb.java @@ -11,34 +11,31 @@ class UploadQueueDb extends SQLiteOpenHelper { - // Database version - private static final int DATABASE_VERSION = 1; - - // Database Name - private static final String DATABASE_NAME = "AMAHI_ANYWHERE_DATABASE"; - - // Table name - static final String TABLE_NAME = "UPLOAD_QUEUE_TABLE"; - - // column names - static final String KEY_ID = "id"; - static final String KEY_FILE_PATH = "file_path"; - - UploadQueueDb(Context context) { - super(context, DATABASE_NAME, null, DATABASE_VERSION); - } - - @Override - public void onCreate(SQLiteDatabase db) { - String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + "(" - + KEY_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " - + KEY_FILE_PATH + " VARCHAR(200) NOT NULL)"; - - db.execSQL(CREATE_TABLE); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - } + // Table name + static final String TABLE_NAME = "UPLOAD_QUEUE_TABLE"; + // column names + static final String KEY_ID = "id"; + static final String KEY_FILE_PATH = "file_path"; + // Database version + private static final int DATABASE_VERSION = 1; + // Database Name + private static final String DATABASE_NAME = "AMAHI_ANYWHERE_DATABASE"; + + UploadQueueDb(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase db) { + String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + "(" + + KEY_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + KEY_FILE_PATH + " VARCHAR(200) NOT NULL)"; + + db.execSQL(CREATE_TABLE); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + } } diff --git a/src/main/java/org/amahi/anywhere/db/UploadQueueDbHelper.java b/src/main/java/org/amahi/anywhere/db/UploadQueueDbHelper.java index 4fff60f8b..1d521f602 100644 --- a/src/main/java/org/amahi/anywhere/db/UploadQueueDbHelper.java +++ b/src/main/java/org/amahi/anywhere/db/UploadQueueDbHelper.java @@ -18,77 +18,77 @@ public class UploadQueueDbHelper { - private UploadQueueDb uploadQueueDb; - private SQLiteDatabase sqLiteDatabase; - private static UploadQueueDbHelper uploadQueueDbHelper; - - public static UploadQueueDbHelper init(Context context) { - if (uploadQueueDbHelper == null) uploadQueueDbHelper = new UploadQueueDbHelper(context); - return uploadQueueDbHelper; - } - - private UploadQueueDbHelper(Context context) { - uploadQueueDb = new UploadQueueDb(context); - sqLiteDatabase = uploadQueueDb.getWritableDatabase(); - } - - public UploadFile addNewImagePath(String imagePath) { - ContentValues values = new ContentValues(); - - values.put(UploadQueueDb.KEY_FILE_PATH, imagePath); - int id = (int) sqLiteDatabase.insert(TABLE_NAME, null, values); - if (id != -1) { - return new UploadFile(id, imagePath); - } else { - return null; - } - } - - public ArrayList getAllImagePaths() { - ArrayList imagePaths = new ArrayList<>(); - - Cursor cursor = sqLiteDatabase.query(TABLE_NAME, null, null, null, null, null, null); - if (cursor != null && cursor.moveToFirst()) { - while (!cursor.isAfterLast()) { - int id = cursor.getInt( - cursor.getColumnIndex(UploadQueueDb.KEY_ID)); - String imagePath = cursor.getString( - cursor.getColumnIndex(UploadQueueDb.KEY_FILE_PATH)); - - UploadFile uploadFile = new UploadFile(id, imagePath); - imagePaths.add(uploadFile); - cursor.moveToNext(); - } - } - if (cursor != null) { - cursor.close(); - } - - return imagePaths; - } - - public void removeFirstImagePath() { - Cursor cursor = sqLiteDatabase.query(TABLE_NAME, null, null, null, null, null, null); - if (cursor.moveToFirst()) { - String rowId = cursor.getString(cursor.getColumnIndex(KEY_ID)); - - sqLiteDatabase.delete(TABLE_NAME, KEY_ID + "=?", new String[]{rowId}); - } - cursor.close(); - } - - public void removeImagePath(int id) { - sqLiteDatabase.delete(TABLE_NAME, KEY_ID + "=?", new String[]{String.valueOf(id)}); - } - - public void clearDb() { - sqLiteDatabase.execSQL("DELETE FROM " + TABLE_NAME); - } - - public void closeDataBase() { - sqLiteDatabase.close(); - uploadQueueDb.close(); - uploadQueueDbHelper = null; - } + private static UploadQueueDbHelper uploadQueueDbHelper; + private UploadQueueDb uploadQueueDb; + private SQLiteDatabase sqLiteDatabase; + + private UploadQueueDbHelper(Context context) { + uploadQueueDb = new UploadQueueDb(context); + sqLiteDatabase = uploadQueueDb.getWritableDatabase(); + } + + public static UploadQueueDbHelper init(Context context) { + if (uploadQueueDbHelper == null) uploadQueueDbHelper = new UploadQueueDbHelper(context); + return uploadQueueDbHelper; + } + + public UploadFile addNewImagePath(String imagePath) { + ContentValues values = new ContentValues(); + + values.put(UploadQueueDb.KEY_FILE_PATH, imagePath); + int id = (int) sqLiteDatabase.insert(TABLE_NAME, null, values); + if (id != -1) { + return new UploadFile(id, imagePath); + } else { + return null; + } + } + + public ArrayList getAllImagePaths() { + ArrayList imagePaths = new ArrayList<>(); + + Cursor cursor = sqLiteDatabase.query(TABLE_NAME, null, null, null, null, null, null); + if (cursor != null && cursor.moveToFirst()) { + while (!cursor.isAfterLast()) { + int id = cursor.getInt( + cursor.getColumnIndex(UploadQueueDb.KEY_ID)); + String imagePath = cursor.getString( + cursor.getColumnIndex(UploadQueueDb.KEY_FILE_PATH)); + + UploadFile uploadFile = new UploadFile(id, imagePath); + imagePaths.add(uploadFile); + cursor.moveToNext(); + } + } + if (cursor != null) { + cursor.close(); + } + + return imagePaths; + } + + public void removeFirstImagePath() { + Cursor cursor = sqLiteDatabase.query(TABLE_NAME, null, null, null, null, null, null); + if (cursor.moveToFirst()) { + String rowId = cursor.getString(cursor.getColumnIndex(KEY_ID)); + + sqLiteDatabase.delete(TABLE_NAME, KEY_ID + "=?", new String[]{rowId}); + } + cursor.close(); + } + + public void removeImagePath(int id) { + sqLiteDatabase.delete(TABLE_NAME, KEY_ID + "=?", new String[]{String.valueOf(id)}); + } + + public void clearDb() { + sqLiteDatabase.execSQL("DELETE FROM " + TABLE_NAME); + } + + public void closeDataBase() { + sqLiteDatabase.close(); + uploadQueueDb.close(); + uploadQueueDbHelper = null; + } } diff --git a/src/main/java/org/amahi/anywhere/fragment/GooglePlaySearchFragment.java b/src/main/java/org/amahi/anywhere/fragment/GooglePlaySearchFragment.java index ddeac2aa0..5ed81aa87 100644 --- a/src/main/java/org/amahi/anywhere/fragment/GooglePlaySearchFragment.java +++ b/src/main/java/org/amahi/anywhere/fragment/GooglePlaySearchFragment.java @@ -19,13 +19,13 @@ package org.amahi.anywhere.fragment; -import android.support.design.widget.Snackbar; -import android.support.v7.app.AlertDialog; import android.app.Dialog; import android.app.DialogFragment; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; +import android.support.design.widget.Snackbar; +import android.support.v7.app.AlertDialog; import org.amahi.anywhere.R; import org.amahi.anywhere.server.model.ServerFile; @@ -35,60 +35,58 @@ /** * Application search dialog. */ -public class GooglePlaySearchFragment extends DialogFragment implements DialogInterface.OnClickListener -{ - public static final String TAG = "google_play_search"; +public class GooglePlaySearchFragment extends DialogFragment implements DialogInterface.OnClickListener { + public static final String TAG = "google_play_search"; - public static GooglePlaySearchFragment newInstance(ServerFile file) { - GooglePlaySearchFragment fragment = new GooglePlaySearchFragment(); + public static GooglePlaySearchFragment newInstance(ServerFile file) { + GooglePlaySearchFragment fragment = new GooglePlaySearchFragment(); - fragment.setArguments(buildArguments(file)); + fragment.setArguments(buildArguments(file)); - return fragment; - } + return fragment; + } - private static Bundle buildArguments(ServerFile file) { - Bundle arguments = new Bundle(); + private static Bundle buildArguments(ServerFile file) { + Bundle arguments = new Bundle(); - arguments.putParcelable(Fragments.Arguments.SERVER_FILE, file); + arguments.putParcelable(Fragments.Arguments.SERVER_FILE, file); - return arguments; - } + return arguments; + } - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - return buildDialog(); - } + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + return buildDialog(); + } - private Dialog buildDialog() { - AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getActivity()); + private Dialog buildDialog() { + AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getActivity()); - dialogBuilder.setMessage(getString(R.string.message_error_search_application)); - dialogBuilder.setPositiveButton(getString(R.string.button_search_application), this); + dialogBuilder.setMessage(getString(R.string.message_error_search_application)); + dialogBuilder.setPositiveButton(getString(R.string.button_search_application), this); - return dialogBuilder.create(); - } + return dialogBuilder.create(); + } - @Override - public void onClick(DialogInterface dialog, int id) { - this.dismiss(); + @Override + public void onClick(DialogInterface dialog, int id) { + this.dismiss(); - startGooglePlaySearch(); - } + startGooglePlaySearch(); + } - private void startGooglePlaySearch() { - String search = getFile().getMime(); + private void startGooglePlaySearch() { + String search = getFile().getMime(); - Intent intent = Intents.Builder.with(getActivity()).buildGooglePlaySearchIntent(search); - if (intent.resolveActivity(getActivity().getPackageManager()) != null) { - startActivity(intent); - } - else { - Snackbar.make(getView(),getString(R.string.application_not_found),Snackbar.LENGTH_SHORT).show(); - } - } + Intent intent = Intents.Builder.with(getActivity()).buildGooglePlaySearchIntent(search); + if (intent.resolveActivity(getActivity().getPackageManager()) != null) { + startActivity(intent); + } else { + Snackbar.make(getView(), getString(R.string.application_not_found), Snackbar.LENGTH_SHORT).show(); + } + } - private ServerFile getFile() { - return getArguments().getParcelable(Fragments.Arguments.SERVER_FILE); - } + private ServerFile getFile() { + return getArguments().getParcelable(Fragments.Arguments.SERVER_FILE); + } } diff --git a/src/main/java/org/amahi/anywhere/fragment/NavigationFragment.java b/src/main/java/org/amahi/anywhere/fragment/NavigationFragment.java index 51db282e9..31d23eb70 100644 --- a/src/main/java/org/amahi/anywhere/fragment/NavigationFragment.java +++ b/src/main/java/org/amahi/anywhere/fragment/NavigationFragment.java @@ -80,453 +80,451 @@ * Navigation fragments. Shows main application sections and servers list as well. */ public class NavigationFragment extends Fragment implements AccountManagerCallback, - OnAccountsUpdateListener, - AdapterView.OnItemSelectedListener, - SwipeRefreshLayout.OnRefreshListener -{ - private static final class State - { - private State() { - } + OnAccountsUpdateListener, + AdapterView.OnItemSelectedListener, + SwipeRefreshLayout.OnRefreshListener { + @Inject + AmahiClient amahiClient; + @Inject + ServerClient serverClient; + private Intent tvIntent; + + @Override + public View onCreateView(LayoutInflater layoutInflater, ViewGroup container, Bundle savedInstanceState) { + return layoutInflater.inflate(R.layout.fragment_navigation, container, false); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + launchIntro(); + + setUpInjections(); + + setUpSettingsMenu(); + + setUpAuthenticationListener(); + + setUpContentRefreshing(); + + setUpServers(savedInstanceState); + } + + private void launchIntro() { + if (Preferences.getFirstRun(getContext()) && !CheckTV.isATV(getContext())) { + Preferences.setFirstRun(getContext()); + startActivity(new Intent(getContext(), IntroductionActivity.class)); + } + } + + private void setUpInjections() { + AmahiApplication.from(getActivity()).inject(this); + } + + private void setUpSettingsMenu() { + setHasOptionsMenu(true); + } + + private void setUpAuthenticationListener() { + getAccountManager().addOnAccountsUpdatedListener(this, null, false); + } + + private AccountManager getAccountManager() { + return AccountManager.get(getActivity()); + } + + @Override + public void onAccountsUpdated(Account[] accounts) { + if (isVisible()) { + return; + } + + if (getAccounts().isEmpty()) { + setUpAccount(); + } + } + + private void setUpContentRefreshing() { + SwipeRefreshLayout refreshLayout = getRefreshLayout(); + + refreshLayout.setColorSchemeResources( + android.R.color.holo_blue_light, + android.R.color.holo_orange_light, + android.R.color.holo_green_light, + android.R.color.holo_red_light); + + refreshLayout.setOnRefreshListener(this); + } + + @Override + public void onRefresh() { + ViewDirector.of(this, R.id.animator_content).show(R.id.empty_view); + setUpServers(new Bundle()); + } + + private List getAccounts() { + return Arrays.asList(getAccountManager().getAccountsByType(AmahiAccount.TYPE)); + } + + private void setUpAccount() { + getAccountManager().addAccount(AmahiAccount.TYPE, AmahiAccount.TYPE_TOKEN, null, null, getActivity(), this, null); + } + + private void setUpAuthenticationToken() { + Account account = getAccounts().get(0); + + getAccountManager().getAuthToken(account, AmahiAccount.TYPE, null, getActivity(), this, null); + } + + @Override + public void run(AccountManagerFuture accountManagerFuture) { + try { + Bundle accountManagerResult = accountManagerFuture.getResult(); + + String authenticationToken = accountManagerResult.getString(AccountManager.KEY_AUTHTOKEN); + + if (authenticationToken != null) { + setUpServers(authenticationToken); + } else { + setUpAuthenticationToken(); + } + } catch (OperationCanceledException e) { + tearDownActivity(); + } catch (IOException | AuthenticatorException e) { + throw new RuntimeException(e); + } + } + + private void tearDownActivity() { + getActivity().finish(); + } + + private void setUpServers(Bundle state) { + getRefreshLayout().setRefreshing(true); + setUpServersAdapter(); + setUpServersContent(state); + setUpServersListener(); + } + + private void setUpServersAdapter() { + if (!areServersLoaded()) + getServersSpinner().setAdapter(new ServersAdapter(getActivity())); + } + + private Spinner getServersSpinner() { + return (Spinner) getView().findViewById(R.id.spinner_servers); + } + + private void setUpServersContent(Bundle state) { + if (isServersStateValid(state)) { + setUpServersState(state); + setUpNavigation(); + } else { + setUpAuthentication(); + } + } + + private boolean isServersStateValid(Bundle state) { + return (state != null) && state.containsKey(State.SERVERS); + } + + private void setUpServersState(Bundle state) { + List servers = state.getParcelableArrayList(State.SERVERS); + + setUpServersContent(servers); + + showContent(); + } + + private void setUpServersContent(List servers) { + if (!CheckTV.isATV(getContext())) + getServersAdapter().replaceWith(filterActiveServers(servers)); + else { + List serverList = filterActiveServers(servers); + String serverName = Preferences.getPreference(getContext()).getString(getString(R.string.pref_server_select_key), servers.get(0).getName()); - public static final String SERVERS = "servers"; - } - - @Inject - AmahiClient amahiClient; - - @Inject - ServerClient serverClient; - - private Intent tvIntent; + if (serverList.get(0).getName().matches(serverName)) + getServersAdapter().replaceWith(serverList); - @Override - public View onCreateView(LayoutInflater layoutInflater, ViewGroup container, Bundle savedInstanceState) { - return layoutInflater.inflate(R.layout.fragment_navigation, container, false); - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - launchIntro(); + else { + int index = findTheServer(serverList); + getServersAdapter().replaceWith(swappedServers(index, serverList)); + } + } + } + + private int findTheServer(List serverList) { + String serverName = Preferences.getPreference(getContext()).getString(getString(R.string.pref_server_select_key), serverList.get(0).getName()); + int i; + for (i = 0; i < serverList.size(); i++) { + if (serverName.matches(serverList.get(i).getName())) + return i; + } + return 0; + } + + private List swappedServers(int index, List serverList) { + Server firstServer = serverList.get(0); + serverList.set(0, serverList.get(index)); + serverList.set(index, firstServer); + return serverList; + } + + private ServersAdapter getServersAdapter() { + return (ServersAdapter) getServersSpinner().getAdapter(); + } + + private List filterActiveServers(List servers) { + List activeServers = new ArrayList(); + + for (Server server : servers) { + if (server.isActive()) { + activeServers.add(server); + } + } + + return activeServers; + } + + private void showContent() { + getRefreshLayout().setRefreshing(false); + ViewDirector.of(this, R.id.animator_content).show(R.id.layout_content); + } + + private void setUpAuthentication() { + if (getAccounts().isEmpty()) { + setUpAccount(); + } else { + setUpAuthenticationToken(); + } + } + + private void setUpServers(String authenticationToken) { + setUpServersAdapter(); + setUpServersContent(authenticationToken); + setUpServersListener(); + } + + private void setUpServersContent(String authenticationToken) { + amahiClient.getServers(getContext(), authenticationToken); + } + + @Subscribe + public void onServersLoaded(ServersLoadedEvent event) { + setUpServersContent(event.getServers()); + + setUpNavigation(); + + showContent(); + + tvIntent = new Intent(getContext(), MainTVActivity.class); + + tvIntent.putParcelableArrayListExtra(getString(R.string.intent_servers), new ArrayList<>(filterActiveServers(event.getServers()))); + } + + private SwipeRefreshLayout getRefreshLayout() { + return (SwipeRefreshLayout) getView().findViewById(R.id.layout_refresh); + } + + private void setUpNavigation() { + setUpNavigationAdapter(); + setUpNavigationListener(); + } + + private void setUpNavigationAdapter() { + //Setting the layout of a vertical list dynamically. + getNavigationListView().setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false)); + + if (!serverClient.isConnected()) { + getNavigationListView().setAdapter(NavigationDrawerAdapter.newRemoteAdapter(getActivity())); + return; + } + + if (serverClient.isConnectedLocal()) { + getNavigationListView().setAdapter(NavigationDrawerAdapter.newLocalAdapter(getActivity())); + } else { + getNavigationListView().setAdapter(NavigationDrawerAdapter.newRemoteAdapter(getActivity())); + } + } + + private RecyclerView getNavigationListView() { + return (RecyclerView) getView().findViewById(R.id.list_navigation); + } + + private void setUpNavigationListener() { + getNavigationListView().addOnItemTouchListener(new RecyclerItemClickListener(getContext(), new RecyclerItemClickListener.OnItemClickListener() { + @Override + public void onItemClick(View view, int position) { + view.setActivated(true); + switch (position) { + case NavigationDrawerAdapter.NavigationItems.SHARES: + BusProvider.getBus().post(new SharesSelectedEvent()); + break; + + case NavigationDrawerAdapter.NavigationItems.APPS: + BusProvider.getBus().post(new AppsSelectedEvent()); + break; + + default: + break; + } + } + })); + } + + @Subscribe + public void onServersLoadFailed(ServersLoadFailedEvent event) { + showError(); + } + + private void showError() { + getRefreshLayout().setRefreshing(false); + ViewDirector.of(this, R.id.animator_content).show(R.id.layout_error); + } + + private void setUpServersListener() { + getServersSpinner().setOnItemSelectedListener(this); + } + + @Override + public void onNothingSelected(AdapterView spinnerView) { + } + + @Override + public void onItemSelected(AdapterView spinnerView, View view, int position, long id) { + Server server = getServersAdapter().getItem(position); + + setUpServerConnection(server); + } + + private void setUpServerConnection(Server server) { + if (serverClient.isConnected(server)) { + setUpServerConnection(); + setUpServerNavigation(); + } else { + serverClient.connect(getContext(), server); + } + } + + @Subscribe + public void onServerConnected(ServerConnectedEvent event) { + setUpServerConnection(); + setUpServerNavigation(); + if (CheckTV.isATV(getContext())) launchTV(); + } + + private void setUpServerConnection() { + if (!isConnectionAvailable() || isConnectionAuto()) { + serverClient.connectAuto(); + return; + } + + if (isConnectionLocal()) { + serverClient.connectLocal(); + } else { + serverClient.connectRemote(); + } + } + + private void launchTV() { + startActivity(tvIntent); + } + + private boolean isConnectionAvailable() { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); + + return preferences.contains(getString(R.string.preference_key_server_connection)); + } + + private boolean isConnectionAuto() { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); + String preferenceConnection = preferences.getString(getString(R.string.preference_key_server_connection), null); + + return preferenceConnection.equals(getString(R.string.preference_key_server_connection_auto)); + } + + private boolean isConnectionLocal() { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); + String preferenceConnection = preferences.getString(getString(R.string.preference_key_server_connection), null); + + return preferenceConnection.equals(getString(R.string.preference_key_server_connection_local)); + } + + private void setUpServerNavigation() { + setUpNavigationAdapter(); + } + + @Subscribe + public void onServerConnectionChanged(ServerConnectionChangedEvent event) { + setUpServerNavigation(); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { + super.onCreateOptionsMenu(menu, menuInflater); + + menuInflater.inflate(R.menu.action_bar_navigation, menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem menuItem) { + switch (menuItem.getItemId()) { + case R.id.menu_settings: + BusProvider.getBus().post(new SettingsSelectedEvent()); + return true; + + default: + return super.onOptionsItemSelected(menuItem); + } + } + + @Override + public void onResume() { + super.onResume(); + + BusProvider.getBus().register(this); + } + + @Override + public void onPause() { + super.onPause(); + + BusProvider.getBus().unregister(this); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + + tearDownServersState(outState); + } + + private void tearDownServersState(Bundle state) { + if (areServersLoaded()) { + state.putParcelableArrayList(State.SERVERS, new ArrayList(getServersAdapter().getItems())); + } + } + + private boolean areServersLoaded() { + return getServersAdapter() != null; + } + + @Override + public void onDestroy() { + super.onDestroy(); - setUpInjections(); - - setUpSettingsMenu(); - - setUpAuthenticationListener(); - - setUpContentRefreshing(); - - setUpServers(savedInstanceState); - } - - private void launchIntro(){ - if(Preferences.getFirstRun(getContext()) && !CheckTV.isATV(getContext())){ - Preferences.setFirstRun(getContext()); - startActivity(new Intent(getContext(), IntroductionActivity.class)); - } - } - - private void setUpInjections() { - AmahiApplication.from(getActivity()).inject(this); - } - - private void setUpSettingsMenu() { - setHasOptionsMenu(true); - } - - private void setUpAuthenticationListener() { - getAccountManager().addOnAccountsUpdatedListener(this, null, false); - } - - private AccountManager getAccountManager() { - return AccountManager.get(getActivity()); - } - - @Override - public void onAccountsUpdated(Account[] accounts) { - if (isVisible()) { - return; - } - - if (getAccounts().isEmpty()) { - setUpAccount(); - } - } - - private void setUpContentRefreshing() { - SwipeRefreshLayout refreshLayout = getRefreshLayout(); - - refreshLayout.setColorSchemeResources( - android.R.color.holo_blue_light, - android.R.color.holo_orange_light, - android.R.color.holo_green_light, - android.R.color.holo_red_light); - - refreshLayout.setOnRefreshListener(this); - } - - @Override - public void onRefresh() { - ViewDirector.of(this, R.id.animator_content).show(R.id.empty_view); - setUpServers(new Bundle()); - } - - private List getAccounts() { - return Arrays.asList(getAccountManager().getAccountsByType(AmahiAccount.TYPE)); - } - - private void setUpAccount() { - getAccountManager().addAccount(AmahiAccount.TYPE, AmahiAccount.TYPE_TOKEN, null, null, getActivity(), this, null); - } - - private void setUpAuthenticationToken() { - Account account = getAccounts().get(0); - - getAccountManager().getAuthToken(account, AmahiAccount.TYPE, null, getActivity(), this, null); - } - - @Override - public void run(AccountManagerFuture accountManagerFuture) { - try { - Bundle accountManagerResult = accountManagerFuture.getResult(); - - String authenticationToken = accountManagerResult.getString(AccountManager.KEY_AUTHTOKEN); - - if (authenticationToken != null) { - setUpServers(authenticationToken); - } else { - setUpAuthenticationToken(); - } - } catch (OperationCanceledException e) { - tearDownActivity(); - } catch (IOException | AuthenticatorException e) { - throw new RuntimeException(e); - } - } - - private void tearDownActivity() { - getActivity().finish(); - } - - private void setUpServers(Bundle state) { - getRefreshLayout().setRefreshing(true); - setUpServersAdapter(); - setUpServersContent(state); - setUpServersListener(); - } - - private void setUpServersAdapter() { - if (!areServersLoaded()) - getServersSpinner().setAdapter(new ServersAdapter(getActivity())); - } - - private Spinner getServersSpinner() { - return (Spinner) getView().findViewById(R.id.spinner_servers); - } - - private void setUpServersContent(Bundle state) { - if (isServersStateValid(state)) { - setUpServersState(state); - setUpNavigation(); - } else { - setUpAuthentication(); - } - } - - private boolean isServersStateValid(Bundle state) { - return (state != null) && state.containsKey(State.SERVERS); - } - - private void setUpServersState(Bundle state) { - List servers = state.getParcelableArrayList(State.SERVERS); - - setUpServersContent(servers); - - showContent(); - } - - private void setUpServersContent(List servers) { - if (!CheckTV.isATV(getContext())) - getServersAdapter().replaceWith(filterActiveServers(servers)); - else { - List serverList = filterActiveServers(servers); - String serverName = Preferences.getPreference(getContext()).getString(getString(R.string.pref_server_select_key), servers.get(0).getName()); + tearDownAuthenticationListener(); + } - if (serverList.get(0).getName().matches(serverName)) - getServersAdapter().replaceWith(serverList); + private void tearDownAuthenticationListener() { + getAccountManager().removeOnAccountsUpdatedListener(this); + } - else { - int index = findTheServer(serverList); - getServersAdapter().replaceWith(swappedServers(index,serverList)); - } - } - } - - private int findTheServer(List serverList) { - String serverName = Preferences.getPreference(getContext()).getString(getString(R.string.pref_server_select_key), serverList.get(0).getName()); - int i; - for (i = 0; i < serverList.size(); i++) { - if (serverName.matches(serverList.get(i).getName())) - return i; - } - return 0; - } - - private List swappedServers(int index, List serverList){ - Server firstServer = serverList.get(0); - serverList.set(0, serverList.get(index)); - serverList.set(index, firstServer); - return serverList; - } - - private ServersAdapter getServersAdapter() { - return (ServersAdapter) getServersSpinner().getAdapter(); - } - - private List filterActiveServers(List servers) { - List activeServers = new ArrayList(); - - for (Server server : servers) { - if (server.isActive()) { - activeServers.add(server); - } - } - - return activeServers; - } - - private void showContent() { - getRefreshLayout().setRefreshing(false); - ViewDirector.of(this, R.id.animator_content).show(R.id.layout_content); - } - - private void setUpAuthentication() { - if (getAccounts().isEmpty()) { - setUpAccount(); - } else { - setUpAuthenticationToken(); - } - } - - private void setUpServers(String authenticationToken) { - setUpServersAdapter(); - setUpServersContent(authenticationToken); - setUpServersListener(); - } - - private void setUpServersContent(String authenticationToken) { - amahiClient.getServers(getContext(), authenticationToken); - } - - @Subscribe - public void onServersLoaded(ServersLoadedEvent event) { - setUpServersContent(event.getServers()); - - setUpNavigation(); - - showContent(); - - tvIntent = new Intent(getContext(), MainTVActivity.class); - - tvIntent.putParcelableArrayListExtra(getString(R.string.intent_servers), new ArrayList<>(filterActiveServers(event.getServers()))); - } - - private SwipeRefreshLayout getRefreshLayout() { - return (SwipeRefreshLayout) getView().findViewById(R.id.layout_refresh); - } - - private void setUpNavigation() { - setUpNavigationAdapter(); - setUpNavigationListener(); - } - - private void setUpNavigationAdapter() { - //Setting the layout of a vertical list dynamically. - getNavigationListView().setLayoutManager(new LinearLayoutManager(getContext(),LinearLayoutManager.VERTICAL,false)); - - if (!serverClient.isConnected()) { - getNavigationListView().setAdapter(NavigationDrawerAdapter.newRemoteAdapter(getActivity())); - return; - } - - if (serverClient.isConnectedLocal()) { - getNavigationListView().setAdapter(NavigationDrawerAdapter.newLocalAdapter(getActivity())); - } else { - getNavigationListView().setAdapter(NavigationDrawerAdapter.newRemoteAdapter(getActivity())); - } - } - - private RecyclerView getNavigationListView() { - return (RecyclerView) getView().findViewById(R.id.list_navigation); - } - - private void setUpNavigationListener() { - getNavigationListView().addOnItemTouchListener(new RecyclerItemClickListener(getContext(), new RecyclerItemClickListener.OnItemClickListener() { - @Override - public void onItemClick(View view, int position) { - view.setActivated(true); - switch (position) { - case NavigationDrawerAdapter.NavigationItems.SHARES: - BusProvider.getBus().post(new SharesSelectedEvent()); - break; - - case NavigationDrawerAdapter.NavigationItems.APPS: - BusProvider.getBus().post(new AppsSelectedEvent()); - break; - - default: - break; - } - } - })); - } - - @Subscribe - public void onServersLoadFailed(ServersLoadFailedEvent event) { - showError(); - } - - private void showError() { - getRefreshLayout().setRefreshing(false); - ViewDirector.of(this, R.id.animator_content).show(R.id.layout_error); - } - - private void setUpServersListener() { - getServersSpinner().setOnItemSelectedListener(this); - } - - @Override - public void onNothingSelected(AdapterView spinnerView) { - } - - @Override - public void onItemSelected(AdapterView spinnerView, View view, int position, long id) { - Server server = getServersAdapter().getItem(position); - - setUpServerConnection(server); - } - - private void setUpServerConnection(Server server) { - if (serverClient.isConnected(server)) { - setUpServerConnection(); - setUpServerNavigation(); - } else { - serverClient.connect(getContext(), server); - } - } - - @Subscribe - public void onServerConnected(ServerConnectedEvent event) { - setUpServerConnection(); - setUpServerNavigation(); - if (CheckTV.isATV(getContext())) launchTV(); - } - - private void setUpServerConnection() { - if (!isConnectionAvailable() || isConnectionAuto()) { - serverClient.connectAuto(); - return; - } - - if (isConnectionLocal()) { - serverClient.connectLocal(); - } else { - serverClient.connectRemote(); - } - } - - private void launchTV(){startActivity(tvIntent);} - - private boolean isConnectionAvailable() { - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); - - return preferences.contains(getString(R.string.preference_key_server_connection)); - } - - private boolean isConnectionAuto() { - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); - String preferenceConnection = preferences.getString(getString(R.string.preference_key_server_connection), null); - - return preferenceConnection.equals(getString(R.string.preference_key_server_connection_auto)); - } - - private boolean isConnectionLocal() { - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); - String preferenceConnection = preferences.getString(getString(R.string.preference_key_server_connection), null); - - return preferenceConnection.equals(getString(R.string.preference_key_server_connection_local)); - } - - private void setUpServerNavigation() { - setUpNavigationAdapter(); - } - - @Subscribe - public void onServerConnectionChanged(ServerConnectionChangedEvent event) { - setUpServerNavigation(); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { - super.onCreateOptionsMenu(menu, menuInflater); - - menuInflater.inflate(R.menu.action_bar_navigation, menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem menuItem) { - switch (menuItem.getItemId()) { - case R.id.menu_settings: - BusProvider.getBus().post(new SettingsSelectedEvent()); - return true; - - default: - return super.onOptionsItemSelected(menuItem); - } - } - - @Override - public void onResume() { - super.onResume(); - - BusProvider.getBus().register(this); - } - - @Override - public void onPause() { - super.onPause(); - - BusProvider.getBus().unregister(this); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - - tearDownServersState(outState); - } - - private void tearDownServersState(Bundle state) { - if (areServersLoaded()) { - state.putParcelableArrayList(State.SERVERS, new ArrayList(getServersAdapter().getItems())); - } - } - - private boolean areServersLoaded() { - return getServersAdapter() != null; - } - - @Override - public void onDestroy() { - super.onDestroy(); + private static final class State { + public static final String SERVERS = "servers"; - tearDownAuthenticationListener(); - } - - private void tearDownAuthenticationListener() { - getAccountManager().removeOnAccountsUpdatedListener(this); - } + private State() { + } + } } diff --git a/src/main/java/org/amahi/anywhere/fragment/ServerAppsFragment.java b/src/main/java/org/amahi/anywhere/fragment/ServerAppsFragment.java index 84dd80374..ddf29d8f5 100644 --- a/src/main/java/org/amahi/anywhere/fragment/ServerAppsFragment.java +++ b/src/main/java/org/amahi/anywhere/fragment/ServerAppsFragment.java @@ -19,7 +19,6 @@ package org.amahi.anywhere.fragment; -import android.content.Context; import android.os.Bundle; import android.os.Parcelable; import android.support.v4.app.Fragment; @@ -52,168 +51,164 @@ /** * Apps fragment. Shows apps list. */ -public class ServerAppsFragment extends Fragment -{ - private static final class State - { - private State() { - } +public class ServerAppsFragment extends Fragment { + @Inject + ServerClient serverClient; + private ServerAppsAdapter mServerAppsAdapter; - public static final String APPS = "apps"; - } + private RecyclerView mRecyclerView; - private ServerAppsAdapter mServerAppsAdapter; + private LinearLayout mEmptyLinearLayout; - private RecyclerView mRecyclerView; + private LinearLayout mErrorLinearLayout; - private LinearLayout mEmptyLinearLayout; + @Override + public View onCreateView(LayoutInflater layoutInflater, ViewGroup container, Bundle savedInstanceState) { + View rootView = layoutInflater.inflate(R.layout.fragment_server_apps, container, false); - private LinearLayout mErrorLinearLayout; + mRecyclerView = (RecyclerView) rootView.findViewById(R.id.list_server_apps); - @Inject - ServerClient serverClient; + mServerAppsAdapter = new ServerAppsAdapter(getActivity()); - @Override - public View onCreateView(LayoutInflater layoutInflater, ViewGroup container, Bundle savedInstanceState) { - View rootView = layoutInflater.inflate(R.layout.fragment_server_apps, container, false); + mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false)); + + mEmptyLinearLayout = (LinearLayout) rootView.findViewById(R.id.empty_server_apps); - mRecyclerView = (RecyclerView)rootView.findViewById(R.id.list_server_apps); + mErrorLinearLayout = (LinearLayout) rootView.findViewById(R.id.error); + + mRecyclerView.addItemDecoration(new + DividerItemDecoration(getActivity(), + DividerItemDecoration.VERTICAL)); + return rootView; + } - mServerAppsAdapter = new ServerAppsAdapter(getActivity()); + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); - mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity(),LinearLayoutManager.VERTICAL,false)); + setUpInjections(); - mEmptyLinearLayout = (LinearLayout)rootView.findViewById(R.id.empty_server_apps); - - mErrorLinearLayout = (LinearLayout) rootView.findViewById(R.id.error); + setUpApps(savedInstanceState); + } + + private void setUpInjections() { + AmahiApplication.from(getActivity()).inject(this); + } - mRecyclerView.addItemDecoration(new - DividerItemDecoration(getActivity(), - DividerItemDecoration.VERTICAL)); - return rootView; - } + private void setUpApps(Bundle state) { + setUpAppsAdapter(); + setUpAppsContent(state); + } + + private void setUpAppsAdapter() { + mRecyclerView.setAdapter(mServerAppsAdapter); + } + + private void setUpAppsContent(Bundle state) { + if (isAppsStateValid(state)) { + setUpAppsState(state); + } else { + setUpAppsContent(); + } + } + + private boolean isAppsStateValid(Bundle state) { + return (state != null) && state.containsKey(State.APPS); + } + + private void setUpAppsState(Bundle state) { + List apps = state.getParcelableArrayList(State.APPS); + if (apps != null) { + mEmptyLinearLayout.setVisibility(View.GONE); + setUpAppsContent(apps); + + showAppsContent(); + } else { + mEmptyLinearLayout.setVisibility(View.VISIBLE); + } + } + + private void setUpAppsContent(List apps) { + getAppsAdapter().replaceWith(apps); + } + + private ServerAppsAdapter getAppsAdapter() { + return mServerAppsAdapter; + } + + private void showAppsContent() { + ViewDirector.of(this, R.id.animator).show(R.id.content); + } + + private void setUpAppsContent() { + if (serverClient.isConnected()) { + serverClient.getApps(); + } + } + + @Subscribe + public void onServerConnectionChanged(ServerConnectionChangedEvent event) { + serverClient.getApps(); + } + + @Subscribe + public void onAppsLoaded(ServerAppsLoadedEvent event) { + setUpAppsContent(event.getServerApps()); - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); + showAppsContent(); + } - setUpInjections(); - - setUpApps(savedInstanceState); - } - - private void setUpInjections() { - AmahiApplication.from(getActivity()).inject(this); - } - - private void setUpApps(Bundle state) { - setUpAppsAdapter(); - setUpAppsContent(state); - } - - private void setUpAppsAdapter() { - mRecyclerView.setAdapter(mServerAppsAdapter); - } - - private void setUpAppsContent(Bundle state) { - if (isAppsStateValid(state)) { - setUpAppsState(state); - } else { - setUpAppsContent(); - } - } - - private boolean isAppsStateValid(Bundle state) { - return (state != null) && state.containsKey(State.APPS); - } - - private void setUpAppsState(Bundle state) { - List apps = state.getParcelableArrayList(State.APPS); - if(apps!=null) { - mEmptyLinearLayout.setVisibility(View.GONE); - setUpAppsContent(apps); - - showAppsContent(); - } - else{ - mEmptyLinearLayout.setVisibility(View.VISIBLE); - } - } - - private void setUpAppsContent(List apps) { - getAppsAdapter().replaceWith(apps); - } - - private ServerAppsAdapter getAppsAdapter() { - return mServerAppsAdapter; - } - - private void showAppsContent() { - ViewDirector.of(this, R.id.animator).show(R.id.content); - } - - private void setUpAppsContent() { - if (serverClient.isConnected()) { - serverClient.getApps(); - } - } - - @Subscribe - public void onServerConnectionChanged(ServerConnectionChangedEvent event) { - serverClient.getApps(); - } - - @Subscribe - public void onAppsLoaded(ServerAppsLoadedEvent event) { - setUpAppsContent(event.getServerApps()); - - showAppsContent(); - } - - @Subscribe - public void onAppsLoadFailed(ServerAppsLoadFailedEvent event) { - showAppsError(); - } - - private void showAppsError() { - ViewDirector.of(this, R.id.animator).show(R.id.error); - mErrorLinearLayout.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - ViewDirector.of(getActivity(), R.id.animator).show(android.R.id.progress); - setUpAppsContent(); - } - }); - } - - @Override - public void onResume() { - super.onResume(); - - BusProvider.getBus().register(this); - } - - @Override - public void onPause() { - super.onPause(); - - BusProvider.getBus().unregister(this); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - - tearDownAppsState(outState); - } - - private void tearDownAppsState(Bundle state) { - if (areAppsLoaded()) { - state.putParcelableArrayList(State.APPS, new ArrayList(getAppsAdapter().getItems())); - } - } - - private boolean areAppsLoaded() { - return getAppsAdapter() != null; - } + @Subscribe + public void onAppsLoadFailed(ServerAppsLoadFailedEvent event) { + showAppsError(); + } + + private void showAppsError() { + ViewDirector.of(this, R.id.animator).show(R.id.error); + mErrorLinearLayout.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + ViewDirector.of(getActivity(), R.id.animator).show(android.R.id.progress); + setUpAppsContent(); + } + }); + } + + @Override + public void onResume() { + super.onResume(); + + BusProvider.getBus().register(this); + } + + @Override + public void onPause() { + super.onPause(); + + BusProvider.getBus().unregister(this); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + + tearDownAppsState(outState); + } + + private void tearDownAppsState(Bundle state) { + if (areAppsLoaded()) { + state.putParcelableArrayList(State.APPS, new ArrayList(getAppsAdapter().getItems())); + } + } + + private boolean areAppsLoaded() { + return getAppsAdapter() != null; + } + + private static final class State { + public static final String APPS = "apps"; + + private State() { + } + } } diff --git a/src/main/java/org/amahi/anywhere/fragment/ServerFileDownloadingFragment.java b/src/main/java/org/amahi/anywhere/fragment/ServerFileDownloadingFragment.java index 8c94dae76..2b646483f 100644 --- a/src/main/java/org/amahi/anywhere/fragment/ServerFileDownloadingFragment.java +++ b/src/main/java/org/amahi/anywhere/fragment/ServerFileDownloadingFragment.java @@ -44,99 +44,98 @@ /** * File downloading dialog. */ -public class ServerFileDownloadingFragment extends DialogFragment -{ - public static final String TAG = "server_file_downloading"; +public class ServerFileDownloadingFragment extends DialogFragment { + public static final String TAG = "server_file_downloading"; - @Inject - Downloader downloader; + @Inject + Downloader downloader; - @Inject - ServerClient serverClient; + @Inject + ServerClient serverClient; - public static ServerFileDownloadingFragment newInstance(ServerShare share, ServerFile file) { - ServerFileDownloadingFragment fragment = new ServerFileDownloadingFragment(); + public static ServerFileDownloadingFragment newInstance(ServerShare share, ServerFile file) { + ServerFileDownloadingFragment fragment = new ServerFileDownloadingFragment(); - Bundle arguments = new Bundle(); - arguments.putParcelable(Fragments.Arguments.SERVER_SHARE, share); - arguments.putParcelable(Fragments.Arguments.SERVER_FILE, file); - fragment.setArguments(arguments); + Bundle arguments = new Bundle(); + arguments.putParcelable(Fragments.Arguments.SERVER_SHARE, share); + arguments.putParcelable(Fragments.Arguments.SERVER_FILE, file); + fragment.setArguments(arguments); - return fragment; - } + return fragment; + } - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - ProgressDialog dialog = new ProgressDialog(getActivity()); + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + ProgressDialog dialog = new ProgressDialog(getActivity()); - dialog.setMessage(getString(R.string.message_progress_file_downloading)); + dialog.setMessage(getString(R.string.message_progress_file_downloading)); - return dialog; - } + return dialog; + } - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); - setUpInjections(); + setUpInjections(); - startFileDownloading(savedInstanceState); - } + startFileDownloading(savedInstanceState); + } - private void setUpInjections() { - AmahiApplication.from(getActivity()).inject(this); - } + private void setUpInjections() { + AmahiApplication.from(getActivity()).inject(this); + } - private void startFileDownloading(Bundle state) { - if (state == null) { - downloader.startFileDownloading(getFileUri(), getFile().getName()); - } - } + private void startFileDownloading(Bundle state) { + if (state == null) { + downloader.startFileDownloading(getFileUri(), getFile().getName()); + } + } - private Uri getFileUri() { - return serverClient.getFileUri(getShare(), getFile()); - } + private Uri getFileUri() { + return serverClient.getFileUri(getShare(), getFile()); + } - private ServerShare getShare() { - return getArguments().getParcelable(Fragments.Arguments.SERVER_SHARE); - } + private ServerShare getShare() { + return getArguments().getParcelable(Fragments.Arguments.SERVER_SHARE); + } - private ServerFile getFile() { - return getArguments().getParcelable(Fragments.Arguments.SERVER_FILE); - } + private ServerFile getFile() { + return getArguments().getParcelable(Fragments.Arguments.SERVER_FILE); + } - @Subscribe - public void onFileDownloaded(FileDownloadedEvent event) { - dismiss(); - } + @Subscribe + public void onFileDownloaded(FileDownloadedEvent event) { + dismiss(); + } - @Subscribe - public void onFileDownloadFailed(FileDownloadFailedEvent event) { - dismiss(); - } + @Subscribe + public void onFileDownloadFailed(FileDownloadFailedEvent event) { + dismiss(); + } - @Override - public void onResume() { - super.onResume(); + @Override + public void onResume() { + super.onResume(); - BusProvider.getBus().register(this); - } + BusProvider.getBus().register(this); + } - @Override - public void onPause() { - super.onPause(); + @Override + public void onPause() { + super.onPause(); - BusProvider.getBus().unregister(this); - } + BusProvider.getBus().unregister(this); + } - @Override - public void onCancel(DialogInterface dialog) { - super.onCancel(dialog); + @Override + public void onCancel(DialogInterface dialog) { + super.onCancel(dialog); - finishFileDownloading(); - } + finishFileDownloading(); + } - private void finishFileDownloading() { - downloader.finishFileDownloading(); - } + private void finishFileDownloading() { + downloader.finishFileDownloading(); + } } diff --git a/src/main/java/org/amahi/anywhere/fragment/ServerFileImageFragment.java b/src/main/java/org/amahi/anywhere/fragment/ServerFileImageFragment.java index cd2a3b4d4..b2d7d964f 100644 --- a/src/main/java/org/amahi/anywhere/fragment/ServerFileImageFragment.java +++ b/src/main/java/org/amahi/anywhere/fragment/ServerFileImageFragment.java @@ -47,84 +47,84 @@ * Image fragment. Shows a single image. */ public class ServerFileImageFragment extends Fragment implements RequestListener { - @Inject - ServerClient serverClient; - - @Override - public View onCreateView(LayoutInflater layoutInflater, ViewGroup container, Bundle savedInstanceState) { - return layoutInflater.inflate(R.layout.fragment_server_file_image, container, false); - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - setUpInjections(); - - setUpImage(); - } - - private void setUpInjections() { - AmahiApplication.from(getActivity()).inject(this); - } - - private void setUpImage() { - setUpImageContent(); - } - - private void setUpImageContent() { - Glide - .with(getActivity()) - .load(getImageUri()) - .diskCacheStrategy(DiskCacheStrategy.ALL) - .listener(this) - .into(getImageView()); - } - - private Uri getImageUri() { - return serverClient.getFileUri(getShare(), getFile()); - } - - private ServerShare getShare() { - return getArguments().getParcelable(Fragments.Arguments.SERVER_SHARE); - } - - private ServerFile getFile() { - return getArguments().getParcelable(Fragments.Arguments.SERVER_FILE); - } - - private TouchImageView getImageView() { - return (TouchImageView) getView().findViewById(R.id.image); - } - - private ProgressBar getProgressBar() { - return (ProgressBar) getView().findViewById(android.R.id.progress); - } - - @Override - public boolean onResourceReady(GlideDrawable resource, Uri model, Target target, boolean isFromMemoryCache, boolean isFirstResource) { - showImageContent(); - return false; - } - - private void showImageContent() { - getImageView().setVisibility(View.VISIBLE); - getProgressBar().setVisibility(View.GONE); - } - - @Override - public boolean onException(Exception e, Uri model, Target target, boolean isFirstResource) { - return false; - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - - tearDownImageContent(); - } - - private void tearDownImageContent() { - Glide.clear(getImageView()); - } + @Inject + ServerClient serverClient; + + @Override + public View onCreateView(LayoutInflater layoutInflater, ViewGroup container, Bundle savedInstanceState) { + return layoutInflater.inflate(R.layout.fragment_server_file_image, container, false); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + setUpInjections(); + + setUpImage(); + } + + private void setUpInjections() { + AmahiApplication.from(getActivity()).inject(this); + } + + private void setUpImage() { + setUpImageContent(); + } + + private void setUpImageContent() { + Glide + .with(getActivity()) + .load(getImageUri()) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .listener(this) + .into(getImageView()); + } + + private Uri getImageUri() { + return serverClient.getFileUri(getShare(), getFile()); + } + + private ServerShare getShare() { + return getArguments().getParcelable(Fragments.Arguments.SERVER_SHARE); + } + + private ServerFile getFile() { + return getArguments().getParcelable(Fragments.Arguments.SERVER_FILE); + } + + private TouchImageView getImageView() { + return (TouchImageView) getView().findViewById(R.id.image); + } + + private ProgressBar getProgressBar() { + return (ProgressBar) getView().findViewById(android.R.id.progress); + } + + @Override + public boolean onResourceReady(GlideDrawable resource, Uri model, Target target, boolean isFromMemoryCache, boolean isFirstResource) { + showImageContent(); + return false; + } + + private void showImageContent() { + getImageView().setVisibility(View.VISIBLE); + getProgressBar().setVisibility(View.GONE); + } + + @Override + public boolean onException(Exception e, Uri model, Target target, boolean isFirstResource) { + return false; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + + tearDownImageContent(); + } + + private void tearDownImageContent() { + Glide.clear(getImageView()); + } } diff --git a/src/main/java/org/amahi/anywhere/fragment/ServerFilesFragment.java b/src/main/java/org/amahi/anywhere/fragment/ServerFilesFragment.java index a52aec2fc..950e57b91 100644 --- a/src/main/java/org/amahi/anywhere/fragment/ServerFilesFragment.java +++ b/src/main/java/org/amahi/anywhere/fragment/ServerFilesFragment.java @@ -93,737 +93,729 @@ */ public class ServerFilesFragment extends Fragment implements - SwipeRefreshLayout.OnRefreshListener, - AdapterView.OnItemClickListener, - AdapterView.OnItemLongClickListener, - ActionMode.Callback, - SearchView.OnQueryTextListener, - FilesFilterBaseAdapter.onFilterListChange, - EasyPermissions.PermissionCallbacks, - CastStateListener -{ - private SearchView searchView; - private MenuItem searchMenuItem; - private LinearLayout mErrorLinearLayout; - private CastContext mCastContext; - private IntroductoryOverlay mIntroductoryOverlay; - private MenuItem mediaRouteMenuItem; - private ProgressDialog deleteProgressDialog; - private int deleteFilePosition; - private int lastCheckedFileIndex = -1; - - - private static final class State { - private State() { - } - - public static final String FILES = "files"; - public static final String FILES_SORT = "files_sort"; - } - - private static final int SHARE_PERMISSIONS = 101; - - private enum FilesSort { - NAME, MODIFICATION_TIME - } - - private FilesSort filesSort = FilesSort.MODIFICATION_TIME; - - private ActionMode filesActions; - - @Inject - ServerClient serverClient; - - @Override - public View onCreateView(LayoutInflater layoutInflater, ViewGroup container, Bundle savedInstanceState) { - View rootView; - if (!isMetadataAvailable()) { - rootView = layoutInflater.inflate(R.layout.fragment_server_files, container, false); - } else { - rootView = layoutInflater.inflate(R.layout.fragment_server_files_metadata, container, false); - } - mErrorLinearLayout = (LinearLayout) rootView.findViewById(R.id.error); - return rootView; - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - setUpInjections(); - - setUpCast(); - - setUpFiles(savedInstanceState); - - setUpProgressDialog(); - } - - private void setUpInjections() { - AmahiApplication.from(getActivity()).inject(this); - } - - private void setUpCast() { - mCastContext = CastContext.getSharedInstance(getActivity()); - } - - - @Override - public void onCastStateChanged(int newState) { - if (newState != CastState.NO_DEVICES_AVAILABLE) { - showIntroductoryOverlay(); - } - } - - private void showIntroductoryOverlay() { - if (mIntroductoryOverlay != null) { - mIntroductoryOverlay.remove(); - } - if ((mediaRouteMenuItem != null) && mediaRouteMenuItem.isVisible()) { - new Handler().post(new Runnable() { - @Override - public void run() { - mIntroductoryOverlay = new IntroductoryOverlay - .Builder(getActivity(), mediaRouteMenuItem) - .setTitleText("Introducing Cast") - .setSingleTime() - .setOnOverlayDismissedListener( - new IntroductoryOverlay.OnOverlayDismissedListener() { - @Override - public void onOverlayDismissed() { - mIntroductoryOverlay = null; - } - }) - .build(); - mIntroductoryOverlay.show(); - } - }); - } - } - - private void setUpFiles(Bundle state) { - setUpFilesMenu(); - setUpFilesActions(); - setUpFilesAdapter(); - setUpFilesContent(state); - setUpFilesContentRefreshing(); - } - - private void setUpProgressDialog() { - deleteProgressDialog = new ProgressDialog(getContext()); - deleteProgressDialog.setMessage(getString(R.string.message_delete_progress)); - deleteProgressDialog.setIndeterminate(true); - deleteProgressDialog.setCancelable(false); - } - - private void setUpFilesMenu() { - setHasOptionsMenu(true); - } - - private void setUpFilesActions() { - getListView().setOnItemClickListener(this); - getListView().setOnItemLongClickListener(this); - } - - private AbsListView getListView() { - return (AbsListView) getView().findViewById(android.R.id.list); - } - - @Override - public boolean onItemLongClick(AdapterView filesListView, View fileView, int filePosition, long fileId) { - if (!areFilesActionsAvailable()) { - getListView().clearChoices(); - getListView().setItemChecked(filePosition, true); - - getListView().startActionMode(this); - - return true; - } else { - return false; - } - } - - private boolean areFilesActionsAvailable() { - return filesActions != null; - } - - @Override - public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { - this.filesActions = actionMode; - - actionMode.getMenuInflater().inflate(R.menu.action_mode_server_files, menu); - - return true; - } - - @Override - public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { - return false; - } - - @Override - public void onDestroyActionMode(ActionMode actionMode) { - this.filesActions = null; - - clearFileChoices(); - } - - private void clearFileChoices() { - getListView().clearChoices(); - getListView().requestLayout(); - } - - @Override - public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) { - switch (menuItem.getItemId()) { - case R.id.menu_share: - if (Android.isPermissionRequired()) { - checkSharePermissions(actionMode); - } else { - startFileSharing(getCheckedFile()); - actionMode.finish(); - } - break; - case R.id.menu_delete: - deleteFile(getCheckedFile(), actionMode); - break; - default: - return false; - } - - return true; - } - - @RequiresApi(api = Build.VERSION_CODES.M) - private void checkSharePermissions(ActionMode actionMode) { - String[] perms = {Manifest.permission.WRITE_EXTERNAL_STORAGE}; - if (EasyPermissions.hasPermissions(getContext(), perms)) { - startFileSharing(getCheckedFile()); - } else { - lastCheckedFileIndex = getListView().getCheckedItemPosition(); - EasyPermissions.requestPermissions(this, getString(R.string.share_permission), - SHARE_PERMISSIONS, perms); - } - actionMode.finish(); - } - - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - - // Forward results to EasyPermissions - EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); - } - - @Override - public void onPermissionsGranted(int requestCode, List perms) { - if (requestCode == SHARE_PERMISSIONS) { - if (lastCheckedFileIndex != -1) { - startFileSharing(getFile(lastCheckedFileIndex)); - } - } - } - - @Override - public void onPermissionsDenied(int requestCode, List perms) { - if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) { - if (requestCode == SHARE_PERMISSIONS) { - showPermissionSnackBar(getString(R.string.share_permission_denied)); - } - } - - } - - private void showPermissionSnackBar(String message) { - Snackbar.make(getView(), message, Snackbar.LENGTH_LONG) - .setAction(R.string.menu_settings, new View.OnClickListener() { - @Override - public void onClick(View v) { - new AppSettingsDialog.Builder(ServerFilesFragment.this).build().show(); - } - }) - .show(); - } - - private void startFileSharing(ServerFile file) { - BusProvider.getBus().post(new ServerFileSharingEvent(getShare(), file)); - } - - private void deleteFile(final ServerFile file, final ActionMode actionMode) { - deleteFilePosition = getListView().getCheckedItemPosition(); - new AlertDialog.Builder(getContext()) - .setTitle(R.string.message_delete_file_title) - .setMessage(R.string.message_delete_file_body) - .setPositiveButton(R.string.button_yes, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - deleteProgressDialog.show(); - serverClient.deleteFile(getShare(), file); - actionMode.finish(); - } - }) - .setNegativeButton(R.string.button_no, null) - .show(); - } - - @Subscribe - public void onFileDeleteEvent(ServerFileDeleteEvent fileDeleteEvent) { - deleteProgressDialog.dismiss(); - if (fileDeleteEvent.isDeleted()) { - if (!isMetadataAvailable()) { - getFilesAdapter().removeFile(deleteFilePosition); - } else { - getFilesMetadataAdapter().removeFile(deleteFilePosition); - } - } else { - Toast.makeText(getContext(), R.string.message_delete_file_error, Toast.LENGTH_SHORT).show(); - } - } - - private ServerFile getCheckedFile() { - return getFile(getListView().getCheckedItemPosition()); - } - - private ServerFile getFile(int position) { - if (!isMetadataAvailable()) { - return getFilesAdapter().getItem(position); - } else { - return getFilesMetadataAdapter().getItem(position); - } - } - - private boolean isMetadataAvailable() { - return ServerShare.Tag.MOVIES.equals(getShare().getTag()); - } - - private ServerFilesAdapter getFilesAdapter() { - return (ServerFilesAdapter) getListAdapter(); - } - - private ServerFilesMetadataAdapter getFilesMetadataAdapter() { - return (ServerFilesMetadataAdapter) getListAdapter(); - } - - private ListAdapter getListAdapter() { - return getListView().getAdapter(); - } - - private void setUpFilesAdapter() { - if (!isMetadataAvailable()) { - setListAdapter(new ServerFilesAdapter(getActivity(), getActivity().getApplicationContext(), serverClient)); - } else { - setListAdapter(new ServerFilesMetadataAdapter(getActivity(), serverClient)); - } - } - - private void setListAdapter(FilesFilterBaseAdapter adapter) { - adapter.setFilterListChangeListener(this); - getListView().setAdapter(adapter); - } - - private void setUpFilesContent(Bundle state) { - if (isFilesStateValid(state)) { - setUpFilesState(state); - } else { - setUpFilesContent(); - } - } - - private boolean isFilesStateValid(Bundle state) { - return (state != null) && state.containsKey(State.FILES) && state.containsKey(State.FILES_SORT); - } - - private void setUpFilesState(Bundle state) { - List files = state.getParcelableArrayList(State.FILES); - - FilesSort filesSort = (FilesSort) state.getSerializable(State.FILES_SORT); - - setUpFilesContent(files); - setUpFilesContentSort(filesSort); - - showFilesContent(); - } - - private void setUpFilesContent(List files) { - if (!isMetadataAvailable()) { - getFilesAdapter().replaceWith(getShare(), files); - } else { - getFilesMetadataAdapter().replaceWith(getShare(), getMetadataFiles(files)); - } - } - - private List getMetadataFiles(List files) { - List metadataFiles = new ArrayList(); - - for (ServerFile file : files) { - if (Mimes.match(file.getMime()) == Mimes.Type.DIRECTORY) { - metadataFiles.add(file); - } - - if (Mimes.match(file.getMime()) == Mimes.Type.VIDEO) { - metadataFiles.add(file); - } - } - return metadataFiles; - } - - private void setUpFilesContentSort(FilesSort filesSort) { - this.filesSort = filesSort; - - getActivity().invalidateOptionsMenu(); - } - - private void showFilesContent() { - if (areFilesAvailable()) { - getView().findViewById(android.R.id.list).setVisibility(View.VISIBLE); - getView().findViewById(android.R.id.empty).setVisibility(View.INVISIBLE); - } else { - getView().findViewById(android.R.id.list).setVisibility(View.INVISIBLE); - getView().findViewById(android.R.id.empty).setVisibility(View.VISIBLE); - } - - ViewDirector.of(this, R.id.animator).show(R.id.content); - } - - private boolean areFilesAvailable() { - if (!isMetadataAvailable()) { - return !getFilesAdapter().isEmpty(); - } else { - return !getFilesMetadataAdapter().isEmpty(); - } - } - - private void setUpFilesContent() { - if (serverClient.isConnected()) { - if (!isDirectoryAvailable()) { - serverClient.getFiles(getShare()); - } else { - serverClient.getFiles(getShare(), getDirectory()); - } - } - } - - private boolean isDirectoryAvailable() { - return getDirectory() != null; - } - - private boolean isDirectory(ServerFile file) { - return Mimes.match(file.getMime()) == Mimes.Type.DIRECTORY; - } - - private ServerFile getDirectory() { - return getArguments().getParcelable(Fragments.Arguments.SERVER_FILE); - } - - private ServerShare getShare() { - return getArguments().getParcelable(Fragments.Arguments.SERVER_SHARE); - } - - @Subscribe - public void onFilesLoaded(ServerFilesLoadedEvent event) { - showFilesContent(event.getServerFiles()); - } - - private void showFilesContent(List files) { - setUpFilesContent(sortFiles(files)); - - showFilesContent(); - - hideFilesContentRefreshing(); - } - - private List sortFiles(List files) { - List sortedFiles = new ArrayList(files); - - Collections.sort(sortedFiles, getFilesComparator()); - - return sortedFiles; - } - - private Comparator getFilesComparator() { - switch (filesSort) { - case NAME: - return new FileNameComparator(); - - case MODIFICATION_TIME: - return new FileModificationTimeComparator(); - - default: - return null; - } - } - - private void hideFilesContentRefreshing() { - getRefreshLayout().setRefreshing(false); - } - - private SwipeRefreshLayout getRefreshLayout() { - return (SwipeRefreshLayout) getView().findViewById(R.id.layout_refresh); - } - - @Subscribe - public void onFilesLoadFailed(ServerFilesLoadFailedEvent event) { - showFilesError(); - - hideFilesContentRefreshing(); - } - - private void showFilesError() { - ViewDirector.of(this, R.id.animator).show(R.id.error); - mErrorLinearLayout.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - ViewDirector.of(getActivity(), R.id.animator).show(android.R.id.progress); - setUpFilesContent(); - } - }); - } - - private void setUpFilesContentRefreshing() { - SwipeRefreshLayout refreshLayout = getRefreshLayout(); - - refreshLayout.setColorSchemeResources( - android.R.color.holo_blue_light, - android.R.color.holo_orange_light, - android.R.color.holo_green_light, - android.R.color.holo_red_light); - - refreshLayout.setOnRefreshListener(this); - } - - @Override - public void onRefresh() { - setUpFilesContent(); - } - - @Override - public void onItemClick(AdapterView filesListView, View fileView, int filePosition, long fileId) { - if (!areFilesActionsAvailable()) { - collapseSearchView(); - startFileOpening(getFile(filePosition)); - - if (isDirectory(getFile(filePosition))) { - setUpTitle(getFile(filePosition).getName()); - } - } - } - - private void startFileOpening(ServerFile file) { - BusProvider.getBus().post(new FileOpeningEvent(getShare(), getFiles(), file)); - } - - private void setUpTitle(String title) { - ((ServerFilesActivity) getActivity()).getSupportActionBar().setTitle(title); - } - - private List getFiles() { - if (!isMetadataAvailable()) { - return getFilesAdapter().getItems(); - } else { - return getFilesMetadataAdapter().getItems(); - } - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { - super.onCreateOptionsMenu(menu, menuInflater); - - menuInflater.inflate(R.menu.action_bar_server_files, menu); - - mediaRouteMenuItem = CastButtonFactory.setUpMediaRouteButton( - getActivity().getApplicationContext(), - menu, R.id.media_route_menu_item); - } - - @Override - public void onPrepareOptionsMenu(Menu menu) { - super.onPrepareOptionsMenu(menu); - - setUpFilesContentSortIcon(menu.findItem(R.id.menu_sort)); - searchMenuItem = menu.findItem(R.id.menu_search); - searchView = (SearchView) searchMenuItem.getActionView(); - - setUpSearchView(); - setSearchCursor(); - } - - private void setUpSearchView() { - SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE); - searchView.setSearchableInfo(searchManager.getSearchableInfo(getActivity().getComponentName())); - searchView.setSubmitButtonEnabled(false); - searchView.setOnQueryTextListener(this); - } - - private void setSearchCursor() { - final int textViewID = searchView.getContext().getResources().getIdentifier("android:id/search_src_text", null, null); - final AutoCompleteTextView searchTextView = (AutoCompleteTextView) searchView.findViewById(textViewID); - try { - Field mCursorDrawableRes = TextView.class.getDeclaredField("mCursorDrawableRes"); - mCursorDrawableRes.setAccessible(true); - mCursorDrawableRes.set(searchTextView, R.drawable.white_cursor); - } catch (Exception ignored) { - } - } - - private void setUpFilesContentSortIcon(MenuItem menuItem) { - switch (filesSort) { - case NAME: - menuItem.setIcon(R.drawable.ic_menu_sort_name); - break; - - case MODIFICATION_TIME: - menuItem.setIcon(R.drawable.ic_menu_sort_modification_time); - break; - - default: - break; - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem menuItem) { - switch (menuItem.getItemId()) { - - case R.id.menu_sort: - setUpFilesContentSortSwitched(); - setUpFilesContentSortIcon(menuItem); - return true; - default: - return super.onOptionsItemSelected(menuItem); - } - } - - private void setUpFilesContentSortSwitched() { - switch (filesSort) { - case NAME: - filesSort = FilesSort.MODIFICATION_TIME; - break; - - case MODIFICATION_TIME: - filesSort = FilesSort.NAME; - break; - - default: - break; - } - - setUpFilesContentSort(); - } - - private void setUpFilesContentSort() { - if (!isMetadataAvailable()) { - getFilesAdapter().replaceWith(getShare(), sortFiles(getFiles())); - } else { - getFilesMetadataAdapter().replaceWith(getShare(), sortFiles(getFiles())); - } - } - - @Override - public boolean onQueryTextSubmit(String s) { - return false; - } - - @Override - public boolean onQueryTextChange(String s) { - if (!isMetadataAvailable()) { - getFilesAdapter().getFilter().filter(s); - } else { - getFilesMetadataAdapter().getFilter().filter(s); - } - return true; - } - - @Override - public void isListEmpty(boolean empty) { - if (getView().findViewById(R.id.none_text) != null) - getView().findViewById(R.id.none_text).setVisibility(empty ? View.VISIBLE : View.GONE); - } - - private void collapseSearchView() { - if (searchView.isShown()) { - searchMenuItem.collapseActionView(); - searchView.setQuery("", false); - } - } - - public boolean checkForDuplicateFile(String fileName) { - List files; - - if (!isMetadataAvailable()) { - files = getFilesAdapter().getItems(); - } else { - files = getFilesMetadataAdapter().getItems(); - } - for (ServerFile serverFile : files) { - if (serverFile.getName().equals(fileName)) { - return true; - } - } - return false; - } - - @Override - public void onResume() { - super.onResume(); - - mCastContext.addCastStateListener(this); - BusProvider.getBus().register(this); - } - - @Override - public void onPause() { - super.onPause(); - - mCastContext.removeCastStateListener(this); - BusProvider.getBus().unregister(this); - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - if (isMetadataAvailable()) { - getFilesMetadataAdapter().tearDownCallbacks(); - } - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - - tearDownFilesState(outState); - } - - private void tearDownFilesState(Bundle state) { - if (areFilesLoaded()) { - state.putParcelableArrayList(State.FILES, new ArrayList(getFiles())); - } - - state.putSerializable(State.FILES_SORT, filesSort); - } - - private boolean areFilesLoaded() { - if (getView() == null) { - return false; - } - - if (!isMetadataAvailable()) { - return getFilesAdapter() != null; - } else { - return getFilesMetadataAdapter() != null; - } - } - - private static final class FileNameComparator implements Comparator { - @Override - public int compare(ServerFile firstFile, ServerFile secondFile) { - return firstFile.getName().compareTo(secondFile.getName()); - } - } - - private static final class FileModificationTimeComparator implements Comparator { - @Override - public int compare(ServerFile firstFile, ServerFile secondFile) { - return -firstFile.getModificationTime().compareTo(secondFile.getModificationTime()); - } - } + SwipeRefreshLayout.OnRefreshListener, + AdapterView.OnItemClickListener, + AdapterView.OnItemLongClickListener, + ActionMode.Callback, + SearchView.OnQueryTextListener, + FilesFilterBaseAdapter.onFilterListChange, + EasyPermissions.PermissionCallbacks, + CastStateListener { + private static final int SHARE_PERMISSIONS = 101; + @Inject + ServerClient serverClient; + private SearchView searchView; + private MenuItem searchMenuItem; + private LinearLayout mErrorLinearLayout; + private CastContext mCastContext; + private IntroductoryOverlay mIntroductoryOverlay; + private MenuItem mediaRouteMenuItem; + private ProgressDialog deleteProgressDialog; + private int deleteFilePosition; + private int lastCheckedFileIndex = -1; + private FilesSort filesSort = FilesSort.MODIFICATION_TIME; + private ActionMode filesActions; + + @Override + public View onCreateView(LayoutInflater layoutInflater, ViewGroup container, Bundle savedInstanceState) { + View rootView; + if (!isMetadataAvailable()) { + rootView = layoutInflater.inflate(R.layout.fragment_server_files, container, false); + } else { + rootView = layoutInflater.inflate(R.layout.fragment_server_files_metadata, container, false); + } + mErrorLinearLayout = (LinearLayout) rootView.findViewById(R.id.error); + return rootView; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + setUpInjections(); + + setUpCast(); + + setUpFiles(savedInstanceState); + + setUpProgressDialog(); + } + + private void setUpInjections() { + AmahiApplication.from(getActivity()).inject(this); + } + + private void setUpCast() { + mCastContext = CastContext.getSharedInstance(getActivity()); + } + + @Override + public void onCastStateChanged(int newState) { + if (newState != CastState.NO_DEVICES_AVAILABLE) { + showIntroductoryOverlay(); + } + } + + private void showIntroductoryOverlay() { + if (mIntroductoryOverlay != null) { + mIntroductoryOverlay.remove(); + } + if ((mediaRouteMenuItem != null) && mediaRouteMenuItem.isVisible()) { + new Handler().post(new Runnable() { + @Override + public void run() { + mIntroductoryOverlay = new IntroductoryOverlay + .Builder(getActivity(), mediaRouteMenuItem) + .setTitleText("Introducing Cast") + .setSingleTime() + .setOnOverlayDismissedListener( + new IntroductoryOverlay.OnOverlayDismissedListener() { + @Override + public void onOverlayDismissed() { + mIntroductoryOverlay = null; + } + }) + .build(); + mIntroductoryOverlay.show(); + } + }); + } + } + + private void setUpFiles(Bundle state) { + setUpFilesMenu(); + setUpFilesActions(); + setUpFilesAdapter(); + setUpFilesContent(state); + setUpFilesContentRefreshing(); + } + + private void setUpProgressDialog() { + deleteProgressDialog = new ProgressDialog(getContext()); + deleteProgressDialog.setMessage(getString(R.string.message_delete_progress)); + deleteProgressDialog.setIndeterminate(true); + deleteProgressDialog.setCancelable(false); + } + + private void setUpFilesMenu() { + setHasOptionsMenu(true); + } + + private void setUpFilesActions() { + getListView().setOnItemClickListener(this); + getListView().setOnItemLongClickListener(this); + } + + private AbsListView getListView() { + return (AbsListView) getView().findViewById(android.R.id.list); + } + + @Override + public boolean onItemLongClick(AdapterView filesListView, View fileView, int filePosition, long fileId) { + if (!areFilesActionsAvailable()) { + getListView().clearChoices(); + getListView().setItemChecked(filePosition, true); + + getListView().startActionMode(this); + + return true; + } else { + return false; + } + } + + private boolean areFilesActionsAvailable() { + return filesActions != null; + } + + @Override + public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { + this.filesActions = actionMode; + + actionMode.getMenuInflater().inflate(R.menu.action_mode_server_files, menu); + + return true; + } + + @Override + public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { + return false; + } + + @Override + public void onDestroyActionMode(ActionMode actionMode) { + this.filesActions = null; + + clearFileChoices(); + } + + private void clearFileChoices() { + getListView().clearChoices(); + getListView().requestLayout(); + } + + @Override + public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) { + switch (menuItem.getItemId()) { + case R.id.menu_share: + if (Android.isPermissionRequired()) { + checkSharePermissions(actionMode); + } else { + startFileSharing(getCheckedFile()); + actionMode.finish(); + } + break; + case R.id.menu_delete: + deleteFile(getCheckedFile(), actionMode); + break; + default: + return false; + } + + return true; + } + + @RequiresApi(api = Build.VERSION_CODES.M) + private void checkSharePermissions(ActionMode actionMode) { + String[] perms = {Manifest.permission.WRITE_EXTERNAL_STORAGE}; + if (EasyPermissions.hasPermissions(getContext(), perms)) { + startFileSharing(getCheckedFile()); + } else { + lastCheckedFileIndex = getListView().getCheckedItemPosition(); + EasyPermissions.requestPermissions(this, getString(R.string.share_permission), + SHARE_PERMISSIONS, perms); + } + actionMode.finish(); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + + // Forward results to EasyPermissions + EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); + } + + @Override + public void onPermissionsGranted(int requestCode, List perms) { + if (requestCode == SHARE_PERMISSIONS) { + if (lastCheckedFileIndex != -1) { + startFileSharing(getFile(lastCheckedFileIndex)); + } + } + } + + @Override + public void onPermissionsDenied(int requestCode, List perms) { + if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) { + if (requestCode == SHARE_PERMISSIONS) { + showPermissionSnackBar(getString(R.string.share_permission_denied)); + } + } + + } + + private void showPermissionSnackBar(String message) { + Snackbar.make(getView(), message, Snackbar.LENGTH_LONG) + .setAction(R.string.menu_settings, new View.OnClickListener() { + @Override + public void onClick(View v) { + new AppSettingsDialog.Builder(ServerFilesFragment.this).build().show(); + } + }) + .show(); + } + + private void startFileSharing(ServerFile file) { + BusProvider.getBus().post(new ServerFileSharingEvent(getShare(), file)); + } + + private void deleteFile(final ServerFile file, final ActionMode actionMode) { + deleteFilePosition = getListView().getCheckedItemPosition(); + new AlertDialog.Builder(getContext()) + .setTitle(R.string.message_delete_file_title) + .setMessage(R.string.message_delete_file_body) + .setPositiveButton(R.string.button_yes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + deleteProgressDialog.show(); + serverClient.deleteFile(getShare(), file); + actionMode.finish(); + } + }) + .setNegativeButton(R.string.button_no, null) + .show(); + } + + @Subscribe + public void onFileDeleteEvent(ServerFileDeleteEvent fileDeleteEvent) { + deleteProgressDialog.dismiss(); + if (fileDeleteEvent.isDeleted()) { + if (!isMetadataAvailable()) { + getFilesAdapter().removeFile(deleteFilePosition); + } else { + getFilesMetadataAdapter().removeFile(deleteFilePosition); + } + } else { + Toast.makeText(getContext(), R.string.message_delete_file_error, Toast.LENGTH_SHORT).show(); + } + } + + private ServerFile getCheckedFile() { + return getFile(getListView().getCheckedItemPosition()); + } + + private ServerFile getFile(int position) { + if (!isMetadataAvailable()) { + return getFilesAdapter().getItem(position); + } else { + return getFilesMetadataAdapter().getItem(position); + } + } + + private boolean isMetadataAvailable() { + return ServerShare.Tag.MOVIES.equals(getShare().getTag()); + } + + private ServerFilesAdapter getFilesAdapter() { + return (ServerFilesAdapter) getListAdapter(); + } + + private ServerFilesMetadataAdapter getFilesMetadataAdapter() { + return (ServerFilesMetadataAdapter) getListAdapter(); + } + + private ListAdapter getListAdapter() { + return getListView().getAdapter(); + } + + private void setListAdapter(FilesFilterBaseAdapter adapter) { + adapter.setFilterListChangeListener(this); + getListView().setAdapter(adapter); + } + + private void setUpFilesAdapter() { + if (!isMetadataAvailable()) { + setListAdapter(new ServerFilesAdapter(getActivity(), getActivity().getApplicationContext(), serverClient)); + } else { + setListAdapter(new ServerFilesMetadataAdapter(getActivity(), serverClient)); + } + } + + private void setUpFilesContent(Bundle state) { + if (isFilesStateValid(state)) { + setUpFilesState(state); + } else { + setUpFilesContent(); + } + } + + private boolean isFilesStateValid(Bundle state) { + return (state != null) && state.containsKey(State.FILES) && state.containsKey(State.FILES_SORT); + } + + private void setUpFilesState(Bundle state) { + List files = state.getParcelableArrayList(State.FILES); + + FilesSort filesSort = (FilesSort) state.getSerializable(State.FILES_SORT); + + setUpFilesContent(files); + setUpFilesContentSort(filesSort); + + showFilesContent(); + } + + private void setUpFilesContent(List files) { + if (!isMetadataAvailable()) { + getFilesAdapter().replaceWith(getShare(), files); + } else { + getFilesMetadataAdapter().replaceWith(getShare(), getMetadataFiles(files)); + } + } + + private List getMetadataFiles(List files) { + List metadataFiles = new ArrayList(); + + for (ServerFile file : files) { + if (Mimes.match(file.getMime()) == Mimes.Type.DIRECTORY) { + metadataFiles.add(file); + } + + if (Mimes.match(file.getMime()) == Mimes.Type.VIDEO) { + metadataFiles.add(file); + } + } + return metadataFiles; + } + + private void setUpFilesContentSort(FilesSort filesSort) { + this.filesSort = filesSort; + + getActivity().invalidateOptionsMenu(); + } + + private void showFilesContent() { + if (areFilesAvailable()) { + getView().findViewById(android.R.id.list).setVisibility(View.VISIBLE); + getView().findViewById(android.R.id.empty).setVisibility(View.INVISIBLE); + } else { + getView().findViewById(android.R.id.list).setVisibility(View.INVISIBLE); + getView().findViewById(android.R.id.empty).setVisibility(View.VISIBLE); + } + + ViewDirector.of(this, R.id.animator).show(R.id.content); + } + + private boolean areFilesAvailable() { + if (!isMetadataAvailable()) { + return !getFilesAdapter().isEmpty(); + } else { + return !getFilesMetadataAdapter().isEmpty(); + } + } + + private void setUpFilesContent() { + if (serverClient.isConnected()) { + if (!isDirectoryAvailable()) { + serverClient.getFiles(getShare()); + } else { + serverClient.getFiles(getShare(), getDirectory()); + } + } + } + + private boolean isDirectoryAvailable() { + return getDirectory() != null; + } + + private boolean isDirectory(ServerFile file) { + return Mimes.match(file.getMime()) == Mimes.Type.DIRECTORY; + } + + private ServerFile getDirectory() { + return getArguments().getParcelable(Fragments.Arguments.SERVER_FILE); + } + + private ServerShare getShare() { + return getArguments().getParcelable(Fragments.Arguments.SERVER_SHARE); + } + + @Subscribe + public void onFilesLoaded(ServerFilesLoadedEvent event) { + showFilesContent(event.getServerFiles()); + } + + private void showFilesContent(List files) { + setUpFilesContent(sortFiles(files)); + + showFilesContent(); + + hideFilesContentRefreshing(); + } + + private List sortFiles(List files) { + List sortedFiles = new ArrayList(files); + + Collections.sort(sortedFiles, getFilesComparator()); + + return sortedFiles; + } + + private Comparator getFilesComparator() { + switch (filesSort) { + case NAME: + return new FileNameComparator(); + + case MODIFICATION_TIME: + return new FileModificationTimeComparator(); + + default: + return null; + } + } + + private void hideFilesContentRefreshing() { + getRefreshLayout().setRefreshing(false); + } + + private SwipeRefreshLayout getRefreshLayout() { + return (SwipeRefreshLayout) getView().findViewById(R.id.layout_refresh); + } + + @Subscribe + public void onFilesLoadFailed(ServerFilesLoadFailedEvent event) { + showFilesError(); + + hideFilesContentRefreshing(); + } + + private void showFilesError() { + ViewDirector.of(this, R.id.animator).show(R.id.error); + mErrorLinearLayout.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + ViewDirector.of(getActivity(), R.id.animator).show(android.R.id.progress); + setUpFilesContent(); + } + }); + } + + private void setUpFilesContentRefreshing() { + SwipeRefreshLayout refreshLayout = getRefreshLayout(); + + refreshLayout.setColorSchemeResources( + android.R.color.holo_blue_light, + android.R.color.holo_orange_light, + android.R.color.holo_green_light, + android.R.color.holo_red_light); + + refreshLayout.setOnRefreshListener(this); + } + + @Override + public void onRefresh() { + setUpFilesContent(); + } + + @Override + public void onItemClick(AdapterView filesListView, View fileView, int filePosition, long fileId) { + if (!areFilesActionsAvailable()) { + collapseSearchView(); + startFileOpening(getFile(filePosition)); + + if (isDirectory(getFile(filePosition))) { + setUpTitle(getFile(filePosition).getName()); + } + } + } + + private void startFileOpening(ServerFile file) { + BusProvider.getBus().post(new FileOpeningEvent(getShare(), getFiles(), file)); + } + + private void setUpTitle(String title) { + ((ServerFilesActivity) getActivity()).getSupportActionBar().setTitle(title); + } + + private List getFiles() { + if (!isMetadataAvailable()) { + return getFilesAdapter().getItems(); + } else { + return getFilesMetadataAdapter().getItems(); + } + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { + super.onCreateOptionsMenu(menu, menuInflater); + + menuInflater.inflate(R.menu.action_bar_server_files, menu); + + mediaRouteMenuItem = CastButtonFactory.setUpMediaRouteButton( + getActivity().getApplicationContext(), + menu, R.id.media_route_menu_item); + } + + @Override + public void onPrepareOptionsMenu(Menu menu) { + super.onPrepareOptionsMenu(menu); + + setUpFilesContentSortIcon(menu.findItem(R.id.menu_sort)); + searchMenuItem = menu.findItem(R.id.menu_search); + searchView = (SearchView) searchMenuItem.getActionView(); + + setUpSearchView(); + setSearchCursor(); + } + + private void setUpSearchView() { + SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE); + searchView.setSearchableInfo(searchManager.getSearchableInfo(getActivity().getComponentName())); + searchView.setSubmitButtonEnabled(false); + searchView.setOnQueryTextListener(this); + } + + private void setSearchCursor() { + final int textViewID = searchView.getContext().getResources().getIdentifier("android:id/search_src_text", null, null); + final AutoCompleteTextView searchTextView = (AutoCompleteTextView) searchView.findViewById(textViewID); + try { + Field mCursorDrawableRes = TextView.class.getDeclaredField("mCursorDrawableRes"); + mCursorDrawableRes.setAccessible(true); + mCursorDrawableRes.set(searchTextView, R.drawable.white_cursor); + } catch (Exception ignored) { + } + } + + private void setUpFilesContentSortIcon(MenuItem menuItem) { + switch (filesSort) { + case NAME: + menuItem.setIcon(R.drawable.ic_menu_sort_name); + break; + + case MODIFICATION_TIME: + menuItem.setIcon(R.drawable.ic_menu_sort_modification_time); + break; + + default: + break; + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem menuItem) { + switch (menuItem.getItemId()) { + + case R.id.menu_sort: + setUpFilesContentSortSwitched(); + setUpFilesContentSortIcon(menuItem); + return true; + default: + return super.onOptionsItemSelected(menuItem); + } + } + + private void setUpFilesContentSortSwitched() { + switch (filesSort) { + case NAME: + filesSort = FilesSort.MODIFICATION_TIME; + break; + + case MODIFICATION_TIME: + filesSort = FilesSort.NAME; + break; + + default: + break; + } + + setUpFilesContentSort(); + } + + private void setUpFilesContentSort() { + if (!isMetadataAvailable()) { + getFilesAdapter().replaceWith(getShare(), sortFiles(getFiles())); + } else { + getFilesMetadataAdapter().replaceWith(getShare(), sortFiles(getFiles())); + } + } + + @Override + public boolean onQueryTextSubmit(String s) { + return false; + } + + @Override + public boolean onQueryTextChange(String s) { + if (!isMetadataAvailable()) { + getFilesAdapter().getFilter().filter(s); + } else { + getFilesMetadataAdapter().getFilter().filter(s); + } + return true; + } + + @Override + public void isListEmpty(boolean empty) { + if (getView().findViewById(R.id.none_text) != null) + getView().findViewById(R.id.none_text).setVisibility(empty ? View.VISIBLE : View.GONE); + } + + private void collapseSearchView() { + if (searchView.isShown()) { + searchMenuItem.collapseActionView(); + searchView.setQuery("", false); + } + } + + public boolean checkForDuplicateFile(String fileName) { + List files; + + if (!isMetadataAvailable()) { + files = getFilesAdapter().getItems(); + } else { + files = getFilesMetadataAdapter().getItems(); + } + for (ServerFile serverFile : files) { + if (serverFile.getName().equals(fileName)) { + return true; + } + } + return false; + } + + @Override + public void onResume() { + super.onResume(); + + mCastContext.addCastStateListener(this); + BusProvider.getBus().register(this); + } + + @Override + public void onPause() { + super.onPause(); + + mCastContext.removeCastStateListener(this); + BusProvider.getBus().unregister(this); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + if (isMetadataAvailable()) { + getFilesMetadataAdapter().tearDownCallbacks(); + } + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + + tearDownFilesState(outState); + } + + private void tearDownFilesState(Bundle state) { + if (areFilesLoaded()) { + state.putParcelableArrayList(State.FILES, new ArrayList(getFiles())); + } + + state.putSerializable(State.FILES_SORT, filesSort); + } + + private boolean areFilesLoaded() { + if (getView() == null) { + return false; + } + + if (!isMetadataAvailable()) { + return getFilesAdapter() != null; + } else { + return getFilesMetadataAdapter() != null; + } + } + + private enum FilesSort { + NAME, MODIFICATION_TIME + } + + private static final class State { + public static final String FILES = "files"; + public static final String FILES_SORT = "files_sort"; + private State() { + } + } + + private static final class FileNameComparator implements Comparator { + @Override + public int compare(ServerFile firstFile, ServerFile secondFile) { + return firstFile.getName().compareTo(secondFile.getName()); + } + } + + private static final class FileModificationTimeComparator implements Comparator { + @Override + public int compare(ServerFile firstFile, ServerFile secondFile) { + return -firstFile.getModificationTime().compareTo(secondFile.getModificationTime()); + } + } } diff --git a/src/main/java/org/amahi/anywhere/fragment/ServerSharesFragment.java b/src/main/java/org/amahi/anywhere/fragment/ServerSharesFragment.java index 8835612f2..68d9fdad4 100644 --- a/src/main/java/org/amahi/anywhere/fragment/ServerSharesFragment.java +++ b/src/main/java/org/amahi/anywhere/fragment/ServerSharesFragment.java @@ -51,136 +51,125 @@ /** * Shares fragment. Shows shares list. */ -public class ServerSharesFragment extends Fragment -{ - private static final class State - { - private State() { - } +public class ServerSharesFragment extends Fragment { + @Inject + ServerClient serverClient; + private RecyclerView mRecyclerView; - public static final String SHARES = "shares"; - } + private ServerSharesAdapter mServerSharesAdapter; - private RecyclerView mRecyclerView; - - private ServerSharesAdapter mServerSharesAdapter; - - private LinearLayout mEmptyLinearLayout; + private LinearLayout mEmptyLinearLayout; private LinearLayout mErrorLinearLayout; - @Inject - ServerClient serverClient; - - @Override - public View onCreateView(LayoutInflater layoutInflater, ViewGroup container, Bundle savedInstanceState) { + @Override + public View onCreateView(LayoutInflater layoutInflater, ViewGroup container, Bundle savedInstanceState) { - View rootView = layoutInflater.inflate(R.layout.fragment_server_shares, container, false); + View rootView = layoutInflater.inflate(R.layout.fragment_server_shares, container, false); - mRecyclerView = (RecyclerView)rootView.findViewById(R.id.list); + mRecyclerView = (RecyclerView) rootView.findViewById(R.id.list); - mServerSharesAdapter = new ServerSharesAdapter(getActivity()); + mServerSharesAdapter = new ServerSharesAdapter(getActivity()); - mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity(),LinearLayoutManager.VERTICAL,false)); + mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false)); - mEmptyLinearLayout = (LinearLayout)rootView.findViewById(R.id.empty); + mEmptyLinearLayout = (LinearLayout) rootView.findViewById(R.id.empty); mErrorLinearLayout = (LinearLayout) rootView.findViewById(R.id.error); - mRecyclerView.addItemDecoration(new - DividerItemDecoration(getActivity(), - DividerItemDecoration.VERTICAL)); + mRecyclerView.addItemDecoration(new + DividerItemDecoration(getActivity(), + DividerItemDecoration.VERTICAL)); - return rootView; - } + return rootView; + } - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); - setUpInjections(); + setUpInjections(); - setUpShares(savedInstanceState); - } + setUpShares(savedInstanceState); + } - private void setUpInjections() { - AmahiApplication.from(getActivity()).inject(this); - } + private void setUpInjections() { + AmahiApplication.from(getActivity()).inject(this); + } - private void setUpShares(Bundle state) { - setUpSharesAdapter(); + private void setUpShares(Bundle state) { + setUpSharesAdapter(); - setUpSharesContent(state); - } + setUpSharesContent(state); + } - private void setUpSharesAdapter() { - mRecyclerView.setAdapter(mServerSharesAdapter); - } + private void setUpSharesAdapter() { + mRecyclerView.setAdapter(mServerSharesAdapter); + } - private void setUpSharesContent(Bundle state) { - if (isSharesStateValid(state)) { - setUpSharesState(state); - } else { - setUpSharesContent(); - } - } + private void setUpSharesContent(Bundle state) { + if (isSharesStateValid(state)) { + setUpSharesState(state); + } else { + setUpSharesContent(); + } + } - private boolean isSharesStateValid(Bundle state) { - return (state != null) && (state.containsKey(State.SHARES)); - } + private boolean isSharesStateValid(Bundle state) { + return (state != null) && (state.containsKey(State.SHARES)); + } - private void setUpSharesState(Bundle state) { - List shares = state.getParcelableArrayList(State.SHARES); - if(shares!=null) { - setUpSharesContent(shares); + private void setUpSharesState(Bundle state) { + List shares = state.getParcelableArrayList(State.SHARES); + if (shares != null) { + setUpSharesContent(shares); - showSharesContent(); + showSharesContent(); - mEmptyLinearLayout.setVisibility(View.GONE); - } - else{ + mEmptyLinearLayout.setVisibility(View.GONE); + } else { - mEmptyLinearLayout.setVisibility(View.VISIBLE); + mEmptyLinearLayout.setVisibility(View.VISIBLE); - } - } + } + } - private void setUpSharesContent(List shares) { - getSharesAdapter().replaceWith(shares); - } + private void setUpSharesContent(List shares) { + getSharesAdapter().replaceWith(shares); + } - private ServerSharesAdapter getSharesAdapter() { - return mServerSharesAdapter; - } + private ServerSharesAdapter getSharesAdapter() { + return mServerSharesAdapter; + } - private void showSharesContent() { - ViewDirector.of(getActivity(), R.id.animator).show(R.id.content); - } + private void showSharesContent() { + ViewDirector.of(getActivity(), R.id.animator).show(R.id.content); + } - private void setUpSharesContent() { - if (serverClient.isConnected()) { - serverClient.getShares(); - } - } + private void setUpSharesContent() { + if (serverClient.isConnected()) { + serverClient.getShares(); + } + } - @Subscribe - public void onServerConnectionChanged(ServerConnectionChangedEvent event) { - serverClient.getShares(); - } + @Subscribe + public void onServerConnectionChanged(ServerConnectionChangedEvent event) { + serverClient.getShares(); + } - @Subscribe - public void onSharesLoaded(ServerSharesLoadedEvent event) { - setUpSharesContent(event.getServerShares()); - showSharesContent(); - } + @Subscribe + public void onSharesLoaded(ServerSharesLoadedEvent event) { + setUpSharesContent(event.getServerShares()); + showSharesContent(); + } - @Subscribe - public void onSharesLoadFailed(ServerSharesLoadFailedEvent event) { - showSharesError(); - } + @Subscribe + public void onSharesLoadFailed(ServerSharesLoadFailedEvent event) { + showSharesError(); + } - private void showSharesError() { - ViewDirector.of(getActivity(), R.id.animator).show(R.id.error); + private void showSharesError() { + ViewDirector.of(getActivity(), R.id.animator).show(R.id.error); mErrorLinearLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { @@ -188,36 +177,43 @@ public void onClick(View view) { setUpSharesContent(); } }); - } + } + + @Override + public void onResume() { + super.onResume(); + + BusProvider.getBus().register(this); + } - @Override - public void onResume() { - super.onResume(); + @Override + public void onPause() { + super.onPause(); - BusProvider.getBus().register(this); - } + BusProvider.getBus().unregister(this); + } - @Override - public void onPause() { - super.onPause(); + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); - BusProvider.getBus().unregister(this); - } + tearDownSharesState(outState); + } - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); + private void tearDownSharesState(Bundle state) { + if (areSharesLoaded()) { + state.putParcelableArrayList(State.SHARES, new ArrayList(getSharesAdapter().getItems())); + } + } - tearDownSharesState(outState); - } + private boolean areSharesLoaded() { + return getSharesAdapter() != null; + } - private void tearDownSharesState(Bundle state) { - if (areSharesLoaded()) { - state.putParcelableArrayList(State.SHARES, new ArrayList(getSharesAdapter().getItems())); - } - } + private static final class State { + public static final String SHARES = "shares"; - private boolean areSharesLoaded() { - return getSharesAdapter() != null; - } -} \ No newline at end of file + private State() { + } + } +} diff --git a/src/main/java/org/amahi/anywhere/fragment/SettingsFragment.java b/src/main/java/org/amahi/anywhere/fragment/SettingsFragment.java index 321a353a4..3df7f3b24 100644 --- a/src/main/java/org/amahi/anywhere/fragment/SettingsFragment.java +++ b/src/main/java/org/amahi/anywhere/fragment/SettingsFragment.java @@ -54,243 +54,243 @@ * Settings fragment. Shows application's settings. */ public class SettingsFragment extends PreferenceFragment implements Preference.OnPreferenceClickListener, - SharedPreferences.OnSharedPreferenceChangeListener, - AccountManagerCallback { - @Inject - ServerClient serverClient; - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setUpInjections(); - setUpSettings(); - } - - private void setUpInjections() { - AmahiApplication.from(getActivity()).inject(this); - } - - private void setUpTitle() { - getActivity().setTitle(R.string.title_settings); - } - - private void setUpSettings() { - setUpSettingsContent(); - setUpSettingsSummary(); - setUpSettingsListeners(); - } - - private void setUpSettingsContent() { - addPreferencesFromResource(R.xml.settings); - } - - private void setUpSettingsSummary() { - ListPreference serverConnection = (ListPreference) getPreference(R.string.preference_key_server_connection); - Preference applicationVersion = getPreference(R.string.preference_key_about_version); - Preference autoUpload = getPreference(R.string.preference_screen_key_upload); - - serverConnection.setSummary(getServerConnectionSummary()); - applicationVersion.setSummary(getApplicationVersionSummary()); - autoUpload.setSummary(getAutoUploadSummary()); - } - - private String getServerConnectionSummary() { - ListPreference serverConnection = (ListPreference) getPreference(R.string.preference_key_server_connection); - - return String.format("%s", serverConnection.getEntry()); - } - - private Preference getPreference(int id) { - return findPreference(getString(id)); - } - - private String getApplicationVersionSummary() { - return String.format( - "Amahi for Android %s\nwww.amahi.org/android", - Android.getApplicationVersion()); - } - - private String getAutoUploadSummary() { - return isUploadEnabled() ? "Enabled" : "Disabled"; - } - - private boolean isUploadEnabled() { - PreferenceManager preferenceManager = getPreferenceManager(); - return preferenceManager.getSharedPreferences() - .getBoolean(getString(R.string.preference_key_upload_switch), false); - } - - private void setUpSettingsListeners() { - Preference accountSignOut = getPreference(R.string.preference_key_account_sign_out); - Preference applicationVersion = getPreference(R.string.preference_key_about_version); - Preference applicationFeedback = getPreference(R.string.preference_key_about_feedback); - Preference applicationRating = getPreference(R.string.preference_key_about_rating); - Preference shareApp = getPreference(R.string.preference_key_tell_a_friend); - Preference autoUpload = getPreference(R.string.preference_screen_key_upload); - - accountSignOut.setOnPreferenceClickListener(this); - applicationVersion.setOnPreferenceClickListener(this); - applicationFeedback.setOnPreferenceClickListener(this); - applicationRating.setOnPreferenceClickListener(this); - shareApp.setOnPreferenceClickListener(this); - autoUpload.setOnPreferenceClickListener(this); - } - - @Override - public boolean onPreferenceClick(Preference preference) { - if (preference.getKey().equals(getString(R.string.preference_key_account_sign_out))) { - tearDownAccount(); - } else if (preference.getKey().equals(getString(R.string.preference_key_about_version))) { - setUpApplicationVersion(); - } else if (preference.getKey().equals(getString(R.string.preference_key_about_feedback))) { - setUpApplicationFeedback(); - } else if (preference.getKey().equals(getString(R.string.preference_key_about_rating))) { - setUpApplicationRating(); - } else if (preference.getKey().equals(getString(R.string.preference_key_tell_a_friend))) { - sharedIntent(); - } else if (preference.getKey().equals(getString(R.string.preference_screen_key_upload))) { - openUploadSettingsFragment(); - } - return true; - } - - private void openUploadSettingsFragment() { - BusProvider.getBus().post(new UploadSettingsOpeningEvent()); - } - - private void tearDownAccount() { - if (!getAccounts().isEmpty()) { - Account account = getAccounts().get(0); - - getAccountManager().removeAccount(account, this, null); - } else { - tearDownActivity(); - } - } - - private List getAccounts() { - return Arrays.asList(getAccountManager().getAccountsByType(AmahiAccount.TYPE)); - } - - private AccountManager getAccountManager() { - return AccountManager.get(getActivity()); - } - - @Override - public void run(AccountManagerFuture accountManagerFuture) { - tearDownActivity(); - } - - private void tearDownActivity() { - Toast.makeText(getActivity(), R.string.message_logout, Toast.LENGTH_SHORT).show(); - Intent myIntent = new Intent(getActivity().getApplicationContext(), NavigationActivity.class); - myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); - startActivity(myIntent); - getActivity().finish(); - } - - private void sharedIntent() { - Intent sendIntent = new Intent(); - sendIntent.setAction(Intent.ACTION_SEND); - sendIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.share_subject)); - sendIntent.putExtra(Intent.EXTRA_TEXT, getString(R.string.share_message)); - sendIntent.setType("text/plain"); - startActivity(Intent.createChooser(sendIntent, getString(R.string.share_screen_title))); - } - - private void setUpApplicationVersion() { - Intent intent = Intents.Builder.with(getActivity()).buildVersionIntent(getActivity()); - startActivity(intent); - } - - private void setUpApplicationFeedback() { - Intent intent = Intents.Builder.with(getActivity()).buildFeedbackIntent(); - if (intent.resolveActivity(getActivity().getPackageManager()) != null) { - startActivity(intent); - } else { - Snackbar.make(getView(), getString(R.string.application_not_found), Snackbar.LENGTH_SHORT).show(); - } - } - - private void setUpApplicationRating() { - Intent intent = Intents.Builder.with(getActivity()).buildGooglePlayIntent(); - if (intent.resolveActivity(getActivity().getPackageManager()) != null) { - startActivity(intent); - } else { - Snackbar.make(getView(), getString(R.string.application_not_found), Snackbar.LENGTH_SHORT).show(); - } - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if (key.equals(getString(R.string.preference_key_server_connection))) { - setUpSettingsSummary(); - - setUpServerConnection(); - } - } - - private void setUpServerConnection() { - if (!serverClient.isConnected()) { - return; - } - - switch (getServerConnection()) { - case AUTO: - serverClient.connectAuto(); - break; - - case LOCAL: - serverClient.connectLocal(); - break; - - case REMOTE: - serverClient.connectRemote(); - break; - - default: - break; - } - } - - private ApiConnection getServerConnection() { - ListPreference serverConnection = (ListPreference) getPreference(R.string.preference_key_server_connection); - - if (serverConnection.getValue().equals(getString(R.string.preference_key_server_connection_auto))) { - return ApiConnection.AUTO; - } - - if (serverConnection.getValue().equals(getString(R.string.preference_key_server_connection_local))) { - return ApiConnection.LOCAL; - } - - if (serverConnection.getValue().equals(getString(R.string.preference_key_server_connection_remote))) { - return ApiConnection.REMOTE; - } - - return ApiConnection.AUTO; - } - - @Override - public void onResume() { - super.onResume(); - - setUpSettingsPreferenceListener(); - setUpTitle(); - } - - private void setUpSettingsPreferenceListener() { - getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); - } - - @Override - public void onPause() { - super.onPause(); - - tearDownSettingsPreferenceListener(); - } - - private void tearDownSettingsPreferenceListener() { - getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); - } + SharedPreferences.OnSharedPreferenceChangeListener, + AccountManagerCallback { + @Inject + ServerClient serverClient; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setUpInjections(); + setUpSettings(); + } + + private void setUpInjections() { + AmahiApplication.from(getActivity()).inject(this); + } + + private void setUpTitle() { + getActivity().setTitle(R.string.title_settings); + } + + private void setUpSettings() { + setUpSettingsContent(); + setUpSettingsSummary(); + setUpSettingsListeners(); + } + + private void setUpSettingsContent() { + addPreferencesFromResource(R.xml.settings); + } + + private void setUpSettingsSummary() { + ListPreference serverConnection = (ListPreference) getPreference(R.string.preference_key_server_connection); + Preference applicationVersion = getPreference(R.string.preference_key_about_version); + Preference autoUpload = getPreference(R.string.preference_screen_key_upload); + + serverConnection.setSummary(getServerConnectionSummary()); + applicationVersion.setSummary(getApplicationVersionSummary()); + autoUpload.setSummary(getAutoUploadSummary()); + } + + private String getServerConnectionSummary() { + ListPreference serverConnection = (ListPreference) getPreference(R.string.preference_key_server_connection); + + return String.format("%s", serverConnection.getEntry()); + } + + private Preference getPreference(int id) { + return findPreference(getString(id)); + } + + private String getApplicationVersionSummary() { + return String.format( + "Amahi for Android %s\nwww.amahi.org/android", + Android.getApplicationVersion()); + } + + private String getAutoUploadSummary() { + return isUploadEnabled() ? "Enabled" : "Disabled"; + } + + private boolean isUploadEnabled() { + PreferenceManager preferenceManager = getPreferenceManager(); + return preferenceManager.getSharedPreferences() + .getBoolean(getString(R.string.preference_key_upload_switch), false); + } + + private void setUpSettingsListeners() { + Preference accountSignOut = getPreference(R.string.preference_key_account_sign_out); + Preference applicationVersion = getPreference(R.string.preference_key_about_version); + Preference applicationFeedback = getPreference(R.string.preference_key_about_feedback); + Preference applicationRating = getPreference(R.string.preference_key_about_rating); + Preference shareApp = getPreference(R.string.preference_key_tell_a_friend); + Preference autoUpload = getPreference(R.string.preference_screen_key_upload); + + accountSignOut.setOnPreferenceClickListener(this); + applicationVersion.setOnPreferenceClickListener(this); + applicationFeedback.setOnPreferenceClickListener(this); + applicationRating.setOnPreferenceClickListener(this); + shareApp.setOnPreferenceClickListener(this); + autoUpload.setOnPreferenceClickListener(this); + } + + @Override + public boolean onPreferenceClick(Preference preference) { + if (preference.getKey().equals(getString(R.string.preference_key_account_sign_out))) { + tearDownAccount(); + } else if (preference.getKey().equals(getString(R.string.preference_key_about_version))) { + setUpApplicationVersion(); + } else if (preference.getKey().equals(getString(R.string.preference_key_about_feedback))) { + setUpApplicationFeedback(); + } else if (preference.getKey().equals(getString(R.string.preference_key_about_rating))) { + setUpApplicationRating(); + } else if (preference.getKey().equals(getString(R.string.preference_key_tell_a_friend))) { + sharedIntent(); + } else if (preference.getKey().equals(getString(R.string.preference_screen_key_upload))) { + openUploadSettingsFragment(); + } + return true; + } + + private void openUploadSettingsFragment() { + BusProvider.getBus().post(new UploadSettingsOpeningEvent()); + } + + private void tearDownAccount() { + if (!getAccounts().isEmpty()) { + Account account = getAccounts().get(0); + + getAccountManager().removeAccount(account, this, null); + } else { + tearDownActivity(); + } + } + + private List getAccounts() { + return Arrays.asList(getAccountManager().getAccountsByType(AmahiAccount.TYPE)); + } + + private AccountManager getAccountManager() { + return AccountManager.get(getActivity()); + } + + @Override + public void run(AccountManagerFuture accountManagerFuture) { + tearDownActivity(); + } + + private void tearDownActivity() { + Toast.makeText(getActivity(), R.string.message_logout, Toast.LENGTH_SHORT).show(); + Intent myIntent = new Intent(getActivity().getApplicationContext(), NavigationActivity.class); + myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + startActivity(myIntent); + getActivity().finish(); + } + + private void sharedIntent() { + Intent sendIntent = new Intent(); + sendIntent.setAction(Intent.ACTION_SEND); + sendIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.share_subject)); + sendIntent.putExtra(Intent.EXTRA_TEXT, getString(R.string.share_message)); + sendIntent.setType("text/plain"); + startActivity(Intent.createChooser(sendIntent, getString(R.string.share_screen_title))); + } + + private void setUpApplicationVersion() { + Intent intent = Intents.Builder.with(getActivity()).buildVersionIntent(getActivity()); + startActivity(intent); + } + + private void setUpApplicationFeedback() { + Intent intent = Intents.Builder.with(getActivity()).buildFeedbackIntent(); + if (intent.resolveActivity(getActivity().getPackageManager()) != null) { + startActivity(intent); + } else { + Snackbar.make(getView(), getString(R.string.application_not_found), Snackbar.LENGTH_SHORT).show(); + } + } + + private void setUpApplicationRating() { + Intent intent = Intents.Builder.with(getActivity()).buildGooglePlayIntent(); + if (intent.resolveActivity(getActivity().getPackageManager()) != null) { + startActivity(intent); + } else { + Snackbar.make(getView(), getString(R.string.application_not_found), Snackbar.LENGTH_SHORT).show(); + } + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (key.equals(getString(R.string.preference_key_server_connection))) { + setUpSettingsSummary(); + + setUpServerConnection(); + } + } + + private void setUpServerConnection() { + if (!serverClient.isConnected()) { + return; + } + + switch (getServerConnection()) { + case AUTO: + serverClient.connectAuto(); + break; + + case LOCAL: + serverClient.connectLocal(); + break; + + case REMOTE: + serverClient.connectRemote(); + break; + + default: + break; + } + } + + private ApiConnection getServerConnection() { + ListPreference serverConnection = (ListPreference) getPreference(R.string.preference_key_server_connection); + + if (serverConnection.getValue().equals(getString(R.string.preference_key_server_connection_auto))) { + return ApiConnection.AUTO; + } + + if (serverConnection.getValue().equals(getString(R.string.preference_key_server_connection_local))) { + return ApiConnection.LOCAL; + } + + if (serverConnection.getValue().equals(getString(R.string.preference_key_server_connection_remote))) { + return ApiConnection.REMOTE; + } + + return ApiConnection.AUTO; + } + + @Override + public void onResume() { + super.onResume(); + + setUpSettingsPreferenceListener(); + setUpTitle(); + } + + private void setUpSettingsPreferenceListener() { + getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); + } + + @Override + public void onPause() { + super.onPause(); + + tearDownSettingsPreferenceListener(); + } + + private void tearDownSettingsPreferenceListener() { + getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); + } } diff --git a/src/main/java/org/amahi/anywhere/fragment/UploadBottomSheet.java b/src/main/java/org/amahi/anywhere/fragment/UploadBottomSheet.java index 053d04f3c..395f43be1 100644 --- a/src/main/java/org/amahi/anywhere/fragment/UploadBottomSheet.java +++ b/src/main/java/org/amahi/anywhere/fragment/UploadBottomSheet.java @@ -46,57 +46,57 @@ */ public class UploadBottomSheet extends BottomSheetDialogFragment implements AdapterView.OnItemClickListener { - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View rootView = inflater.inflate(R.layout.upload_bottom_sheet, container); - rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - BottomSheetDialog bottomSheetDialog = (BottomSheetDialog)getDialog(); - FrameLayout bottomSheet = (FrameLayout)bottomSheetDialog.findViewById(android.support.design.R.id.design_bottom_sheet); - assert bottomSheet != null; - BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet); - behavior.setState(BottomSheetBehavior.STATE_EXPANDED); - behavior.setPeekHeight(0); - } - }); - return rootView; - } + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View rootView = inflater.inflate(R.layout.upload_bottom_sheet, container); + rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + BottomSheetDialog bottomSheetDialog = (BottomSheetDialog) getDialog(); + FrameLayout bottomSheet = (FrameLayout) bottomSheetDialog.findViewById(android.support.design.R.id.design_bottom_sheet); + assert bottomSheet != null; + BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet); + behavior.setState(BottomSheetBehavior.STATE_EXPANDED); + behavior.setPeekHeight(0); + } + }); + return rootView; + } - @Override - public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - setUpListView(view); - } + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + setUpListView(view); + } - private ArrayList getListItems() { - ArrayList uploadOptions = new ArrayList<>(); + private ArrayList getListItems() { + ArrayList uploadOptions = new ArrayList<>(); - uploadOptions.add(new UploadOption(UploadOption.CAMERA, - getString(R.string.upload_camera), - R.drawable.ic_camera)); + uploadOptions.add(new UploadOption(UploadOption.CAMERA, + getString(R.string.upload_camera), + R.drawable.ic_camera)); - uploadOptions.add(new UploadOption(UploadOption.FILE, - getString(R.string.upload_photo), - R.drawable.ic_cloud_upload)); + uploadOptions.add(new UploadOption(UploadOption.FILE, + getString(R.string.upload_photo), + R.drawable.ic_cloud_upload)); - return uploadOptions; - } + return uploadOptions; + } - private void setUpListView(View view) { - UploadOptionsAdapter adapter = new UploadOptionsAdapter(getContext(), getListItems()); - ListView listView = (ListView) view.findViewById(R.id.upload_options_list); - assert listView != null; - listView.setAdapter(adapter); - listView.setOnItemClickListener(this); - } + private void setUpListView(View view) { + UploadOptionsAdapter adapter = new UploadOptionsAdapter(getContext(), getListItems()); + ListView listView = (ListView) view.findViewById(R.id.upload_options_list); + assert listView != null; + listView.setAdapter(adapter); + listView.setOnItemClickListener(this); + } - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - UploadOption uploadOption = getListItems().get(position); - BusProvider.getBus().post(new UploadClickEvent(uploadOption.getType())); - dismiss(); - } + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + UploadOption uploadOption = getListItems().get(position); + BusProvider.getBus().post(new UploadClickEvent(uploadOption.getType())); + dismiss(); + } } diff --git a/src/main/java/org/amahi/anywhere/fragment/UploadSettingsFragment.java b/src/main/java/org/amahi/anywhere/fragment/UploadSettingsFragment.java index 8c15236ce..e9b63d250 100644 --- a/src/main/java/org/amahi/anywhere/fragment/UploadSettingsFragment.java +++ b/src/main/java/org/amahi/anywhere/fragment/UploadSettingsFragment.java @@ -46,7 +46,6 @@ import org.amahi.anywhere.AmahiApplication; import org.amahi.anywhere.R; import org.amahi.anywhere.account.AmahiAccount; -import org.amahi.anywhere.activity.ServerFilesActivity; import org.amahi.anywhere.bus.BusProvider; import org.amahi.anywhere.bus.ServerConnectedEvent; import org.amahi.anywhere.bus.ServerConnectionChangedEvent; @@ -71,349 +70,349 @@ * Upload Settings fragment. Shows upload settings. */ public class UploadSettingsFragment extends PreferenceFragment implements - Preference.OnPreferenceChangeListener, - AccountManagerCallback, - EasyPermissions.PermissionCallbacks { - - private static final int READ_PERMISSIONS = 110; - @Inject - AmahiClient amahiClient; - - @Inject - ServerClient serverClient; + Preference.OnPreferenceChangeListener, + AccountManagerCallback, + EasyPermissions.PermissionCallbacks { + + private static final int READ_PERMISSIONS = 110; + @Inject + AmahiClient amahiClient; + + @Inject + ServerClient serverClient; - private String authenticationToken; - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setUpInjections(); - - setUpTitle(); - - setUpSettings(); - } - - private void setUpInjections() { - AmahiApplication.from(getActivity()).inject(this); - } - - private void setUpTitle() { - getActivity().setTitle(R.string.preference_title_upload_settings); - } - - private void setUpSettings() { - setUpSettingsContent(); - setUpSettingsTitle(); - toggleUploadSettings(isUploadEnabled()); - setUpSettingsListeners(); - } - - private void setUpSettingsContent() { - addPreferencesFromResource(R.xml.upload_settings); - } - - private void setUpSettingsTitle() { - getAutoUploadSwitchPreference().setTitle(getAutoUploadTitle(isUploadEnabled())); - } - - private AccountManager getAccountManager() { - return AccountManager.get(getActivity()); - } - - private List getAccounts() { - return Arrays.asList(getAccountManager().getAccountsByType(AmahiAccount.TYPE)); - } - - private void setUpAuthenticationToken() { - if (authenticationToken != null) { - setUpServersContent(authenticationToken); - } else { - Account account = getAccounts().get(0); - getAccountManager().getAuthToken(account, AmahiAccount.TYPE, null, getActivity(), this, null); - } - - } - - @Override - public void run(AccountManagerFuture future) { - try { - Bundle accountManagerResult = future.getResult(); - - authenticationToken = accountManagerResult.getString(AccountManager.KEY_AUTHTOKEN); - - setUpAuthenticationToken(); - - } catch (OperationCanceledException e) { - tearDownActivity(); - } catch (IOException | AuthenticatorException e) { - throw new RuntimeException(e); - } - } - - private void setUpServersContent(String authenticationToken) { - amahiClient.getServers(getActivity(), authenticationToken); - } - - @Subscribe - public void onServersLoaded(ServersLoadedEvent event) { - setUpServersContent(event.getServers()); - } - - private void setUpServersContent(List servers) { - ArrayList activeServers = filterActiveServers(servers); - String[] serverNames = new String[activeServers.size()]; - String[] serverSessions = new String[activeServers.size()]; - - for (int i = 0; i < activeServers.size(); i++) { - Server activeServer = activeServers.get(i); - serverNames[i] = activeServer.getName(); - serverSessions[i] = activeServer.getSession(); - } - - getHdaPreference().setEntries(serverNames); - getHdaPreference().setEntryValues(serverSessions); - getHdaPreference().setEnabled(true); - - String session = getHdaPreference().getValue(); - if (session != null) { - setUpServer(session); - } - } - - private ArrayList filterActiveServers(List servers) { - ArrayList activeServers = new ArrayList<>(); - - for (Server server : servers) { - if (server.isActive()) { - activeServers.add(server); - } - } - - return activeServers; - } - - private boolean isUploadEnabled() { - PreferenceManager preferenceManager = getPreferenceManager(); - return preferenceManager.getSharedPreferences() - .getBoolean(getString(R.string.preference_key_upload_switch), false); - } - - private String getAutoUploadTitle(boolean isUploadEnabled) { - return isUploadEnabled ? "Disable" : "Enable"; - } - - private void setUpSettingsListeners() { - getAutoUploadSwitchPreference().setOnPreferenceChangeListener(this); - getHdaPreference().setOnPreferenceChangeListener(this); - getSharePreference().setOnPreferenceChangeListener(this); - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - String key = preference.getKey(); - if (key.equals(getString(R.string.preference_key_upload_switch))) { - boolean isUploadEnabled = (boolean) newValue; - if (isUploadEnabled) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - checkReadPermissions(); - return false; - } - } - toggleUploadSettings(isUploadEnabled); - preference.setTitle(getAutoUploadTitle(isUploadEnabled)); - } else if (key.equals(getString(R.string.preference_key_upload_hda))) { - setUpServer(String.valueOf(newValue)); - } else if (key.equals(getString(R.string.preference_key_upload_share))) { - getPathPreference().setEnabled(true); - getAllowOnDataPreference().setEnabled(true); - } - return true; - } - - private void setUpServer(String session) { - getSharePreference().setEnabled(false); - getPathPreference().setEnabled(false); - getAllowOnDataPreference().setEnabled(false); - - Server server = new Server(session); - setUpServerConnection(server); - } - - @Subscribe - public void onServerConnected(ServerConnectedEvent event) { - setUpServerConnection(); - } - - private void setUpServerConnection(Server server) { - if (serverClient.isConnected(server)) { - setUpServerConnection(); - } else { - serverClient.connect(getActivity(), server); - } - } - - private void setUpServerConnection() { - if (!isConnectionAvailable() || isConnectionAuto()) { - serverClient.connectAuto(); - return; - } - - if (isConnectionLocal()) { - serverClient.connectLocal(); - } else { - serverClient.connectRemote(); - } - } - - - @Subscribe - public void onServerConnectionChanged(ServerConnectionChangedEvent event) { - setUpSharesContent(); - } - - private void setUpSharesContent() { - if (serverClient.isConnected()) { - serverClient.getShares(); - } - } - - @Subscribe - public void onSharesLoaded(ServerSharesLoadedEvent event) { - setUpSharesContent(event.getServerShares()); - } - - private void setUpSharesContent(List shares) { - String[] shareNames = new String[shares.size()]; - for (int i = 0; i < shares.size(); i++) { - shareNames[i] = shares.get(i).getName(); - } - getSharePreference().setEntries(shareNames); - getSharePreference().setEntryValues(shareNames); - getSharePreference().setEnabled(true); - - String selectedShare = getSharePreference().getValue(); - if (selectedShare != null) { - getPathPreference().setEnabled(true); - getAllowOnDataPreference().setEnabled(true); - } - } - - private boolean isConnectionAvailable() { - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); - - return preferences.contains(getString(R.string.preference_key_server_connection)); - } - - private boolean isConnectionAuto() { - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); - String preferenceConnection = preferences.getString(getString(R.string.preference_key_server_connection), null); - - return preferenceConnection.equals(getString(R.string.preference_key_server_connection_auto)); - } - - private boolean isConnectionLocal() { - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); - String preferenceConnection = preferences.getString(getString(R.string.preference_key_server_connection), null); - - return preferenceConnection.equals(getString(R.string.preference_key_server_connection_local)); - } - - private void toggleUploadSettings(boolean isUploadEnabled) { - if (isUploadEnabled) { - setUpAuthenticationToken(); - } else { - getHdaPreference().setEnabled(false); - getSharePreference().setEnabled(false); - getPathPreference().setEnabled(false); - getAllowOnDataPreference().setEnabled(false); - } - } - - private Preference getPreference(int id) { - return findPreference(getString(id)); - } - - private SwitchPreference getAutoUploadSwitchPreference() { - return (SwitchPreference) getPreference(R.string.preference_key_upload_switch); - } - - private ListPreference getHdaPreference() { - return (ListPreference) getPreference(R.string.preference_key_upload_hda); - } - - private ListPreference getSharePreference() { - return (ListPreference) getPreference(R.string.preference_key_upload_share); - } - - private EditTextPreference getPathPreference() { - return (EditTextPreference) getPreference(R.string.preference_key_upload_path); - } - - private SwitchPreference getAllowOnDataPreference() { - return (SwitchPreference) getPreference(R.string.preference_key_upload_data); - } - - private void tearDownActivity() { - getActivity().finish(); - } - - - @Override - public void onResume() { - super.onResume(); - - BusProvider.getBus().register(this); - } - - @Override - public void onPause() { - super.onPause(); - - BusProvider.getBus().unregister(this); - } - - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - - // Forward results to EasyPermissions - EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); - } - - @Override - public void onPermissionsGranted(int requestCode, List perms) { - if (requestCode == READ_PERMISSIONS) { - toggleUploadSettings(true); - getAutoUploadSwitchPreference().setTitle(getAutoUploadTitle(true)); - } - } - - @Override - public void onPermissionsDenied(int requestCode, List perms) { - if (requestCode == READ_PERMISSIONS) { - showPermissionSnackBar(getString(R.string.file_upload_permission_denied)); - } - } - - private void showPermissionSnackBar(String message) { - Snackbar.make(getView(), message, Snackbar.LENGTH_LONG) - .setAction(R.string.menu_settings, new View.OnClickListener() { - @Override - public void onClick(View v) { - new AppSettingsDialog.Builder(UploadSettingsFragment.this).build().show(); - } - }) - .show(); - } - - @RequiresApi(api = Build.VERSION_CODES.M) - private void checkReadPermissions() { - String[] perms = {Manifest.permission.READ_EXTERNAL_STORAGE}; - if (!EasyPermissions.hasPermissions(getContext(), perms)) { - EasyPermissions.requestPermissions(this, getString(R.string.file_upload_permission), - READ_PERMISSIONS, perms); - } - } + private String authenticationToken; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setUpInjections(); + + setUpTitle(); + + setUpSettings(); + } + + private void setUpInjections() { + AmahiApplication.from(getActivity()).inject(this); + } + + private void setUpTitle() { + getActivity().setTitle(R.string.preference_title_upload_settings); + } + + private void setUpSettings() { + setUpSettingsContent(); + setUpSettingsTitle(); + toggleUploadSettings(isUploadEnabled()); + setUpSettingsListeners(); + } + + private void setUpSettingsContent() { + addPreferencesFromResource(R.xml.upload_settings); + } + + private void setUpSettingsTitle() { + getAutoUploadSwitchPreference().setTitle(getAutoUploadTitle(isUploadEnabled())); + } + + private AccountManager getAccountManager() { + return AccountManager.get(getActivity()); + } + + private List getAccounts() { + return Arrays.asList(getAccountManager().getAccountsByType(AmahiAccount.TYPE)); + } + + private void setUpAuthenticationToken() { + if (authenticationToken != null) { + setUpServersContent(authenticationToken); + } else { + Account account = getAccounts().get(0); + getAccountManager().getAuthToken(account, AmahiAccount.TYPE, null, getActivity(), this, null); + } + + } + + @Override + public void run(AccountManagerFuture future) { + try { + Bundle accountManagerResult = future.getResult(); + + authenticationToken = accountManagerResult.getString(AccountManager.KEY_AUTHTOKEN); + + setUpAuthenticationToken(); + + } catch (OperationCanceledException e) { + tearDownActivity(); + } catch (IOException | AuthenticatorException e) { + throw new RuntimeException(e); + } + } + + private void setUpServersContent(String authenticationToken) { + amahiClient.getServers(getActivity(), authenticationToken); + } + + @Subscribe + public void onServersLoaded(ServersLoadedEvent event) { + setUpServersContent(event.getServers()); + } + + private void setUpServersContent(List servers) { + ArrayList activeServers = filterActiveServers(servers); + String[] serverNames = new String[activeServers.size()]; + String[] serverSessions = new String[activeServers.size()]; + + for (int i = 0; i < activeServers.size(); i++) { + Server activeServer = activeServers.get(i); + serverNames[i] = activeServer.getName(); + serverSessions[i] = activeServer.getSession(); + } + + getHdaPreference().setEntries(serverNames); + getHdaPreference().setEntryValues(serverSessions); + getHdaPreference().setEnabled(true); + + String session = getHdaPreference().getValue(); + if (session != null) { + setUpServer(session); + } + } + + private ArrayList filterActiveServers(List servers) { + ArrayList activeServers = new ArrayList<>(); + + for (Server server : servers) { + if (server.isActive()) { + activeServers.add(server); + } + } + + return activeServers; + } + + private boolean isUploadEnabled() { + PreferenceManager preferenceManager = getPreferenceManager(); + return preferenceManager.getSharedPreferences() + .getBoolean(getString(R.string.preference_key_upload_switch), false); + } + + private String getAutoUploadTitle(boolean isUploadEnabled) { + return isUploadEnabled ? "Disable" : "Enable"; + } + + private void setUpSettingsListeners() { + getAutoUploadSwitchPreference().setOnPreferenceChangeListener(this); + getHdaPreference().setOnPreferenceChangeListener(this); + getSharePreference().setOnPreferenceChangeListener(this); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + String key = preference.getKey(); + if (key.equals(getString(R.string.preference_key_upload_switch))) { + boolean isUploadEnabled = (boolean) newValue; + if (isUploadEnabled) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + checkReadPermissions(); + return false; + } + } + toggleUploadSettings(isUploadEnabled); + preference.setTitle(getAutoUploadTitle(isUploadEnabled)); + } else if (key.equals(getString(R.string.preference_key_upload_hda))) { + setUpServer(String.valueOf(newValue)); + } else if (key.equals(getString(R.string.preference_key_upload_share))) { + getPathPreference().setEnabled(true); + getAllowOnDataPreference().setEnabled(true); + } + return true; + } + + private void setUpServer(String session) { + getSharePreference().setEnabled(false); + getPathPreference().setEnabled(false); + getAllowOnDataPreference().setEnabled(false); + + Server server = new Server(session); + setUpServerConnection(server); + } + + @Subscribe + public void onServerConnected(ServerConnectedEvent event) { + setUpServerConnection(); + } + + private void setUpServerConnection(Server server) { + if (serverClient.isConnected(server)) { + setUpServerConnection(); + } else { + serverClient.connect(getActivity(), server); + } + } + + private void setUpServerConnection() { + if (!isConnectionAvailable() || isConnectionAuto()) { + serverClient.connectAuto(); + return; + } + + if (isConnectionLocal()) { + serverClient.connectLocal(); + } else { + serverClient.connectRemote(); + } + } + + + @Subscribe + public void onServerConnectionChanged(ServerConnectionChangedEvent event) { + setUpSharesContent(); + } + + private void setUpSharesContent() { + if (serverClient.isConnected()) { + serverClient.getShares(); + } + } + + @Subscribe + public void onSharesLoaded(ServerSharesLoadedEvent event) { + setUpSharesContent(event.getServerShares()); + } + + private void setUpSharesContent(List shares) { + String[] shareNames = new String[shares.size()]; + for (int i = 0; i < shares.size(); i++) { + shareNames[i] = shares.get(i).getName(); + } + getSharePreference().setEntries(shareNames); + getSharePreference().setEntryValues(shareNames); + getSharePreference().setEnabled(true); + + String selectedShare = getSharePreference().getValue(); + if (selectedShare != null) { + getPathPreference().setEnabled(true); + getAllowOnDataPreference().setEnabled(true); + } + } + + private boolean isConnectionAvailable() { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); + + return preferences.contains(getString(R.string.preference_key_server_connection)); + } + + private boolean isConnectionAuto() { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); + String preferenceConnection = preferences.getString(getString(R.string.preference_key_server_connection), null); + + return preferenceConnection.equals(getString(R.string.preference_key_server_connection_auto)); + } + + private boolean isConnectionLocal() { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); + String preferenceConnection = preferences.getString(getString(R.string.preference_key_server_connection), null); + + return preferenceConnection.equals(getString(R.string.preference_key_server_connection_local)); + } + + private void toggleUploadSettings(boolean isUploadEnabled) { + if (isUploadEnabled) { + setUpAuthenticationToken(); + } else { + getHdaPreference().setEnabled(false); + getSharePreference().setEnabled(false); + getPathPreference().setEnabled(false); + getAllowOnDataPreference().setEnabled(false); + } + } + + private Preference getPreference(int id) { + return findPreference(getString(id)); + } + + private SwitchPreference getAutoUploadSwitchPreference() { + return (SwitchPreference) getPreference(R.string.preference_key_upload_switch); + } + + private ListPreference getHdaPreference() { + return (ListPreference) getPreference(R.string.preference_key_upload_hda); + } + + private ListPreference getSharePreference() { + return (ListPreference) getPreference(R.string.preference_key_upload_share); + } + + private EditTextPreference getPathPreference() { + return (EditTextPreference) getPreference(R.string.preference_key_upload_path); + } + + private SwitchPreference getAllowOnDataPreference() { + return (SwitchPreference) getPreference(R.string.preference_key_upload_data); + } + + private void tearDownActivity() { + getActivity().finish(); + } + + + @Override + public void onResume() { + super.onResume(); + + BusProvider.getBus().register(this); + } + + @Override + public void onPause() { + super.onPause(); + + BusProvider.getBus().unregister(this); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + + // Forward results to EasyPermissions + EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); + } + + @Override + public void onPermissionsGranted(int requestCode, List perms) { + if (requestCode == READ_PERMISSIONS) { + toggleUploadSettings(true); + getAutoUploadSwitchPreference().setTitle(getAutoUploadTitle(true)); + } + } + + @Override + public void onPermissionsDenied(int requestCode, List perms) { + if (requestCode == READ_PERMISSIONS) { + showPermissionSnackBar(getString(R.string.file_upload_permission_denied)); + } + } + + private void showPermissionSnackBar(String message) { + Snackbar.make(getView(), message, Snackbar.LENGTH_LONG) + .setAction(R.string.menu_settings, new View.OnClickListener() { + @Override + public void onClick(View v) { + new AppSettingsDialog.Builder(UploadSettingsFragment.this).build().show(); + } + }) + .show(); + } + + @RequiresApi(api = Build.VERSION_CODES.M) + private void checkReadPermissions() { + String[] perms = {Manifest.permission.READ_EXTERNAL_STORAGE}; + if (!EasyPermissions.hasPermissions(getContext(), perms)) { + EasyPermissions.requestPermissions(this, getString(R.string.file_upload_permission), + READ_PERMISSIONS, perms); + } + } } diff --git a/src/main/java/org/amahi/anywhere/job/NetConnectivityJob.java b/src/main/java/org/amahi/anywhere/job/NetConnectivityJob.java index 2e5f08a08..371c707e5 100644 --- a/src/main/java/org/amahi/anywhere/job/NetConnectivityJob.java +++ b/src/main/java/org/amahi/anywhere/job/NetConnectivityJob.java @@ -26,66 +26,60 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.net.Uri; import android.os.Build; -import android.provider.MediaStore; import android.support.annotation.RequiresApi; import android.util.Log; import org.amahi.anywhere.AmahiApplication.JobIds; import org.amahi.anywhere.service.UploadService; -import org.amahi.anywhere.util.Intents; - -import java.util.ArrayList; -import java.util.List; /** * Job to monitor when there is a change to photos in the media provider. */ @RequiresApi(api = Build.VERSION_CODES.N) public class NetConnectivityJob extends JobService { - private final String TAG = this.getClass().getName(); + // A pre-built JobInfo we use for scheduling our job. + static final JobInfo JOB_INFO; - // A pre-built JobInfo we use for scheduling our job. - static final JobInfo JOB_INFO; + static { + JobInfo.Builder builder = new JobInfo.Builder(JobIds.NET_CONNECTIVITY_JOB, + new ComponentName("org.amahi.anywhere", NetConnectivityJob.class.getName())); + builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); + JOB_INFO = builder.build(); + } - static { - JobInfo.Builder builder = new JobInfo.Builder(JobIds.NET_CONNECTIVITY_JOB, - new ComponentName("org.amahi.anywhere", NetConnectivityJob.class.getName())); - builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); - JOB_INFO = builder.build(); - } + private final String TAG = this.getClass().getName(); - // Schedule this job, replace any existing one. - public static void scheduleJob(Context context) { - JobScheduler js = context.getSystemService(JobScheduler.class); - js.schedule(JOB_INFO); - Log.i("NetworkConnectivityJob", "JOB SCHEDULED!"); - } + // Schedule this job, replace any existing one. + public static void scheduleJob(Context context) { + JobScheduler js = context.getSystemService(JobScheduler.class); + js.schedule(JOB_INFO); + Log.i("NetworkConnectivityJob", "JOB SCHEDULED!"); + } - // Check whether this job is currently scheduled. - public static boolean isScheduled(Context context) { - JobScheduler js = context.getSystemService(JobScheduler.class); - JobInfo job = js.getPendingJob(JobIds.NET_CONNECTIVITY_JOB); - return job != null; - } + // Check whether this job is currently scheduled. + public static boolean isScheduled(Context context) { + JobScheduler js = context.getSystemService(JobScheduler.class); + JobInfo job = js.getPendingJob(JobIds.NET_CONNECTIVITY_JOB); + return job != null; + } - // Cancel this job, if currently scheduled. - public static void cancelJob(Context context) { - JobScheduler js = context.getSystemService(JobScheduler.class); - js.cancel(JobIds.NET_CONNECTIVITY_JOB); - } + // Cancel this job, if currently scheduled. + public static void cancelJob(Context context) { + JobScheduler js = context.getSystemService(JobScheduler.class); + js.cancel(JobIds.NET_CONNECTIVITY_JOB); + } - @Override - public boolean onStartJob(JobParameters params) { - Log.i(TAG, "JOB STARTED!"); - Intent intent = new Intent(this, UploadService.class); - startService(intent); - return false; - } + @Override + public boolean onStartJob(JobParameters params) { + Log.i(TAG, "JOB STARTED!"); + Intent intent = new Intent(this, UploadService.class); + startService(intent); + return false; + } - @Override - public boolean onStopJob(JobParameters params) { - return false; - } + @Override + public boolean onStopJob(JobParameters params) { + return false; + } } diff --git a/src/main/java/org/amahi/anywhere/job/PhotosContentJob.java b/src/main/java/org/amahi/anywhere/job/PhotosContentJob.java index b734e717d..395152c0f 100644 --- a/src/main/java/org/amahi/anywhere/job/PhotosContentJob.java +++ b/src/main/java/org/amahi/anywhere/job/PhotosContentJob.java @@ -43,86 +43,83 @@ */ @RequiresApi(api = Build.VERSION_CODES.N) public class PhotosContentJob extends JobService { - private final String TAG = this.getClass().getName(); - - // The root URI of the media provider, to monitor for generic changes to its content. - static final Uri MEDIA_URI = Uri.parse("content://" + MediaStore.AUTHORITY + "/"); - - // Path segments for image-specific URIs in the provider. - static final List EXTERNAL_PATH_SEGMENTS - = MediaStore.Images.Media.EXTERNAL_CONTENT_URI.getPathSegments(); - - // A pre-built JobInfo we use for scheduling our job. - static final JobInfo JOB_INFO; - - static { - JobInfo.Builder builder = new JobInfo.Builder(JobIds.PHOTOS_CONTENT_JOB, - new ComponentName("org.amahi.anywhere", PhotosContentJob.class.getName())); - // Look for specific changes to images in the provider. - builder.addTriggerContentUri(new JobInfo.TriggerContentUri( - MediaStore.Images.Media.EXTERNAL_CONTENT_URI, - JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS)); - // Also look for general reports of changes in the overall provider. - builder.addTriggerContentUri(new JobInfo.TriggerContentUri(MEDIA_URI, 0)); - JOB_INFO = builder.build(); - } - - JobParameters mRunningParams; - - // Schedule this job, replace any existing one. - public static void scheduleJob(Context context) { - JobScheduler js = context.getSystemService(JobScheduler.class); - js.schedule(JOB_INFO); - Log.i("PhotosContentJob", "JOB SCHEDULED!"); - } - - // Check whether this job is currently scheduled. - public static boolean isScheduled(Context context) { - JobScheduler js = context.getSystemService(JobScheduler.class); - JobInfo job = js.getPendingJob(JobIds.PHOTOS_CONTENT_JOB); - return job != null; - } - - // Cancel this job, if currently scheduled. - public static void cancelJob(Context context) { - JobScheduler js = context.getSystemService(JobScheduler.class); - js.cancel(JobIds.PHOTOS_CONTENT_JOB); - } - - @Override - public boolean onStartJob(JobParameters params) { - Log.i("PhotosContentJob", "JOB STARTED!"); - mRunningParams = params; - - // Did we trigger due to a content change? - if (params.getTriggeredContentAuthorities() != null) { - if (params.getTriggeredContentUris() != null) { - // If we have details about which URIs changed, then iterate through them - // and collect valid uris and send them to UploadService - ArrayList uris = new ArrayList<>(); - for (Uri uri : params.getTriggeredContentUris()) { - List path = uri.getPathSegments(); - if (path != null && path.size() == EXTERNAL_PATH_SEGMENTS.size() + 1) { - // This is a specific file. - uris.add(uri); - } - } - Intent intent = Intents.Builder.with(this).buildUploadServiceIntent(uris); - startService(intent); - } else { - // We don't have any details about URIs (because too many changed at once) - Log.i(TAG, "Photos rescan needed!"); - } - } else { - Log.i(TAG, "(No photos content)"); - } - - scheduleJob(PhotosContentJob.this); - return false; - } - - @Override - public boolean onStopJob(JobParameters params) { - return false; - } + // The root URI of the media provider, to monitor for generic changes to its content. + static final Uri MEDIA_URI = Uri.parse("content://" + MediaStore.AUTHORITY + "/"); + // Path segments for image-specific URIs in the provider. + static final List EXTERNAL_PATH_SEGMENTS + = MediaStore.Images.Media.EXTERNAL_CONTENT_URI.getPathSegments(); + // A pre-built JobInfo we use for scheduling our job. + static final JobInfo JOB_INFO; + + static { + JobInfo.Builder builder = new JobInfo.Builder(JobIds.PHOTOS_CONTENT_JOB, + new ComponentName("org.amahi.anywhere", PhotosContentJob.class.getName())); + // Look for specific changes to images in the provider. + builder.addTriggerContentUri(new JobInfo.TriggerContentUri( + MediaStore.Images.Media.EXTERNAL_CONTENT_URI, + JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS)); + // Also look for general reports of changes in the overall provider. + builder.addTriggerContentUri(new JobInfo.TriggerContentUri(MEDIA_URI, 0)); + JOB_INFO = builder.build(); + } + + private final String TAG = this.getClass().getName(); + JobParameters mRunningParams; + + // Schedule this job, replace any existing one. + public static void scheduleJob(Context context) { + JobScheduler js = context.getSystemService(JobScheduler.class); + js.schedule(JOB_INFO); + Log.i("PhotosContentJob", "JOB SCHEDULED!"); + } + + // Check whether this job is currently scheduled. + public static boolean isScheduled(Context context) { + JobScheduler js = context.getSystemService(JobScheduler.class); + JobInfo job = js.getPendingJob(JobIds.PHOTOS_CONTENT_JOB); + return job != null; + } + + // Cancel this job, if currently scheduled. + public static void cancelJob(Context context) { + JobScheduler js = context.getSystemService(JobScheduler.class); + js.cancel(JobIds.PHOTOS_CONTENT_JOB); + } + + @Override + public boolean onStartJob(JobParameters params) { + Log.i("PhotosContentJob", "JOB STARTED!"); + mRunningParams = params; + + // Did we trigger due to a content change? + if (params.getTriggeredContentAuthorities() != null) { + if (params.getTriggeredContentUris() != null) { + // If we have details about which URIs changed, then iterate through them + // and collect valid uris and send them to UploadService + ArrayList uris = new ArrayList<>(); + for (Uri uri : params.getTriggeredContentUris()) { + List path = uri.getPathSegments(); + if (path != null && path.size() == EXTERNAL_PATH_SEGMENTS.size() + 1) { + // This is a specific file. + uris.add(uri); + } + } + Intent intent = Intents.Builder.with(this).buildUploadServiceIntent(uris); + startService(intent); + } else { + // We don't have any details about URIs (because too many changed at once) + Log.i(TAG, "Photos rescan needed!"); + } + } else { + Log.i(TAG, "(No photos content)"); + } + + scheduleJob(PhotosContentJob.this); + return false; + } + + @Override + public boolean onStopJob(JobParameters params) { + return false; + } } diff --git a/src/main/java/org/amahi/anywhere/model/UploadFile.java b/src/main/java/org/amahi/anywhere/model/UploadFile.java index 6b24344f3..caf607514 100644 --- a/src/main/java/org/amahi/anywhere/model/UploadFile.java +++ b/src/main/java/org/amahi/anywhere/model/UploadFile.java @@ -20,19 +20,19 @@ package org.amahi.anywhere.model; public class UploadFile { - private int id; - private String path; + private int id; + private String path; - public UploadFile(int id, String path) { - this.id = id; - this.path = path; - } + public UploadFile(int id, String path) { + this.id = id; + this.path = path; + } - public int getId() { - return id; - } + public int getId() { + return id; + } - public String getPath() { - return path; - } + public String getPath() { + return path; + } } diff --git a/src/main/java/org/amahi/anywhere/model/UploadOption.java b/src/main/java/org/amahi/anywhere/model/UploadOption.java index 8a4de4306..f4bbc92b7 100644 --- a/src/main/java/org/amahi/anywhere/model/UploadOption.java +++ b/src/main/java/org/amahi/anywhere/model/UploadOption.java @@ -27,34 +27,32 @@ * Upload option model for display in {@link UploadBottomSheet} */ public class UploadOption { - public static final int CAMERA = 1; - public static final int FILE = 2; - - @IntDef({CAMERA, FILE}) - public @interface Types { - } - - @Types - private int type; - private String name; - private int icon; - - public UploadOption(@Types int type, String name, int icon) { - this.name = name; - this.icon = icon; - this.type = type; - } - - @Types - public int getType() { - return type; - } - - public String getName() { - return name; - } - - public int getIcon() { - return icon; - } + public static final int CAMERA = 1; + public static final int FILE = 2; + @Types + private int type; + private String name; + private int icon; + public UploadOption(@Types int type, String name, int icon) { + this.name = name; + this.icon = icon; + this.type = type; + } + + @Types + public int getType() { + return type; + } + + public String getName() { + return name; + } + + public int getIcon() { + return icon; + } + + @IntDef({CAMERA, FILE}) + public @interface Types { + } } diff --git a/src/main/java/org/amahi/anywhere/receiver/AudioReceiver.java b/src/main/java/org/amahi/anywhere/receiver/AudioReceiver.java index 785dcfce9..58a357f81 100644 --- a/src/main/java/org/amahi/anywhere/receiver/AudioReceiver.java +++ b/src/main/java/org/amahi/anywhere/receiver/AudioReceiver.java @@ -36,63 +36,62 @@ * Audio system events receiver. Proxies system audio events such as changing track * or audio focus to the local {@link com.squareup.otto.Bus} as {@link org.amahi.anywhere.bus.BusEvent}. */ -public class AudioReceiver extends BroadcastReceiver -{ - @Override - public void onReceive(Context context, Intent intent) { - if (intent == null) { - return; - } - - String action = intent.getAction(); - - if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(action)) { - handleAudioChangeEvent(); - } - - if (Intent.ACTION_MEDIA_BUTTON.equals(action)) { - handleAudioControlEvent(intent); - } - } - - private void handleAudioChangeEvent() { - BusProvider.getBus().post(new AudioControlPauseEvent()); - } - - private void handleAudioControlEvent(Intent intent) { - KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); - - if (event == null) { - return; - } - - if (event.getAction() != KeyEvent.ACTION_DOWN) { - return; - } - - switch (event.getKeyCode()) { - case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: - BusProvider.getBus().post(new AudioControlPlayPauseEvent()); - break; - - case KeyEvent.KEYCODE_MEDIA_PLAY: - BusProvider.getBus().post(new AudioControlPlayEvent()); - break; - - case KeyEvent.KEYCODE_MEDIA_PAUSE: - BusProvider.getBus().post(new AudioControlPauseEvent()); - break; - - case KeyEvent.KEYCODE_MEDIA_NEXT: - BusProvider.getBus().post(new AudioControlNextEvent()); - break; - - case KeyEvent.KEYCODE_MEDIA_PREVIOUS: - BusProvider.getBus().post(new AudioControlPreviousEvent()); - break; - - default: - break; - } - } +public class AudioReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + if (intent == null) { + return; + } + + String action = intent.getAction(); + + if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(action)) { + handleAudioChangeEvent(); + } + + if (Intent.ACTION_MEDIA_BUTTON.equals(action)) { + handleAudioControlEvent(intent); + } + } + + private void handleAudioChangeEvent() { + BusProvider.getBus().post(new AudioControlPauseEvent()); + } + + private void handleAudioControlEvent(Intent intent) { + KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); + + if (event == null) { + return; + } + + if (event.getAction() != KeyEvent.ACTION_DOWN) { + return; + } + + switch (event.getKeyCode()) { + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: + BusProvider.getBus().post(new AudioControlPlayPauseEvent()); + break; + + case KeyEvent.KEYCODE_MEDIA_PLAY: + BusProvider.getBus().post(new AudioControlPlayEvent()); + break; + + case KeyEvent.KEYCODE_MEDIA_PAUSE: + BusProvider.getBus().post(new AudioControlPauseEvent()); + break; + + case KeyEvent.KEYCODE_MEDIA_NEXT: + BusProvider.getBus().post(new AudioControlNextEvent()); + break; + + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + BusProvider.getBus().post(new AudioControlPreviousEvent()); + break; + + default: + break; + } + } } diff --git a/src/main/java/org/amahi/anywhere/receiver/CameraReceiver.java b/src/main/java/org/amahi/anywhere/receiver/CameraReceiver.java index f0a8a7e23..adec0a32a 100644 --- a/src/main/java/org/amahi/anywhere/receiver/CameraReceiver.java +++ b/src/main/java/org/amahi/anywhere/receiver/CameraReceiver.java @@ -22,22 +22,18 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.net.Uri; import android.util.Log; -import org.amahi.anywhere.service.UploadService; import org.amahi.anywhere.util.Intents; -import java.util.ArrayList; - /** * Camera new picture event receiver. */ public class CameraReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - Log.e("NEW_IMAGE", "onReceive"); - Intent uploadService = Intents.Builder.with(context).buildUploadServiceIntent(intent.getData()); - context.startService(uploadService); - } + @Override + public void onReceive(Context context, Intent intent) { + Log.e("NEW_IMAGE", "onReceive"); + Intent uploadService = Intents.Builder.with(context).buildUploadServiceIntent(intent.getData()); + context.startService(uploadService); + } } diff --git a/src/main/java/org/amahi/anywhere/receiver/NetworkReceiver.java b/src/main/java/org/amahi/anywhere/receiver/NetworkReceiver.java index a1054082d..2ba39adaf 100644 --- a/src/main/java/org/amahi/anywhere/receiver/NetworkReceiver.java +++ b/src/main/java/org/amahi/anywhere/receiver/NetworkReceiver.java @@ -35,36 +35,36 @@ * to the local {@link com.squareup.otto.Bus} as {@link org.amahi.anywhere.bus.BusEvent}. */ public class NetworkReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) { - handleNetworkChangeEvent(context); - } - } + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) { + handleNetworkChangeEvent(context); + } + } - private void handleNetworkChangeEvent(Context context) { - NetworkUtils networkUtils = new NetworkUtils(context); - NetworkInfo network = networkUtils.getNetwork(); - if (networkUtils.isNetworkConnected(network)) { - BusProvider.getBus().post(new NetworkChangedEvent(network.getType())); - } + private void handleNetworkChangeEvent(Context context) { + NetworkUtils networkUtils = new NetworkUtils(context); + NetworkInfo network = networkUtils.getNetwork(); + if (networkUtils.isNetworkConnected(network)) { + BusProvider.getBus().post(new NetworkChangedEvent(network.getType())); + } - if (networkUtils.isUploadAllowed()) { - startUploadService(context); - } else { - stopUploadService(context); - } - } + if (networkUtils.isUploadAllowed()) { + startUploadService(context); + } else { + stopUploadService(context); + } + } - private void startUploadService(Context context) { - Intent uploadService = new Intent(context, UploadService.class); - context.startService(uploadService); - } + private void startUploadService(Context context) { + Intent uploadService = new Intent(context, UploadService.class); + context.startService(uploadService); + } - private void stopUploadService(Context context) { - Intent uploadService = new Intent(context, UploadService.class); - context.stopService(uploadService); - } + private void stopUploadService(Context context) { + Intent uploadService = new Intent(context, UploadService.class); + context.stopService(uploadService); + } } diff --git a/src/main/java/org/amahi/anywhere/server/ApiAdapter.java b/src/main/java/org/amahi/anywhere/server/ApiAdapter.java index 2e22140d2..2ef308504 100644 --- a/src/main/java/org/amahi/anywhere/server/ApiAdapter.java +++ b/src/main/java/org/amahi/anywhere/server/ApiAdapter.java @@ -32,22 +32,21 @@ * dependency injection provided components. */ @Singleton -public class ApiAdapter -{ - private final Retrofit.Builder apiBuilder; - - @Inject - public ApiAdapter(OkHttpClient client, Factory factory) { - this.apiBuilder = buildApiBuilder(client, factory); - } - - private Retrofit.Builder buildApiBuilder(OkHttpClient client, Factory factory) { - return new Retrofit.Builder() - .client(client) - .addConverterFactory(factory); - } - - public T create(Class api, String apiUrl) { - return apiBuilder.baseUrl(apiUrl).build().create(api); - } +public class ApiAdapter { + private final Retrofit.Builder apiBuilder; + + @Inject + public ApiAdapter(OkHttpClient client, Factory factory) { + this.apiBuilder = buildApiBuilder(client, factory); + } + + private Retrofit.Builder buildApiBuilder(OkHttpClient client, Factory factory) { + return new Retrofit.Builder() + .client(client) + .addConverterFactory(factory); + } + + public T create(Class api, String apiUrl) { + return apiBuilder.baseUrl(apiUrl).build().create(api); + } } diff --git a/src/main/java/org/amahi/anywhere/server/ApiConnection.java b/src/main/java/org/amahi/anywhere/server/ApiConnection.java index 7ca3f9bdd..918e9e253 100644 --- a/src/main/java/org/amahi/anywhere/server/ApiConnection.java +++ b/src/main/java/org/amahi/anywhere/server/ApiConnection.java @@ -19,9 +19,8 @@ package org.amahi.anywhere.server; -public enum ApiConnection -{ - AUTO, - LOCAL, - REMOTE +public enum ApiConnection { + AUTO, + LOCAL, + REMOTE } diff --git a/src/main/java/org/amahi/anywhere/server/ApiConnectionDetector.java b/src/main/java/org/amahi/anywhere/server/ApiConnectionDetector.java index bf8c02e52..4256de27c 100644 --- a/src/main/java/org/amahi/anywhere/server/ApiConnectionDetector.java +++ b/src/main/java/org/amahi/anywhere/server/ApiConnectionDetector.java @@ -36,54 +36,52 @@ * API connection guesser. Tries to connect to the server address to determine if it is available * and returns it if succeed or another one otherwise. */ -public class ApiConnectionDetector -{ - private static final class Connection - { - private Connection() { - } +public class ApiConnectionDetector { + private OkHttpClient httpClient; - static final int TIMEOUT = 1; - } + public ApiConnectionDetector() { + this.httpClient = buildHttpClient(); + } - private OkHttpClient httpClient; + private OkHttpClient buildHttpClient() { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder(); + clientBuilder.connectTimeout(Connection.TIMEOUT, TimeUnit.SECONDS); + httpClient = clientBuilder.build(); + return httpClient; + } - public ApiConnectionDetector() { - this.httpClient = buildHttpClient(); - } + public String detect(ServerRoute serverRoute) { + Timber.tag("CONNECTION"); - private OkHttpClient buildHttpClient() { - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder(); - clientBuilder.connectTimeout(Connection.TIMEOUT, TimeUnit.SECONDS); - httpClient = clientBuilder.build(); - return httpClient; - } + try { + Request httpRequest = new Request.Builder() + .url(getConnectionUrl(serverRoute.getLocalAddress())) + .build(); - public String detect(ServerRoute serverRoute) { - Timber.tag("CONNECTION"); + Response httpResponse = httpClient + .newCall(httpRequest) + .execute(); - try { - Request httpRequest = new Request.Builder() - .url(getConnectionUrl(serverRoute.getLocalAddress())) - .build(); + httpResponse.body().close(); - Response httpResponse = httpClient - .newCall(httpRequest) - .execute(); + Timber.d("Using local address."); - httpResponse.body().close(); + return serverRoute.getLocalAddress(); + } catch (IOException e) { + Timber.d("Using remote address."); - Timber.d("Using local address."); + return serverRoute.getRemoteAddress(); + } + } - return serverRoute.getLocalAddress(); - } catch (IOException e) { - Timber.d("Using remote address."); + private URL getConnectionUrl(String serverAddress) throws IOException { + return new URL(Uri.parse(serverAddress).buildUpon().appendPath("shares").build().toString()); + } - return serverRoute.getRemoteAddress(); - } - } + private static final class Connection { + static final int TIMEOUT = 1; - private URL getConnectionUrl(String serverAddress) throws IOException { - return new URL(Uri.parse(serverAddress).buildUpon().appendPath("shares").build().toString()); - } + private Connection() { + } + } } diff --git a/src/main/java/org/amahi/anywhere/server/ApiHeaders.java b/src/main/java/org/amahi/anywhere/server/ApiHeaders.java index 9a45f97b9..8d3d838a5 100644 --- a/src/main/java/org/amahi/anywhere/server/ApiHeaders.java +++ b/src/main/java/org/amahi/anywhere/server/ApiHeaders.java @@ -33,42 +33,38 @@ /** * API headers accessor. */ -class ApiHeaders implements Interceptor -{ - private static final class HeaderFields - { - private HeaderFields() { - } +class ApiHeaders implements Interceptor { + private final String acceptHeader; + private final String userAgentHeader; + public ApiHeaders(Context context) { + this.acceptHeader = getAcceptHeader(); + this.userAgentHeader = getUserAgentHeader(context); + } - public static final String ACCEPT = "Accept"; - public static final String USER_AGENT = "User-Agent"; - } + private String getAcceptHeader() { + return "application/json"; + } - private final String acceptHeader; - private final String userAgentHeader; + private String getUserAgentHeader(Context context) { + return Identifier.getUserAgent(context); + } - public ApiHeaders(Context context) { - this.acceptHeader = getAcceptHeader(); - this.userAgentHeader = getUserAgentHeader(context); - } + @Override + public Response intercept(Chain chain) throws IOException { + Request original = chain.request(); + Request request = original.newBuilder() + .addHeader(HeaderFields.ACCEPT, acceptHeader) + .addHeader(HeaderFields.USER_AGENT, userAgentHeader) + .method(original.method(), original.body()) + .build(); - private String getAcceptHeader() { - return "application/json"; - } + return chain.proceed(request); + } - private String getUserAgentHeader(Context context) { - return Identifier.getUserAgent(context); - } - - @Override - public Response intercept(Chain chain) throws IOException { - Request original = chain.request(); - Request request = original.newBuilder() - .addHeader(HeaderFields.ACCEPT, acceptHeader) - .addHeader(HeaderFields.USER_AGENT, userAgentHeader) - .method(original.method(), original.body()) - .build(); - - return chain.proceed(request); - } + private static final class HeaderFields { + public static final String ACCEPT = "Accept"; + public static final String USER_AGENT = "User-Agent"; + private HeaderFields() { + } + } } diff --git a/src/main/java/org/amahi/anywhere/server/ApiModule.java b/src/main/java/org/amahi/anywhere/server/ApiModule.java index b7405e9e2..836f3eef1 100644 --- a/src/main/java/org/amahi/anywhere/server/ApiModule.java +++ b/src/main/java/org/amahi/anywhere/server/ApiModule.java @@ -40,42 +40,41 @@ * for possible consumers. */ @Module( - complete = false, - library = true + complete = false, + library = true ) -public class ApiModule -{ - @Provides - @Singleton - OkHttpClient provideHttpClient(ApiHeaders headers, HttpLoggingInterceptor logging) { - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder(); - clientBuilder.addInterceptor(headers); - clientBuilder.addInterceptor(logging); - return clientBuilder.build(); - } +public class ApiModule { + @Provides + @Singleton + OkHttpClient provideHttpClient(ApiHeaders headers, HttpLoggingInterceptor logging) { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder(); + clientBuilder.addInterceptor(headers); + clientBuilder.addInterceptor(logging); + return clientBuilder.build(); + } - @Provides - @Singleton - ApiHeaders provideHeaders(Context context) { - return new ApiHeaders(context); - } + @Provides + @Singleton + ApiHeaders provideHeaders(Context context) { + return new ApiHeaders(context); + } - @Provides - @Singleton - Converter.Factory provideJsonConverterFactory(Gson json) { - return GsonConverterFactory.create(json); - } + @Provides + @Singleton + Converter.Factory provideJsonConverterFactory(Gson json) { + return GsonConverterFactory.create(json); + } - @Provides - @Singleton - Gson provideJson() { - return new GsonBuilder().setDateFormat(Time.Format.RFC_1123).create(); - } + @Provides + @Singleton + Gson provideJson() { + return new GsonBuilder().setDateFormat(Time.Format.RFC_1123).create(); + } - @Provides - @Singleton - HttpLoggingInterceptor provideLogging() { - // change the level below to HttpLoggingInterceptor.Level.BODY to get the whole body in the logs - return new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.HEADERS); - } + @Provides + @Singleton + HttpLoggingInterceptor provideLogging() { + // change the level below to HttpLoggingInterceptor.Level.BODY to get the whole body in the logs + return new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.HEADERS); + } } diff --git a/src/main/java/org/amahi/anywhere/server/api/AmahiApi.java b/src/main/java/org/amahi/anywhere/server/api/AmahiApi.java index d97b01383..a7a4cd991 100644 --- a/src/main/java/org/amahi/anywhere/server/api/AmahiApi.java +++ b/src/main/java/org/amahi/anywhere/server/api/AmahiApi.java @@ -35,17 +35,16 @@ /** * Amahi API declaration. */ -public interface AmahiApi -{ - @FormUrlEncoded - @POST("/api2/oauth/token?grant_type=password") - Call authenticate( - @Field("client_id") String clientId, - @Field("client_secret") String clientSecret, - @Field("username") String username, - @Field("password") String password); +public interface AmahiApi { + @FormUrlEncoded + @POST("/api2/oauth/token?grant_type=password") + Call authenticate( + @Field("client_id") String clientId, + @Field("client_secret") String clientSecret, + @Field("username") String username, + @Field("password") String password); - @GET("/api2/servers") - Call> getServers( - @Query("access_token") String authenticationToken); + @GET("/api2/servers") + Call> getServers( + @Query("access_token") String authenticationToken); } diff --git a/src/main/java/org/amahi/anywhere/server/api/ProxyApi.java b/src/main/java/org/amahi/anywhere/server/api/ProxyApi.java index 2a6365e9a..46b4112c1 100644 --- a/src/main/java/org/amahi/anywhere/server/api/ProxyApi.java +++ b/src/main/java/org/amahi/anywhere/server/api/ProxyApi.java @@ -29,9 +29,8 @@ /** * Proxy API declaration. */ -public interface ProxyApi -{ - @PUT("/client") - Call getServerRoute( - @Header("Session") String session); +public interface ProxyApi { + @PUT("/client") + Call getServerRoute( + @Header("Session") String session); } diff --git a/src/main/java/org/amahi/anywhere/server/api/ServerApi.java b/src/main/java/org/amahi/anywhere/server/api/ServerApi.java index ecc2fa26f..937c789f8 100644 --- a/src/main/java/org/amahi/anywhere/server/api/ServerApi.java +++ b/src/main/java/org/amahi/anywhere/server/api/ServerApi.java @@ -43,35 +43,35 @@ public interface ServerApi { @GET("/shares") Call> getShares( - @Header("Session") String session); + @Header("Session") String session); @GET("/files") Call> getFiles( - @Header("Session") String session, - @Query("s") String share, - @Query("p") String path); + @Header("Session") String session, + @Query("s") String share, + @Query("p") String path); @DELETE("/files") Call deleteFile( - @Header("Session") String session, - @Query("s") String share, - @Query("p") String path); + @Header("Session") String session, + @Query("s") String share, + @Query("p") String path); @Multipart @POST("/files") Call uploadFile( - @Header("Session") String session, - @Query("s") String share, - @Query("p") String path, - @Part MultipartBody.Part file); + @Header("Session") String session, + @Query("s") String share, + @Query("p") String path, + @Part MultipartBody.Part file); @GET("/md") Call getFileMetadata( - @Header("Session") String session, - @Query("f") String fileName, - @Query("h") String hint); + @Header("Session") String session, + @Query("f") String fileName, + @Query("h") String hint); @GET("/apps") Call> getApps( - @Header("Session") String session); + @Header("Session") String session); } diff --git a/src/main/java/org/amahi/anywhere/server/client/AmahiClient.java b/src/main/java/org/amahi/anywhere/server/client/AmahiClient.java index c61ece367..419312354 100644 --- a/src/main/java/org/amahi/anywhere/server/client/AmahiClient.java +++ b/src/main/java/org/amahi/anywhere/server/client/AmahiClient.java @@ -34,24 +34,23 @@ * Amahi API implementation. Wraps {@link org.amahi.anywhere.server.api.AmahiApi}. */ @Singleton -public class AmahiClient -{ - private final AmahiApi api; - - @Inject - public AmahiClient(ApiAdapter apiAdapter) { - this.api = buildApi(apiAdapter); - } - - private AmahiApi buildApi(ApiAdapter apiAdapter) { - return apiAdapter.create(AmahiApi.class, Api.getAmahiUrl()); - } - - public void authenticate(String username, String password) { - api.authenticate(Api.getClientId(), Api.getClientSecret(), username, password).enqueue(new AuthenticationResponse()); - } - - public void getServers(Context context, String authenticationToken) { - api.getServers(authenticationToken).enqueue(new ServersResponse(context)); - } +public class AmahiClient { + private final AmahiApi api; + + @Inject + public AmahiClient(ApiAdapter apiAdapter) { + this.api = buildApi(apiAdapter); + } + + private AmahiApi buildApi(ApiAdapter apiAdapter) { + return apiAdapter.create(AmahiApi.class, Api.getAmahiUrl()); + } + + public void authenticate(String username, String password) { + api.authenticate(Api.getClientId(), Api.getClientSecret(), username, password).enqueue(new AuthenticationResponse()); + } + + public void getServers(Context context, String authenticationToken) { + api.getServers(authenticationToken).enqueue(new ServersResponse(context)); + } } diff --git a/src/main/java/org/amahi/anywhere/server/client/ServerClient.java b/src/main/java/org/amahi/anywhere/server/client/ServerClient.java index afe1c6853..030842188 100644 --- a/src/main/java/org/amahi/anywhere/server/client/ServerClient.java +++ b/src/main/java/org/amahi/anywhere/server/client/ServerClient.java @@ -74,238 +74,238 @@ */ @Singleton public class ServerClient { - private final ApiAdapter apiAdapter; - private final ProxyApi proxyApi; - private ServerApi serverApi; - - private Server server; - private ServerRoute serverRoute; - private String serverAddress; - private ApiConnection serverConnection; - - private int network; - - @Inject - public ServerClient(ApiAdapter apiAdapter) { - this.apiAdapter = apiAdapter; - this.proxyApi = buildProxyApi(); - - this.serverConnection = ApiConnection.AUTO; - - this.network = Integer.MIN_VALUE; - - setUpBus(); - } - - private ProxyApi buildProxyApi() { - return apiAdapter.create(ProxyApi.class, Api.getProxyUrl()); - } - - private void setUpBus() { - BusProvider.getBus().register(this); - } - - @Subscribe - public void onNetworkChanged(NetworkChangedEvent event) { - if (this.serverConnection != ApiConnection.AUTO) { - return; - } - - if (!isServerRouteLoaded()) { - return; - } - - if (this.network != event.getNetwork()) { - this.network = event.getNetwork(); - - startServerConnectionDetection(); - } - } - - private boolean isServerRouteLoaded() { - return serverRoute != null; - } - - private void startServerConnectionDetection() { - this.serverAddress = serverRoute.getLocalAddress(); - this.serverApi = buildServerApi(); - - ServerConnectionDetectingTask.execute(serverRoute); - } - - private ServerApi buildServerApi() { - return apiAdapter.create(ServerApi.class, serverAddress); - } - - @Subscribe - public void onServerConnectionDetected(ServerConnectionDetectedEvent event) { - this.serverAddress = event.getServerAddress(); - this.serverApi = buildServerApi(); - - finishServerConnectionDetection(); - } - - private void finishServerConnectionDetection() { - BusProvider.getBus().post(new ServerConnectionChangedEvent()); - } - - public boolean isConnected() { - return (server != null) && (serverRoute != null) && (serverAddress != null); - } - - public boolean isConnected(Server server) { - return (this.server != null) && (this.server.getSession().equals(server.getSession())); - } - - public boolean isConnectedLocal() { - return serverAddress.equals(serverRoute.getLocalAddress()); - } - - public void connect(Context context, Server server) { - this.server = server; - - if (server.isDebug()) { - try { - ServerRoute serverRoute = new ServerRoute(); - JSONArray jsonArray = new JSONArray(loadServersFromAsset(context)); - JSONObject jsonObject = jsonArray.getJSONObject(server.getIndex()); - serverRoute.setLocalAddress(jsonObject.getString("local_address")); - serverRoute.setRemoteAddress(jsonObject.getString("remote_address")); - BusProvider.getBus().post(new ServerRouteLoadedEvent(serverRoute)); - } catch (JSONException e) { - e.printStackTrace(); - } - } else { - startServerConnection(); - } - } - - private void startServerConnection() { - proxyApi.getServerRoute(server.getSession()).enqueue(new ServerRouteResponse()); - } - - @Subscribe - public void onServerRouteLoaded(ServerRouteLoadedEvent event) { - this.serverRoute = event.getServerRoute(); - - finishServerConnection(); - } - - private void finishServerConnection() { - BusProvider.getBus().post(new ServerConnectedEvent(server)); - } - - public void connectAuto() { - this.serverConnection = ApiConnection.AUTO; - if (!isServerRouteLoaded()) { - return; - } - startServerConnectionDetection(); - } - - public void connectLocal() { - this.serverConnection = ApiConnection.LOCAL; - if (!isServerRouteLoaded()) { - return; - } - this.serverAddress = serverRoute.getLocalAddress(); - this.serverApi = buildServerApi(); - } - - public void connectRemote() { - this.serverConnection = ApiConnection.REMOTE; - if (!isServerRouteLoaded()) { - return; - } - this.serverAddress = serverRoute.getRemoteAddress(); - this.serverApi = buildServerApi(); - } - - public String getServerAddress() { - return serverAddress; - } - - public void getShares() { - serverApi.getShares(server.getSession()).enqueue(new ServerSharesResponse()); - } - - public void getFiles(ServerShare share) { - if (share == null) { - return; - } - - serverApi.getFiles(server.getSession(), share.getName(), null).enqueue(new ServerFilesResponse(share)); - } - - public void getFiles(ServerShare share, ServerFile directory) { - serverApi.getFiles(server.getSession(), share.getName(), directory.getPath()).enqueue(new ServerFilesResponse(directory, share)); - } - - public void deleteFile(ServerShare share, ServerFile serverFile) { - serverApi.deleteFile(server.getSession(), share.getName(), serverFile.getPath()) - .enqueue(new ServerFileDeleteResponse()); - } - - private MultipartBody.Part createFilePart(int id, File file) { - return MultipartBody.Part.createFormData("file", - file.getName(), - new ProgressRequestBody(id, file)); - } - - public void uploadFile(int id, File file, String shareName, String path) { - MultipartBody.Part filePart = createFilePart(id, file); - uploadFileAsync(id, filePart, shareName, path); - } - - public void uploadFile(int id, File file, ServerShare share, ServerFile directory) { - MultipartBody.Part filePart = createFilePart(id, file); - String path = "/"; - if (directory != null) - path = directory.getPath(); - uploadFileAsync(id, filePart, share.getName(), path); - } - - private void uploadFileAsync(int id, MultipartBody.Part filePart, String shareName, String path) { - serverApi.uploadFile(server.getSession(), shareName, path, filePart) - .enqueue(new ServerFileUploadResponse(id)); - } - - private void uploadFileSync(int id, MultipartBody.Part filePart, String shareName, String path) { - try { - Response response = serverApi - .uploadFile(server.getSession(), shareName, path, filePart) - .execute(); - if (response.isSuccessful()) { - BusProvider.getBus().post( - new ServerFileUploadCompleteEvent(id, true)); - } else { - BusProvider.getBus().post( - new ServerFileUploadCompleteEvent(id, false)); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - - public Uri getFileUri(ServerShare share, ServerFile file) { - return Uri.parse(serverAddress) - .buildUpon() - .path("files") - .appendQueryParameter("s", share.getName()) - .appendQueryParameter("p", file.getPath()) - .appendQueryParameter("mtime", Time.getEpochTimeString(file.getModificationTime())) - .appendQueryParameter("session", server.getSession()) - .build(); - } - - public void getFileMetadata(ServerShare share, ServerFile file, Callback callback) { - if ((server == null) || (share == null) || (file == null)) { - return; - } - serverApi.getFileMetadata(server.getSession(), file.getName(), share.getTag()).enqueue(callback); - } - - public void getApps() { - serverApi.getApps(server.getSession()).enqueue(new ServerAppsResponse()); - } + private final ApiAdapter apiAdapter; + private final ProxyApi proxyApi; + private ServerApi serverApi; + + private Server server; + private ServerRoute serverRoute; + private String serverAddress; + private ApiConnection serverConnection; + + private int network; + + @Inject + public ServerClient(ApiAdapter apiAdapter) { + this.apiAdapter = apiAdapter; + this.proxyApi = buildProxyApi(); + + this.serverConnection = ApiConnection.AUTO; + + this.network = Integer.MIN_VALUE; + + setUpBus(); + } + + private ProxyApi buildProxyApi() { + return apiAdapter.create(ProxyApi.class, Api.getProxyUrl()); + } + + private void setUpBus() { + BusProvider.getBus().register(this); + } + + @Subscribe + public void onNetworkChanged(NetworkChangedEvent event) { + if (this.serverConnection != ApiConnection.AUTO) { + return; + } + + if (!isServerRouteLoaded()) { + return; + } + + if (this.network != event.getNetwork()) { + this.network = event.getNetwork(); + + startServerConnectionDetection(); + } + } + + private boolean isServerRouteLoaded() { + return serverRoute != null; + } + + private void startServerConnectionDetection() { + this.serverAddress = serverRoute.getLocalAddress(); + this.serverApi = buildServerApi(); + + ServerConnectionDetectingTask.execute(serverRoute); + } + + private ServerApi buildServerApi() { + return apiAdapter.create(ServerApi.class, serverAddress); + } + + @Subscribe + public void onServerConnectionDetected(ServerConnectionDetectedEvent event) { + this.serverAddress = event.getServerAddress(); + this.serverApi = buildServerApi(); + + finishServerConnectionDetection(); + } + + private void finishServerConnectionDetection() { + BusProvider.getBus().post(new ServerConnectionChangedEvent()); + } + + public boolean isConnected() { + return (server != null) && (serverRoute != null) && (serverAddress != null); + } + + public boolean isConnected(Server server) { + return (this.server != null) && (this.server.getSession().equals(server.getSession())); + } + + public boolean isConnectedLocal() { + return serverAddress.equals(serverRoute.getLocalAddress()); + } + + public void connect(Context context, Server server) { + this.server = server; + + if (server.isDebug()) { + try { + ServerRoute serverRoute = new ServerRoute(); + JSONArray jsonArray = new JSONArray(loadServersFromAsset(context)); + JSONObject jsonObject = jsonArray.getJSONObject(server.getIndex()); + serverRoute.setLocalAddress(jsonObject.getString("local_address")); + serverRoute.setRemoteAddress(jsonObject.getString("remote_address")); + BusProvider.getBus().post(new ServerRouteLoadedEvent(serverRoute)); + } catch (JSONException e) { + e.printStackTrace(); + } + } else { + startServerConnection(); + } + } + + private void startServerConnection() { + proxyApi.getServerRoute(server.getSession()).enqueue(new ServerRouteResponse()); + } + + @Subscribe + public void onServerRouteLoaded(ServerRouteLoadedEvent event) { + this.serverRoute = event.getServerRoute(); + + finishServerConnection(); + } + + private void finishServerConnection() { + BusProvider.getBus().post(new ServerConnectedEvent(server)); + } + + public void connectAuto() { + this.serverConnection = ApiConnection.AUTO; + if (!isServerRouteLoaded()) { + return; + } + startServerConnectionDetection(); + } + + public void connectLocal() { + this.serverConnection = ApiConnection.LOCAL; + if (!isServerRouteLoaded()) { + return; + } + this.serverAddress = serverRoute.getLocalAddress(); + this.serverApi = buildServerApi(); + } + + public void connectRemote() { + this.serverConnection = ApiConnection.REMOTE; + if (!isServerRouteLoaded()) { + return; + } + this.serverAddress = serverRoute.getRemoteAddress(); + this.serverApi = buildServerApi(); + } + + public String getServerAddress() { + return serverAddress; + } + + public void getShares() { + serverApi.getShares(server.getSession()).enqueue(new ServerSharesResponse()); + } + + public void getFiles(ServerShare share) { + if (share == null) { + return; + } + + serverApi.getFiles(server.getSession(), share.getName(), null).enqueue(new ServerFilesResponse(share)); + } + + public void getFiles(ServerShare share, ServerFile directory) { + serverApi.getFiles(server.getSession(), share.getName(), directory.getPath()).enqueue(new ServerFilesResponse(directory, share)); + } + + public void deleteFile(ServerShare share, ServerFile serverFile) { + serverApi.deleteFile(server.getSession(), share.getName(), serverFile.getPath()) + .enqueue(new ServerFileDeleteResponse()); + } + + private MultipartBody.Part createFilePart(int id, File file) { + return MultipartBody.Part.createFormData("file", + file.getName(), + new ProgressRequestBody(id, file)); + } + + public void uploadFile(int id, File file, String shareName, String path) { + MultipartBody.Part filePart = createFilePart(id, file); + uploadFileAsync(id, filePart, shareName, path); + } + + public void uploadFile(int id, File file, ServerShare share, ServerFile directory) { + MultipartBody.Part filePart = createFilePart(id, file); + String path = "/"; + if (directory != null) + path = directory.getPath(); + uploadFileAsync(id, filePart, share.getName(), path); + } + + private void uploadFileAsync(int id, MultipartBody.Part filePart, String shareName, String path) { + serverApi.uploadFile(server.getSession(), shareName, path, filePart) + .enqueue(new ServerFileUploadResponse(id)); + } + + private void uploadFileSync(int id, MultipartBody.Part filePart, String shareName, String path) { + try { + Response response = serverApi + .uploadFile(server.getSession(), shareName, path, filePart) + .execute(); + if (response.isSuccessful()) { + BusProvider.getBus().post( + new ServerFileUploadCompleteEvent(id, true)); + } else { + BusProvider.getBus().post( + new ServerFileUploadCompleteEvent(id, false)); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + public Uri getFileUri(ServerShare share, ServerFile file) { + return Uri.parse(serverAddress) + .buildUpon() + .path("files") + .appendQueryParameter("s", share.getName()) + .appendQueryParameter("p", file.getPath()) + .appendQueryParameter("mtime", Time.getEpochTimeString(file.getModificationTime())) + .appendQueryParameter("session", server.getSession()) + .build(); + } + + public void getFileMetadata(ServerShare share, ServerFile file, Callback callback) { + if ((server == null) || (share == null) || (file == null)) { + return; + } + serverApi.getFileMetadata(server.getSession(), file.getName(), share.getTag()).enqueue(callback); + } + + public void getApps() { + serverApi.getApps(server.getSession()).enqueue(new ServerAppsResponse()); + } } diff --git a/src/main/java/org/amahi/anywhere/server/model/Authentication.java b/src/main/java/org/amahi/anywhere/server/model/Authentication.java index 59f50aa19..37ec3b38a 100644 --- a/src/main/java/org/amahi/anywhere/server/model/Authentication.java +++ b/src/main/java/org/amahi/anywhere/server/model/Authentication.java @@ -24,12 +24,11 @@ /** * Authentication API resource. */ -public class Authentication -{ - @SerializedName("access_token") - private String token; +public class Authentication { + @SerializedName("access_token") + private String token; - public String getToken() { - return token; - } + public String getToken() { + return token; + } } diff --git a/src/main/java/org/amahi/anywhere/server/model/Server.java b/src/main/java/org/amahi/anywhere/server/model/Server.java index 5cb6d81ea..48f0b29cf 100644 --- a/src/main/java/org/amahi/anywhere/server/model/Server.java +++ b/src/main/java/org/amahi/anywhere/server/model/Server.java @@ -27,80 +27,74 @@ /** * Server API resource. */ -public class Server implements Parcelable -{ - @SerializedName("name") - private String name; - - @SerializedName("session_token") - private String session; - - @SerializedName("active") - private boolean active; - - private boolean debug = false; - - private int index; - - public String getName() { - return name; - } - - public String getSession() { - return session; - } - - public int getIndex() { - return index; - } - - public boolean isActive() { - return active; - } - - public boolean isDebug() { - return debug; - } - - public static final Creator CREATOR = new Creator() { - @Override - public Server createFromParcel(Parcel parcel) { - return new Server(parcel); - } - - @Override - public Server[] newArray(int size) { - return new Server[size]; - } - }; - - public Server(int index, String name, String session) { - this.index = index; - this.name = name; - this.session = session; - this.active = true; - this.debug = true; - } - - public Server(String session) { - this.session = session; - } - - public Server(Parcel parcel) { - this.name = parcel.readString(); - this.session = parcel.readString(); - this.active = Boolean.valueOf(parcel.readString()); - } - - @Override - public void writeToParcel(Parcel parcel, int flags) { - parcel.writeString(name); - parcel.writeString(session); - parcel.writeString(String.valueOf(active)); - } - - @Override - public int describeContents() { - return 0; - } +public class Server implements Parcelable { + public static final Creator CREATOR = new Creator() { + @Override + public Server createFromParcel(Parcel parcel) { + return new Server(parcel); + } + + @Override + public Server[] newArray(int size) { + return new Server[size]; + } + }; + @SerializedName("name") + private String name; + @SerializedName("session_token") + private String session; + @SerializedName("active") + private boolean active; + private boolean debug = false; + private int index; + + public Server(int index, String name, String session) { + this.index = index; + this.name = name; + this.session = session; + this.active = true; + this.debug = true; + } + + public Server(String session) { + this.session = session; + } + + public Server(Parcel parcel) { + this.name = parcel.readString(); + this.session = parcel.readString(); + this.active = Boolean.valueOf(parcel.readString()); + } + + public String getName() { + return name; + } + + public String getSession() { + return session; + } + + public int getIndex() { + return index; + } + + public boolean isActive() { + return active; + } + + public boolean isDebug() { + return debug; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeString(name); + parcel.writeString(session); + parcel.writeString(String.valueOf(active)); + } + + @Override + public int describeContents() { + return 0; + } } diff --git a/src/main/java/org/amahi/anywhere/server/model/ServerApp.java b/src/main/java/org/amahi/anywhere/server/model/ServerApp.java index dd0177c55..1f66aff5c 100644 --- a/src/main/java/org/amahi/anywhere/server/model/ServerApp.java +++ b/src/main/java/org/amahi/anywhere/server/model/ServerApp.java @@ -27,57 +27,52 @@ /** * App API resource. */ -public class ServerApp implements Parcelable -{ - @SerializedName("name") - private String name; +public class ServerApp implements Parcelable { + public static final Creator CREATOR = new Creator() { + @Override + public ServerApp createFromParcel(Parcel parcel) { + return new ServerApp(parcel); + } - @SerializedName("logo") - private String logoUrl; + @Override + public ServerApp[] newArray(int size) { + return new ServerApp[size]; + } + }; + @SerializedName("name") + private String name; + @SerializedName("logo") + private String logoUrl; + @SerializedName("vhost") + private String host; - @SerializedName("vhost") - private String host; + private ServerApp(Parcel parcel) { + this.name = parcel.readString(); + this.logoUrl = parcel.readString(); + this.host = parcel.readString(); + } - public String getName() { - return name; - } + public String getName() { + return name; + } - public String getLogoUrl() { - return logoUrl; - } + public String getLogoUrl() { + return logoUrl; + } - public String getHost() { - return host; - } + public String getHost() { + return host; + } - public static final Creator CREATOR = new Creator() - { - @Override - public ServerApp createFromParcel(Parcel parcel) { - return new ServerApp(parcel); - } + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeString(name); + parcel.writeString(logoUrl); + parcel.writeString(host); + } - @Override - public ServerApp[] newArray(int size) { - return new ServerApp[size]; - } - }; - - private ServerApp(Parcel parcel) { - this.name = parcel.readString(); - this.logoUrl = parcel.readString(); - this.host = parcel.readString(); - } - - @Override - public void writeToParcel(Parcel parcel, int flags) { - parcel.writeString(name); - parcel.writeString(logoUrl); - parcel.writeString(host); - } - - @Override - public int describeContents() { - return 0; - } + @Override + public int describeContents() { + return 0; + } } diff --git a/src/main/java/org/amahi/anywhere/server/model/ServerFile.java b/src/main/java/org/amahi/anywhere/server/model/ServerFile.java index dd1f267cb..8219bcc8d 100644 --- a/src/main/java/org/amahi/anywhere/server/model/ServerFile.java +++ b/src/main/java/org/amahi/anywhere/server/model/ServerFile.java @@ -30,60 +30,74 @@ /** * File API resource. */ -public class ServerFile implements Parcelable -{ - private ServerFile parentFile; - private ServerShare parentShare; - - @SerializedName("name") - private String name; - - @SerializedName("mime_type") - private String mime; - - @SerializedName("mtime") - private Date modificationTime; - +public class ServerFile implements Parcelable { + public static final Creator CREATOR = new Creator() { + @Override + public ServerFile createFromParcel(Parcel parcel) { + return new ServerFile(parcel); + } + + @Override + public ServerFile[] newArray(int size) { + return new ServerFile[size]; + } + }; + private ServerFile parentFile; + private ServerShare parentShare; + @SerializedName("name") + private String name; + @SerializedName("mime_type") + private String mime; + @SerializedName("mtime") + private Date modificationTime; @SerializedName("size") private long size; - private ServerFileMetadata fileMetadata; - - private boolean isMetaDataFetched; + private boolean isMetaDataFetched; + + private ServerFile(Parcel parcel) { + this.parentFile = parcel.readParcelable(ServerFile.class.getClassLoader()); + this.name = parcel.readString(); + this.mime = parcel.readString(); + this.modificationTime = new Date(parcel.readLong()); + this.size = parcel.readLong(); + } public long getSize() { - return size; - } + return size; + } - public void setParentFile(ServerFile parentFile) { - this.parentFile = parentFile; - } + public ServerShare getParentShare() { + return parentShare; + } - public void setParentShare(ServerShare parentShare){ - this.parentShare = parentShare; - } + public void setParentShare(ServerShare parentShare) { + this.parentShare = parentShare; + } - public ServerShare getParentShare(){return parentShare;} + public ServerFile getParentFile() { + return parentFile; + } - public ServerFile getParentFile() { - return parentFile; - } + public void setParentFile(ServerFile parentFile) { + this.parentFile = parentFile; + } - public String getName() { - return name; - } + public String getName() { + return name; + } - public String getNameOnly() { - return name.replace("." + getExtension(), ""); - } + public String getNameOnly() { + return name.replace("." + getExtension(), ""); + } - public String getMime() { - return mime; - } + public String getMime() { + return mime; + } - public Date getModificationTime() { - return modificationTime; - } + public Date getModificationTime() { + return modificationTime; + } public ServerFileMetadata getFileMetadata() { return fileMetadata; @@ -93,102 +107,81 @@ public void setFileMetadata(ServerFileMetadata fileMetadata) { this.fileMetadata = fileMetadata; } - public boolean isMetaDataFetched() { - return isMetaDataFetched; - } - - public void setMetaDataFetched(boolean metaDataFetched) { - isMetaDataFetched = metaDataFetched; - } - - public String getPath() { - Uri.Builder uri = new Uri.Builder(); - - if (parentFile != null) { - uri.appendPath(parentFile.getPath()); - } - - uri.appendPath(name); - - return uri.build().getPath(); - } - - public String getExtension() { - String[] splitString = name.split("\\."); - if(splitString.length > 1) { - return splitString[splitString.length-1]; - } else { - return ""; - } - } - - public static final Creator CREATOR = new Creator() - { - @Override - public ServerFile createFromParcel(Parcel parcel) { - return new ServerFile(parcel); - } - - @Override - public ServerFile[] newArray(int size) { - return new ServerFile[size]; - } - }; - - private ServerFile(Parcel parcel) { - this.parentFile = parcel.readParcelable(ServerFile.class.getClassLoader()); - this.name = parcel.readString(); - this.mime = parcel.readString(); - this.modificationTime = new Date(parcel.readLong()); - this.size= parcel.readLong(); - } - - @Override - public void writeToParcel(Parcel parcel, int flags) { - parcel.writeParcelable(parentFile, flags); - parcel.writeString(name); - parcel.writeString(mime); - parcel.writeLong(modificationTime.getTime()); - parcel.writeLong(size); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public boolean equals(Object object) { - if (this == object) { - return true; - } - - if (object == null) { - return false; - } - - if (getClass() != object.getClass()) { - return false; - } - - ServerFile file = (ServerFile) object; - - if ((parentFile != null) && (!parentFile.equals(file.parentFile))) { - return false; - } - - if (!name.equals(file.name)) { - return false; - } - - if (!mime.equals(file.mime)) { - return false; - } - - if (!modificationTime.equals(file.modificationTime)) { - return false; - } - - return true; - } + public boolean isMetaDataFetched() { + return isMetaDataFetched; + } + + public void setMetaDataFetched(boolean metaDataFetched) { + isMetaDataFetched = metaDataFetched; + } + + public String getPath() { + Uri.Builder uri = new Uri.Builder(); + + if (parentFile != null) { + uri.appendPath(parentFile.getPath()); + } + + uri.appendPath(name); + + return uri.build().getPath(); + } + + public String getExtension() { + String[] splitString = name.split("\\."); + if (splitString.length > 1) { + return splitString[splitString.length - 1]; + } else { + return ""; + } + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeParcelable(parentFile, flags); + parcel.writeString(name); + parcel.writeString(mime); + parcel.writeLong(modificationTime.getTime()); + parcel.writeLong(size); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + + if (object == null) { + return false; + } + + if (getClass() != object.getClass()) { + return false; + } + + ServerFile file = (ServerFile) object; + + if ((parentFile != null) && (!parentFile.equals(file.parentFile))) { + return false; + } + + if (!name.equals(file.name)) { + return false; + } + + if (!mime.equals(file.mime)) { + return false; + } + + if (!modificationTime.equals(file.modificationTime)) { + return false; + } + + return true; + } } diff --git a/src/main/java/org/amahi/anywhere/server/model/ServerFileMetadata.java b/src/main/java/org/amahi/anywhere/server/model/ServerFileMetadata.java index d970881ef..571537f5d 100644 --- a/src/main/java/org/amahi/anywhere/server/model/ServerFileMetadata.java +++ b/src/main/java/org/amahi/anywhere/server/model/ServerFileMetadata.java @@ -24,48 +24,44 @@ import com.google.gson.annotations.SerializedName; -public class ServerFileMetadata implements Parcelable -{ - @SerializedName("title") - private String title; +public class ServerFileMetadata implements Parcelable { + public static final Creator CREATOR = new Creator() { + @Override + public ServerFileMetadata createFromParcel(Parcel parcel) { + return new ServerFileMetadata(parcel); + } - @SerializedName("artwork") - private String artworkUrl; + @Override + public ServerFileMetadata[] newArray(int size) { + return new ServerFileMetadata[size]; + } + }; + @SerializedName("title") + private String title; + @SerializedName("artwork") + private String artworkUrl; - public String getTitle() { - return title; - } + private ServerFileMetadata(Parcel parcel) { + this.title = parcel.readString(); + this.artworkUrl = parcel.readString(); + } - public String getArtworkUrl() { - return artworkUrl; - } + public String getTitle() { + return title; + } - public static final Creator CREATOR = new Creator() - { - @Override - public ServerFileMetadata createFromParcel(Parcel parcel) { - return new ServerFileMetadata(parcel); - } + public String getArtworkUrl() { + return artworkUrl; + } - @Override - public ServerFileMetadata[] newArray(int size) { - return new ServerFileMetadata[size]; - } - }; + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeString(title); + parcel.writeString(artworkUrl); + } - private ServerFileMetadata(Parcel parcel) { - this.title = parcel.readString(); - this.artworkUrl = parcel.readString(); - } - - @Override - public void writeToParcel(Parcel parcel, int flags) { - parcel.writeString(title); - parcel.writeString(artworkUrl); - } - - @Override - public int describeContents() { - return 0; - } + @Override + public int describeContents() { + return 0; + } } diff --git a/src/main/java/org/amahi/anywhere/server/model/ServerRoute.java b/src/main/java/org/amahi/anywhere/server/model/ServerRoute.java index 80e9106ac..5241e1b9b 100644 --- a/src/main/java/org/amahi/anywhere/server/model/ServerRoute.java +++ b/src/main/java/org/amahi/anywhere/server/model/ServerRoute.java @@ -24,27 +24,26 @@ /** * Server route API resource. */ -public class ServerRoute -{ - @SerializedName("local_addr") - private String localAddress; +public class ServerRoute { + @SerializedName("local_addr") + private String localAddress; - @SerializedName("relay_addr") - private String remoteAddress; + @SerializedName("relay_addr") + private String remoteAddress; - public String getLocalAddress() { - return localAddress; - } + public String getLocalAddress() { + return localAddress; + } - public String getRemoteAddress() { - return remoteAddress; - } + public void setLocalAddress(String localAddress) { + this.localAddress = localAddress; + } - public void setLocalAddress(String localAddress) { - this.localAddress = localAddress; - } + public String getRemoteAddress() { + return remoteAddress; + } - public void setRemoteAddress(String remoteAddress) { - this.remoteAddress = remoteAddress; - } + public void setRemoteAddress(String remoteAddress) { + this.remoteAddress = remoteAddress; + } } diff --git a/src/main/java/org/amahi/anywhere/server/model/ServerShare.java b/src/main/java/org/amahi/anywhere/server/model/ServerShare.java index 313461176..ed9623a4e 100644 --- a/src/main/java/org/amahi/anywhere/server/model/ServerShare.java +++ b/src/main/java/org/amahi/anywhere/server/model/ServerShare.java @@ -24,76 +24,69 @@ import com.google.gson.annotations.SerializedName; -import java.io.Serializable; import java.util.List; /** * Share API resource. */ -public class ServerShare implements Parcelable -{ - public static final class Tag - { - private Tag() { - } - - public static final String FILES = "files"; - - public static final String MOVIES = "movie"; - public static final String TV = "tv"; - } - - @SerializedName("name") - private String name; - - @SerializedName("tags") - private List tags; - - public String getName() { - return name; - } - - public String getTag() { - for (String tag : tags) { - if (tag.contains(Tag.MOVIES)) { - return Tag.MOVIES; - } - - if (tag.contains(Tag.TV)) { - return Tag.TV; - } - } - - return Tag.FILES; - } - - public static final Creator CREATOR = new Creator() - { - @Override - public ServerShare createFromParcel(Parcel parcel) { - return new ServerShare(parcel); - } - - @Override - public ServerShare[] newArray(int size) { - return new ServerShare[size]; - } - }; - - @SuppressWarnings("unchecked") - private ServerShare(Parcel parcel) { - this.name = parcel.readString(); - this.tags = parcel.readArrayList(String.class.getClassLoader()); - } - - @Override - public void writeToParcel(Parcel parcel, int flags) { - parcel.writeString(name); - parcel.writeList(tags); - } - - @Override - public int describeContents() { - return 0; - } +public class ServerShare implements Parcelable { + public static final Creator CREATOR = new Creator() { + @Override + public ServerShare createFromParcel(Parcel parcel) { + return new ServerShare(parcel); + } + + @Override + public ServerShare[] newArray(int size) { + return new ServerShare[size]; + } + }; + @SerializedName("name") + private String name; + + @SerializedName("tags") + private List tags; + + @SuppressWarnings("unchecked") + private ServerShare(Parcel parcel) { + this.name = parcel.readString(); + this.tags = parcel.readArrayList(String.class.getClassLoader()); + } + + public String getName() { + return name; + } + + public String getTag() { + for (String tag : tags) { + if (tag.contains(Tag.MOVIES)) { + return Tag.MOVIES; + } + + if (tag.contains(Tag.TV)) { + return Tag.TV; + } + } + + return Tag.FILES; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeString(name); + parcel.writeList(tags); + } + + @Override + public int describeContents() { + return 0; + } + + public static final class Tag { + public static final String FILES = "files"; + public static final String MOVIES = "movie"; + public static final String TV = "tv"; + private Tag() { + } + } } diff --git a/src/main/java/org/amahi/anywhere/server/response/AuthenticationResponse.java b/src/main/java/org/amahi/anywhere/server/response/AuthenticationResponse.java index 6b0919a07..59c104732 100644 --- a/src/main/java/org/amahi/anywhere/server/response/AuthenticationResponse.java +++ b/src/main/java/org/amahi/anywhere/server/response/AuthenticationResponse.java @@ -36,22 +36,21 @@ * Authentication response proxy. Consumes API callback and posts it via {@link com.squareup.otto.Bus} * as {@link org.amahi.anywhere.bus.BusEvent}. */ -public class AuthenticationResponse implements Callback -{ - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) - BusProvider.getBus().post(new AuthenticationSucceedEvent(response.body())); - else - this.onFailure(call, new HttpException(response)); - } +public class AuthenticationResponse implements Callback { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) + BusProvider.getBus().post(new AuthenticationSucceedEvent(response.body())); + else + this.onFailure(call, new HttpException(response)); + } - @Override - public void onFailure(Call call, Throwable t) { - if (t instanceof IOException) { //implies no network connection - BusProvider.getBus().post(new AuthenticationConnectionFailedEvent()); - } else { - BusProvider.getBus().post(new AuthenticationFailedEvent()); - } - } + @Override + public void onFailure(Call call, Throwable t) { + if (t instanceof IOException) { //implies no network connection + BusProvider.getBus().post(new AuthenticationConnectionFailedEvent()); + } else { + BusProvider.getBus().post(new AuthenticationFailedEvent()); + } + } } diff --git a/src/main/java/org/amahi/anywhere/server/response/ServerAppsResponse.java b/src/main/java/org/amahi/anywhere/server/response/ServerAppsResponse.java index 33127ef0a..327fa0c5d 100644 --- a/src/main/java/org/amahi/anywhere/server/response/ServerAppsResponse.java +++ b/src/main/java/org/amahi/anywhere/server/response/ServerAppsResponse.java @@ -35,18 +35,17 @@ * Apps response proxy. Consumes API callback and posts it via {@link com.squareup.otto.Bus} * as {@link org.amahi.anywhere.bus.BusEvent}. */ -public class ServerAppsResponse implements Callback> -{ - @Override - public void onResponse(Call> call, Response> response) { - if (response.isSuccessful()) - BusProvider.getBus().post(new ServerAppsLoadedEvent(response.body())); - else - this.onFailure(call, new HttpException(response)); - } +public class ServerAppsResponse implements Callback> { + @Override + public void onResponse(Call> call, Response> response) { + if (response.isSuccessful()) + BusProvider.getBus().post(new ServerAppsLoadedEvent(response.body())); + else + this.onFailure(call, new HttpException(response)); + } - @Override - public void onFailure(Call> call, Throwable t) { - BusProvider.getBus().post(new ServerAppsLoadFailedEvent()); - } + @Override + public void onFailure(Call> call, Throwable t) { + BusProvider.getBus().post(new ServerAppsLoadFailedEvent()); + } } diff --git a/src/main/java/org/amahi/anywhere/server/response/ServerFileUploadResponse.java b/src/main/java/org/amahi/anywhere/server/response/ServerFileUploadResponse.java index 25fc0354d..9b2cbafe2 100644 --- a/src/main/java/org/amahi/anywhere/server/response/ServerFileUploadResponse.java +++ b/src/main/java/org/amahi/anywhere/server/response/ServerFileUploadResponse.java @@ -34,22 +34,22 @@ * as {@link org.amahi.anywhere.bus.BusEvent}. */ public class ServerFileUploadResponse implements Callback { - private int id; - - public ServerFileUploadResponse(int id) { - this.id = id; - } - - @Override - public void onResponse(Call call, Response response) { - if (response.isSuccessful()) { - BusProvider.getBus().post(new ServerFileUploadCompleteEvent(id, true)); - } else - this.onFailure(call, new HttpException(response)); - } - - @Override - public void onFailure(Call call, Throwable t) { - BusProvider.getBus().post(new ServerFileUploadCompleteEvent(id, false)); - } + private int id; + + public ServerFileUploadResponse(int id) { + this.id = id; + } + + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + BusProvider.getBus().post(new ServerFileUploadCompleteEvent(id, true)); + } else + this.onFailure(call, new HttpException(response)); + } + + @Override + public void onFailure(Call call, Throwable t) { + BusProvider.getBus().post(new ServerFileUploadCompleteEvent(id, false)); + } } diff --git a/src/main/java/org/amahi/anywhere/server/response/ServerFilesResponse.java b/src/main/java/org/amahi/anywhere/server/response/ServerFilesResponse.java index a98eb293d..a514d2d99 100644 --- a/src/main/java/org/amahi/anywhere/server/response/ServerFilesResponse.java +++ b/src/main/java/org/amahi/anywhere/server/response/ServerFilesResponse.java @@ -19,8 +19,6 @@ package org.amahi.anywhere.server.response; -import android.util.Log; - import org.amahi.anywhere.bus.BusProvider; import org.amahi.anywhere.bus.ServerFilesLoadFailedEvent; import org.amahi.anywhere.bus.ServerFilesLoadedEvent; @@ -40,41 +38,39 @@ * Files response proxy. Consumes API callback and posts it via {@link com.squareup.otto.Bus} * as {@link org.amahi.anywhere.bus.BusEvent}. */ -public class ServerFilesResponse implements Callback> -{ - private ServerFile serverDirectory; - private ServerShare serverShare; +public class ServerFilesResponse implements Callback> { + private ServerFile serverDirectory; + private ServerShare serverShare; - public ServerFilesResponse(ServerFile serverDirectory, ServerShare serverShare) { - this.serverDirectory = serverDirectory; - this.serverShare = serverShare; - } + public ServerFilesResponse(ServerFile serverDirectory, ServerShare serverShare) { + this.serverDirectory = serverDirectory; + this.serverShare = serverShare; + } - public ServerFilesResponse(ServerShare serverShare){ - this.serverShare = serverShare; - } + public ServerFilesResponse(ServerShare serverShare) { + this.serverShare = serverShare; + } - @Override - public void onResponse(Call> call, Response> response) { - if (response.isSuccessful()) { - List serverFiles = response.body(); - if (serverFiles == null) { - serverFiles = Collections.emptyList(); - } + @Override + public void onResponse(Call> call, Response> response) { + if (response.isSuccessful()) { + List serverFiles = response.body(); + if (serverFiles == null) { + serverFiles = Collections.emptyList(); + } - for (ServerFile serverFile : serverFiles) { - serverFile.setParentFile(serverDirectory); - serverFile.setParentShare(serverShare); - } + for (ServerFile serverFile : serverFiles) { + serverFile.setParentFile(serverDirectory); + serverFile.setParentShare(serverShare); + } - BusProvider.getBus().post(new ServerFilesLoadedEvent(serverFiles)); - } - else - this.onFailure(call, new HttpException(response)); - } + BusProvider.getBus().post(new ServerFilesLoadedEvent(serverFiles)); + } else + this.onFailure(call, new HttpException(response)); + } - @Override - public void onFailure(Call> call, Throwable t) { - BusProvider.getBus().post(new ServerFilesLoadFailedEvent()); - } + @Override + public void onFailure(Call> call, Throwable t) { + BusProvider.getBus().post(new ServerFilesLoadFailedEvent()); + } } diff --git a/src/main/java/org/amahi/anywhere/server/response/ServerRouteResponse.java b/src/main/java/org/amahi/anywhere/server/response/ServerRouteResponse.java index d38d949b7..1d8db0de4 100644 --- a/src/main/java/org/amahi/anywhere/server/response/ServerRouteResponse.java +++ b/src/main/java/org/amahi/anywhere/server/response/ServerRouteResponse.java @@ -33,8 +33,7 @@ * Server route response proxy. Consumes API callback and posts it via {@link com.squareup.otto.Bus} * as {@link org.amahi.anywhere.bus.BusEvent}. */ -public class ServerRouteResponse implements Callback -{ +public class ServerRouteResponse implements Callback { @Override public void onResponse(Call call, Response response) { if (response.isSuccessful()) diff --git a/src/main/java/org/amahi/anywhere/server/response/ServerSharesResponse.java b/src/main/java/org/amahi/anywhere/server/response/ServerSharesResponse.java index 4755f3132..db3fa108e 100644 --- a/src/main/java/org/amahi/anywhere/server/response/ServerSharesResponse.java +++ b/src/main/java/org/amahi/anywhere/server/response/ServerSharesResponse.java @@ -35,18 +35,17 @@ * Shares response proxy. Consumes API callback and posts it via {@link com.squareup.otto.Bus} * as {@link org.amahi.anywhere.bus.BusEvent}. */ -public class ServerSharesResponse implements Callback> -{ - @Override - public void onResponse(Call> call, Response> response) { - if (response.isSuccessful()) - BusProvider.getBus().post(new ServerSharesLoadedEvent(response.body())); - else - this.onFailure(call, new HttpException(response)); - } +public class ServerSharesResponse implements Callback> { + @Override + public void onResponse(Call> call, Response> response) { + if (response.isSuccessful()) + BusProvider.getBus().post(new ServerSharesLoadedEvent(response.body())); + else + this.onFailure(call, new HttpException(response)); + } - @Override - public void onFailure(Call> call, Throwable t) { - BusProvider.getBus().post(new ServerSharesLoadFailedEvent()); - } + @Override + public void onFailure(Call> call, Throwable t) { + BusProvider.getBus().post(new ServerSharesLoadFailedEvent()); + } } diff --git a/src/main/java/org/amahi/anywhere/server/response/ServersResponse.java b/src/main/java/org/amahi/anywhere/server/response/ServersResponse.java index 827cdc488..cad888a6f 100644 --- a/src/main/java/org/amahi/anywhere/server/response/ServersResponse.java +++ b/src/main/java/org/amahi/anywhere/server/response/ServersResponse.java @@ -44,45 +44,44 @@ * Servers response proxy. Consumes API callback and posts it via {@link com.squareup.otto.Bus} * as {@link org.amahi.anywhere.bus.BusEvent}. */ -public class ServersResponse implements Callback> -{ - private Context context; +public class ServersResponse implements Callback> { + private Context context; - public ServersResponse(Context context) { - this.context = context; - } + public ServersResponse(Context context) { + this.context = context; + } - private List getLocalServers() { - List servers = new ArrayList<>(); - try { - JSONArray jsonArray = new JSONArray(loadServersFromAsset(context)); - for (int i = 0; i < jsonArray.length(); i++) { - JSONObject jsonObject = jsonArray.getJSONObject(i); - Server server = new Server(i, jsonObject.getString("name"), - jsonObject.getString("session_token")); - servers.add(server); - } - } catch (JSONException e) { - e.printStackTrace(); - } - return servers; - } + private List getLocalServers() { + List servers = new ArrayList<>(); + try { + JSONArray jsonArray = new JSONArray(loadServersFromAsset(context)); + for (int i = 0; i < jsonArray.length(); i++) { + JSONObject jsonObject = jsonArray.getJSONObject(i); + Server server = new Server(i, jsonObject.getString("name"), + jsonObject.getString("session_token")); + servers.add(server); + } + } catch (JSONException e) { + e.printStackTrace(); + } + return servers; + } - @Override - public void onResponse(Call> call, Response> response) { - if (response.isSuccessful()) { - List servers = response.body(); - if (BuildConfig.DEBUG) { - servers.addAll(getLocalServers()); - } - BusProvider.getBus().post(new ServersLoadedEvent(servers)); - } else - this.onFailure(call, new HttpException(response)); - } + @Override + public void onResponse(Call> call, Response> response) { + if (response.isSuccessful()) { + List servers = response.body(); + if (BuildConfig.DEBUG) { + servers.addAll(getLocalServers()); + } + BusProvider.getBus().post(new ServersLoadedEvent(servers)); + } else + this.onFailure(call, new HttpException(response)); + } - @Override - public void onFailure(Call> call, Throwable t) { - BusProvider.getBus().post(new ServersLoadFailedEvent()); - } + @Override + public void onFailure(Call> call, Throwable t) { + BusProvider.getBus().post(new ServersLoadFailedEvent()); + } } diff --git a/src/main/java/org/amahi/anywhere/service/AudioService.java b/src/main/java/org/amahi/anywhere/service/AudioService.java index 8f5845f74..e96556429 100644 --- a/src/main/java/org/amahi/anywhere/service/AudioService.java +++ b/src/main/java/org/amahi/anywhere/service/AudioService.java @@ -76,457 +76,452 @@ * handles audio focus changes as well. */ public class AudioService extends MediaBrowserServiceCompat implements - AudioManager.OnAudioFocusChangeListener, - MediaPlayer.OnPreparedListener, - MediaPlayer.OnCompletionListener, - MediaPlayer.OnErrorListener -{ - private MediaNotificationManager mMediaNotificationManager; - - private enum AudioFocus - { - GAIN, LOSS - } - - private MediaPlayer audioPlayer; - private MediaSessionCompat mediaSession; - private AudioFocus audioFocus; - - private ServerShare audioShare; - private List audioFiles; - private ServerFile audioFile; - - private AudioMetadataFormatter audioMetadataFormatter; - private Bitmap audioAlbumArt; - - @Inject - ServerClient serverClient; - - @Override - public IBinder onBind(Intent intent) { - return new AudioServiceBinder(this); - } - - @Override - public void onCreate() { - super.onCreate(); - - setUpInjections(); - - setUpBus(); - - setUpAudioPlayer(); - setUpAudioPlayerRemote(); - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - MediaButtonReceiver.handleIntent(mediaSession, intent); - return super.onStartCommand(intent, flags, startId); - } - - @Nullable - @Override - public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, @Nullable Bundle rootHints) { - if(TextUtils.equals(clientPackageName, getPackageName())) { - return new BrowserRoot(getString(R.string.application_name), null); - } - - return null; - } - - //Not important for general audio service, required for class - @Override - public void onLoadChildren(@NonNull String parentId, @NonNull Result> result) { - result.sendResult(null); - } - - private void setUpInjections() { - AmahiApplication.from(this).inject(this); - } - - private void setUpBus() { - BusProvider.getBus().register(this); - } - - private void setUpAudioPlayer() { - audioPlayer = new MediaPlayer(); - - audioPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); - audioPlayer.setWakeMode(this, PowerManager.PARTIAL_WAKE_LOCK); - audioPlayer.setVolume(1.0f, 1.0f); - - audioPlayer.setOnPreparedListener(this); - audioPlayer.setOnCompletionListener(this); - audioPlayer.setOnErrorListener(this); - } - - private void setUpAudioPlayerRemote() { - AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); - ComponentName audioReceiver = new ComponentName(getPackageName(), AudioReceiver.class.getName()); - - Intent audioIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); - audioIntent.setComponent(audioReceiver); - PendingIntent audioPendingIntent = PendingIntent.getBroadcast(this, 0, audioIntent, 0); - - mediaSession = new MediaSessionCompat(this, "PlayerService", audioReceiver, audioPendingIntent); - mediaSession.setCallback(new MediaSessionCallback()); - mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | - MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS); - mediaSession.setMediaButtonReceiver(audioPendingIntent); - setSessionToken(mediaSession.getSessionToken()); - - try { - mMediaNotificationManager = new MediaNotificationManager(this); - } catch (RemoteException e) { - throw new IllegalStateException("Could not create a MediaNotificationManager", e); - } - - mediaSession.setPlaybackState(new PlaybackStateCompat.Builder() - .setState(PlaybackStateCompat.STATE_NONE, 0, 0) - .setActions(getAvailableActions()) - .build()); - - audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); - } - - public boolean isAudioStarted() { - return (audioShare != null) && (audioFiles != null) && (audioFile != null); - } - - public void startAudio(ServerShare audioShare, List audioFiles, ServerFile audioFile) { - this.audioShare = audioShare; - this.audioFiles = audioFiles; - this.audioFile = audioFile; - - setUpAudioPlayback(); - setUpAudioMetadata(); - } - - private void setUpAudioPlayback() { - try { - audioPlayer.setDataSource(this, getAudioUri()); - audioPlayer.prepareAsync(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - private Uri getAudioUri() { - return serverClient.getFileUri(audioShare, audioFile); - } - - @Override - public void onPrepared(MediaPlayer audioPlayer) { - BusProvider.getBus().post(new AudioPreparedEvent()); - playAudio(); - } - - private void setUpAudioMetadata() { - AudioMetadataRetrievingTask.execute(getAudioUri(), audioFile); - } - - @Subscribe - public void onAudioMetadataRetrieved(AudioMetadataRetrievedEvent event) { - if (audioFile != null) { - this.audioMetadataFormatter = new AudioMetadataFormatter( - event.getAudioTitle(), event.getAudioArtist(), event.getAudioAlbum()); - this.audioMetadataFormatter.setDuration(event.getDuration()); - this.audioAlbumArt = event.getAudioAlbumArt(); - - setUpAudioPlayerRemote(audioMetadataFormatter, audioAlbumArt); - - mMediaNotificationManager.startNotification(); - } - } - - private void setUpAudioPlayerRemote(AudioMetadataFormatter audioMetadataFormatter, Bitmap audioAlbumArt) { - - mediaSession.setMetadata(new MediaMetadataCompat.Builder() - .putString(MediaMetadataCompat.METADATA_KEY_TITLE, audioMetadataFormatter.getAudioTitle(audioFile)) - .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, audioMetadataFormatter.getAudioSubtitle(audioShare)) - .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, audioMetadataFormatter.getAudioSubtitle(audioShare)) - .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, getAudioPlayerRemoteArtwork(audioAlbumArt)) - .build()); - } - - private Bitmap getAudioPlayerRemoteArtwork(Bitmap audioAlbumArt) { - if (audioAlbumArt == null) { - return null; - } - - Bitmap.Config artworkConfig = audioAlbumArt.getConfig(); - - if (artworkConfig == null) { - artworkConfig = Bitmap.Config.ARGB_8888; - } - - return audioAlbumArt.copy(artworkConfig, false); - } - - public PendingIntent createContentIntent() { - Intent audioIntent = Intents.Builder.with(this).buildServerFileIntent(audioShare, audioFiles, audioFile); - return PendingIntent.getActivity(this, 0, audioIntent, PendingIntent.FLAG_CANCEL_CURRENT); - } - - public ServerFile getAudioFile() { - return audioFile; - } - - public AudioMetadataFormatter getAudioMetadataFormatter() { - return audioMetadataFormatter; - } - - public Bitmap getAudioAlbumArt() { - return audioAlbumArt; - } - - public MediaPlayer getAudioPlayer() { - return audioPlayer; - } - - @Subscribe - public void onAudioControlPlayPause(AudioControlPlayPauseEvent event) { - if (audioPlayer.isPlaying()) { - pauseAudio(); - } else { - playAudio(); - } - } - - @Subscribe - public void onAudioControlPlay(AudioControlPlayEvent event) { - playAudio(); - } - - @Subscribe - public void onAudioControlPause(AudioControlPauseEvent event) { - pauseAudio(); - } - - @Subscribe - public void onAudioControlNext(AudioControlNextEvent event) { - startNextAudio(); - } - - @Subscribe - public void onAudioControlPrevious(AudioControlPreviousEvent event) { - startPreviousAudio(); - } - - public void playAudio() { - mediaSession.setActive(true); - audioPlayer.start(); - setMediaPlaybackState(PlaybackStateCompat.STATE_PLAYING); - } - - public void pauseAudio() { - mediaSession.setActive(false); - audioPlayer.pause(); - setMediaPlaybackState(PlaybackStateCompat.STATE_PAUSED); - } - - private void setMediaPlaybackState(int state) { - PlaybackStateCompat.Builder playbackStateBuilder = new PlaybackStateCompat.Builder(); - playbackStateBuilder.setActions(getAvailableActions()); - playbackStateBuilder.setState(state, audioPlayer.getCurrentPosition(), 1.0f, SystemClock.elapsedRealtime()); - mediaSession.setPlaybackState(playbackStateBuilder.build()); - } - - private long getAvailableActions() { - long actions = PlaybackStateCompat.ACTION_PLAY_PAUSE | - PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS | - PlaybackStateCompat.ACTION_SKIP_TO_NEXT; - if (audioPlayer.isPlaying()) { - actions |= PlaybackStateCompat.ACTION_PAUSE; - } else { - actions |= PlaybackStateCompat.ACTION_PLAY; - } - return actions; - } - - private void startNextAudio() { - this.audioFile = getNextAudioFile(); - - tearDownAudioPlayback(); - - setUpAudioPlayback(); - setUpAudioMetadata(); - } - - private ServerFile getNextAudioFile() { - int currentAudioFilePosition = audioFiles.indexOf(audioFile); - - if (currentAudioFilePosition == audioFiles.size() - 1) { - return audioFiles.get(0); - } - - return audioFiles.get(currentAudioFilePosition + 1); - } - - private void tearDownAudioPlayback() { - if(isAudioPlaying()) - pauseAudio(); - audioPlayer.reset(); - } - - private void startPreviousAudio() { - this.audioFile = getPreviousAudioFile(); - - tearDownAudioPlayback(); - - setUpAudioPlayback(); - setUpAudioMetadata(); - } - - private ServerFile getPreviousAudioFile() { - int currentAudioFilePosition = audioFiles.indexOf(audioFile); - - if (currentAudioFilePosition == 0) { - return audioFiles.get(audioFiles.size() - 1); - } - - return audioFiles.get(currentAudioFilePosition - 1); - } - - @Override - public void onAudioFocusChange(int audioFocus) { - switch (audioFocus) { - case AudioManager.AUDIOFOCUS_GAIN: - handleAudioFocusGain(); - break; - - case AudioManager.AUDIOFOCUS_LOSS: - case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: - handleAudioFocusLoss(); - break; - - case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: - handleAudioFocusDuck(); - break; - - default: - break; - } - } - - private void handleAudioFocusGain() { - if (isAudioPlaying()) { - setUpAudioVolume(); - } else { - if (audioFocus == AudioFocus.LOSS) { - playAudio(); - } - } - - this.audioFocus = AudioFocus.GAIN; - } - - private boolean isAudioPlaying() { - try { - return isAudioStarted() && audioPlayer.isPlaying(); - } catch (IllegalStateException e) { - return false; - } - } - - private void setUpAudioVolume() { - audioPlayer.setVolume(1.0f, 1.0f); - } - - private void handleAudioFocusLoss() { - if (isAudioPlaying()) { - pauseAudio(); - this.audioFocus = AudioFocus.LOSS; - } - } - - private void handleAudioFocusDuck() { - if (isAudioPlaying()) { - tearDownAudioVolume(); - } - } - - private void tearDownAudioVolume() { - audioPlayer.setVolume(0.3f, 0.3f); - } - - @Override - public void onCompletion(MediaPlayer audioPlayer) { - BusProvider.getBus().post(new AudioCompletedEvent()); - - startNextAudio(); - } - - @Override - public boolean onError(MediaPlayer audioPlayer, int errorReason, int errorExtra) { - getAudioPlayer().reset(); - return true; - } - - @Override - public void onDestroy() { - super.onDestroy(); - - tearDownBus(); - - tearDownAudioPlayer(); - tearDownAudioPlayerRemote(); - tearDownAudioPlayerNotification(); - } - - private void tearDownBus() { - BusProvider.getBus().unregister(this); - } - - private void tearDownAudioPlayer() { - audioPlayer.reset(); - audioPlayer.release(); - } - - private void tearDownAudioPlayerRemote() { - AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); - - audioManager.abandonAudioFocus(this); - mediaSession.release(); - } - - private void tearDownAudioPlayerNotification() { - mMediaNotificationManager.stopNotification(); - } - - public static final class AudioServiceBinder extends Binder - { - private final AudioService audioService; - - public AudioServiceBinder(AudioService audioService) { - this.audioService = audioService; - } - - public AudioService getAudioService() { - return audioService; - } - } - - private class MediaSessionCallback extends MediaSessionCompat.Callback { - @Override - public void onPlay() { - playAudio(); - } - - @Override - public void onPause() { - pauseAudio(); - } - - @Override - public void onSkipToNext() { - startNextAudio(); - } - - @Override - public void onSkipToPrevious() { - startPreviousAudio(); - } - } + AudioManager.OnAudioFocusChangeListener, + MediaPlayer.OnPreparedListener, + MediaPlayer.OnCompletionListener, + MediaPlayer.OnErrorListener { + @Inject + ServerClient serverClient; + private MediaNotificationManager mMediaNotificationManager; + private MediaPlayer audioPlayer; + private MediaSessionCompat mediaSession; + private AudioFocus audioFocus; + + private ServerShare audioShare; + private List audioFiles; + private ServerFile audioFile; + + private AudioMetadataFormatter audioMetadataFormatter; + private Bitmap audioAlbumArt; + + @Override + public IBinder onBind(Intent intent) { + return new AudioServiceBinder(this); + } + + @Override + public void onCreate() { + super.onCreate(); + + setUpInjections(); + + setUpBus(); + + setUpAudioPlayer(); + setUpAudioPlayerRemote(); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + MediaButtonReceiver.handleIntent(mediaSession, intent); + return super.onStartCommand(intent, flags, startId); + } + + @Nullable + @Override + public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, @Nullable Bundle rootHints) { + if (TextUtils.equals(clientPackageName, getPackageName())) { + return new BrowserRoot(getString(R.string.application_name), null); + } + + return null; + } + + //Not important for general audio service, required for class + @Override + public void onLoadChildren(@NonNull String parentId, @NonNull Result> result) { + result.sendResult(null); + } + + private void setUpInjections() { + AmahiApplication.from(this).inject(this); + } + + private void setUpBus() { + BusProvider.getBus().register(this); + } + + private void setUpAudioPlayer() { + audioPlayer = new MediaPlayer(); + + audioPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); + audioPlayer.setWakeMode(this, PowerManager.PARTIAL_WAKE_LOCK); + audioPlayer.setVolume(1.0f, 1.0f); + + audioPlayer.setOnPreparedListener(this); + audioPlayer.setOnCompletionListener(this); + audioPlayer.setOnErrorListener(this); + } + + private void setUpAudioPlayerRemote() { + AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); + ComponentName audioReceiver = new ComponentName(getPackageName(), AudioReceiver.class.getName()); + + Intent audioIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); + audioIntent.setComponent(audioReceiver); + PendingIntent audioPendingIntent = PendingIntent.getBroadcast(this, 0, audioIntent, 0); + + mediaSession = new MediaSessionCompat(this, "PlayerService", audioReceiver, audioPendingIntent); + mediaSession.setCallback(new MediaSessionCallback()); + mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | + MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS); + mediaSession.setMediaButtonReceiver(audioPendingIntent); + setSessionToken(mediaSession.getSessionToken()); + + try { + mMediaNotificationManager = new MediaNotificationManager(this); + } catch (RemoteException e) { + throw new IllegalStateException("Could not create a MediaNotificationManager", e); + } + + mediaSession.setPlaybackState(new PlaybackStateCompat.Builder() + .setState(PlaybackStateCompat.STATE_NONE, 0, 0) + .setActions(getAvailableActions()) + .build()); + + audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); + } + + public boolean isAudioStarted() { + return (audioShare != null) && (audioFiles != null) && (audioFile != null); + } + + public void startAudio(ServerShare audioShare, List audioFiles, ServerFile audioFile) { + this.audioShare = audioShare; + this.audioFiles = audioFiles; + this.audioFile = audioFile; + + setUpAudioPlayback(); + setUpAudioMetadata(); + } + + private void setUpAudioPlayback() { + try { + audioPlayer.setDataSource(this, getAudioUri()); + audioPlayer.prepareAsync(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private Uri getAudioUri() { + return serverClient.getFileUri(audioShare, audioFile); + } + + @Override + public void onPrepared(MediaPlayer audioPlayer) { + BusProvider.getBus().post(new AudioPreparedEvent()); + playAudio(); + } + + private void setUpAudioMetadata() { + AudioMetadataRetrievingTask.execute(getAudioUri(), audioFile); + } + + @Subscribe + public void onAudioMetadataRetrieved(AudioMetadataRetrievedEvent event) { + if (audioFile != null) { + this.audioMetadataFormatter = new AudioMetadataFormatter( + event.getAudioTitle(), event.getAudioArtist(), event.getAudioAlbum()); + this.audioMetadataFormatter.setDuration(event.getDuration()); + this.audioAlbumArt = event.getAudioAlbumArt(); + + setUpAudioPlayerRemote(audioMetadataFormatter, audioAlbumArt); + + mMediaNotificationManager.startNotification(); + } + } + + private void setUpAudioPlayerRemote(AudioMetadataFormatter audioMetadataFormatter, Bitmap audioAlbumArt) { + + mediaSession.setMetadata(new MediaMetadataCompat.Builder() + .putString(MediaMetadataCompat.METADATA_KEY_TITLE, audioMetadataFormatter.getAudioTitle(audioFile)) + .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, audioMetadataFormatter.getAudioSubtitle(audioShare)) + .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, audioMetadataFormatter.getAudioSubtitle(audioShare)) + .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, getAudioPlayerRemoteArtwork(audioAlbumArt)) + .build()); + } + + private Bitmap getAudioPlayerRemoteArtwork(Bitmap audioAlbumArt) { + if (audioAlbumArt == null) { + return null; + } + + Bitmap.Config artworkConfig = audioAlbumArt.getConfig(); + + if (artworkConfig == null) { + artworkConfig = Bitmap.Config.ARGB_8888; + } + + return audioAlbumArt.copy(artworkConfig, false); + } + + public PendingIntent createContentIntent() { + Intent audioIntent = Intents.Builder.with(this).buildServerFileIntent(audioShare, audioFiles, audioFile); + return PendingIntent.getActivity(this, 0, audioIntent, PendingIntent.FLAG_CANCEL_CURRENT); + } + + public ServerFile getAudioFile() { + return audioFile; + } + + public AudioMetadataFormatter getAudioMetadataFormatter() { + return audioMetadataFormatter; + } + + public Bitmap getAudioAlbumArt() { + return audioAlbumArt; + } + + public MediaPlayer getAudioPlayer() { + return audioPlayer; + } + + @Subscribe + public void onAudioControlPlayPause(AudioControlPlayPauseEvent event) { + if (audioPlayer.isPlaying()) { + pauseAudio(); + } else { + playAudio(); + } + } + + @Subscribe + public void onAudioControlPlay(AudioControlPlayEvent event) { + playAudio(); + } + + @Subscribe + public void onAudioControlPause(AudioControlPauseEvent event) { + pauseAudio(); + } + + @Subscribe + public void onAudioControlNext(AudioControlNextEvent event) { + startNextAudio(); + } + + @Subscribe + public void onAudioControlPrevious(AudioControlPreviousEvent event) { + startPreviousAudio(); + } + + public void playAudio() { + mediaSession.setActive(true); + audioPlayer.start(); + setMediaPlaybackState(PlaybackStateCompat.STATE_PLAYING); + } + + public void pauseAudio() { + mediaSession.setActive(false); + audioPlayer.pause(); + setMediaPlaybackState(PlaybackStateCompat.STATE_PAUSED); + } + + private void setMediaPlaybackState(int state) { + PlaybackStateCompat.Builder playbackStateBuilder = new PlaybackStateCompat.Builder(); + playbackStateBuilder.setActions(getAvailableActions()); + playbackStateBuilder.setState(state, audioPlayer.getCurrentPosition(), 1.0f, SystemClock.elapsedRealtime()); + mediaSession.setPlaybackState(playbackStateBuilder.build()); + } + + private long getAvailableActions() { + long actions = PlaybackStateCompat.ACTION_PLAY_PAUSE | + PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS | + PlaybackStateCompat.ACTION_SKIP_TO_NEXT; + if (audioPlayer.isPlaying()) { + actions |= PlaybackStateCompat.ACTION_PAUSE; + } else { + actions |= PlaybackStateCompat.ACTION_PLAY; + } + return actions; + } + + private void startNextAudio() { + this.audioFile = getNextAudioFile(); + + tearDownAudioPlayback(); + + setUpAudioPlayback(); + setUpAudioMetadata(); + } + + private ServerFile getNextAudioFile() { + int currentAudioFilePosition = audioFiles.indexOf(audioFile); + + if (currentAudioFilePosition == audioFiles.size() - 1) { + return audioFiles.get(0); + } + + return audioFiles.get(currentAudioFilePosition + 1); + } + + private void tearDownAudioPlayback() { + if (isAudioPlaying()) + pauseAudio(); + audioPlayer.reset(); + } + + private void startPreviousAudio() { + this.audioFile = getPreviousAudioFile(); + + tearDownAudioPlayback(); + + setUpAudioPlayback(); + setUpAudioMetadata(); + } + + private ServerFile getPreviousAudioFile() { + int currentAudioFilePosition = audioFiles.indexOf(audioFile); + + if (currentAudioFilePosition == 0) { + return audioFiles.get(audioFiles.size() - 1); + } + + return audioFiles.get(currentAudioFilePosition - 1); + } + + @Override + public void onAudioFocusChange(int audioFocus) { + switch (audioFocus) { + case AudioManager.AUDIOFOCUS_GAIN: + handleAudioFocusGain(); + break; + + case AudioManager.AUDIOFOCUS_LOSS: + case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: + handleAudioFocusLoss(); + break; + + case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: + handleAudioFocusDuck(); + break; + + default: + break; + } + } + + private void handleAudioFocusGain() { + if (isAudioPlaying()) { + setUpAudioVolume(); + } else { + if (audioFocus == AudioFocus.LOSS) { + playAudio(); + } + } + + this.audioFocus = AudioFocus.GAIN; + } + + private boolean isAudioPlaying() { + try { + return isAudioStarted() && audioPlayer.isPlaying(); + } catch (IllegalStateException e) { + return false; + } + } + + private void setUpAudioVolume() { + audioPlayer.setVolume(1.0f, 1.0f); + } + + private void handleAudioFocusLoss() { + if (isAudioPlaying()) { + pauseAudio(); + this.audioFocus = AudioFocus.LOSS; + } + } + + private void handleAudioFocusDuck() { + if (isAudioPlaying()) { + tearDownAudioVolume(); + } + } + + private void tearDownAudioVolume() { + audioPlayer.setVolume(0.3f, 0.3f); + } + + @Override + public void onCompletion(MediaPlayer audioPlayer) { + BusProvider.getBus().post(new AudioCompletedEvent()); + + startNextAudio(); + } + + @Override + public boolean onError(MediaPlayer audioPlayer, int errorReason, int errorExtra) { + getAudioPlayer().reset(); + return true; + } + + @Override + public void onDestroy() { + super.onDestroy(); + + tearDownBus(); + + tearDownAudioPlayer(); + tearDownAudioPlayerRemote(); + tearDownAudioPlayerNotification(); + } + + private void tearDownBus() { + BusProvider.getBus().unregister(this); + } + + private void tearDownAudioPlayer() { + audioPlayer.reset(); + audioPlayer.release(); + } + + private void tearDownAudioPlayerRemote() { + AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); + + audioManager.abandonAudioFocus(this); + mediaSession.release(); + } + + private void tearDownAudioPlayerNotification() { + mMediaNotificationManager.stopNotification(); + } + + private enum AudioFocus { + GAIN, LOSS + } + + public static final class AudioServiceBinder extends Binder { + private final AudioService audioService; + + public AudioServiceBinder(AudioService audioService) { + this.audioService = audioService; + } + + public AudioService getAudioService() { + return audioService; + } + } + + private class MediaSessionCallback extends MediaSessionCompat.Callback { + @Override + public void onPlay() { + playAudio(); + } + + @Override + public void onPause() { + pauseAudio(); + } + + @Override + public void onSkipToNext() { + startNextAudio(); + } + + @Override + public void onSkipToPrevious() { + startPreviousAudio(); + } + } } diff --git a/src/main/java/org/amahi/anywhere/service/UploadService.java b/src/main/java/org/amahi/anywhere/service/UploadService.java index ec6ba5e5a..86f6d3874 100644 --- a/src/main/java/org/amahi/anywhere/service/UploadService.java +++ b/src/main/java/org/amahi/anywhere/service/UploadService.java @@ -60,254 +60,254 @@ */ public class UploadService extends Service implements UploadManager.UploadCallbacks { - @Inject - ServerClient serverClient; - - private UploadManager uploadManager; - private UploadQueueDbHelper uploadQueueDbHelper; - private NotificationCompat.Builder notificationBuilder; - private NetworkUtils networkUtils; - - @Nullable - @Override - public IBinder onBind(Intent intent) { - return null; - } - - @Override - public void onCreate() { - super.onCreate(); - setUpInjections(); - setUpBus(); - setUpDbHelper(); - setUpNetworkUtils(); - } - - private void setUpInjections() { - AmahiApplication.from(this).inject(this); - } - - private void setUpBus() { - BusProvider.getBus().register(this); - } - - private void setUpDbHelper() { - uploadQueueDbHelper = UploadQueueDbHelper.init(this); - } - - private void setUpNetworkUtils() { - networkUtils = new NetworkUtils(this); - } - - @Override - public int onStartCommand(@Nullable Intent intent, int flags, int startId) { - - if (intent != null && intent.hasExtra(Intents.Extras.IMAGE_URIS)) { - if (isAutoUploadEnabled()) { - ArrayList uris = intent.getParcelableArrayListExtra(Intents.Extras.IMAGE_URIS); - for (Uri uri : uris) { - String imagePath = queryImagePath(uri); - if (imagePath != null) { - UploadFile uploadFile = uploadQueueDbHelper.addNewImagePath(imagePath); - if (uploadFile != null && uploadManager != null) - uploadManager.add(uploadFile); - } - } - } - } - - if (isAutoUploadEnabled()) { - if (isUploadAllowed()) { - connectToServer(); - } else { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - NetConnectivityJob.scheduleJob(this); - } - } - } - - return super.onStartCommand(intent, flags, startId); - } - - private boolean isAutoUploadEnabled() { - return PreferenceManager.getDefaultSharedPreferences(this) - .getBoolean(getString(R.string.preference_key_upload_switch), false); - } - - private boolean isUploadAllowed() { - return networkUtils.isUploadAllowed(); - } - - private void connectToServer() { - Server server = getUploadServer(); - if (server != null) { - setUpServerConnection(server); - } - } - - private void setUpServerConnection(@NonNull Server server) { - if (serverClient.isConnected(server)) { - setUpServerConnection(); - } else { - serverClient.connect(this, server); - } - } - - @Subscribe - public void onServerConnected(ServerConnectedEvent event) { - Server uploadServer = getUploadServer(); - if (uploadServer != null && uploadServer == event.getServer()) { - setUpServerConnection(); - } - } - - private void setUpServerConnection() { - if (!isConnectionAvailable() || isConnectionAuto()) { - serverClient.connectAuto(); - return; - } - - if (isConnectionLocal()) { - serverClient.connectLocal(); - } else { - serverClient.connectRemote(); - } - } - - private boolean isConnectionAvailable() { - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); - - return preferences.contains(getString(R.string.preference_key_server_connection)); - } - - private boolean isConnectionAuto() { - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); - String preferenceConnection = preferences.getString(getString(R.string.preference_key_server_connection), null); - - return preferenceConnection.equals(getString(R.string.preference_key_server_connection_auto)); - } - - private boolean isConnectionLocal() { - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); - String preferenceConnection = preferences.getString(getString(R.string.preference_key_server_connection), null); - - return preferenceConnection.equals(getString(R.string.preference_key_server_connection_local)); - } - - @Subscribe - public void onServerConnectionChanged(ServerConnectionChangedEvent event) { - if (uploadManager == null) { - setUpUploadManager(); - } - uploadManager.startUploading(); - } - - private Server getUploadServer() { - String session = PreferenceManager.getDefaultSharedPreferences(this) - .getString(getString(R.string.preference_key_upload_hda), null); - if (session != null) { - return new Server(session); - } else { - return null; - } - } - - private void setUpUploadManager() { - ArrayList uploadFiles = uploadQueueDbHelper.getAllImagePaths(); - uploadManager = new UploadManager(this, uploadFiles); - } - - private String queryImagePath(Uri imageUri) { - String filePath = null; - if ("content".equals(imageUri.getScheme())) { - Cursor cursor = this.getContentResolver() - .query(imageUri, null, null, null, null); - if (cursor != null) { - cursor.moveToFirst(); - int columnIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA); - filePath = cursor.getString(columnIndex); - cursor.close(); - } - } else { - filePath = imageUri.toString(); - } - return filePath; - } - - @Override - public void uploadStarted(int id, String fileName) { - notificationBuilder = new NotificationCompat.Builder(getApplicationContext()); - notificationBuilder - .setOngoing(true) - .setSmallIcon(R.drawable.ic_app_logo) - .setContentTitle(getString(R.string.notification_upload_title)) - .setContentText(getString(R.string.notification_upload_message, fileName)) - .setProgress(100, 0, false) - .build(); - Notification notification = notificationBuilder.build(); - startForeground(id, notification); - } - - @Override - public void uploadProgress(int id, int progress) { - NotificationManager notificationManager = (NotificationManager) getApplicationContext() - .getSystemService(Context.NOTIFICATION_SERVICE); - notificationBuilder - .setProgress(100, progress, false); - Notification notification = notificationBuilder.build(); - notificationManager.notify(id, notification); - } - - @Override - public void uploadSuccess(int id) { - uploadComplete(id, getString(R.string.message_upload_success)); - } - - @Override - public void uploadError(int id) { - uploadComplete(id, getString(R.string.message_upload_error)); - } - - private void uploadComplete(int id, String title) { - stopForeground(false); - NotificationManager notificationManager = (NotificationManager) getApplicationContext() - .getSystemService(Context.NOTIFICATION_SERVICE); - - notificationBuilder - .setContentTitle(title) - .setOngoing(false) - .setProgress(0, 0, false); - - Notification notification = notificationBuilder.build(); - notificationManager.notify(id, notification); - } - - @Override - public void removeFileFromDb(int id) { - uploadQueueDbHelper.removeImagePath(id); - } - - @Override - public void uploadQueueFinished() { - tearDownUploadManager(); - } - - @Override - public void onDestroy() { - super.onDestroy(); - uploadQueueDbHelper.closeDataBase(); - tearDownUploadManager(); - tearDownBus(); - } - - private void tearDownUploadManager() { - if (uploadManager != null) { - uploadManager.tearDownBus(); - uploadManager = null; - } - } - - public void tearDownBus() { - BusProvider.getBus().unregister(this); - } + @Inject + ServerClient serverClient; + + private UploadManager uploadManager; + private UploadQueueDbHelper uploadQueueDbHelper; + private NotificationCompat.Builder notificationBuilder; + private NetworkUtils networkUtils; + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public void onCreate() { + super.onCreate(); + setUpInjections(); + setUpBus(); + setUpDbHelper(); + setUpNetworkUtils(); + } + + private void setUpInjections() { + AmahiApplication.from(this).inject(this); + } + + private void setUpBus() { + BusProvider.getBus().register(this); + } + + private void setUpDbHelper() { + uploadQueueDbHelper = UploadQueueDbHelper.init(this); + } + + private void setUpNetworkUtils() { + networkUtils = new NetworkUtils(this); + } + + @Override + public int onStartCommand(@Nullable Intent intent, int flags, int startId) { + + if (intent != null && intent.hasExtra(Intents.Extras.IMAGE_URIS)) { + if (isAutoUploadEnabled()) { + ArrayList uris = intent.getParcelableArrayListExtra(Intents.Extras.IMAGE_URIS); + for (Uri uri : uris) { + String imagePath = queryImagePath(uri); + if (imagePath != null) { + UploadFile uploadFile = uploadQueueDbHelper.addNewImagePath(imagePath); + if (uploadFile != null && uploadManager != null) + uploadManager.add(uploadFile); + } + } + } + } + + if (isAutoUploadEnabled()) { + if (isUploadAllowed()) { + connectToServer(); + } else { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + NetConnectivityJob.scheduleJob(this); + } + } + } + + return super.onStartCommand(intent, flags, startId); + } + + private boolean isAutoUploadEnabled() { + return PreferenceManager.getDefaultSharedPreferences(this) + .getBoolean(getString(R.string.preference_key_upload_switch), false); + } + + private boolean isUploadAllowed() { + return networkUtils.isUploadAllowed(); + } + + private void connectToServer() { + Server server = getUploadServer(); + if (server != null) { + setUpServerConnection(server); + } + } + + private void setUpServerConnection(@NonNull Server server) { + if (serverClient.isConnected(server)) { + setUpServerConnection(); + } else { + serverClient.connect(this, server); + } + } + + @Subscribe + public void onServerConnected(ServerConnectedEvent event) { + Server uploadServer = getUploadServer(); + if (uploadServer != null && uploadServer == event.getServer()) { + setUpServerConnection(); + } + } + + private void setUpServerConnection() { + if (!isConnectionAvailable() || isConnectionAuto()) { + serverClient.connectAuto(); + return; + } + + if (isConnectionLocal()) { + serverClient.connectLocal(); + } else { + serverClient.connectRemote(); + } + } + + private boolean isConnectionAvailable() { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); + + return preferences.contains(getString(R.string.preference_key_server_connection)); + } + + private boolean isConnectionAuto() { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); + String preferenceConnection = preferences.getString(getString(R.string.preference_key_server_connection), null); + + return preferenceConnection.equals(getString(R.string.preference_key_server_connection_auto)); + } + + private boolean isConnectionLocal() { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); + String preferenceConnection = preferences.getString(getString(R.string.preference_key_server_connection), null); + + return preferenceConnection.equals(getString(R.string.preference_key_server_connection_local)); + } + + @Subscribe + public void onServerConnectionChanged(ServerConnectionChangedEvent event) { + if (uploadManager == null) { + setUpUploadManager(); + } + uploadManager.startUploading(); + } + + private Server getUploadServer() { + String session = PreferenceManager.getDefaultSharedPreferences(this) + .getString(getString(R.string.preference_key_upload_hda), null); + if (session != null) { + return new Server(session); + } else { + return null; + } + } + + private void setUpUploadManager() { + ArrayList uploadFiles = uploadQueueDbHelper.getAllImagePaths(); + uploadManager = new UploadManager(this, uploadFiles); + } + + private String queryImagePath(Uri imageUri) { + String filePath = null; + if ("content".equals(imageUri.getScheme())) { + Cursor cursor = this.getContentResolver() + .query(imageUri, null, null, null, null); + if (cursor != null) { + cursor.moveToFirst(); + int columnIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA); + filePath = cursor.getString(columnIndex); + cursor.close(); + } + } else { + filePath = imageUri.toString(); + } + return filePath; + } + + @Override + public void uploadStarted(int id, String fileName) { + notificationBuilder = new NotificationCompat.Builder(getApplicationContext()); + notificationBuilder + .setOngoing(true) + .setSmallIcon(R.drawable.ic_app_logo) + .setContentTitle(getString(R.string.notification_upload_title)) + .setContentText(getString(R.string.notification_upload_message, fileName)) + .setProgress(100, 0, false) + .build(); + Notification notification = notificationBuilder.build(); + startForeground(id, notification); + } + + @Override + public void uploadProgress(int id, int progress) { + NotificationManager notificationManager = (NotificationManager) getApplicationContext() + .getSystemService(Context.NOTIFICATION_SERVICE); + notificationBuilder + .setProgress(100, progress, false); + Notification notification = notificationBuilder.build(); + notificationManager.notify(id, notification); + } + + @Override + public void uploadSuccess(int id) { + uploadComplete(id, getString(R.string.message_upload_success)); + } + + @Override + public void uploadError(int id) { + uploadComplete(id, getString(R.string.message_upload_error)); + } + + private void uploadComplete(int id, String title) { + stopForeground(false); + NotificationManager notificationManager = (NotificationManager) getApplicationContext() + .getSystemService(Context.NOTIFICATION_SERVICE); + + notificationBuilder + .setContentTitle(title) + .setOngoing(false) + .setProgress(0, 0, false); + + Notification notification = notificationBuilder.build(); + notificationManager.notify(id, notification); + } + + @Override + public void removeFileFromDb(int id) { + uploadQueueDbHelper.removeImagePath(id); + } + + @Override + public void uploadQueueFinished() { + tearDownUploadManager(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + uploadQueueDbHelper.closeDataBase(); + tearDownUploadManager(); + tearDownBus(); + } + + private void tearDownUploadManager() { + if (uploadManager != null) { + uploadManager.tearDownBus(); + uploadManager = null; + } + } + + public void tearDownBus() { + BusProvider.getBus().unregister(this); + } } diff --git a/src/main/java/org/amahi/anywhere/service/VideoService.java b/src/main/java/org/amahi/anywhere/service/VideoService.java index d3cdb0be4..a5b16bc01 100644 --- a/src/main/java/org/amahi/anywhere/service/VideoService.java +++ b/src/main/java/org/amahi/anywhere/service/VideoService.java @@ -24,7 +24,6 @@ import android.net.Uri; import android.os.Binder; import android.os.IBinder; -import android.util.Log; import com.squareup.otto.Subscribe; @@ -47,148 +46,144 @@ /** * Video service. Does all the work related to the video playback. */ -public class VideoService extends Service -{ - private ServerShare videoShare; - private ServerFile videoFile; - - private LibVLC mLibVLC; - private MediaPlayer mMediaPlayer = null; - - @Inject - ServerClient serverClient; - - @Override - public IBinder onBind(Intent intent) { - return new VideoServiceBinder(this); - } - - @Override - public void onCreate() { - super.onCreate(); - - setUpInjections(); - - setUpVideoPlayer(); - - BusProvider.getBus().register(this); - } - - private void setUpInjections() { - AmahiApplication.from(this).inject(this); - } - - private void setUpVideoPlayer() { - final ArrayList args = new ArrayList<>(); - args.add("-vvv"); - mLibVLC = new LibVLC(this, args); - mMediaPlayer = new MediaPlayer(mLibVLC); - } - - public boolean isVideoStarted() { - return (videoShare != null) && (videoFile != null); - } - - public void startVideo(ServerShare videoShare, ServerFile videoFile, boolean isSubtitleEnabled) { - this.videoShare = videoShare; - this.videoFile = videoFile; - - setUpVideoPlayback(isSubtitleEnabled); - } - - private void setUpVideoPlayback(boolean isSubtitleEnabled) { - Media media = new Media(mLibVLC, getVideoUri()); - mMediaPlayer.setMedia(media); - media.release(); - if (isSubtitleEnabled) { - searchSubtitleFile(); - } - mMediaPlayer.play(); - } - - private Uri getVideoUri() { - return serverClient.getFileUri(videoShare, videoFile); - } - - private void searchSubtitleFile() { - if (serverClient.isConnected()){ - if (!isDirectoryAvailable()) { - serverClient.getFiles(videoShare); - } else { - serverClient.getFiles(videoShare, getDirectory()); - } - } - } - - @Subscribe - public void onFilesLoaded(ServerFilesLoadedEvent event) { - List files = event.getServerFiles(); - for (ServerFile file:files) { - if (videoFile.getNameOnly().equals(file.getNameOnly())) { - if (Mimes.match(file.getMime()) == Mimes.Type.SUBTITLE) { - mMediaPlayer.getMedia().addSlave( - new Media.Slave( - Media.Slave.Type.Subtitle, 4, getSubtitleUri(file))); - break; - } - } - } - } - - private String getSubtitleUri(ServerFile file) { - return serverClient.getFileUri(videoShare, file).toString(); - } - - private boolean isDirectoryAvailable() { - return getDirectory() != null; - } - - private ServerFile getDirectory() { - return videoFile.getParentFile(); - } - - public MediaPlayer getMediaPlayer() { - return mMediaPlayer; - } - - public boolean isVideoPlaying() { - return mMediaPlayer.isPlaying(); - } - - public void playVideo() { - mMediaPlayer.play(); - } - - public void pauseVideo() { - mMediaPlayer.pause(); - } - - @Override - public void onDestroy() { - super.onDestroy(); - - tearDownVideoPlayback(); - BusProvider.getBus().unregister(this); - } - - - private void tearDownVideoPlayback() { - mMediaPlayer.stop(); - mMediaPlayer.release(); - mLibVLC.release(); - } - - - public static final class VideoServiceBinder extends Binder - { - private final VideoService videoService; - - VideoServiceBinder(VideoService videoService) { - this.videoService = videoService; - } - - public VideoService getVideoService() { - return videoService; - } - } +public class VideoService extends Service { + @Inject + ServerClient serverClient; + private ServerShare videoShare; + private ServerFile videoFile; + private LibVLC mLibVLC; + private MediaPlayer mMediaPlayer = null; + + @Override + public IBinder onBind(Intent intent) { + return new VideoServiceBinder(this); + } + + @Override + public void onCreate() { + super.onCreate(); + + setUpInjections(); + + setUpVideoPlayer(); + + BusProvider.getBus().register(this); + } + + private void setUpInjections() { + AmahiApplication.from(this).inject(this); + } + + private void setUpVideoPlayer() { + final ArrayList args = new ArrayList<>(); + args.add("-vvv"); + mLibVLC = new LibVLC(this, args); + mMediaPlayer = new MediaPlayer(mLibVLC); + } + + public boolean isVideoStarted() { + return (videoShare != null) && (videoFile != null); + } + + public void startVideo(ServerShare videoShare, ServerFile videoFile, boolean isSubtitleEnabled) { + this.videoShare = videoShare; + this.videoFile = videoFile; + + setUpVideoPlayback(isSubtitleEnabled); + } + + private void setUpVideoPlayback(boolean isSubtitleEnabled) { + Media media = new Media(mLibVLC, getVideoUri()); + mMediaPlayer.setMedia(media); + media.release(); + if (isSubtitleEnabled) { + searchSubtitleFile(); + } + mMediaPlayer.play(); + } + + private Uri getVideoUri() { + return serverClient.getFileUri(videoShare, videoFile); + } + + private void searchSubtitleFile() { + if (serverClient.isConnected()) { + if (!isDirectoryAvailable()) { + serverClient.getFiles(videoShare); + } else { + serverClient.getFiles(videoShare, getDirectory()); + } + } + } + + @Subscribe + public void onFilesLoaded(ServerFilesLoadedEvent event) { + List files = event.getServerFiles(); + for (ServerFile file : files) { + if (videoFile.getNameOnly().equals(file.getNameOnly())) { + if (Mimes.match(file.getMime()) == Mimes.Type.SUBTITLE) { + mMediaPlayer.getMedia().addSlave( + new Media.Slave( + Media.Slave.Type.Subtitle, 4, getSubtitleUri(file))); + break; + } + } + } + } + + private String getSubtitleUri(ServerFile file) { + return serverClient.getFileUri(videoShare, file).toString(); + } + + private boolean isDirectoryAvailable() { + return getDirectory() != null; + } + + private ServerFile getDirectory() { + return videoFile.getParentFile(); + } + + public MediaPlayer getMediaPlayer() { + return mMediaPlayer; + } + + public boolean isVideoPlaying() { + return mMediaPlayer.isPlaying(); + } + + public void playVideo() { + mMediaPlayer.play(); + } + + public void pauseVideo() { + mMediaPlayer.pause(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + + tearDownVideoPlayback(); + BusProvider.getBus().unregister(this); + } + + + private void tearDownVideoPlayback() { + mMediaPlayer.stop(); + mMediaPlayer.release(); + mLibVLC.release(); + } + + + public static final class VideoServiceBinder extends Binder { + private final VideoService videoService; + + VideoServiceBinder(VideoService videoService) { + this.videoService = videoService; + } + + public VideoService getVideoService() { + return videoService; + } + } } diff --git a/src/main/java/org/amahi/anywhere/task/AudioMetadataRetrievingTask.java b/src/main/java/org/amahi/anywhere/task/AudioMetadataRetrievingTask.java index 6de356c2d..b6ee96b6c 100644 --- a/src/main/java/org/amahi/anywhere/task/AudioMetadataRetrievingTask.java +++ b/src/main/java/org/amahi/anywhere/task/AudioMetadataRetrievingTask.java @@ -76,7 +76,7 @@ protected BusEvent doInBackground(Void... parameters) { Bitmap audioAlbumArt = extractAlbumArt(audioMetadataRetriever); return new AudioMetadataRetrievedEvent(audioTitle, audioArtist, audioAlbum, - duration, audioAlbumArt, viewHolder, serverFile); + duration, audioAlbumArt, viewHolder, serverFile); } catch (RuntimeException e) { return new AudioMetadataRetrievedEvent(null, null, null, null, null, viewHolder, serverFile); } finally { diff --git a/src/main/java/org/amahi/anywhere/tv/activity/ServerFileTvActivity.java b/src/main/java/org/amahi/anywhere/tv/activity/ServerFileTvActivity.java index 2b59968cd..3d6b0707e 100644 --- a/src/main/java/org/amahi/anywhere/tv/activity/ServerFileTvActivity.java +++ b/src/main/java/org/amahi/anywhere/tv/activity/ServerFileTvActivity.java @@ -20,7 +20,6 @@ package org.amahi.anywhere.tv.activity; import android.app.Activity; -import android.app.Fragment; import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; @@ -32,7 +31,6 @@ import org.amahi.anywhere.bus.FileOpeningEvent; import org.amahi.anywhere.server.model.ServerFile; import org.amahi.anywhere.server.model.ServerShare; -import org.amahi.anywhere.tv.fragment.ServerFileTvFragment; import org.amahi.anywhere.util.Fragments; import org.amahi.anywhere.util.Intents; diff --git a/src/main/java/org/amahi/anywhere/tv/activity/TVWebViewActivity.java b/src/main/java/org/amahi/anywhere/tv/activity/TVWebViewActivity.java index f024d2382..15ac1da2e 100644 --- a/src/main/java/org/amahi/anywhere/tv/activity/TVWebViewActivity.java +++ b/src/main/java/org/amahi/anywhere/tv/activity/TVWebViewActivity.java @@ -55,8 +55,8 @@ private void setUpInjections() { AmahiApplication.from(this).inject(this); } - private void setWebPage(){ - WebView webView = (WebView)findViewById(R.id.tv_web_view); + private void setWebPage() { + WebView webView = (WebView) findViewById(R.id.tv_web_view); webView.loadUrl(String.valueOf(getWebResourceUri())); } diff --git a/src/main/java/org/amahi/anywhere/tv/activity/TvPlaybackVideoActivity.java b/src/main/java/org/amahi/anywhere/tv/activity/TvPlaybackVideoActivity.java index 0acfd828d..3a2ec19f3 100644 --- a/src/main/java/org/amahi/anywhere/tv/activity/TvPlaybackVideoActivity.java +++ b/src/main/java/org/amahi/anywhere/tv/activity/TvPlaybackVideoActivity.java @@ -124,18 +124,18 @@ public void onBackPressed() { playPause(); builder.setTitle(getString(R.string.exit_title)) - .setMessage(getString(R.string.exit_message)) - .setPositiveButton(getString(R.string.yes), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - TvPlaybackVideoActivity.super.onBackPressed(); - } - }) - .setNegativeButton(getString(R.string.no), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }).show(); + .setMessage(getString(R.string.exit_message)) + .setPositiveButton(getString(R.string.yes), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + TvPlaybackVideoActivity.super.onBackPressed(); + } + }) + .setNegativeButton(getString(R.string.no), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }).show(); } -} \ No newline at end of file +} diff --git a/src/main/java/org/amahi/anywhere/tv/fragment/ConnectionFragment.java b/src/main/java/org/amahi/anywhere/tv/fragment/ConnectionFragment.java index c0b20c8b7..3c3d7c72a 100644 --- a/src/main/java/org/amahi/anywhere/tv/fragment/ConnectionFragment.java +++ b/src/main/java/org/amahi/anywhere/tv/fragment/ConnectionFragment.java @@ -65,9 +65,9 @@ private SharedPreferences getTVPreference() { @Override public GuidanceStylist.Guidance onCreateGuidance(Bundle savedInstanceState) { return new GuidanceStylist.Guidance(getString(R.string.pref_title_connection), - getString(R.string.pref_connection_desc), - "", - ContextCompat.getDrawable(getActivity(), R.drawable.ic_app_logo_shadowless)); + getString(R.string.pref_connection_desc), + "", + ContextCompat.getDrawable(getActivity(), R.drawable.ic_app_logo_shadowless)); } @Override @@ -93,12 +93,12 @@ private void setTitle(List actions) { String desc = getString(R.string.pref_connection_desc); actions.add(new GuidedAction.Builder(mContext) - .title(title) - .description(desc) - .multilineDescription(true) - .infoOnly(true) - .enabled(false) - .build()); + .title(title) + .description(desc) + .multilineDescription(true) + .infoOnly(true) + .enabled(false) + .build()); } private void populateNames() { @@ -135,15 +135,15 @@ private void setCheckedActionButtons(List actions) { for (int i = 0; i < OPTION_NAMES.size(); i++) { addCheckedAction(actions, - R.drawable.ic_app_logo, + R.drawable.ic_app_logo, - getActivity(), + getActivity(), - OPTION_NAMES.get(i), + OPTION_NAMES.get(i), - OPTION_DESCRIPTIONS.get(i), + OPTION_DESCRIPTIONS.get(i), - OPTION_CHECKED.get(i)); + OPTION_CHECKED.get(i)); } } @@ -151,11 +151,11 @@ private void addCheckedAction(List actions, int iconResId, Context String title, String desc, boolean checked) { GuidedAction guidedAction = new GuidedAction.Builder(context) - .title(title) - .description(desc) - .checkSetId(OPTION_CHECK_SET_ID) - .icon(iconResId) - .build(); + .title(title) + .description(desc) + .checkSetId(OPTION_CHECK_SET_ID) + .icon(iconResId) + .build(); guidedAction.setChecked(checked); diff --git a/src/main/java/org/amahi/anywhere/tv/fragment/IntroFragment.java b/src/main/java/org/amahi/anywhere/tv/fragment/IntroFragment.java index b275c8084..85b132717 100644 --- a/src/main/java/org/amahi/anywhere/tv/fragment/IntroFragment.java +++ b/src/main/java/org/amahi/anywhere/tv/fragment/IntroFragment.java @@ -44,12 +44,12 @@ public class IntroFragment extends OnboardingFragment { private static final int[] CONTENT_IMAGES = { - R.drawable.ic_app_logo, - R.drawable.network, - R.drawable.photos, - R.drawable.music, - R.drawable.movies, - R.drawable.tick, + R.drawable.ic_app_logo, + R.drawable.network, + R.drawable.photos, + R.drawable.music, + R.drawable.movies, + R.drawable.tick, }; private ArrayList mTitles, mDescriptions; private ArrayList mColors; @@ -123,7 +123,7 @@ protected View onCreateBackgroundView(LayoutInflater inflater, ViewGroup contain @Override protected View onCreateContentView(LayoutInflater inflater, ViewGroup container) { mContentView = (ImageView) inflater.inflate(R.layout.onboarding_image, container, - false); + false); ViewGroup.MarginLayoutParams layoutParams = ((ViewGroup.MarginLayoutParams) mContentView.getLayoutParams()); @@ -224,4 +224,4 @@ private Animator createFadeOutAnimator(View view) { protected void onFinishFragment() { startActivity(new Intent(getActivity(), NavigationActivity.class)); } -} \ No newline at end of file +} diff --git a/src/main/java/org/amahi/anywhere/tv/fragment/MainTVFragment.java b/src/main/java/org/amahi/anywhere/tv/fragment/MainTVFragment.java index 90bb252ef..51231b87f 100644 --- a/src/main/java/org/amahi/anywhere/tv/fragment/MainTVFragment.java +++ b/src/main/java/org/amahi/anywhere/tv/fragment/MainTVFragment.java @@ -20,26 +20,16 @@ package org.amahi.anywhere.tv.fragment; import android.content.Intent; -import android.graphics.Bitmap; import android.graphics.Color; -import android.net.Uri; import android.os.Bundle; -import android.support.v17.leanback.app.BackgroundManager; import android.support.v17.leanback.app.BrowseFragment; import android.support.v17.leanback.widget.ArrayObjectAdapter; import android.support.v17.leanback.widget.HeaderItem; import android.support.v17.leanback.widget.ListRow; import android.support.v17.leanback.widget.ListRowPresenter; -import android.support.v17.leanback.widget.OnItemViewSelectedListener; import android.support.v17.leanback.widget.Presenter; import android.support.v17.leanback.widget.PresenterSelector; -import android.support.v17.leanback.widget.Row; -import android.support.v17.leanback.widget.RowPresenter; -import android.util.DisplayMetrics; -import com.bumptech.glide.Glide; -import com.bumptech.glide.request.animation.GlideAnimation; -import com.bumptech.glide.request.target.SimpleTarget; import com.squareup.otto.Subscribe; import org.amahi.anywhere.AmahiApplication; @@ -58,7 +48,6 @@ import org.amahi.anywhere.tv.presenter.MainTVPresenter; import org.amahi.anywhere.tv.presenter.SettingsItemPresenter; import org.amahi.anywhere.util.Intents; -import org.amahi.anywhere.util.Mimes; import java.util.ArrayList; import java.util.Collections; @@ -187,12 +176,12 @@ private void addSettings(ArrayObjectAdapter adapter) { adapter.add(0, settingsRow); } - private void sortHeaders(){ - for(int i=0;i actions) { String desc = getString(R.string.pref_server_active_list_desc); actions.add(new GuidedAction.Builder(mContext) - .title(title) - .description(desc) - .multilineDescription(true) - .infoOnly(true) - .enabled(false) - .build()); + .title(title) + .description(desc) + .multilineDescription(true) + .infoOnly(true) + .enabled(false) + .build()); } private void populateData() { @@ -151,15 +150,15 @@ private void setCheckedActionButtons(List actions) { for (int i = 0; i < OPTION_NAMES.size(); i++) { addCheckedAction(actions, - R.drawable.ic_app_logo, + R.drawable.ic_app_logo, - getActivity(), + getActivity(), - OPTION_NAMES.get(i), + OPTION_NAMES.get(i), - OPTION_DESCRIPTIONS.get(i), + OPTION_DESCRIPTIONS.get(i), - OPTION_CHECKED.get(i)); + OPTION_CHECKED.get(i)); } } @@ -167,11 +166,11 @@ private void addCheckedAction(List actions, int iconResId, Context String title, String desc, boolean checked) { GuidedAction guidedAction = new GuidedAction.Builder(context) - .title(title) - .description(desc) - .checkSetId(OPTION_CHECK_SET_ID) - .icon(iconResId) - .build(); + .title(title) + .description(desc) + .checkSetId(OPTION_CHECK_SET_ID) + .icon(iconResId) + .build(); guidedAction.setChecked(checked); diff --git a/src/main/java/org/amahi/anywhere/tv/fragment/SignOutFragment.java b/src/main/java/org/amahi/anywhere/tv/fragment/SignOutFragment.java index 187046f5b..b3fb8455b 100644 --- a/src/main/java/org/amahi/anywhere/tv/fragment/SignOutFragment.java +++ b/src/main/java/org/amahi/anywhere/tv/fragment/SignOutFragment.java @@ -103,10 +103,10 @@ public void onGuidedActionClicked(GuidedAction action) { private void addAction(List actions, long id, String title, String desc) { actions.add(new GuidedAction.Builder(mContext) - .id(id) - .title(title) - .description(desc) - .build()); + .id(id) + .title(title) + .description(desc) + .build()); } private void tearDownAccount() { diff --git a/src/main/java/org/amahi/anywhere/tv/fragment/ThemeFragment.java b/src/main/java/org/amahi/anywhere/tv/fragment/ThemeFragment.java index 09fb58f7e..6c705bf16 100644 --- a/src/main/java/org/amahi/anywhere/tv/fragment/ThemeFragment.java +++ b/src/main/java/org/amahi/anywhere/tv/fragment/ThemeFragment.java @@ -58,9 +58,9 @@ public ThemeFragment(Context context) { @Override public GuidanceStylist.Guidance onCreateGuidance(Bundle savedInstanceState) { return new GuidanceStylist.Guidance(getString(R.string.pref_title_select_theme), - getString(R.string.pref_theme_desc), - "", - ContextCompat.getDrawable(getActivity(), R.drawable.ic_app_logo_shadowless)); + getString(R.string.pref_theme_desc), + "", + ContextCompat.getDrawable(getActivity(), R.drawable.ic_app_logo_shadowless)); } @Override @@ -89,12 +89,12 @@ private void setTitle(List actions) { String desc = getString(R.string.pref_theme_detail_desc); actions.add(new GuidedAction.Builder(mContext) - .title(title) - .description(desc) - .multilineDescription(true) - .infoOnly(true) - .enabled(false) - .build()); + .title(title) + .description(desc) + .multilineDescription(true) + .infoOnly(true) + .enabled(false) + .build()); } @@ -128,15 +128,15 @@ private void setCheckedActionButtons(List actions) { for (int i = 0; i < OPTION_NAMES.size(); i++) { addCheckedAction(actions, - R.drawable.ic_app_logo, + R.drawable.ic_app_logo, - getActivity(), + getActivity(), - OPTION_NAMES.get(i), + OPTION_NAMES.get(i), - OPTION_DESCRIPTIONS.get(i), + OPTION_DESCRIPTIONS.get(i), - OPTION_CHECKED.get(i)); + OPTION_CHECKED.get(i)); } } @@ -144,11 +144,11 @@ private void addCheckedAction(List actions, int iconResId, Context String title, String desc, boolean checked) { GuidedAction guidedAction = new GuidedAction.Builder(context) - .title(title) - .description(desc) - .checkSetId(OPTION_CHECK_SET_ID) - .icon(iconResId) - .build(); + .title(title) + .description(desc) + .checkSetId(OPTION_CHECK_SET_ID) + .icon(iconResId) + .build(); guidedAction.setChecked(checked); @@ -161,10 +161,10 @@ private void setBackButton(List actions) { private void addAction(List actions, long id, String title, String desc) { actions.add(new GuidedAction.Builder(mContext) - .id(id) - .title(title) - .description(desc) - .build()); + .id(id) + .title(title) + .description(desc) + .build()); } @Override diff --git a/src/main/java/org/amahi/anywhere/tv/fragment/TvPlaybackAudioFragment.java b/src/main/java/org/amahi/anywhere/tv/fragment/TvPlaybackAudioFragment.java index 61a65dba0..6d89fe19c 100644 --- a/src/main/java/org/amahi/anywhere/tv/fragment/TvPlaybackAudioFragment.java +++ b/src/main/java/org/amahi/anywhere/tv/fragment/TvPlaybackAudioFragment.java @@ -73,27 +73,22 @@ public class TvPlaybackAudioFragment extends PlaybackFragment { private static final int DEFAULT_UPDATE_PERIOD = 1000; private static final int UPDATE_PERIOD = 16; - + @Inject + ServerClient serverClient; private ArrayObjectAdapter mRowsAdapter; private ArrayObjectAdapter mPrimaryActionsAdapter; - private PlaybackControlsRow mPlaybackControlsRow; private PlaybackControlsRow.PlayPauseAction mPlayPauseAction; private PlaybackControlsRow.SkipNextAction mSkipNextAction; private PlaybackControlsRow.SkipPreviousAction mSkipPreviousAction; private PlaybackControlsRow.FastForwardAction mFastForwardAction; private PlaybackControlsRow.RewindAction mRewindAction; - private int mCurrentPlaybackState; private Handler mHandler; private Runnable mRunnable; - private MediaPlayer mediaPlayer; private ArrayList mAudioList; - @Inject - ServerClient serverClient; - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -145,7 +140,7 @@ private void setUpInjections() { } private void replaceFragment(ServerFile serverFile) { - getFragmentManager().beginTransaction().replace(R.id.playback_controls_fragment_container, Fragments.Builder.buildAudioFragment(serverFile,getAudioShare(),getAudioFiles())).commit(); + getFragmentManager().beginTransaction().replace(R.id.playback_controls_fragment_container, Fragments.Builder.buildAudioFragment(serverFile, getAudioShare(), getAudioFiles())).commit(); } private void setUpRows() { @@ -180,7 +175,7 @@ public void onActionClicked(Action action) { setAdapter(mRowsAdapter); } - private void setDataSource(){ + private void setDataSource() { try { mediaPlayer.setDataSource(getActivity(), getFileUri()); } catch (IOException e) { @@ -188,14 +183,14 @@ private void setDataSource(){ } } - private void prepareAudio(){ + private void prepareAudio() { try { mediaPlayer.prepare(); } catch (IOException e) { e.printStackTrace(); } } - + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public void togglePlayPause(boolean isPaused) { if (isPaused) { diff --git a/src/main/java/org/amahi/anywhere/tv/fragment/TvPlaybackVideoFragment.java b/src/main/java/org/amahi/anywhere/tv/fragment/TvPlaybackVideoFragment.java index f40d2d010..dca14f94f 100644 --- a/src/main/java/org/amahi/anywhere/tv/fragment/TvPlaybackVideoFragment.java +++ b/src/main/java/org/amahi/anywhere/tv/fragment/TvPlaybackVideoFragment.java @@ -74,34 +74,26 @@ public class TvPlaybackVideoFragment extends PlaybackFragment { private static final int DEFAULT_UPDATE_PERIOD = 1000; private static final int UPDATE_PERIOD = 16; - + @Inject + ServerClient serverClient; private SurfaceHolder mSurfaceHolder; private MediaPlayer mediaPlayer; private LibVLC mLibVlc; - private Handler mHandler; private Runnable mRunnable; private Object mSavedState; - private PlaybackControlsRow mPlaybackControlsRow; - private int mCurrentPlaybackState; private int mDuration; - private ArrayList mVideoList; - private ArrayObjectAdapter mRowsAdapter; private ArrayObjectAdapter mPrimaryActionsAdapter; - private PlaybackControlsRow.SkipPreviousAction mSkipPreviousAction; private PlaybackControlsRow.PlayPauseAction mPlayPauseAction; private PlaybackControlsRow.FastForwardAction mFastForwardAction; private PlaybackControlsRow.RewindAction mRewindAction; private PlaybackControlsRow.SkipNextAction mSkipNextAction; - @Inject - ServerClient serverClient; - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -135,8 +127,8 @@ public void onEvent(MediaPlayer.Event event) { setOnItemViewClickedListener(new OnItemViewClickedListener() { @Override public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item, RowPresenter.ViewHolder rowViewHolder, Row row) { - if(item instanceof ServerFile){ - ServerFile serverFile = (ServerFile)item; + if (item instanceof ServerFile) { + ServerFile serverFile = (ServerFile) item; replaceFragment(serverFile); } } @@ -164,7 +156,7 @@ private ArrayList setAllVideoFiles() { } private void replaceFragment(ServerFile serverFile) { - getFragmentManager().beginTransaction().replace(R.id.playback_controls_fragment_container, Fragments.Builder.buildVideoFragment(serverFile,getVideoShare(),getVideoFiles())).commit(); + getFragmentManager().beginTransaction().replace(R.id.playback_controls_fragment_container, Fragments.Builder.buildVideoFragment(serverFile, getVideoShare(), getVideoFiles())).commit(); } private boolean isVideo(ServerFile serverFile) { @@ -263,21 +255,21 @@ public void onActionClicked(Action action) { setAdapter(mRowsAdapter); } - private void addOtherRows(){ + private void addOtherRows() { ArrayObjectAdapter adapter = new ArrayObjectAdapter(new MainTVPresenter(getActivity(), serverClient, getVideoShare())); - for(ServerFile serverFile:mVideoList) adapter.add(serverFile); + for (ServerFile serverFile : mVideoList) adapter.add(serverFile); - mRowsAdapter.add(new ListRow(getHeader(),adapter)); + mRowsAdapter.add(new ListRow(getHeader(), adapter)); } - private HeaderItem getHeader(){ + private HeaderItem getHeader() { HeaderItem headerItem; - if(getVideoFile().getParentFile()==null) - headerItem = new HeaderItem("Video(s) in "+getVideoShare().getName()); + if (getVideoFile().getParentFile() == null) + headerItem = new HeaderItem("Video(s) in " + getVideoShare().getName()); else - headerItem = new HeaderItem("Video(s) in "+getVideoFile().getParentFile().getName()); + headerItem = new HeaderItem("Video(s) in " + getVideoFile().getParentFile().getName()); return headerItem; } @@ -292,7 +284,7 @@ public void togglePlayPause(boolean isPaused) { } public void rewind() { - if(mPlaybackControlsRow.getCurrentTime() - (10*1000)>0){ + if (mPlaybackControlsRow.getCurrentTime() - (10 * 1000) > 0) { mediaPlayer.setTime(mPlaybackControlsRow.getCurrentTime() - (10 * 1000)); mPlaybackControlsRow.setCurrentTime((int) mediaPlayer.getTime()); } @@ -336,12 +328,12 @@ private void addPlaybackControlsRow() { mFastForwardAction = new PlaybackControlsRow.FastForwardAction(getActivity()); mSkipNextAction = new PlaybackControlsRow.SkipNextAction(getActivity()); mSkipPreviousAction = new PlaybackControlsRow.SkipPreviousAction(getActivity()); - if(!isMetadataAvailable()) + if (!isMetadataAvailable()) mPrimaryActionsAdapter.add(mSkipPreviousAction); mPrimaryActionsAdapter.add(mRewindAction); mPrimaryActionsAdapter.add(mPlayPauseAction); mPrimaryActionsAdapter.add(mFastForwardAction); - if(!isMetadataAvailable()) + if (!isMetadataAvailable()) mPrimaryActionsAdapter.add(mSkipNextAction); playbackStateChanged(); } @@ -446,11 +438,11 @@ public void onDestroy() { mediaPlayer = null; } - public PlaybackControlsRow.PlayPauseAction getmPlayPauseAction(){ + public PlaybackControlsRow.PlayPauseAction getmPlayPauseAction() { return mPlayPauseAction; } - public Object getmSavedState(){ + public Object getmSavedState() { return mSavedState; } -} \ No newline at end of file +} diff --git a/src/main/java/org/amahi/anywhere/tv/presenter/AudioDetailsDescriptionPresenter.java b/src/main/java/org/amahi/anywhere/tv/presenter/AudioDetailsDescriptionPresenter.java index 72bf243a5..3691fad1e 100644 --- a/src/main/java/org/amahi/anywhere/tv/presenter/AudioDetailsDescriptionPresenter.java +++ b/src/main/java/org/amahi/anywhere/tv/presenter/AudioDetailsDescriptionPresenter.java @@ -13,23 +13,22 @@ public class AudioDetailsDescriptionPresenter extends AbstractDetailsDescriptionPresenter { private Context mContext; - public AudioDetailsDescriptionPresenter(Context context){ + public AudioDetailsDescriptionPresenter(Context context) { this.mContext = context; } @Override protected void onBindDescription(ViewHolder viewHolder, Object item) { - AudioMetadataRetrievedEvent event = (AudioMetadataRetrievedEvent)item; + AudioMetadataRetrievedEvent event = (AudioMetadataRetrievedEvent) item; - if(event.getAudioTitle()!=null) + if (event.getAudioTitle() != null) viewHolder.getTitle().setText(event.getAudioTitle()); else viewHolder.getTitle().setText(event.getServerFile().getName()); - if(event.getAudioAlbum()!=null && event.getAudioArtist()!=null){ - viewHolder.getSubtitle().setText(event.getAudioAlbum()+" - "+event.getAudioArtist()); - } - else + if (event.getAudioAlbum() != null && event.getAudioArtist() != null) { + viewHolder.getSubtitle().setText(event.getAudioAlbum() + " - " + event.getAudioArtist()); + } else viewHolder.getSubtitle().setText(getDate(event.getServerFile())); viewHolder.getBody().setText(getSize(event.getServerFile())); diff --git a/src/main/java/org/amahi/anywhere/tv/presenter/IconHeaderPresenter.java b/src/main/java/org/amahi/anywhere/tv/presenter/IconHeaderPresenter.java index 9627923db..d52c1433a 100644 --- a/src/main/java/org/amahi/anywhere/tv/presenter/IconHeaderPresenter.java +++ b/src/main/java/org/amahi/anywhere/tv/presenter/IconHeaderPresenter.java @@ -42,10 +42,10 @@ public class IconHeaderPresenter extends RowHeaderPresenter { @Override public ViewHolder onCreateViewHolder(ViewGroup parent) { mUnselectedAlpha = parent.getResources() - .getFraction(R.fraction.lb_browse_header_unselect_alpha, 1, 1); + .getFraction(R.fraction.lb_browse_header_unselect_alpha, 1, 1); LayoutInflater inflater = (LayoutInflater) parent.getContext() - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); View view = inflater.inflate(R.layout.tv_header_item, null); view.setAlpha(mUnselectedAlpha); @@ -79,6 +79,6 @@ public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) { @Override protected void onSelectLevelChanged(RowHeaderPresenter.ViewHolder holder) { holder.view.setAlpha(mUnselectedAlpha + holder.getSelectLevel() * - (1.0f - mUnselectedAlpha)); + (1.0f - mUnselectedAlpha)); } } diff --git a/src/main/java/org/amahi/anywhere/tv/presenter/MainTVPresenter.java b/src/main/java/org/amahi/anywhere/tv/presenter/MainTVPresenter.java index c83238175..6405c2228 100644 --- a/src/main/java/org/amahi/anywhere/tv/presenter/MainTVPresenter.java +++ b/src/main/java/org/amahi/anywhere/tv/presenter/MainTVPresenter.java @@ -83,9 +83,9 @@ public MainTVPresenter(Context context, ServerClient serverClient, ServerShare p @Override public Presenter.ViewHolder onCreateViewHolder(ViewGroup parent) { mDefaultBackgroundColor = - ContextCompat.getColor(parent.getContext(), R.color.background_secondary); + ContextCompat.getColor(parent.getContext(), R.color.background_secondary); mSelectedBackgroundColor = - ContextCompat.getColor(parent.getContext(), R.color.primary); + ContextCompat.getColor(parent.getContext(), R.color.primary); ImageCardView cardView = new ImageCardView(parent.getContext()) { @Override public void setSelected(boolean selected) { @@ -165,7 +165,7 @@ private void populateData(ServerFile serverFile, ViewHolder viewHolder) { if (isImage(serverFile)) { setUpImageIcon(serverFile, viewHolder.mCardView.getMainImageView(), getImageUri(serverFile)); } else if (isAudio(serverFile)) { - AudioMetadataRetrievingTask.execute(getImageUri(serverFile), serverFile,viewHolder); + AudioMetadataRetrievingTask.execute(getImageUri(serverFile), serverFile, viewHolder); } else { setUpDrawable(serverFile, viewHolder); } @@ -229,11 +229,11 @@ private boolean isVideo(ServerFile file) { private void setUpImageIcon(ServerFile file, ImageView fileIconView, Uri url) { Glide.with(fileIconView.getContext()) - .load(url.toString()) - .diskCacheStrategy(DiskCacheStrategy.ALL) - .centerCrop() - .placeholder(Mimes.getTVFileIcon(file)) - .into(fileIconView); + .load(url.toString()) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .centerCrop() + .placeholder(Mimes.getTVFileIcon(file)) + .into(fileIconView); } private Uri getImageUri(ServerFile file) { @@ -257,7 +257,7 @@ public class ViewHolder extends Presenter.ViewHolder { ViewHolder(View view) { super(view); mCardView = (ImageCardView) view; - mCardView.getMainImageView().setImageDrawable(ContextCompat.getDrawable(mContext,R.drawable.tv_ic_audio)); + mCardView.getMainImageView().setImageDrawable(ContextCompat.getDrawable(mContext, R.drawable.tv_ic_audio)); } } -} \ No newline at end of file +} diff --git a/src/main/java/org/amahi/anywhere/util/AudioMetadataFormatter.java b/src/main/java/org/amahi/anywhere/util/AudioMetadataFormatter.java index 778f2a5e8..c443c3c34 100644 --- a/src/main/java/org/amahi/anywhere/util/AudioMetadataFormatter.java +++ b/src/main/java/org/amahi/anywhere/util/AudioMetadataFormatter.java @@ -40,14 +40,14 @@ public AudioMetadataFormatter(String audioTitle, String audioArtist, String audi this.audioAlbum = audioAlbum; } - public void setDuration(long duration) { - this.duration = duration; - } - public long getDuration() { return duration; } + public void setDuration(long duration) { + this.duration = duration; + } + public String getAudioTitle(ServerFile audioFile) { if (TextUtils.isEmpty(audioTitle)) { return audioFile.getName(); diff --git a/src/main/java/org/amahi/anywhere/util/CastOptionsProvider.java b/src/main/java/org/amahi/anywhere/util/CastOptionsProvider.java index b8a9497bc..ccf01c167 100644 --- a/src/main/java/org/amahi/anywhere/util/CastOptionsProvider.java +++ b/src/main/java/org/amahi/anywhere/util/CastOptionsProvider.java @@ -37,25 +37,25 @@ */ public class CastOptionsProvider implements OptionsProvider { - @Override - public CastOptions getCastOptions(Context appContext) { - NotificationOptions notificationOptions = new NotificationOptions.Builder() - .setTargetActivityClassName(ExpandedControlsActivity.class.getName()) - .build(); - CastMediaOptions mediaOptions = new CastMediaOptions.Builder() - .setNotificationOptions(notificationOptions) - .setExpandedControllerActivityClassName(ExpandedControlsActivity.class.getName()) - .build(); - - return new CastOptions.Builder() - .setReceiverApplicationId(BuildConfig.CHROMECAST_APP_ID) - .setCastMediaOptions(mediaOptions) - .build(); - } - - @Override - public List getAdditionalSessionProviders(Context context) { - return null; - } + @Override + public CastOptions getCastOptions(Context appContext) { + NotificationOptions notificationOptions = new NotificationOptions.Builder() + .setTargetActivityClassName(ExpandedControlsActivity.class.getName()) + .build(); + CastMediaOptions mediaOptions = new CastMediaOptions.Builder() + .setNotificationOptions(notificationOptions) + .setExpandedControllerActivityClassName(ExpandedControlsActivity.class.getName()) + .build(); + + return new CastOptions.Builder() + .setReceiverApplicationId(BuildConfig.CHROMECAST_APP_ID) + .setCastMediaOptions(mediaOptions) + .build(); + } + + @Override + public List getAdditionalSessionProviders(Context context) { + return null; + } } diff --git a/src/main/java/org/amahi/anywhere/util/Downloader.java b/src/main/java/org/amahi/anywhere/util/Downloader.java index 8c80ca45d..821e0eca4 100644 --- a/src/main/java/org/amahi/anywhere/util/Downloader.java +++ b/src/main/java/org/amahi/anywhere/util/Downloader.java @@ -27,12 +27,13 @@ import android.database.Cursor; import android.net.Uri; import android.os.Environment; -import java.io.File; import org.amahi.anywhere.bus.BusProvider; import org.amahi.anywhere.bus.FileDownloadFailedEvent; import org.amahi.anywhere.bus.FileDownloadedEvent; +import java.io.File; + import javax.inject.Inject; import javax.inject.Singleton; @@ -67,16 +68,16 @@ private void setUpDownloadReceiver() { } private void startDownloading(Uri downloadUri, String downloadName) { - + //code to delete the file if it already exists - File file = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)+"/"+downloadName); - if(file.exists()) - file.delete(); - + File file = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS) + "/" + downloadName); + if (file.exists()) + file.delete(); + DownloadManager.Request downloadRequest = new DownloadManager.Request(downloadUri) - .setDestinationInExternalFilesDir(context, Environment.DIRECTORY_DOWNLOADS, downloadName) - .setVisibleInDownloadsUi(false) - .setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN); + .setDestinationInExternalFilesDir(context, Environment.DIRECTORY_DOWNLOADS, downloadName) + .setVisibleInDownloadsUi(false) + .setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN); this.downloadId = getDownloadManager(context).enqueue(downloadRequest); } @@ -100,18 +101,18 @@ private boolean isDownloadCurrent(Intent intent) { private void finishDownloading() { DownloadManager.Query downloadQuery = new DownloadManager.Query() - .setFilterById(downloadId); + .setFilterById(downloadId); Cursor downloadInformation = getDownloadManager(context).query(downloadQuery); downloadInformation.moveToFirst(); int downloadStatus = downloadInformation.getInt( - downloadInformation.getColumnIndex(DownloadManager.COLUMN_STATUS)); + downloadInformation.getColumnIndex(DownloadManager.COLUMN_STATUS)); if (downloadStatus == DownloadManager.STATUS_SUCCESSFUL) { String downloadUri = downloadInformation.getString( - downloadInformation.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)); + downloadInformation.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)); BusProvider.getBus().post(new FileDownloadedEvent(Uri.parse(downloadUri))); } else { diff --git a/src/main/java/org/amahi/anywhere/util/Fragments.java b/src/main/java/org/amahi/anywhere/util/Fragments.java index bfcf2132c..4e20c6a0d 100644 --- a/src/main/java/org/amahi/anywhere/util/Fragments.java +++ b/src/main/java/org/amahi/anywhere/util/Fragments.java @@ -47,6 +47,7 @@ private Fragments() { public static final class Arguments { public static final String SERVER_FILE = "server_file"; public static final String SERVER_SHARE = "server_share"; + private Arguments() { } } @@ -143,9 +144,9 @@ public void set(Fragment fragment, int fragmentContainerId) { } fragmentManager - .beginTransaction() - .add(fragmentContainerId, fragment) - .commit(); + .beginTransaction() + .add(fragmentContainerId, fragment) + .commit(); } private boolean isSet(int fragmentContainerId) { @@ -154,17 +155,17 @@ private boolean isSet(int fragmentContainerId) { public void replace(Fragment fragment, int fragmentContainerId) { fragmentManager - .beginTransaction() - .replace(fragmentContainerId, fragment) - .commit(); + .beginTransaction() + .replace(fragmentContainerId, fragment) + .commit(); } public void replaceBackstacked(Fragment fragment, int fragmentContainerId) { fragmentManager - .beginTransaction() - .replace(fragmentContainerId, fragment) - .addToBackStack(null) - .commit(); + .beginTransaction() + .replace(fragmentContainerId, fragment) + .addToBackStack(null) + .commit(); } } } diff --git a/src/main/java/org/amahi/anywhere/util/FullScreenHelper.java b/src/main/java/org/amahi/anywhere/util/FullScreenHelper.java index ab8a4f4d9..5d140f89e 100644 --- a/src/main/java/org/amahi/anywhere/util/FullScreenHelper.java +++ b/src/main/java/org/amahi/anywhere/util/FullScreenHelper.java @@ -47,11 +47,11 @@ public class FullScreenHelper { @Override public void run() { mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE - | View.SYSTEM_UI_FLAG_FULLSCREEN - | View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); + | View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); } }; private ActionBar actionBar; @@ -161,7 +161,7 @@ public void hide() { public void show() { // Show the system bar mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); mVisible = true; // Schedule a runnable to display UI elements after a delay diff --git a/src/main/java/org/amahi/anywhere/util/Identifier.java b/src/main/java/org/amahi/anywhere/util/Identifier.java index 604259a80..9ca69c93d 100644 --- a/src/main/java/org/amahi/anywhere/util/Identifier.java +++ b/src/main/java/org/amahi/anywhere/util/Identifier.java @@ -17,12 +17,12 @@ private Identifier() { public static String getUserAgent(Context context) { return String.format(Locale.US, Format.USER_AGENT, - Android.getApplicationVersion(), - Android.getVersion(), - Android.getDeviceName(), - Android.getDeviceScreenSize(context), - Android.getDeviceScreenHeight(context), - Android.getDeviceScreenWidth(context)); + Android.getApplicationVersion(), + Android.getVersion(), + Android.getDeviceName(), + Android.getDeviceScreenSize(context), + Android.getDeviceScreenHeight(context), + Android.getDeviceScreenWidth(context)); } public static String getUserAgent(Context context, Map fields) { @@ -44,6 +44,7 @@ public static String getUserAgent(Context context, Map fields) { private static final class Format { public static final String USER_AGENT = "AmahiAnywhere/%s (Android %s; %s) Size/%.1f Resolution/%dx%d"; public static final String USER_AGENT_FIELD = "%s/%s"; + private Format() { } } diff --git a/src/main/java/org/amahi/anywhere/util/Intents.java b/src/main/java/org/amahi/anywhere/util/Intents.java index 9858661f5..38d111863 100644 --- a/src/main/java/org/amahi/anywhere/util/Intents.java +++ b/src/main/java/org/amahi/anywhere/util/Intents.java @@ -64,6 +64,7 @@ public static final class Extras { public static final String SERVER_FILES = "server_files"; public static final String SERVER_SHARE = "server_share"; public static final String IMAGE_URIS = "image_uris"; + private Extras() { } } @@ -72,6 +73,7 @@ private static final class Uris { static final String EMAIL = "mailto:%s?subject=%s"; static final String GOOGLE_PLAY = "market://details?id=%s"; static final String GOOGLE_PLAY_SEARCH = "market://search?q=%s"; + private Uris() { } } @@ -159,8 +161,8 @@ public boolean isServerFileOpeningSupported(ServerFile file) { PackageManager packageManager = context.getPackageManager(); List applications = packageManager.queryIntentActivities( - buildServerFileOpeningIntent(file), - PackageManager.MATCH_DEFAULT_ONLY); + buildServerFileOpeningIntent(file), + PackageManager.MATCH_DEFAULT_ONLY); return !applications.isEmpty(); } @@ -219,20 +221,20 @@ public Intent buildGooglePlaySearchIntent(String search) { return intent; } - public Intent buildMediaPickerIntent () { + public Intent buildMediaPickerIntent() { Intent intent = new Intent(Intent.ACTION_PICK, - MediaStore.Images.Media.EXTERNAL_CONTENT_URI); + MediaStore.Images.Media.EXTERNAL_CONTENT_URI); intent.setType("image/* video/*"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[] {"image/*", "video/*"}); + intent.putExtra(Intent.EXTRA_MIME_TYPES, new String[]{"image/*", "video/*"}); } intent = Intent.createChooser(intent, context.getString(R.string.message_media_upload)); return intent; } public Intent buildCameraIntent() { - return new Intent(MediaStore.ACTION_IMAGE_CAPTURE); - } + return new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + } public Intent buildUploadServiceIntent(Uri uri) { ArrayList uris = new ArrayList<>(); @@ -240,7 +242,7 @@ public Intent buildUploadServiceIntent(Uri uri) { return buildUploadServiceIntent(uris); } - public Intent buildUploadServiceIntent(ArrayList uris) { + public Intent buildUploadServiceIntent(ArrayList uris) { Intent uploadService = new Intent(context, UploadService.class); uploadService.putParcelableArrayListExtra(Extras.IMAGE_URIS, uris); return uploadService; diff --git a/src/main/java/org/amahi/anywhere/util/MediaNotificationManager.java b/src/main/java/org/amahi/anywhere/util/MediaNotificationManager.java index 619832283..dbfddefe2 100644 --- a/src/main/java/org/amahi/anywhere/util/MediaNotificationManager.java +++ b/src/main/java/org/amahi/anywhere/util/MediaNotificationManager.java @@ -48,31 +48,63 @@ */ public class MediaNotificationManager extends BroadcastReceiver { - private static final int NOTIFICATION_ID = 412; - private static final int REQUEST_CODE = 100; - public static final String ACTION_PAUSE = "org.amahi.anywhere.pause"; public static final String ACTION_PLAY = "org.amahi.anywhere.play"; public static final String ACTION_PREV = "org.amahi.anywhere.prev"; public static final String ACTION_NEXT = "org.amahi.anywhere.next"; + private static final int NOTIFICATION_ID = 412; + private static final int REQUEST_CODE = 100; private static final String TAG = "notification_manager"; private final AudioService mService; + private final NotificationManagerCompat mNotificationManager; + private final PendingIntent mPauseIntent; + private final PendingIntent mPlayIntent; + private final PendingIntent mPreviousIntent; + private final PendingIntent mNextIntent; private MediaSessionCompat.Token mSessionToken; private MediaControllerCompat mController; private MediaControllerCompat.TransportControls mTransportControls; - private PlaybackStateCompat mPlaybackState; private MediaMetadataCompat mMetadata; + private boolean mStarted = false; + private final MediaControllerCompat.Callback mCb = new MediaControllerCompat.Callback() { + @Override + public void onPlaybackStateChanged(@NonNull PlaybackStateCompat state) { + mPlaybackState = state; + Log.d(TAG, "Received new playback state"); + if (state.getState() == PlaybackStateCompat.STATE_STOPPED || + state.getState() == PlaybackStateCompat.STATE_NONE) { + stopNotification(); + } else { + Notification notification = createNotification(); + if (notification != null) { + mNotificationManager.notify(NOTIFICATION_ID, notification); + } + } + } - private final NotificationManagerCompat mNotificationManager; - - private final PendingIntent mPauseIntent; - private final PendingIntent mPlayIntent; - private final PendingIntent mPreviousIntent; - private final PendingIntent mNextIntent; + @Override + public void onMetadataChanged(MediaMetadataCompat metadata) { + mMetadata = metadata; + Log.d(TAG, "Received new metadata"); + Notification notification = createNotification(); + if (notification != null) { + mNotificationManager.notify(NOTIFICATION_ID, notification); + } + } - private boolean mStarted = false; + @Override + public void onSessionDestroyed() { + super.onSessionDestroyed(); + Log.d(TAG, "Session was destroyed, resetting to the new session token"); + try { + updateSessionToken(); + } catch (RemoteException e) { + Log.e(TAG, "could not connect media controller", e); + } + } + }; public MediaNotificationManager(AudioService service) throws RemoteException { mService = service; @@ -82,13 +114,13 @@ public MediaNotificationManager(AudioService service) throws RemoteException { String pkg = mService.getPackageName(); mPauseIntent = PendingIntent.getBroadcast(mService, REQUEST_CODE, - new Intent(ACTION_PAUSE).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT); + new Intent(ACTION_PAUSE).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT); mPlayIntent = PendingIntent.getBroadcast(mService, REQUEST_CODE, - new Intent(ACTION_PLAY).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT); + new Intent(ACTION_PLAY).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT); mPreviousIntent = PendingIntent.getBroadcast(mService, REQUEST_CODE, - new Intent(ACTION_PREV).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT); + new Intent(ACTION_PREV).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT); mNextIntent = PendingIntent.getBroadcast(mService, REQUEST_CODE, - new Intent(ACTION_NEXT).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT); + new Intent(ACTION_NEXT).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT); // Cancel all notifications to handle the case where the Service was killed and // restarted by the system. @@ -169,7 +201,7 @@ public void onReceive(Context context, Intent intent) { private void updateSessionToken() throws RemoteException { MediaSessionCompat.Token freshToken = mService.getSessionToken(); if (mSessionToken == null && freshToken != null || - mSessionToken != null && !mSessionToken.equals(freshToken)) { + mSessionToken != null && !mSessionToken.equals(freshToken)) { if (mController != null) { mController.unregisterCallback(mCb); } @@ -184,44 +216,6 @@ private void updateSessionToken() throws RemoteException { } } - private final MediaControllerCompat.Callback mCb = new MediaControllerCompat.Callback() { - @Override - public void onPlaybackStateChanged(@NonNull PlaybackStateCompat state) { - mPlaybackState = state; - Log.d(TAG, "Received new playback state"); - if (state.getState() == PlaybackStateCompat.STATE_STOPPED || - state.getState() == PlaybackStateCompat.STATE_NONE) { - stopNotification(); - } else { - Notification notification = createNotification(); - if (notification != null) { - mNotificationManager.notify(NOTIFICATION_ID, notification); - } - } - } - - @Override - public void onMetadataChanged(MediaMetadataCompat metadata) { - mMetadata = metadata; - Log.d(TAG, "Received new metadata"); - Notification notification = createNotification(); - if (notification != null) { - mNotificationManager.notify(NOTIFICATION_ID, notification); - } - } - - @Override - public void onSessionDestroyed() { - super.onSessionDestroyed(); - Log.d(TAG, "Session was destroyed, resetting to the new session token"); - try { - updateSessionToken(); - } catch (RemoteException e) { - Log.e(TAG, "could not connect media controller", e); - } - } - }; - private Notification createNotification() { Log.d(TAG, "updateNotificationMetadata. mMetadata=" + mMetadata); if (mMetadata == null || mPlaybackState == null) { @@ -230,12 +224,12 @@ private Notification createNotification() { NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(mService); notificationBuilder.addAction(android.R.drawable.ic_media_previous, - mService.getString(R.string.label_previous), mPreviousIntent); + mService.getString(R.string.label_previous), mPreviousIntent); addPlayPauseAction(notificationBuilder); notificationBuilder.addAction(android.R.drawable.ic_media_next, - mService.getString(R.string.label_next), mNextIntent); + mService.getString(R.string.label_next), mNextIntent); MediaDescriptionCompat description = mMetadata.getDescription(); @@ -246,16 +240,16 @@ private Notification createNotification() { } notificationBuilder - .setStyle(new NotificationCompat.MediaStyle() - .setShowActionsInCompactView(1) // show only play/pause in compact view - .setMediaSession(mSessionToken)) - .setSmallIcon(getAudioPlayerNotificationIcon()) - .setLargeIcon(getAudioPlayerNotificationArtwork(audioAlbumArt)) - .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) - .setUsesChronometer(true) - .setContentIntent(mService.createContentIntent()) - .setContentTitle(description.getTitle()) - .setContentText(description.getSubtitle()); + .setStyle(new NotificationCompat.MediaStyle() + .setShowActionsInCompactView(1) // show only play/pause in compact view + .setMediaSession(mSessionToken)) + .setSmallIcon(getAudioPlayerNotificationIcon()) + .setLargeIcon(getAudioPlayerNotificationArtwork(audioAlbumArt)) + .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + .setUsesChronometer(true) + .setContentIntent(mService.createContentIntent()) + .setContentTitle(description.getTitle()) + .setContentText(description.getSubtitle()); setNotificationPlaybackState(notificationBuilder); return notificationBuilder.build(); @@ -299,16 +293,16 @@ private void setNotificationPlaybackState(NotificationCompat.Builder builder) { return; } if (mPlaybackState.getState() == PlaybackStateCompat.STATE_PLAYING - && mPlaybackState.getPosition() >= 0) { + && mPlaybackState.getPosition() >= 0) { builder - .setWhen(System.currentTimeMillis() - mPlaybackState.getPosition()) - .setShowWhen(true) - .setUsesChronometer(true); + .setWhen(System.currentTimeMillis() - mPlaybackState.getPosition()) + .setShowWhen(true) + .setUsesChronometer(true); } else { builder - .setWhen(0) - .setShowWhen(false) - .setUsesChronometer(false); + .setWhen(0) + .setShowWhen(false) + .setUsesChronometer(false); } // Make sure that the notification can be dismissed by the user when we are not playing: diff --git a/src/main/java/org/amahi/anywhere/util/NetworkUtils.java b/src/main/java/org/amahi/anywhere/util/NetworkUtils.java index d430fc88c..c1a975c05 100644 --- a/src/main/java/org/amahi/anywhere/util/NetworkUtils.java +++ b/src/main/java/org/amahi/anywhere/util/NetworkUtils.java @@ -32,33 +32,33 @@ */ public class NetworkUtils { - private Context context; + private Context context; - public NetworkUtils(Context context) { - this.context = context; - } + public NetworkUtils(Context context) { + this.context = context; + } - public NetworkInfo getNetwork() { - return getNetworkManager().getActiveNetworkInfo(); - } + public NetworkInfo getNetwork() { + return getNetworkManager().getActiveNetworkInfo(); + } - private ConnectivityManager getNetworkManager() { - return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - } + private ConnectivityManager getNetworkManager() { + return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + } - public boolean isNetworkConnected(NetworkInfo network) { - return (network != null) && network.isConnected(); - } + public boolean isNetworkConnected(NetworkInfo network) { + return (network != null) && network.isConnected(); + } - public boolean isUploadAllowed() { - NetworkInfo network = getNetwork(); - return isNetworkConnected(network) && - (network.getType() != ConnectivityManager.TYPE_MOBILE || - isUploadAllowedOnMobileData()); - } + public boolean isUploadAllowed() { + NetworkInfo network = getNetwork(); + return isNetworkConnected(network) && + (network.getType() != ConnectivityManager.TYPE_MOBILE || + isUploadAllowedOnMobileData()); + } - private boolean isUploadAllowedOnMobileData() { - return PreferenceManager.getDefaultSharedPreferences(context) - .getBoolean(context.getString(R.string.preference_key_upload_data), false); - } + private boolean isUploadAllowedOnMobileData() { + return PreferenceManager.getDefaultSharedPreferences(context) + .getBoolean(context.getString(R.string.preference_key_upload_data), false); + } } diff --git a/src/main/java/org/amahi/anywhere/util/ProgressRequestBody.java b/src/main/java/org/amahi/anywhere/util/ProgressRequestBody.java index b75052ddf..703fff390 100644 --- a/src/main/java/org/amahi/anywhere/util/ProgressRequestBody.java +++ b/src/main/java/org/amahi/anywhere/util/ProgressRequestBody.java @@ -38,68 +38,67 @@ * for file upload. */ public class ProgressRequestBody extends RequestBody { - private int mId; - private File mFile; - private int lastProgress = 0; - - private static final int DEFAULT_BUFFER_SIZE = 2048; - - public ProgressRequestBody(int id, File file) { - mId = id; - mFile = new File(file.getPath()); - } - - @Override - public MediaType contentType() { - // Only for uploading images - return MediaType.parse("image/*"); - } - - @Override - public long contentLength() throws IOException { - return mFile.length(); - } - - @Override - public void writeTo(BufferedSink sink) throws IOException { - long fileLength = mFile.length(); - byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; - FileInputStream in = new FileInputStream(mFile); - long uploaded = 0; - - //noinspection TryFinallyCanBeTryWithResources - try { - int read; - Handler handler = new Handler(Looper.getMainLooper()); - while ((read = in.read(buffer)) != -1) { - - uploaded += read; - sink.write(buffer, 0, read); - - // update progress on UI thread - handler.post(new ProgressUpdater(uploaded, fileLength)); - } - } finally { - in.close(); - } - } - - private class ProgressUpdater implements Runnable { - private long mUploaded; - private long mTotal; - - ProgressUpdater(long uploaded, long total) { - mUploaded = uploaded; - mTotal = total; - } - - @Override - public void run() { - int progress = (int) (100 * mUploaded / mTotal); - if (lastProgress != progress) { - lastProgress = progress; - BusProvider.getBus().post(new ServerFileUploadProgressEvent(mId, progress)); - } - } - } + private static final int DEFAULT_BUFFER_SIZE = 2048; + private int mId; + private File mFile; + private int lastProgress = 0; + + public ProgressRequestBody(int id, File file) { + mId = id; + mFile = new File(file.getPath()); + } + + @Override + public MediaType contentType() { + // Only for uploading images + return MediaType.parse("image/*"); + } + + @Override + public long contentLength() throws IOException { + return mFile.length(); + } + + @Override + public void writeTo(BufferedSink sink) throws IOException { + long fileLength = mFile.length(); + byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; + FileInputStream in = new FileInputStream(mFile); + long uploaded = 0; + + //noinspection TryFinallyCanBeTryWithResources + try { + int read; + Handler handler = new Handler(Looper.getMainLooper()); + while ((read = in.read(buffer)) != -1) { + + uploaded += read; + sink.write(buffer, 0, read); + + // update progress on UI thread + handler.post(new ProgressUpdater(uploaded, fileLength)); + } + } finally { + in.close(); + } + } + + private class ProgressUpdater implements Runnable { + private long mUploaded; + private long mTotal; + + ProgressUpdater(long uploaded, long total) { + mUploaded = uploaded; + mTotal = total; + } + + @Override + public void run() { + int progress = (int) (100 * mUploaded / mTotal); + if (lastProgress != progress) { + lastProgress = progress; + BusProvider.getBus().post(new ServerFileUploadProgressEvent(mId, progress)); + } + } + } } diff --git a/src/main/java/org/amahi/anywhere/util/RecyclerItemClickListener.java b/src/main/java/org/amahi/anywhere/util/RecyclerItemClickListener.java index 3588d35aa..17affcd41 100644 --- a/src/main/java/org/amahi/anywhere/util/RecyclerItemClickListener.java +++ b/src/main/java/org/amahi/anywhere/util/RecyclerItemClickListener.java @@ -31,13 +31,8 @@ import android.view.View; public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener { - private OnItemClickListener mListener; - - public interface OnItemClickListener { - public void onItemClick(View view, int position); - } - GestureDetector mGestureDetector; + private OnItemClickListener mListener; public RecyclerItemClickListener(Context context, OnItemClickListener listener) { mListener = listener; @@ -66,4 +61,8 @@ public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) { public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { } + + public interface OnItemClickListener { + public void onItemClick(View view, int position); + } } diff --git a/src/main/java/org/amahi/anywhere/util/Time.java b/src/main/java/org/amahi/anywhere/util/Time.java index 25087d3a5..027187cac 100644 --- a/src/main/java/org/amahi/anywhere/util/Time.java +++ b/src/main/java/org/amahi/anywhere/util/Time.java @@ -35,16 +35,16 @@ public static String getEpochTimeString(Date date) { return String.valueOf(date.getTime()); } + public static long getDuration(String videoUrl) { + MediaMetadataRetriever mmr = new MediaMetadataRetriever(); + mmr.setDataSource(videoUrl, new HashMap()); + return Long.parseLong(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)); + } + public static final class Format { public static final String RFC_1123 = "EEE, dd MMM yyyy HH:mm:ss zzz"; private Format() { } } - - public static long getDuration(String videoUrl) { - MediaMetadataRetriever mmr = new MediaMetadataRetriever(); - mmr.setDataSource(videoUrl, new HashMap()); - return Long.parseLong(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)); - } } diff --git a/src/main/java/org/amahi/anywhere/util/UploadManager.java b/src/main/java/org/amahi/anywhere/util/UploadManager.java index 647a83e58..abea08e83 100644 --- a/src/main/java/org/amahi/anywhere/util/UploadManager.java +++ b/src/main/java/org/amahi/anywhere/util/UploadManager.java @@ -42,117 +42,115 @@ * An Upload Manager that manages all the uploads one by one present in the queue. */ public class UploadManager { - private boolean isRunning = false; - - @Inject - public ServerClient serverClient; - - private Context context; - private ArrayList uploadFiles; - private UploadCallbacks uploadCallbacks; - - public - UploadManager(T context, ArrayList uploadFiles) { - - this.context = context; - this.uploadCallbacks = context; - this.uploadFiles = uploadFiles; - - setUpInjections(); - setUpBus(); - } - - private void setUpInjections() { - AmahiApplication.from(context).inject(this); - } - - private void setUpBus() { - BusProvider.getBus().register(this); - } - - public void tearDownBus() { - BusProvider.getBus().unregister(this); - } - - public void startUploading() { - if (!isRunning) { - isRunning = true; - processNextFile(); - } - } - - private void processNextFile() { - if (uploadFiles.isEmpty()) { - isRunning = false; - uploadCallbacks.uploadQueueFinished(); - } else { - UploadFile currentFile = uploadFiles.remove(0); - upload(currentFile); - } - } - - private void upload(UploadFile uploadFile) { - File image = new File(uploadFile.getPath()); - if (image.exists()) { - uploadCallbacks.uploadStarted(uploadFile.getId(), image.getName()); - serverClient.uploadFile(uploadFile.getId(), image, getUploadShareName(), - getUploadPath()); - } else { - uploadCallbacks.removeFileFromDb(uploadFile.getId()); - processNextFile(); - } - - } - - private String getUploadShareName() { - return PreferenceManager.getDefaultSharedPreferences(context) - .getString(context.getString(R.string.preference_key_upload_share), null); - } - - private String getUploadPath() { - return PreferenceManager.getDefaultSharedPreferences(context) - .getString(context.getString(R.string.preference_key_upload_path), null); - } - - - public void add(UploadFile uploadFile) { - uploadFiles.add(uploadFile); - } - - @Subscribe - public void onFileUploadProgressEvent(ServerFileUploadProgressEvent event) { - uploadCallbacks.uploadProgress(event.getId(), event.getProgress()); - } - - @Subscribe - public void onFileUploadCompleteEvent(ServerFileUploadCompleteEvent event) { - if (event.wasUploadSuccessful()) { - uploadCallbacks.removeFileFromDb(event.getId()); - uploadCallbacks.uploadSuccess(event.getId()); - } else { - uploadCallbacks.uploadError(event.getId()); - } - - final Handler handler = new Handler(); - handler.postDelayed(new Runnable() { - @Override - public void run() { - processNextFile(); - } - }, 500); - } - - public interface UploadCallbacks { - void uploadStarted(int id, String fileName); - - void uploadProgress(int id, int progress); - - void uploadSuccess(int id); - - void uploadError(int id); - - void removeFileFromDb(int id); - - void uploadQueueFinished(); - } + @Inject + public ServerClient serverClient; + private boolean isRunning = false; + private Context context; + private ArrayList uploadFiles; + private UploadCallbacks uploadCallbacks; + + public + UploadManager(T context, ArrayList uploadFiles) { + + this.context = context; + this.uploadCallbacks = context; + this.uploadFiles = uploadFiles; + + setUpInjections(); + setUpBus(); + } + + private void setUpInjections() { + AmahiApplication.from(context).inject(this); + } + + private void setUpBus() { + BusProvider.getBus().register(this); + } + + public void tearDownBus() { + BusProvider.getBus().unregister(this); + } + + public void startUploading() { + if (!isRunning) { + isRunning = true; + processNextFile(); + } + } + + private void processNextFile() { + if (uploadFiles.isEmpty()) { + isRunning = false; + uploadCallbacks.uploadQueueFinished(); + } else { + UploadFile currentFile = uploadFiles.remove(0); + upload(currentFile); + } + } + + private void upload(UploadFile uploadFile) { + File image = new File(uploadFile.getPath()); + if (image.exists()) { + uploadCallbacks.uploadStarted(uploadFile.getId(), image.getName()); + serverClient.uploadFile(uploadFile.getId(), image, getUploadShareName(), + getUploadPath()); + } else { + uploadCallbacks.removeFileFromDb(uploadFile.getId()); + processNextFile(); + } + + } + + private String getUploadShareName() { + return PreferenceManager.getDefaultSharedPreferences(context) + .getString(context.getString(R.string.preference_key_upload_share), null); + } + + private String getUploadPath() { + return PreferenceManager.getDefaultSharedPreferences(context) + .getString(context.getString(R.string.preference_key_upload_path), null); + } + + + public void add(UploadFile uploadFile) { + uploadFiles.add(uploadFile); + } + + @Subscribe + public void onFileUploadProgressEvent(ServerFileUploadProgressEvent event) { + uploadCallbacks.uploadProgress(event.getId(), event.getProgress()); + } + + @Subscribe + public void onFileUploadCompleteEvent(ServerFileUploadCompleteEvent event) { + if (event.wasUploadSuccessful()) { + uploadCallbacks.removeFileFromDb(event.getId()); + uploadCallbacks.uploadSuccess(event.getId()); + } else { + uploadCallbacks.uploadError(event.getId()); + } + + final Handler handler = new Handler(); + handler.postDelayed(new Runnable() { + @Override + public void run() { + processNextFile(); + } + }, 500); + } + + public interface UploadCallbacks { + void uploadStarted(int id, String fileName); + + void uploadProgress(int id, int progress); + + void uploadSuccess(int id); + + void uploadError(int id); + + void removeFileFromDb(int id); + + void uploadQueueFinished(); + } } diff --git a/src/main/java/org/amahi/anywhere/util/VideoSwipeGestures.java b/src/main/java/org/amahi/anywhere/util/VideoSwipeGestures.java index 1988e1c3b..3744ac02f 100644 --- a/src/main/java/org/amahi/anywhere/util/VideoSwipeGestures.java +++ b/src/main/java/org/amahi/anywhere/util/VideoSwipeGestures.java @@ -41,27 +41,13 @@ public class VideoSwipeGestures implements View.OnTouchListener { private final AudioManager audio; - private float volumePer; private final int maxVolume; + private float volumePer; private Activity activity; private PercentageView percentageView; private SeekView seekView; private float seekDistance = 0; private SeekControl seekControl; - - - public interface SeekControl { - int getCurrentPosition(); - - void seekTo(int time); - - int getDuration(); - } - - private enum Direction { - LEFT, RIGHT, UP, DOWN, NONE - } - private GestureDetector gestureDetector; public VideoSwipeGestures(Activity activity, SeekControl seekControl, FrameLayout container) { @@ -95,6 +81,64 @@ public boolean onTouch(View v, MotionEvent event) { return false; } + private void changeBrightness(float distance) { + WindowManager.LayoutParams layout = activity.getWindow().getAttributes(); + layout.screenBrightness += distance; + if (layout.screenBrightness > 1f) { + layout.screenBrightness = 1f; + } else if (layout.screenBrightness < 0f) { + layout.screenBrightness = 0f; + } + percentageView.setProgress((int) (layout.screenBrightness * 100)); + activity.getWindow().setAttributes(layout); + } + + private void changeVolume(float distance) { + float val = volumePer + distance; + if (val > 1f) { + val = 1f; + } else if (val < 0f) { + val = 0f; + } + percentageView.setProgress((int) (val * 100)); + audio.setStreamVolume(AudioManager.STREAM_MUSIC, Math.round(val * maxVolume), 0); + volumePer = val; + + } + + private void seek(float distance) { + seekDistance += distance; + if (seekControl != null && seekView != null) { + float seekValue = seekControl.getCurrentPosition() + distance; + if (seekValue > 0 && seekValue < seekControl.getDuration()) { + seekControl.seekTo((int) seekValue); + String displayText = String.format(Locale.getDefault(), + "%02d:%02d (%02d:%02d)", + (int) Math.abs(seekDistance / 60000), + (int) Math.abs((seekDistance % 60000) / 1000), + (int) (seekValue / 60000), + (int) ((seekValue % 60000) / 1000)); + if (seekDistance > 0) + seekView.setText("+" + displayText); + else + seekView.setText("-" + displayText); + } + } + } + + + private enum Direction { + LEFT, RIGHT, UP, DOWN, NONE + } + + public interface SeekControl { + int getCurrentPosition(); + + void seekTo(int time); + + int getDuration(); + } + private class CustomGestureDetect implements GestureDetector.OnGestureListener { private Direction direction = Direction.NONE; @@ -196,50 +240,4 @@ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float ve } - - private void changeBrightness(float distance) { - WindowManager.LayoutParams layout = activity.getWindow().getAttributes(); - layout.screenBrightness += distance; - if (layout.screenBrightness > 1f) { - layout.screenBrightness = 1f; - } else if (layout.screenBrightness < 0f) { - layout.screenBrightness = 0f; - } - percentageView.setProgress((int) (layout.screenBrightness * 100)); - activity.getWindow().setAttributes(layout); - } - - private void changeVolume(float distance) { - float val = volumePer + distance; - if (val > 1f) { - val = 1f; - } else if (val < 0f) { - val = 0f; - } - percentageView.setProgress((int) (val * 100)); - audio.setStreamVolume(AudioManager.STREAM_MUSIC, Math.round(val * maxVolume), 0); - volumePer = val; - - } - - private void seek(float distance) { - seekDistance += distance; - if (seekControl != null && seekView != null) { - float seekValue = seekControl.getCurrentPosition() + distance; - if (seekValue > 0 && seekValue < seekControl.getDuration()) { - seekControl.seekTo((int) seekValue); - String displayText = String.format(Locale.getDefault(), - "%02d:%02d (%02d:%02d)", - (int) Math.abs(seekDistance / 60000), - (int) Math.abs((seekDistance % 60000) / 1000), - (int) (seekValue / 60000), - (int) ((seekValue % 60000) / 1000)); - if (seekDistance > 0) - seekView.setText("+" + displayText); - else - seekView.setText("-" + displayText); - } - } - } - } diff --git a/src/main/java/org/amahi/anywhere/view/PercentageView.java b/src/main/java/org/amahi/anywhere/view/PercentageView.java index be6d32c5f..666efc5c8 100644 --- a/src/main/java/org/amahi/anywhere/view/PercentageView.java +++ b/src/main/java/org/amahi/anywhere/view/PercentageView.java @@ -40,14 +40,8 @@ public class PercentageView { public static final int VOLUME = 1; public static final int BRIGHTNESS = 2; - - @IntDef({VOLUME, BRIGHTNESS}) - @interface TYPE { - } - private ViewHolder viewHolder; private View view; - public PercentageView(FrameLayout parentView) { LayoutInflater inflater = (LayoutInflater) parentView.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inflater.inflate(R.layout.percentage_view, parentView, false); @@ -59,29 +53,17 @@ public View getView() { return view; } - private class ViewHolder { - private ProgressBar progressBar; - private TextView valuePercent; - private ImageView icon; - - ViewHolder(View itemView) { - progressBar = (ProgressBar) itemView.findViewById(R.id.progress_bar); - icon = (ImageView) itemView.findViewById(R.id.type_icon); - valuePercent = (TextView) itemView.findViewById(R.id.value_percent); - } - } - public void setType(@TYPE int type) { switch (type) { case VOLUME: viewHolder.icon.setImageResource(R.drawable.ic_volume_up); viewHolder.progressBar.getProgressDrawable().setColorFilter( - Color.BLUE, android.graphics.PorterDuff.Mode.SRC_IN); + Color.BLUE, android.graphics.PorterDuff.Mode.SRC_IN); break; case BRIGHTNESS: viewHolder.icon.setImageResource(R.drawable.ic_brightness); viewHolder.progressBar.getProgressDrawable().setColorFilter( - Color.YELLOW, android.graphics.PorterDuff.Mode.SRC_IN); + Color.YELLOW, android.graphics.PorterDuff.Mode.SRC_IN); break; } } @@ -102,5 +84,21 @@ public void show() { public boolean isShowing() { return view.getVisibility() == View.VISIBLE; } + + @IntDef({VOLUME, BRIGHTNESS}) + @interface TYPE { + } + + private class ViewHolder { + private ProgressBar progressBar; + private TextView valuePercent; + private ImageView icon; + + ViewHolder(View itemView) { + progressBar = (ProgressBar) itemView.findViewById(R.id.progress_bar); + icon = (ImageView) itemView.findViewById(R.id.type_icon); + valuePercent = (TextView) itemView.findViewById(R.id.value_percent); + } + } } diff --git a/src/main/java/org/amahi/anywhere/view/TouchImageView.java b/src/main/java/org/amahi/anywhere/view/TouchImageView.java index 506b741f3..78fd2a325 100644 --- a/src/main/java/org/amahi/anywhere/view/TouchImageView.java +++ b/src/main/java/org/amahi/anywhere/view/TouchImageView.java @@ -99,15 +99,15 @@ public boolean onTouch(View v, MotionEvent event) { float deltaY = curr.y - last.y; if (deltaX != 0f || deltaY != 0f) { float fixTransX = getFixDragTrans(deltaX, viewWidth, - origWidth * saveScale); + origWidth * saveScale); float fixTransY = getFixDragTrans(deltaY, viewHeight, - origHeight * saveScale); + origHeight * saveScale); if (saveScale > 1f) { matrix.getValues(m); float absTransX = Math.abs(m[Matrix.MTRANS_X]); float transXMax = (origWidth * (saveScale - 1f)); if ((transXMax - absTransX < 0.5f && fixTransX < 0f) - || (absTransX < 0.5f && fixTransX > 0f)) + || (absTransX < 0.5f && fixTransX > 0f)) getParent().requestDisallowInterceptTouchEvent(false); else getParent().requestDisallowInterceptTouchEvent(true); @@ -216,7 +216,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // Rescales image on rotation // if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight - || viewWidth == 0 || viewHeight == 0) + || viewWidth == 0 || viewHeight == 0) return; oldMeasuredHeight = viewHeight; oldMeasuredWidth = viewWidth; @@ -227,7 +227,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { Drawable drawable = getDrawable(); if (drawable == null || drawable.getIntrinsicWidth() == 0 - || drawable.getIntrinsicHeight() == 0) + || drawable.getIntrinsicHeight() == 0) return; int bmWidth = drawable.getIntrinsicWidth(); int bmHeight = drawable.getIntrinsicHeight(); @@ -241,9 +241,9 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // Center the image float redundantYSpace = (float) viewHeight - - (scale * (float) bmHeight); + - (scale * (float) bmHeight); float redundantXSpace = (float) viewWidth - - (scale * (float) bmWidth); + - (scale * (float) bmWidth); redundantYSpace /= (float) 2; redundantXSpace /= (float) 2; @@ -263,7 +263,7 @@ private enum State { } private class ScaleListener extends - ScaleGestureDetector.SimpleOnScaleGestureListener { + ScaleGestureDetector.SimpleOnScaleGestureListener { @Override public boolean onScaleBegin(ScaleGestureDetector detector) { mode = State.ZOOM; @@ -284,15 +284,15 @@ public boolean onScale(ScaleGestureDetector detector) { } if (origWidth * saveScale <= viewWidth - || origHeight * saveScale <= viewHeight) + || origHeight * saveScale <= viewHeight) matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2, - viewHeight / 2); + viewHeight / 2); else matrix.postScale(mScaleFactor, mScaleFactor, - detector.getFocusX(), detector.getFocusY()); + detector.getFocusX(), detector.getFocusY()); fixTrans(); return true; } } -} \ No newline at end of file +} diff --git a/src/main/res/drawable/ic_add.xml b/src/main/res/drawable/ic_add.xml index 6b6146ecc..cd5c04578 100644 --- a/src/main/res/drawable/ic_add.xml +++ b/src/main/res/drawable/ic_add.xml @@ -1,9 +1,9 @@ + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" /> diff --git a/src/main/res/drawable/ic_brightness.xml b/src/main/res/drawable/ic_brightness.xml index 67118763f..e104f0faa 100644 --- a/src/main/res/drawable/ic_brightness.xml +++ b/src/main/res/drawable/ic_brightness.xml @@ -2,13 +2,12 @@ + android:viewportHeight="24" + android:viewportWidth="24"> - + - \ No newline at end of file + diff --git a/src/main/res/drawable/ic_camera.xml b/src/main/res/drawable/ic_camera.xml index c872f1670..a1a55a589 100644 --- a/src/main/res/drawable/ic_camera.xml +++ b/src/main/res/drawable/ic_camera.xml @@ -1,12 +1,12 @@ + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0" /> + android:pathData="M9,2L7.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2L9,2zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z" /> diff --git a/src/main/res/drawable/ic_cloud_upload.xml b/src/main/res/drawable/ic_cloud_upload.xml index 086281669..8df209ae1 100644 --- a/src/main/res/drawable/ic_cloud_upload.xml +++ b/src/main/res/drawable/ic_cloud_upload.xml @@ -1,9 +1,9 @@ + android:width="24dp" + android:height="24dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0"> + android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM14,13v4h-4v-4H7l5,-5 5,5h-3z" /> diff --git a/src/main/res/drawable/ic_delete.xml b/src/main/res/drawable/ic_delete.xml index 650c02224..acc5ba61b 100644 --- a/src/main/res/drawable/ic_delete.xml +++ b/src/main/res/drawable/ic_delete.xml @@ -2,12 +2,11 @@ + android:viewportHeight="24" + android:viewportWidth="24"> - - \ No newline at end of file + + diff --git a/src/main/res/drawable/ic_volume_up.xml b/src/main/res/drawable/ic_volume_up.xml index 2ddbcc801..23fe61f5f 100644 --- a/src/main/res/drawable/ic_volume_up.xml +++ b/src/main/res/drawable/ic_volume_up.xml @@ -2,14 +2,13 @@ + android:viewportHeight="24" + android:viewportWidth="24"> - - \ No newline at end of file + + diff --git a/src/main/res/drawable/percentage_bar.xml b/src/main/res/drawable/percentage_bar.xml index b005cbb54..2b45fd9f1 100644 --- a/src/main/res/drawable/percentage_bar.xml +++ b/src/main/res/drawable/percentage_bar.xml @@ -3,7 +3,7 @@ - + @@ -12,8 +12,8 @@ android:clipOrientation="vertical" android:gravity="bottom"> - + - \ No newline at end of file + diff --git a/src/main/res/drawable/splash_page.xml b/src/main/res/drawable/splash_page.xml index 406b2292f..8c76f09e7 100644 --- a/src/main/res/drawable/splash_page.xml +++ b/src/main/res/drawable/splash_page.xml @@ -1,13 +1,12 @@ - + + android:src="@drawable/ic_banner" /> diff --git a/src/main/res/layout/activity_intro.xml b/src/main/res/layout/activity_intro.xml index c41a34589..c58ae69d0 100644 --- a/src/main/res/layout/activity_intro.xml +++ b/src/main/res/layout/activity_intro.xml @@ -1,9 +1,11 @@ + android:layout_width="match_parent" + android:layout_height="match_parent"> + - \ No newline at end of file + android:layout_height="match_parent" /> + diff --git a/src/main/res/layout/activity_main_tv.xml b/src/main/res/layout/activity_main_tv.xml index 778a0b9ea..6190508f0 100644 --- a/src/main/res/layout/activity_main_tv.xml +++ b/src/main/res/layout/activity_main_tv.xml @@ -1,6 +1,5 @@ - + android:layout_width="match_parent" + android:layout_height="match_parent" /> diff --git a/src/main/res/layout/activity_native_video.xml b/src/main/res/layout/activity_native_video.xml index 958c57aee..e423cf838 100644 --- a/src/main/res/layout/activity_native_video.xml +++ b/src/main/res/layout/activity_native_video.xml @@ -1,5 +1,4 @@ - - - @@ -42,7 +40,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" - android:fitsSystemWindows="false"/> + android:fitsSystemWindows="false" /> @@ -54,7 +52,7 @@ + android:layout_height="match_parent" /> @@ -63,5 +61,5 @@ android:id="@android:id/progress" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center"/> - \ No newline at end of file + android:layout_gravity="center" /> + diff --git a/src/main/res/layout/activity_navigation.xml b/src/main/res/layout/activity_navigation.xml index 4f38298d6..3230ab763 100644 --- a/src/main/res/layout/activity_navigation.xml +++ b/src/main/res/layout/activity_navigation.xml @@ -29,10 +29,10 @@ android:layout_height="match_parent" /> + android:layout="@layout/tv_loading" /> - \ No newline at end of file + diff --git a/src/main/res/layout/activity_server_file_tv.xml b/src/main/res/layout/activity_server_file_tv.xml index 2d9bdf8a9..480f9b7d8 100644 --- a/src/main/res/layout/activity_server_file_tv.xml +++ b/src/main/res/layout/activity_server_file_tv.xml @@ -1,7 +1,6 @@ - \ No newline at end of file + android:orientation="vertical" /> diff --git a/src/main/res/layout/activity_server_file_video.xml b/src/main/res/layout/activity_server_file_video.xml index f6a3956aa..7bceb30e6 100644 --- a/src/main/res/layout/activity_server_file_video.xml +++ b/src/main/res/layout/activity_server_file_video.xml @@ -17,8 +17,7 @@ ~ along with Amahi. If not, see . --> - @@ -42,7 +41,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" - android:fitsSystemWindows="false"/> + android:fitsSystemWindows="false" /> @@ -55,12 +54,12 @@ android:id="@+id/subtitles_stub" android:layout_width="1dp" android:layout_height="1dp" - android:layout="@layout/subtitles_surface"/> + android:layout="@layout/subtitles_surface" /> + android:layout_height="match_parent" /> @@ -69,7 +68,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" - android:fitsSystemWindows="false"/> + android:fitsSystemWindows="false" /> @@ -77,5 +76,5 @@ android:id="@android:id/progress" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center"/> - \ No newline at end of file + android:layout_gravity="center" /> + diff --git a/src/main/res/layout/activity_server_file_web.xml b/src/main/res/layout/activity_server_file_web.xml index db7151c2a..fd094679b 100644 --- a/src/main/res/layout/activity_server_file_web.xml +++ b/src/main/res/layout/activity_server_file_web.xml @@ -22,5 +22,4 @@ android:layout_width="fill_parent" android:layout_height="fill_parent" android:inAnimation="@android:anim/fade_in" - android:outAnimation="@android:anim/fade_out"> - \ No newline at end of file + android:outAnimation="@android:anim/fade_out"> diff --git a/src/main/res/layout/activity_server_files.xml b/src/main/res/layout/activity_server_files.xml index e6e5534b1..19ad017f8 100644 --- a/src/main/res/layout/activity_server_files.xml +++ b/src/main/res/layout/activity_server_files.xml @@ -18,8 +18,7 @@ ~ You should have received a copy of the GNU General Public License ~ along with Amahi. If not, see . --> - @@ -29,18 +28,18 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" - android:visibility="gone"/> + android:visibility="gone" /> + android:layout_height="match_parent" + android:layout_above="@id/castMiniController"> + android:layout_height="match_parent" /> + android:src="@drawable/ic_add" /> diff --git a/src/main/res/layout/activity_settings.xml b/src/main/res/layout/activity_settings.xml index a25ccc2e6..9c37b4658 100644 --- a/src/main/res/layout/activity_settings.xml +++ b/src/main/res/layout/activity_settings.xml @@ -1,9 +1,8 @@ - + android:layout_height="match_parent" + android:orientation="vertical"> - \ No newline at end of file + diff --git a/src/main/res/layout/activity_tv_audio_playback.xml b/src/main/res/layout/activity_tv_audio_playback.xml index f5dc7c143..9b80a8dcc 100644 --- a/src/main/res/layout/activity_tv_audio_playback.xml +++ b/src/main/res/layout/activity_tv_audio_playback.xml @@ -1,13 +1,15 @@ + android:layout_width="match_parent" + android:layout_height="match_parent"> - + android:layout_gravity="center" + android:scaleType="centerCrop" /> + android:layout_width="match_parent" + android:layout_height="match_parent"> + android:layout_gravity="center" /> + android:layout_height="match_parent" /> diff --git a/src/main/res/layout/activity_tv_web.xml b/src/main/res/layout/activity_tv_web.xml index 01db300b4..bd75464d1 100644 --- a/src/main/res/layout/activity_tv_web.xml +++ b/src/main/res/layout/activity_tv_web.xml @@ -1,12 +1,12 @@ - + + android:layout_height="match_parent" /> - \ No newline at end of file + diff --git a/src/main/res/layout/container_files_dummy.xml b/src/main/res/layout/container_files_dummy.xml index 915c30353..5efe51528 100644 --- a/src/main/res/layout/container_files_dummy.xml +++ b/src/main/res/layout/container_files_dummy.xml @@ -1,7 +1,6 @@ - + android:visibility="invisible" /> diff --git a/src/main/res/layout/intro_first_layout.xml b/src/main/res/layout/intro_first_layout.xml index 702e58fbf..84608690a 100644 --- a/src/main/res/layout/intro_first_layout.xml +++ b/src/main/res/layout/intro_first_layout.xml @@ -1,50 +1,51 @@ - + android:layout_height="match_parent" + android:orientation="vertical"> + android:layout_centerHorizontal="true" + android:layout_marginTop="90dp" + app:srcCompat="@drawable/ic_banner" /> + android:layout_marginTop="60dp"> + + + android:textSize="20sp" /> + android:layout_below="@id/text_title" + android:padding="16dp" + android:text="@string/intro_desc_phone_1" + android:textSize="15sp" /> - \ No newline at end of file + diff --git a/src/main/res/layout/onboarding_image.xml b/src/main/res/layout/onboarding_image.xml index f74359301..39f21d9d6 100644 --- a/src/main/res/layout/onboarding_image.xml +++ b/src/main/res/layout/onboarding_image.xml @@ -1,5 +1,6 @@ + android:layout_width="match_parent" + android:layout_height="match_parent"> - \ No newline at end of file + diff --git a/src/main/res/layout/percentage_view.xml b/src/main/res/layout/percentage_view.xml index 8a57e6235..6bf826208 100644 --- a/src/main/res/layout/percentage_view.xml +++ b/src/main/res/layout/percentage_view.xml @@ -1,6 +1,5 @@ - @@ -19,7 +18,7 @@ android:layout_marginTop="30dp" android:background="#50000000" android:padding="8dp" - android:progressDrawable="@drawable/percentage_bar"/> + android:progressDrawable="@drawable/percentage_bar" /> + android:layout_height="30dp" /> + android:textSize="25sp" /> diff --git a/src/main/res/layout/seek_view.xml b/src/main/res/layout/seek_view.xml index fc21af5ca..c15a47b53 100644 --- a/src/main/res/layout/seek_view.xml +++ b/src/main/res/layout/seek_view.xml @@ -1,7 +1,6 @@ - @@ -14,5 +13,5 @@ android:layout_marginBottom="10dp" android:textColor="@android:color/white" android:textSize="30sp" - android:textStyle="bold"/> + android:textStyle="bold" /> diff --git a/src/main/res/layout/subtitles_surface.xml b/src/main/res/layout/subtitles_surface.xml index 701bc75fd..61a997c12 100644 --- a/src/main/res/layout/subtitles_surface.xml +++ b/src/main/res/layout/subtitles_surface.xml @@ -1,6 +1,4 @@ - - \ No newline at end of file + android:layout_height="1dp"> diff --git a/src/main/res/layout/tv_header_item.xml b/src/main/res/layout/tv_header_item.xml index e468ec7a2..56ca3b84b 100644 --- a/src/main/res/layout/tv_header_item.xml +++ b/src/main/res/layout/tv_header_item.xml @@ -1,20 +1,21 @@ + android:layout_height="match_parent" + android:orientation="horizontal"> + android:src="@drawable/ic_menu_settings" + android:visibility="gone" /> + + android:layout_height="wrap_content" + android:layout_marginTop="6dp" + android:textSize="18sp" /> - \ No newline at end of file + diff --git a/src/main/res/layout/tv_loading.xml b/src/main/res/layout/tv_loading.xml index ed048ba83..98495a36a 100644 --- a/src/main/res/layout/tv_loading.xml +++ b/src/main/res/layout/tv_loading.xml @@ -1,23 +1,22 @@ - + android:visibility="invisible"> + android:src="@drawable/ic_banner" /> + android:layout_centerHorizontal="true" /> diff --git a/src/main/res/layout/upload_bottom_sheet.xml b/src/main/res/layout/upload_bottom_sheet.xml index 1e597f6da..529b0c390 100644 --- a/src/main/res/layout/upload_bottom_sheet.xml +++ b/src/main/res/layout/upload_bottom_sheet.xml @@ -1,6 +1,5 @@ - + android:textSize="20sp" /> + android:layout_marginBottom="8dp" + android:divider="@null" /> - \ No newline at end of file + diff --git a/src/main/res/layout/upload_list_item.xml b/src/main/res/layout/upload_list_item.xml index 8b498dc35..7451c12d0 100644 --- a/src/main/res/layout/upload_list_item.xml +++ b/src/main/res/layout/upload_list_item.xml @@ -1,6 +1,5 @@ - @@ -11,7 +10,7 @@ android:layout_height="24dp" android:layout_alignParentStart="true" android:layout_centerVertical="true" - tools:ignore="ContentDescription"/> + tools:ignore="ContentDescription" /> - \ No newline at end of file + android:textSize="16sp" /> + diff --git a/src/main/res/layout/view_server_file_item.xml b/src/main/res/layout/view_server_file_item.xml index 427b01a57..ac5f1291a 100644 --- a/src/main/res/layout/view_server_file_item.xml +++ b/src/main/res/layout/view_server_file_item.xml @@ -24,14 +24,14 @@ android:foreground="?android:attr/selectableItemBackgroundBorderless" android:orientation="horizontal" android:padding="8dp"> - + + android:scaleType="centerCrop" + android:src="@drawable/ic_file_audio" /> . --> -

+ app:showAsAction="always" /> - \ No newline at end of file + diff --git a/src/main/res/menu/action_bar_expanded_controller.xml b/src/main/res/menu/action_bar_expanded_controller.xml index da19f507e..c7cd62850 100644 --- a/src/main/res/menu/action_bar_expanded_controller.xml +++ b/src/main/res/menu/action_bar_expanded_controller.xml @@ -19,12 +19,12 @@ + xmlns:app="http://schemas.android.com/apk/res-auto"> + app:showAsAction="always" /> - \ No newline at end of file + diff --git a/src/main/res/menu/action_bar_server_file_image.xml b/src/main/res/menu/action_bar_server_file_image.xml index 23aa1266d..af2fc13f5 100644 --- a/src/main/res/menu/action_bar_server_file_image.xml +++ b/src/main/res/menu/action_bar_server_file_image.xml @@ -33,6 +33,6 @@ android:orderInCategory="101" android:title="@string/media_route_menu_item" app:actionProviderClass="android.support.v7.app.MediaRouteActionProvider" - app:showAsAction="always"/> + app:showAsAction="always" /> - \ No newline at end of file + diff --git a/src/main/res/menu/action_bar_server_files.xml b/src/main/res/menu/action_bar_server_files.xml index 6eb63d8e2..e2aff5c65 100644 --- a/src/main/res/menu/action_bar_server_files.xml +++ b/src/main/res/menu/action_bar_server_files.xml @@ -18,7 +18,7 @@ --> + xmlns:app="http://schemas.android.com/apk/res-auto"> + app:showAsAction="collapseActionView|always" /> + app:showAsAction="always" /> + app:showAsAction="always" /> - \ No newline at end of file + diff --git a/src/main/res/menu/action_mode_server_files.xml b/src/main/res/menu/action_mode_server_files.xml index 65ba87fa3..dd61fbb56 100644 --- a/src/main/res/menu/action_mode_server_files.xml +++ b/src/main/res/menu/action_mode_server_files.xml @@ -17,20 +17,19 @@ ~ along with Amahi. If not, see . --> - + app:showAsAction="always" /> + app:showAsAction="always" /> - \ No newline at end of file + diff --git a/src/main/res/values-v21/themes.xml b/src/main/res/values-v21/themes.xml index 9a1fb4f0e..2cfa88aca 100644 --- a/src/main/res/values-v21/themes.xml +++ b/src/main/res/values-v21/themes.xml @@ -1,14 +1,14 @@ - - - + + + + - \ No newline at end of file + diff --git a/src/main/res/xml/file_paths.xml b/src/main/res/xml/file_paths.xml index 9296c4cd0..c1c842c40 100644 --- a/src/main/res/xml/file_paths.xml +++ b/src/main/res/xml/file_paths.xml @@ -2,5 +2,5 @@ - \ No newline at end of file + path="Android/data/org.amahi.anywhere/files/Pictures" /> + diff --git a/src/main/res/xml/settings.xml b/src/main/res/xml/settings.xml index 23ae988ee..8d54a0ef5 100644 --- a/src/main/res/xml/settings.xml +++ b/src/main/res/xml/settings.xml @@ -23,7 +23,7 @@ + android:title="@string/preference_title_account_sign_out" /> @@ -34,11 +34,11 @@ android:entries="@array/preference_entries_server_connection" android:entryValues="@array/preference_entries_keys_server_connection" android:key="@string/preference_key_server_connection" - android:title="@string/preference_title_server_connection"/> + android:title="@string/preference_title_server_connection" /> + android:title="@string/preference_title_upload_settings" /> @@ -46,19 +46,19 @@ + android:title="@string/preference_title_about_version" /> + android:title="@string/preference_title_about_feedback" /> + android:title="@string/preference_title_about_rating" /> + android:title="@string/preference_title_tell_a_friend" /> diff --git a/src/main/res/xml/upload_settings.xml b/src/main/res/xml/upload_settings.xml index 052e6b7a7..a11f5af7d 100644 --- a/src/main/res/xml/upload_settings.xml +++ b/src/main/res/xml/upload_settings.xml @@ -17,33 +17,32 @@ ~ along with Amahi. If not, see . --> - + + android:key="@string/preference_key_upload_switch" /> + android:title="@string/preference_title_upload_hda" /> + android:title="@string/preference_title_upload_share" /> + android:title="@string/preference_title_upload_path" /> + android:title="@string/preference_title_upload_data" /> diff --git a/src/test/java/org/amahi/anywhere/PermissionTest.java b/src/test/java/org/amahi/anywhere/PermissionTest.java index b5803238a..f94f5b7da 100644 --- a/src/test/java/org/amahi/anywhere/PermissionTest.java +++ b/src/test/java/org/amahi/anywhere/PermissionTest.java @@ -14,7 +14,8 @@ /** * Test for checking permissions in {@link AndroidManifest} */ -@RunWith(RobolectricTestRunner.class) // for the test suite when we will want to run this from the test suite +@RunWith(RobolectricTestRunner.class) +// for the test suite when we will want to run this from the test suite @Config(constants = BuildConfig.class, sdk = 23) public class PermissionTest { @@ -25,16 +26,16 @@ public void permissionCheck() { //List of expected permissions to be present in AndroidManifest.xml String[] expectedPermissions = { - "android.permission.ACCESS_NETWORK_STATE", - "android.permission.DOWNLOAD_WITHOUT_NOTIFICATION", - "android.permission.INTERNET", - "android.permission.READ_EXTERNAL_STORAGE", - "android.permission.WRITE_EXTERNAL_STORAGE", - "android.permission.AUTHENTICATE_ACCOUNTS", - "android.permission.GET_ACCOUNTS", - "android.permission.MANAGE_ACCOUNTS", - "android.permission.USE_CREDENTIALS", - "android.permission.WAKE_LOCK" + "android.permission.ACCESS_NETWORK_STATE", + "android.permission.DOWNLOAD_WITHOUT_NOTIFICATION", + "android.permission.INTERNET", + "android.permission.READ_EXTERNAL_STORAGE", + "android.permission.WRITE_EXTERNAL_STORAGE", + "android.permission.AUTHENTICATE_ACCOUNTS", + "android.permission.GET_ACCOUNTS", + "android.permission.MANAGE_ACCOUNTS", + "android.permission.USE_CREDENTIALS", + "android.permission.WAKE_LOCK" }; //Checking expected permissions one by one @@ -51,8 +52,8 @@ public void permissionCheck() { private void showError(String permission) { Description description = new StringDescription(); description.appendText("Expected permission ") - .appendText(permission) - .appendText(" is missing from AndroidManifest.xml"); + .appendText(permission) + .appendText(" is missing from AndroidManifest.xml"); throw new AssertionError(description.toString()); }