package io.homeassistant.android;
import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.support.customtabs.CustomTabsCallback;
import android.support.customtabs.CustomTabsClient;
import android.support.customtabs.CustomTabsIntent;
import android.support.customtabs.CustomTabsServiceConnection;
import android.support.customtabs.CustomTabsSession;
import android.support.design.widget.CoordinatorLayout;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.view.menu.MenuBuilder;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.FrameLayout;
import com.afollestad.ason.Ason;
import io.homeassistant.android.api.results.RequestResult;
import io.homeassistant.android.view.LoginView;
import io.homeassistant.android.view.ViewAdapter;
public class HassActivity extends AppCompatActivity implements CommunicationHandler.ServiceCommunicator {
private final Handler communicationHandler = new CommunicationHandler(this);
@VisibleForTesting()
public HassService service;
private final ServiceConnection hassConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
service = ((HassService.HassBinder) binder).getService();
service.setActivityHandler(communicationHandler);
// Make sure that service is connected, if not it'll re-attempt
service.connect();
}
@Override
public void onServiceDisconnected(ComponentName name) {
service.setActivityHandler(null);
service = null;
}
};
private CustomTabsSession customTabsSession;
private final CustomTabsServiceConnection chromeConnection = new CustomTabsServiceConnection() {
@Override
public void onCustomTabsServiceConnected(ComponentName name, CustomTabsClient client) {
client.warmup(0);
customTabsSession = client.newSession(new CustomTabsCallback());
if (customTabsSession == null) {
return;
}
// Delay to not slow down native app loading
communicationHandler.postDelayed(() -> customTabsSession.mayLaunchUrl(Uri.parse(Utils.getUrl(HassActivity.this)), null, null), 1500);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
private ViewAdapter viewAdapter = new ViewAdapter(this);
private FrameLayout rootView;
private CoordinatorLayout mainLayout;
private SwipeRefreshLayout swipeRefreshLayout;
private LoginView loginLayout;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hass);
Toolbar t = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(t);
getApplicationContext().bindService(new Intent(this, HassService.class), hassConnection, BIND_AUTO_CREATE);
rootView = (FrameLayout) findViewById(R.id.root);
mainLayout = (CoordinatorLayout) findViewById(R.id.main_coordinator);
if (Utils.getUrl(this).isEmpty() || Utils.getPassword(this).isEmpty()) {
addLoginLayout();
}
swipeRefreshLayout = (SwipeRefreshLayout) mainLayout.findViewById(R.id.swipe_refresh);
swipeRefreshLayout.setColorSchemeResources(R.color.accent);
swipeRefreshLayout.setOnRefreshListener(() -> {
if (service != null) {
service.loadStates();
}
});
swipeRefreshLayout.setRefreshing(true);
RecyclerView viewRecycler = (RecyclerView) mainLayout.findViewById(R.id.view_recycler);
viewRecycler.setLayoutManager(new StaggeredGridLayoutManager(getResources().getInteger(R.integer.view_columns), StaggeredGridLayoutManager.VERTICAL));
viewRecycler.setAdapter(viewAdapter);
viewRecycler.setRecycledViewPool(viewAdapter.recycledViewPool);
}
private void addLoginLayout() {
mainLayout.setVisibility(View.GONE);
loginLayout = (LoginView) getLayoutInflater().inflate(R.layout.custom_login, rootView, true).findViewById(R.id.login_layout);
}
@Override
protected void onStart() {
super.onStart();
if (service != null) {
// Make sure that service is connected, if not it'll re-attempt
service.connect();
}
}
@Override
protected void onDestroy() {
// Keep service alive for configuration changes. No connection will be leaked as it's bound to application context
if (!isChangingConfigurations()) {
getApplicationContext().unbindService(hassConnection);
}
unbindService(chromeConnection);
super.onDestroy();
}
@SuppressLint("RestrictedApi")
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (menu instanceof MenuBuilder) {
((MenuBuilder) menu).setOptionalIconsVisible(true);
}
String packageName = CustomTabsClient.getPackageName(this, null);
CustomTabsClient.bindCustomTabsService(this, !TextUtils.isEmpty(packageName) ? packageName : "com.android.chrome", chromeConnection);
getMenuInflater().inflate(R.menu.hass, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_custom_tab:
if (customTabsSession != null) {
@SuppressWarnings("deprecation") CustomTabsIntent intent = new CustomTabsIntent.Builder(customTabsSession)
.setShowTitle(true)
.enableUrlBarHiding()
.setToolbarColor(getResources().getColor(R.color.primary))
.build();
intent.launchUrl(this, Uri.parse(Utils.getUrl(this)));
}
return true;
case R.id.menu_logout:
if (loginLayout == null) {
Utils.getPrefs(this).edit().remove(Common.PREF_HASS_PASSWORD_KEY).apply();
service.disconnect();
addLoginLayout();
}
return true;
case R.id.menu_settings:
Intent settings = new Intent(this, SettingsActivity.class);
startActivity(settings);
return true;
default:
return false;
}
}
public void attemptLogin() {
// Force reconnect, this call is safe if not connected
service.disconnect();
service.connect();
}
@Override
public void loginSuccess() {
if (loginLayout != null) {
rootView.removeView(loginLayout);
loginLayout = null;
mainLayout.setVisibility(View.VISIBLE);
}
}
@Override
public void loginFailed(int reason) {
if (loginLayout == null) {
addLoginLayout();
}
loginLayout.showLoginError(reason);
}
@Override
public void updateStates() {
viewAdapter.updateEntities(service.getEntityMap());
swipeRefreshLayout.setRefreshing(false);
}
public boolean send(Ason message, @Nullable RequestResult.OnRequestResultListener resultListener) {
return service.send(message, resultListener);
}
}