/** * Copyright (C) 2016 eBusiness Information * * This file is part of OSM Contributor. * * OSM Contributor is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OSM Contributor is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OSM Contributor. If not, see <http://www.gnu.org/licenses/>. */ package io.jawg.osmcontributor.ui.activities; import android.Manifest; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v7.app.AppCompatActivity; import android.text.Html; import android.view.View; import android.widget.TextView; import android.widget.Toast; import com.yarolegovich.lovelydialog.LovelyStandardDialog; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; import java.util.ArrayList; import java.util.List; import javax.inject.Inject; import butterknife.BindView; import butterknife.ButterKnife; import io.jawg.osmcontributor.OsmTemplateApplication; import io.jawg.osmcontributor.R; import io.jawg.osmcontributor.database.events.DbInitializedEvent; import io.jawg.osmcontributor.database.events.InitDbEvent; import io.jawg.osmcontributor.model.events.InitCredentialsEvent; import io.jawg.osmcontributor.rest.events.GoogleAuthenticatedEvent; import io.jawg.osmcontributor.ui.dialogs.LoginDialogFragment; import io.jawg.osmcontributor.ui.events.login.ErrorLoginEvent; import io.jawg.osmcontributor.ui.events.login.CheckFirstConnectionEvent; import io.jawg.osmcontributor.ui.events.login.LoginInitializedEvent; import io.jawg.osmcontributor.ui.events.login.PleaseOpenLoginDialogEvent; import io.jawg.osmcontributor.ui.events.login.SplashScreenTimerFinishedEvent; import io.jawg.osmcontributor.ui.events.login.UpdateGoogleCredentialsEvent; import io.jawg.osmcontributor.ui.events.login.ValidLoginEvent; import io.jawg.osmcontributor.ui.events.map.ArpiBitmapsPrecomputedEvent; import io.jawg.osmcontributor.ui.events.map.PrecomputeArpiBitmapsEvent; import io.jawg.osmcontributor.ui.utils.views.EventCountDownTimer; import timber.log.Timber; public class SplashScreenActivity extends AppCompatActivity { /*=========================================*/ /*------------ATTRIBUTES-------------------*/ /*=========================================*/ /** * For Android 6.0 and higher, we have to request dangerous permissions like * ACCESS_FINE_LOCATION or WRITE_EXTERNAL_STORAGE at runtime. This static variable * is used to get the user response in callback. */ private static final int ALLOW_PERMISSIONS = 100; @Inject EventBus bus; @BindView(R.id.edited_by) TextView editBy; @BindView(R.id.powered_by) TextView poweredBy; @BindView(R.id.mapsquare) TextView mapsquare; private LoginDialogFragment loginDialogFragment; /*=========================================*/ /*------------CODE-------------------------*/ /*=========================================*/ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_splash_screen); ((OsmTemplateApplication) getApplication()).getOsmTemplateComponent().inject(this); ButterKnife.bind(this); bus.register(this); mapsquare.setText(Html.fromHtml(getString(R.string.mapsquare))); editBy.setText(Html.fromHtml(getString(R.string.splash_screen_edited_by))); poweredBy.setText(Html.fromHtml(getString(R.string.splash_screen_powered_by))); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { requestPermissionIfNeeded(); } else { initEvent(); } } @Override protected void onDestroy() { bus.unregister(this); super.onDestroy(); } /*=========================================*/ /*------------PRIVATE CODE-----------------*/ /*=========================================*/ /** * Check whether all the initialization finished response events are there and we should start MapActivity. * * @return Whether we should start MapActivity. */ private boolean shouldStartMapActivity() { return bus.getStickyEvent(DbInitializedEvent.class) != null && bus.getStickyEvent(SplashScreenTimerFinishedEvent.class) != null && bus.getStickyEvent(ArpiBitmapsPrecomputedEvent.class) != null && bus.getStickyEvent(LoginInitializedEvent.class) != null; } /** * Remove all the initialization finished sticky events and start the MapActivity. */ private void startMapActivity() { bus.removeStickyEvent(DbInitializedEvent.class); bus.removeStickyEvent(SplashScreenTimerFinishedEvent.class); bus.removeStickyEvent(ArpiBitmapsPrecomputedEvent.class); bus.removeStickyEvent(LoginInitializedEvent.class); Intent intent = new Intent(this, MapActivity.class); startActivity(intent); finish(); } private void initEvent() { EventCountDownTimer timer = new EventCountDownTimer(3000, 3000, bus); timer.setStickyEvent(new SplashScreenTimerFinishedEvent()); timer.start(); bus.post(new InitCredentialsEvent()); bus.post(new InitDbEvent()); bus.post(new PrecomputeArpiBitmapsEvent()); bus.post(new CheckFirstConnectionEvent()); } private void startMapActivityIfNeeded() { if (shouldStartMapActivity()) { startMapActivity(); } } /*=========================================*/ /*----------------EVENTS-------------------*/ /*=========================================*/ @Subscribe(sticky = true, threadMode = ThreadMode.ASYNC) public void onDbInitializedEvent(DbInitializedEvent event) { Timber.d("Database initialized"); startMapActivityIfNeeded(); } @Subscribe(threadMode = ThreadMode.ASYNC) public void onSplashScreenTimerFinishedEvent(SplashScreenTimerFinishedEvent event) { Timber.d("Timer finished"); startMapActivityIfNeeded(); } @Subscribe(sticky = true, threadMode = ThreadMode.ASYNC) public void onArpiBitmapsPrecomputedEvent(ArpiBitmapsPrecomputedEvent event) { Timber.d("Arpi bitmaps precomputed"); startMapActivityIfNeeded(); } @Subscribe(sticky = true, threadMode = ThreadMode.ASYNC) public void onLoginInitializedEvent(LoginInitializedEvent event) { startMapActivityIfNeeded(); } @Subscribe(threadMode = ThreadMode.MAIN) public void onPleaseOpenLoginDialogEvent(PleaseOpenLoginDialogEvent event) { loginDialogFragment = LoginDialogFragment.newInstance(bus); loginDialogFragment.show(getFragmentManager(), LoginDialogFragment.class.getSimpleName()); } @Subscribe(threadMode = ThreadMode.MAIN) public void onGoogleAuthenticatedEvent(GoogleAuthenticatedEvent event) { if (event.isSuccessful()) { bus.post(new UpdateGoogleCredentialsEvent(event.getToken(), event.getTokenSecret(), event.getConsumer(), event.getConsumerSecret())); } else { Toast.makeText(getApplicationContext(), R.string.error_login, Toast.LENGTH_SHORT).show(); } loginDialogFragment.dismiss(); } @Subscribe(threadMode = ThreadMode.MAIN) public void onValidLoginEvent(ValidLoginEvent event) { Toast.makeText(getApplicationContext(), R.string.valid_login, Toast.LENGTH_SHORT).show(); loginDialogFragment.dismiss(); } @Subscribe(threadMode = ThreadMode.MAIN) public void onErrorLoginEvent(ErrorLoginEvent event) { Toast.makeText(getApplicationContext(), R.string.error_first_login, Toast.LENGTH_SHORT).show(); loginDialogFragment.resetLoginFields(); } /*=========================================*/ /*-----------FOR ANDROID 6.0---------------*/ /*=========================================*/ /** * This method must be called if the android version is 6.0 or higher. * Check if the app has ACCESS_LOCATION (COARSE and FINE) and WRITE_EXTERNAL_STORAGE. * If the app doesn't have both permission, a request is prompted to the user. * For more informations about permission in Android 6.0, please refer to * https://developer.android.com/training/permissions/requesting.html?hl=Fr#explain */ private void requestPermissionIfNeeded() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // Check if permission are enable by the user. Dangerous permissions requested are : int hasEnableCoarseLocationPerm = checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION); int hasEnableFineLocationPerm = checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION); int hasEnableExternalWritePerm = checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE); // Add to list permission to be requested. List<String> permissionToRequest = new ArrayList<>(); if (hasEnableCoarseLocationPerm == PackageManager.PERMISSION_DENIED) { permissionToRequest.add(Manifest.permission.ACCESS_COARSE_LOCATION); } if (hasEnableFineLocationPerm == PackageManager.PERMISSION_DENIED) { permissionToRequest.add(Manifest.permission.ACCESS_FINE_LOCATION); } if (hasEnableExternalWritePerm == PackageManager.PERMISSION_DENIED) { permissionToRequest.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); } // If the user have already allow permission, launch map activity, else, ask the user to allow permission if (!permissionToRequest.isEmpty()) { requestPermissions(permissionToRequest.toArray(new String[permissionToRequest.size()]), ALLOW_PERMISSIONS); } else { initEvent(); } } } /** * This method is a callback. Check the user's answer after requesting permission. * * @param requestCode app request code (here, we only handle ALLOW_PERMISSION * @param permissions permissions requested (here, ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION, WRITE_EXTERNAL_STORAGE) * @param grantResults user's decision */ @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { // If request is cancelled, the result arrays are empty. if (requestCode == ALLOW_PERMISSIONS && grantResults.length > 0) { List<String> permissionsNotAllowed = new ArrayList<>(); // For each permission, check if is granted for (int i = 0; i < permissions.length; i++) { if (grantResults[i] == PackageManager.PERMISSION_DENIED) { permissionsNotAllowed.add(permissions[i]); } } if (permissionsNotAllowed.isEmpty()) { initEvent(); } else { permissionNotEnabled(); } } else { permissionNotEnabled(); } } /** * This method is called is a permission (or all permissions) are declined by the user. * If permissions are refused, we indicate why we request permissions and that, whitout it, * the app can not work. */ private void permissionNotEnabled() { new LovelyStandardDialog(this) .setTopColorRes(R.color.colorPrimaryDark) .setIcon(R.mipmap.icon) .setTitle(R.string.permissions_title) .setMessage(R.string.permissions_information) .setPositiveButton(android.R.string.ok, new View.OnClickListener() { @Override public void onClick(View v) { requestPermissionIfNeeded(); } }).show(); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (loginDialogFragment != null) { loginDialogFragment.onActivityResult(requestCode, resultCode, data); } } }