diff options
Diffstat (limited to 'android/src/com/mapswithme/maps/MwmActivity.java')
-rw-r--r-- | android/src/com/mapswithme/maps/MwmActivity.java | 1417 |
1 files changed, 1417 insertions, 0 deletions
diff --git a/android/src/com/mapswithme/maps/MwmActivity.java b/android/src/com/mapswithme/maps/MwmActivity.java new file mode 100644 index 0000000000..b36d0ef110 --- /dev/null +++ b/android/src/com/mapswithme/maps/MwmActivity.java @@ -0,0 +1,1417 @@ +package com.mapswithme.maps; + +import android.app.Dialog; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.res.Configuration; +import android.graphics.Point; +import android.location.Location; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.support.v7.app.AlertDialog; +import android.util.Log; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.widget.ImageButton; +import android.widget.Toast; + +import com.mapswithme.country.ActiveCountryTree; +import com.mapswithme.country.DownloadActivity; +import com.mapswithme.country.DownloadFragment; +import com.mapswithme.country.StorageOptions; +import com.mapswithme.maps.Framework.OnBalloonListener; +import com.mapswithme.maps.MapStorage.Index; +import com.mapswithme.maps.activity.CustomNavigateUpListener; +import com.mapswithme.maps.ads.LikesManager; +import com.mapswithme.maps.api.ParsedMwmRequest; +import com.mapswithme.maps.base.BaseMwmFragmentActivity; +import com.mapswithme.maps.bookmarks.BookmarkCategoriesActivity; +import com.mapswithme.maps.bookmarks.ChooseBookmarkCategoryActivity; +import com.mapswithme.maps.bookmarks.data.Bookmark; +import com.mapswithme.maps.bookmarks.data.BookmarkManager; +import com.mapswithme.maps.bookmarks.data.MapObject; +import com.mapswithme.maps.bookmarks.data.MapObject.ApiPoint; +import com.mapswithme.maps.bookmarks.data.ParcelablePoint; +import com.mapswithme.maps.dialog.RoutingErrorDialogFragment; +import com.mapswithme.maps.location.LocationHelper; +import com.mapswithme.maps.location.LocationPredictor; +import com.mapswithme.maps.routing.RoutingInfo; +import com.mapswithme.maps.routing.RoutingResultCodesProcessor; +import com.mapswithme.maps.search.SearchActivity; +import com.mapswithme.maps.search.SearchFragment; +import com.mapswithme.maps.search.SearchToolbarController; +import com.mapswithme.maps.settings.SettingsActivity; +import com.mapswithme.maps.settings.StoragePathManager; +import com.mapswithme.maps.settings.StoragePathManager.MoveFilesListener; +import com.mapswithme.maps.settings.UnitLocale; +import com.mapswithme.maps.sound.TtsPlayer; +import com.mapswithme.maps.widget.BottomButtonsLayout; +import com.mapswithme.maps.widget.FadeView; +import com.mapswithme.maps.widget.RoutingLayout; +import com.mapswithme.maps.widget.placepage.BasePlacePageAnimationController; +import com.mapswithme.maps.widget.placepage.PlacePageView; +import com.mapswithme.maps.widget.placepage.PlacePageView.State; +import com.mapswithme.util.BottomSheetHelper; +import com.mapswithme.util.Constants; +import com.mapswithme.util.InputUtils; +import com.mapswithme.util.LocationUtils; +import com.mapswithme.util.UiUtils; +import com.mapswithme.util.Utils; +import com.mapswithme.util.Yota; +import com.mapswithme.util.sharing.ShareAction; +import com.mapswithme.util.sharing.SharingHelper; +import com.mapswithme.util.statistics.AlohaHelper; +import com.mapswithme.util.statistics.Statistics; + +import java.io.Serializable; +import java.util.Stack; + +public class MwmActivity extends BaseMwmFragmentActivity + implements LocationHelper.LocationListener, OnBalloonListener, View.OnTouchListener, BasePlacePageAnimationController.OnVisibilityChangedListener, + OnClickListener, Framework.RoutingListener, MapFragment.MapRenderingListener, CustomNavigateUpListener, Framework.RoutingProgressListener +{ + public static final String EXTRA_TASK = "map_task"; + private final static String TAG = "MwmActivity"; + private final static String EXTRA_CONSUMED = "mwm.extra.intent.processed"; + private final static String EXTRA_SCREENSHOTS_TASK = "screenshots_task"; + private final static String SCREENSHOTS_TASK_LOCATE = "locate_task"; + private final static String SCREENSHOTS_TASK_PPP = "show_place_page"; + private final static String EXTRA_LAT = "lat"; + private final static String EXTRA_LON = "lon"; + // Need it for change map style + private static final String EXTRA_SET_MAP_STYLE = "set_map_style"; + // Instance state + private static final String STATE_PP_OPENED = "PpOpened"; + private static final String STATE_MAP_OBJECT = "MapObject"; + private static final String STATE_BUTTONS_OPENED = "ButtonsOpened"; + + // Map tasks that we run AFTER rendering initialized + private final Stack<MapTask> mTasks = new Stack<>(); + private BroadcastReceiver mExternalStorageReceiver; + private final StoragePathManager mPathManager = new StoragePathManager(); + private AlertDialog mStorageDisconnectedDialog; + private ImageButton mBtnLocation; + // map + private MapFragment mMapFragment; + // Place page + private PlacePageView mPlacePage; + // Routing + private RoutingLayout mLayoutRouting; + + private boolean mNeedCheckUpdate = true; + private int mLocationStateModeListenerId = LocationState.SLOT_UNDEFINED; + // These flags are initialized to the invalid combination to force update on the first check + // after launching. + // These flags are static because the MwmActivity is recreated while screen orientation changing + // but they shall not be reinitialized on screen orientation changing. + private static boolean mStorageAvailable = false; + private static boolean mStorageWritable = true; + + private FadeView mFadeView; + + private ViewGroup mNavigationButtons; + private View mToolbarSearch; + private ImageButton mBtnZoomIn; + private ImageButton mBtnZoomOut; + private BottomButtonsLayout mBottomButtons; + + private boolean mIsFragmentContainer; + + private LocationPredictor mLocationPredictor; + private LikesManager mLikesManager; + private SearchToolbarController mSearchController; + + public static Intent createShowMapIntent(Context context, Index index, boolean doAutoDownload) + { + return new Intent(context, DownloadResourcesActivity.class) + .putExtra(DownloadResourcesActivity.EXTRA_COUNTRY_INDEX, index) + .putExtra(DownloadResourcesActivity.EXTRA_AUTODOWNLOAD_COUNTRY, doAutoDownload); + } + + public static void setMapStyle(Context context, int mapStyle) + { + final Intent mapIntent = new Intent(context, MwmActivity.class); + mapIntent.putExtra(EXTRA_SET_MAP_STYLE, mapStyle); + context.startActivity(mapIntent); + // Next we need to handle intent + } + + public static void startSearch(Context context, String query) + { + final MwmActivity activity = (MwmActivity) context; + if (activity.mIsFragmentContainer) + activity.showSearch(); + else + SearchActivity.startWithQuery(context, query); + } + + public static Intent createUpdateMapsIntent() + { + return new Intent(MwmApplication.get(), DownloadResourcesActivity.class) + .putExtra(DownloadResourcesActivity.EXTRA_UPDATE_COUNTRIES, true); + } + + private void pauseLocation() + { + LocationHelper.INSTANCE.removeLocationListener(this); + // Enable automatic turning screen off while app is idle + Utils.keepScreenOn(false, getWindow()); + mLocationPredictor.pause(); + } + + private void listenLocationUpdates() + { + LocationHelper.INSTANCE.addLocationListener(this); + // Do not turn off the screen while displaying position + Utils.keepScreenOn(true, getWindow()); + mLocationPredictor.resume(); + } + + /** + * Invalidates location state in core. + * Updates location button accordingly. + */ + public void invalidateLocationState() + { + final int currentLocationMode = LocationState.INSTANCE.getLocationStateMode(); + refreshLocationState(currentLocationMode); + LocationState.INSTANCE.invalidatePosition(); + } + + private void checkUserMarkActivation() + { + final Intent intent = getIntent(); + if (intent != null && intent.hasExtra(EXTRA_SCREENSHOTS_TASK)) + { + final String value = intent.getStringExtra(EXTRA_SCREENSHOTS_TASK); + if (value.equals(SCREENSHOTS_TASK_PPP)) + { + final double lat = Double.parseDouble(intent.getStringExtra(EXTRA_LAT)); + final double lon = Double.parseDouble(intent.getStringExtra(EXTRA_LON)); + mFadeView.getHandler().postDelayed(new Runnable() + { + @Override + public void run() + { + Framework.nativeActivateUserMark(lat, lon); + } + }, 1000); + } + } + } + + @Override + public void onRenderingInitialized() + { + runOnUiThread(new Runnable() + { + @Override + public void run() + { + // Run all checks in main thread after rendering is initialized. + checkMeasurementSystem(); + checkUpdateMapsWithoutSearchIndex(); + checkKitkatMigrationMove(); + checkLiteMapsInPro(); + checkUserMarkActivation(); + } + }); + + runTasks(); + } + + private void runTasks() + { + // Task are not UI-thread bounded, + // if any task need UI-thread it should implicitly + // use Activity.runOnUiThread(). + while (!mTasks.isEmpty()) + mTasks.pop().run(this); + } + + private void checkMeasurementSystem() + { + UnitLocale.initializeCurrentUnits(); + } + + private void checkKitkatMigrationMove() + { + mPathManager.checkKitkatMigration(this); + } + + private void checkLiteMapsInPro() + { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && + (Utils.isPackageInstalled(Constants.Package.MWM_LITE_PACKAGE) || Utils.isPackageInstalled(Constants.Package.MWM_SAMSUNG_PACKAGE))) + { + if (!mPathManager.containsLiteMapsOnSdcard()) + return; + + mPathManager.moveMapsLiteToPro(this, + new MoveFilesListener() + { + @Override + public void moveFilesFinished(String newPath) + { + UiUtils.showAlertDialog(MwmActivity.this, R.string.move_lite_maps_to_pro_ok); + } + + @Override + public void moveFilesFailed(int errorCode) + { + UiUtils.showAlertDialog(MwmActivity.this, R.string.move_lite_maps_to_pro_failed); + } + } + ); + } + } + + private void checkUpdateMapsWithoutSearchIndex() + { + // do it only once + if (mNeedCheckUpdate) + { + mNeedCheckUpdate = false; + + MapStorage.INSTANCE.updateMapsWithoutSearchIndex(R.string.advise_update_maps, this, new MapStorage.UpdateFunctor() + { + @Override + public void doUpdate() + { + runOnUiThread(new Runnable() + { + @Override + public void run() + { + showDownloader(false); + } + }); + } + + @Override + public void doCancel() + { + } + }); + } + } + + private void showBookmarks() + { + popAllFragments(); + startActivity(new Intent(this, BookmarkCategoriesActivity.class)); + } + + private void showSearchIfContainsSearchIndex() + { + if (!MapStorage.INSTANCE.updateMapsWithoutSearchIndex(R.string.search_update_maps, this, new MapStorage.UpdateFunctor() + { + @Override + public void doUpdate() + { + showDownloader(false); + } + + @Override + public void doCancel() + { + showSearch(); + } + })) + { + showSearch(); + } + } + + private void showSearch() + { + if (mIsFragmentContainer) + { + if (getSupportFragmentManager().findFragmentByTag(SearchFragment.class.getName()) != null) // search is already shown + return; + hidePlacePage(); + Framework.deactivatePopup(); + popFragment(); + replaceFragment(SearchFragment.class.getName(), true, getIntent().getExtras()); + } + else + startActivity(new Intent(this, SearchActivity.class)); + } + + @Override + public void replaceFragment(String fragmentClassName, boolean addToBackStack, Bundle args) + { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + Fragment fragment = Fragment.instantiate(this, fragmentClassName, args); + transaction.setCustomAnimations(R.anim.fragment_slide_in_bottom, R.anim.fragment_slide_out_bottom, + R.anim.fragment_slide_in_bottom, R.anim.fragment_slide_out_bottom); + transaction.replace(R.id.fragment_container, fragment, fragment.getClass().getName()); + if (addToBackStack) + transaction.addToBackStack(null); + + transaction.commit(); + } + + private void shareMyLocation() + { + final Location loc = LocationHelper.INSTANCE.getLastLocation(); + if (loc != null) + { + final String geoUrl = Framework.nativeGetGe0Url(loc.getLatitude(), loc.getLongitude(), Framework.getDrawScale(), ""); + final String httpUrl = Framework.getHttpGe0Url(loc.getLatitude(), loc.getLongitude(), Framework.getDrawScale(), ""); + final String body = getString(R.string.my_position_share_sms, geoUrl, httpUrl); + ShareAction.ANY_SHARE.share(this, body); + } + else + { + new AlertDialog.Builder(MwmActivity.this) + .setMessage(R.string.unknown_current_position) + .setCancelable(true) + .setPositiveButton(android.R.string.ok, new Dialog.OnClickListener() + { + @Override + public void onClick(DialogInterface dialog, int which) + { + dialog.dismiss(); + } + }) + .create() + .show(); + } + } + + private void showDownloader(boolean openDownloadedList) + { + if (mIsFragmentContainer) + { + if (getSupportFragmentManager().findFragmentByTag(DownloadFragment.class.getName()) != null) // downloader is already shown + return; + popFragment(); + hidePlacePage(); + SearchToolbarController.cancelSearch(); + mSearchController.refreshToolbar(); + replaceFragment(DownloadFragment.class.getName(), true, new Bundle()); + mFadeView.fadeIn(false); + } + else + { + final Intent intent = new Intent(this, DownloadActivity.class).putExtra(DownloadActivity.EXTRA_OPEN_DOWNLOADED_LIST, openDownloadedList); + startActivity(intent); + } + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_map); + initViews(); + + TtsPlayer.INSTANCE.init(); + + if (MwmApplication.get().nativeIsBenchmarking()) + Utils.keepScreenOn(true, getWindow()); + + // TODO consider implementing other model of listeners connection, without activities being bound + Framework.nativeSetRoutingListener(this); + Framework.nativeSetRouteProgressListener(this); + Framework.nativeSetBalloonListener(this); + + final Intent intent = getIntent(); + // We need check for tasks both in onCreate and onNewIntent + // because of bug in OS: https://code.google.com/p/android/issues/detail?id=38629 + addTask(intent); + + if (intent != null && intent.hasExtra(EXTRA_SCREENSHOTS_TASK)) + { + String value = intent.getStringExtra(EXTRA_SCREENSHOTS_TASK); + if (value.equals(SCREENSHOTS_TASK_LOCATE)) + switchNextLocationState(); + } + + mLocationPredictor = new LocationPredictor(new Handler(), this); + mLikesManager = new LikesManager(this); + mSearchController = new SearchToolbarController(this); + + SharingHelper.prepare(); + } + + private void initViews() + { + initMap(); + initYota(); + initPlacePage(); + initRoutingBox(); + initNavigationButtons(); + if (findViewById(R.id.fragment_container) != null) + mIsFragmentContainer = true; + } + + private void initRoutingBox() + { + mLayoutRouting = (RoutingLayout) findViewById(R.id.layout__routing); + mLayoutRouting.setListener(new RoutingLayout.ActionListener() + { + @Override + public void onCloseRouting() + { + refreshZoomButtonsVisibility(); + } + + @Override + public void onStartRouteFollow() {} + + @Override + public void onRouteTypeChange(int type) {} + }); + } + + private void initMap() + { + mFadeView = (FadeView) findViewById(R.id.fade_view); + mFadeView.setFadeListener(new FadeView.FadeListener() + { + @Override + public void onFadeOut() + { + if (mBottomButtons.areButtonsVisible()) + mBottomButtons.slideButtonsOut(); + } + + @Override + public void onFadeIn() + { + + } + }); + mMapFragment = (MapFragment) getSupportFragmentManager().findFragmentByTag(MapFragment.FRAGMENT_TAG); + if (mMapFragment == null) + { + mMapFragment = (MapFragment) MapFragment.instantiate(this, MapFragment.class.getName(), null); + getSupportFragmentManager().beginTransaction(). + replace(R.id.map_fragment_container, mMapFragment, MapFragment.FRAGMENT_TAG).commit(); + } + findViewById(R.id.map_fragment_container).setOnTouchListener(this); + } + + @SuppressWarnings("deprecation") + private void initNavigationButtons() + { + mBottomButtons = (BottomButtonsLayout) findViewById(R.id.map_bottom_buttons); + mBottomButtons.hideButtons(); + mBottomButtons.findViewById(R.id.btn__open_menu).setOnClickListener(this); + mBottomButtons.findViewById(R.id.ll__share).setOnClickListener(this); + mBottomButtons.findViewById(R.id.ll__search).setOnClickListener(this); + mBottomButtons.findViewById(R.id.ll__download_maps).setOnClickListener(this); + mBottomButtons.findViewById(R.id.ll__bookmarks).setOnClickListener(this); + mBottomButtons.findViewById(R.id.ll__settings).setOnClickListener(this); + + mNavigationButtons = (ViewGroup) findViewById(R.id.navigation_buttons); + mBtnZoomIn = (ImageButton) mNavigationButtons.findViewById(R.id.map_button_plus); + mBtnZoomIn.setOnClickListener(this); + mBtnZoomOut = (ImageButton) mNavigationButtons.findViewById(R.id.map_button_minus); + mBtnZoomOut.setOnClickListener(this); + mBtnLocation = (ImageButton) mNavigationButtons.findViewById(R.id.btn__myposition); + mBtnLocation.setOnClickListener(this); + + mToolbarSearch = findViewById(R.id.toolbar_search); + } + + private void initPlacePage() + { + mPlacePage = (PlacePageView) findViewById(R.id.info_box); + mPlacePage.setOnVisibilityChangedListener(this); + mPlacePage.findViewById(R.id.ll__route).setOnClickListener(this); + } + + private void initYota() + { + final View yopmeButton = findViewById(R.id.yop_it); + if (Yota.isFirstYota()) + yopmeButton.setOnClickListener(this); + else + yopmeButton.setVisibility(View.INVISIBLE); + } + + @Override + public void onDestroy() + { + Framework.nativeRemoveBalloonListener(); + BottomSheetHelper.free(); + super.onDestroy(); + } + + @Override + protected void onSaveInstanceState(Bundle outState) + { + if (mPlacePage.getState() != State.HIDDEN) + { + outState.putBoolean(STATE_PP_OPENED, true); + outState.putParcelable(STATE_MAP_OBJECT, mPlacePage.getMapObject()); + } + else if (mBottomButtons.areButtonsVisible()) + outState.putBoolean(STATE_BUTTONS_OPENED, true); + + super.onSaveInstanceState(outState); + } + + @Override + protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) + { + if (savedInstanceState.getBoolean(STATE_PP_OPENED)) + { + mPlacePage.setMapObject((MapObject) savedInstanceState.getParcelable(STATE_MAP_OBJECT)); + mPlacePage.setState(State.PREVIEW); + } + + if (savedInstanceState.getBoolean(STATE_BUTTONS_OPENED)) + { + mFadeView.fadeInInstantly(); + mBottomButtons.showButtons(); + } + + super.onRestoreInstanceState(savedInstanceState); + } + + @Override + protected void onNewIntent(Intent intent) + { + super.onNewIntent(intent); + + if (intent != null) + { + if (intent.hasExtra(EXTRA_TASK)) + addTask(intent); + else if (intent.hasExtra(EXTRA_SET_MAP_STYLE)) + { + final int mapStyle = intent.getIntExtra(EXTRA_SET_MAP_STYLE, Framework.MAP_STYLE_LIGHT); + Framework.setMapStyle(mapStyle); + } + } + } + + private void addTask(Intent intent) + { + if (intent != null + && !intent.getBooleanExtra(EXTRA_CONSUMED, false) + && intent.hasExtra(EXTRA_TASK) + && ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0)) + { + final MapTask mapTask = (MapTask) intent.getSerializableExtra(EXTRA_TASK); + mTasks.add(mapTask); + intent.removeExtra(EXTRA_TASK); + + if (mMapFragment.isRenderingInitialized()) + runTasks(); + + // mark intent as consumed + intent.putExtra(EXTRA_CONSUMED, true); + } + } + + @Override + public void onLocationError(int errorCode) + { + mMapFragment.nativeOnLocationError(errorCode); + + // Notify user about turned off location services + if (errorCode == LocationHelper.ERROR_DENIED) + { + LocationState.INSTANCE.turnOff(); + + // Do not show this dialog on Kindle Fire - it doesn't have location services + // and even wifi settings can't be opened programmatically + if (!Utils.isAmazonDevice()) + { + new AlertDialog.Builder(this).setTitle(R.string.location_is_disabled_long_text) + .setPositiveButton(R.string.connection_settings, new DialogInterface.OnClickListener() + { + @Override + public void onClick(DialogInterface dialog, int which) + { + try + { + startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS)); + } catch (final Exception e1) + { + // On older Android devices location settings are merged with security + try + { + startActivity(new Intent(android.provider.Settings.ACTION_SECURITY_SETTINGS)); + } catch (final Exception e2) + { + Log.w(TAG, "Can't run activity" + e2); + } + } + + dialog.dismiss(); + } + }) + .setNegativeButton(R.string.close, new DialogInterface.OnClickListener() + { + @Override + public void onClick(DialogInterface dialog, int which) + { + dialog.dismiss(); + } + }) + .create() + .show(); + } + } + else if (errorCode == LocationHelper.ERROR_GPS_OFF) + { + Toast.makeText(this, R.string.gps_is_disabled_long_text, Toast.LENGTH_LONG).show(); + } + } + + @Override + public void onLocationUpdated(final Location l) + { + if (!l.getProvider().equals(LocationHelper.LOCATION_PREDICTOR_PROVIDER)) + mLocationPredictor.reset(l); + + mMapFragment.nativeLocationUpdated( + l.getTime(), + l.getLatitude(), + l.getLongitude(), + l.getAccuracy(), + l.getAltitude(), + l.getSpeed(), + l.getBearing()); + + if (mPlacePage.getState() != State.HIDDEN) + mPlacePage.refreshLocation(l); + + RoutingLayout.State state = mLayoutRouting.getState(); + if (state != RoutingLayout.State.HIDDEN) + { + mLayoutRouting.updateRouteInfo(); + + // TODO think about moving TtsPlayer logic to RoutingLayout to minimize native calls. + if (state == RoutingLayout.State.TURN_INSTRUCTIONS) + { + final String[] turnNotifications = Framework.nativeGenerateTurnSound(); + if (turnNotifications != null) + TtsPlayer.INSTANCE.speakNotifications(turnNotifications); + } + } + } + + @Override + public void onCompassUpdated(long time, double magneticNorth, double trueNorth, double accuracy) + { + final int rotation = getWindowManager().getDefaultDisplay().getRotation(); + magneticNorth = LocationUtils.correctCompassAngle(rotation, magneticNorth); + trueNorth = LocationUtils.correctCompassAngle(rotation, trueNorth); + final double north = (trueNorth >= 0.0) ? trueNorth : magneticNorth; + + mMapFragment.nativeCompassUpdated(time, magneticNorth, trueNorth, accuracy); + if (mPlacePage.getState() != State.HIDDEN) + mPlacePage.refreshAzimuth(north); + + if (mLayoutRouting.getState() != RoutingLayout.State.HIDDEN) + mLayoutRouting.refreshAzimuth(north); + } + + // Callback from native location state mode element processing. + public void onLocationStateModeChangedCallback(final int newMode) + { + runOnUiThread(new Runnable() + { + @Override + public void run() + { + refreshLocationState(newMode); + } + }); + } + + private void refreshLocationState(int newMode) + { + LocationButtonImageSetter.setButtonViewFromState(newMode, mBtnLocation); + switch (newMode) + { + case LocationState.UNKNOWN_POSITION: + pauseLocation(); + break; + case LocationState.PENDING_POSITION: + listenLocationUpdates(); + break; + default: + break; + } + } + + private void listenLocationStateModeUpdates() + { + mLocationStateModeListenerId = LocationState.INSTANCE.addLocationStateModeListener(this); + } + + private void stopWatchingCompassStatusUpdate() + { + LocationState.INSTANCE.removeLocationStateModeListener(mLocationStateModeListenerId); + } + + @Override + protected void onResume() + { + super.onResume(); + + listenLocationStateModeUpdates(); + invalidateLocationState(); + startWatchingExternalStorage(); + mSearchController.refreshToolbar(); + mPlacePage.onResume(); + mLikesManager.showLikeDialogForCurrentSession(); + refreshZoomButtonsAfterLayout(); + } + + private void refreshZoomButtonsAfterLayout() + { + mFadeView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() + { + @SuppressWarnings("deprecation") + @Override + public void onGlobalLayout() + { + refreshZoomButtonsVisibility(); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) + mFadeView.getViewTreeObserver().removeGlobalOnLayoutListener(this); + else + mFadeView.getViewTreeObserver().removeOnGlobalLayoutListener(this); + } + }); + } + + private void refreshZoomButtonsVisibility() + { + final boolean showZoomSetting = MwmApplication.get().nativeGetBoolean(SettingsActivity.ZOOM_BUTTON_ENABLED, true) || Framework.nativeIsRoutingActive(); + UiUtils.showIf(showZoomSetting && + !UiUtils.areViewsIntersecting(mToolbarSearch, mBtnZoomIn) && + !UiUtils.areViewsIntersecting(mLayoutRouting, mBtnZoomIn), + mBtnZoomIn, mBtnZoomOut); + } + + @Override + protected void onPause() + { + pauseLocation(); + stopWatchingExternalStorage(); + stopWatchingCompassStatusUpdate(); + TtsPlayer.INSTANCE.stop(); + super.onPause(); + mLikesManager.cancelLikeDialog(); + } + + private void updateExternalStorageState() + { + boolean available = false, writable = false; + final String state = Environment.getExternalStorageState(); + if (Environment.MEDIA_MOUNTED.equals(state)) + available = writable = true; + else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) + available = true; + + if (mStorageAvailable != available || mStorageWritable != writable) + { + mStorageAvailable = available; + mStorageWritable = writable; + handleExternalStorageState(available, writable); + } + } + + private void handleExternalStorageState(boolean available, boolean writeable) + { + if (available && writeable) + { + // Add local maps to the model + mMapFragment.nativeStorageConnected(); + + // @TODO enable downloader button and dismiss blocking popup + + if (mStorageDisconnectedDialog != null) + mStorageDisconnectedDialog.dismiss(); + } + else if (available) + { + // Add local maps to the model + mMapFragment.nativeStorageConnected(); + + // @TODO disable downloader button and dismiss blocking popup + + if (mStorageDisconnectedDialog != null) + mStorageDisconnectedDialog.dismiss(); + } + else + { + // Remove local maps from the model + mMapFragment.nativeStorageDisconnected(); + + // @TODO enable downloader button and show blocking popup + + if (mStorageDisconnectedDialog == null) + { + mStorageDisconnectedDialog = new AlertDialog.Builder(this) + .setTitle(R.string.external_storage_is_not_available) + .setMessage(getString(R.string.disconnect_usb_cable)) + .setCancelable(false) + .create(); + } + mStorageDisconnectedDialog.show(); + } + } + + private void startWatchingExternalStorage() + { + mExternalStorageReceiver = new BroadcastReceiver() + { + @Override + public void onReceive(Context context, Intent intent) + { + updateExternalStorageState(); + } + }; + + registerReceiver(mExternalStorageReceiver, StoragePathManager.getMediaChangesIntentFilter()); + updateExternalStorageState(); + } + + private void stopWatchingExternalStorage() + { + mPathManager.stopExternalStorageWatching(); + if (mExternalStorageReceiver != null) + { + unregisterReceiver(mExternalStorageReceiver); + mExternalStorageReceiver = null; + } + } + + @Override + public void onBackPressed() + { + if (mPlacePage.getState() != State.HIDDEN) + { + hidePlacePage(); + Framework.deactivatePopup(); + } + else if (mBottomButtons.areButtonsVisible()) + { + mBottomButtons.toggle(); + mFadeView.fadeOut(false); + } + else if (canFragmentInterceptBackPress()) + return; + else if (popFragment()) + { + InputUtils.hideKeyboard(mFadeView); + mFadeView.fadeOut(false); + } + else + super.onBackPressed(); + } + + private boolean isMapFaded() + { + return mFadeView.getVisibility() == View.VISIBLE; + } + + private boolean canFragmentInterceptBackPress() + { + final FragmentManager manager = getSupportFragmentManager(); + DownloadFragment fragment = (DownloadFragment) manager.findFragmentByTag(DownloadFragment.class.getName()); + return fragment != null && fragment.isResumed() && fragment.onBackPressed(); + } + + private boolean popFragment() + { + for (String tag : new String[]{SearchFragment.class.getName(), DownloadFragment.class.getName()}) + if (popFragment(tag)) + return true; + + return false; + } + + private void popAllFragments() + { + for (String tag : new String[]{SearchFragment.class.getName(), DownloadFragment.class.getName()}) + popFragment(tag); + } + + private boolean popFragment(String className) + { + final FragmentManager manager = getSupportFragmentManager(); + Fragment fragment = manager.findFragmentByTag(className); + // TODO d.yunitsky + // we cant pop fragment, if it isn't resumed, cause of 'at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1375)' + if (fragment != null && fragment.isResumed()) + { + manager.popBackStackImmediate(); + return true; + } + + return false; + } + + // Callbacks from native map objects touch event. + @Override + public void onApiPointActivated(final double lat, final double lon, final String name, final String id) + { + if (ParsedMwmRequest.hasRequest()) + { + final ParsedMwmRequest request = ParsedMwmRequest.getCurrentRequest(); + request.setPointData(lat, lon, name, id); + + runOnUiThread(new Runnable() + { + @Override + public void run() + { + final String poiType = ParsedMwmRequest.getCurrentRequest().getCallerName(MwmApplication.get()).toString(); + activateMapObject(new ApiPoint(name, id, poiType, lat, lon)); + } + }); + } + } + + @Override + public void onPoiActivated(final String name, final String type, final String address, final double lat, final double lon, + final int[] metaTypes, final String[] metaValues) + { + final MapObject poi = new MapObject.Poi(name, lat, lon, type); + poi.addMetadata(metaTypes, metaValues); + + runOnUiThread(new Runnable() + { + @Override + public void run() + { + activateMapObject(poi); + } + }); + } + + @Override + public void onBookmarkActivated(final int category, final int bookmarkIndex) + { + runOnUiThread(new Runnable() + { + @Override + public void run() + { + activateMapObject(BookmarkManager.INSTANCE.getBookmark(category, bookmarkIndex)); + } + }); + } + + @Override + public void onMyPositionActivated(final double lat, final double lon) + { + final MapObject mypos = new MapObject.MyPosition(getString(R.string.my_position), lat, lon); + + runOnUiThread(new Runnable() + { + @Override + public void run() + { + if (!Framework.nativeIsRoutingActive()) + { + activateMapObject(mypos); + } + } + }); + } + + @Override + public void onAdditionalLayerActivated(final String name, final String type, final double lat, final double lon, final int[] metaTypes, final String[] metaValues) + { + runOnUiThread(new Runnable() + { + @Override + public void run() + { + final MapObject sr = new MapObject.SearchResult(name, type, lat, lon); + sr.addMetadata(metaTypes, metaValues); + activateMapObject(sr); + } + }); + } + + private void activateMapObject(MapObject object) + { + mPlacePage.bringToFront(); + if (!mPlacePage.hasMapObject(object)) + { + mPlacePage.setMapObject(object); + mPlacePage.setState(State.PREVIEW); + popAllFragments(); + if (isMapFaded()) + mFadeView.fadeOut(false); + } + } + + private void hidePlacePage() + { + mPlacePage.setState(State.HIDDEN); + mPlacePage.setMapObject(null); + } + + @Override + public void onDismiss() + { + if (!mPlacePage.hasMapObject(null)) + { + runOnUiThread(new Runnable() + { + @Override + public void run() + { + hidePlacePage(); + Framework.deactivatePopup(); + } + }); + } + } + + @Override + public void onPreviewVisibilityChanged(boolean isVisible) + { + if (isVisible) + { + if (previewIntersectsBottomMenu()) + mBottomButtons.setVisibility(View.GONE); + if (previewIntersectsZoomButtons()) + UiUtils.hide(mBtnZoomIn, mBtnZoomOut); + } + else + { + Framework.deactivatePopup(); + mPlacePage.setMapObject(null); + refreshZoomButtonsVisibility(); + mBottomButtons.setVisibility(View.VISIBLE); + } + } + + private boolean previewIntersectsBottomMenu() + { + return !(UiUtils.isBigTablet() || (UiUtils.isSmallTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE)); + } + + private boolean previewIntersectsZoomButtons() + { + return !(UiUtils.isBigTablet() || UiUtils.isSmallTablet()); + } + + @Override + public void onPlacePageVisibilityChanged(boolean isVisible) + { + if (isVisible) + { + AlohaHelper.logClick(AlohaHelper.PP_OPEN); + if (placePageIntersectsZoomButtons()) + UiUtils.hide(mBtnZoomIn, mBtnZoomOut); + else + refreshZoomButtonsVisibility(); + } + else + AlohaHelper.logClick(AlohaHelper.PP_CLOSE); + } + + private boolean placePageIntersectsZoomButtons() + { + return !(UiUtils.isBigTablet() || (UiUtils.isSmallTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE)); + } + + @Override + public void onClick(View v) + { + switch (v.getId()) + { + case R.id.ll__share: + AlohaHelper.logClick(AlohaHelper.MENU_SHARE); + shareMyLocation(); + mBottomButtons.hideButtons(); + UiUtils.hide(mFadeView); + UiUtils.clearAnimationAfterAlpha(mFadeView); + break; + case R.id.ll__settings: + AlohaHelper.logClick(AlohaHelper.MENU_SETTINGS); + startActivity(new Intent(this, SettingsActivity.class)); + mBottomButtons.hideButtons(); + UiUtils.hide(mFadeView); + UiUtils.clearAnimationAfterAlpha(mFadeView); + break; + case R.id.ll__download_maps: + AlohaHelper.logClick(AlohaHelper.MENU_DOWNLOADER); + showDownloader(false); + mBottomButtons.hideButtons(); + UiUtils.hide(mFadeView); + UiUtils.clearAnimationAfterAlpha(mFadeView); + break; + case R.id.ll__route: + AlohaHelper.logClick(AlohaHelper.PP_ROUTE); + mLayoutRouting.setEndPoint(mPlacePage.getMapObject()); + mLayoutRouting.setState(RoutingLayout.State.PREPARING, true); + mPlacePage.setState(PlacePageView.State.HIDDEN); + break; + case R.id.map_button_plus: + AlohaHelper.logClick(AlohaHelper.ZOOM_IN); + mMapFragment.nativeScale(3.0 / 2); + break; + case R.id.map_button_minus: + AlohaHelper.logClick(AlohaHelper.ZOOM_OUT); + mMapFragment.nativeScale(2 / 3.0); + break; + case R.id.btn__open_menu: + AlohaHelper.logClick(AlohaHelper.TOOLBAR_MENU); + mFadeView.fadeIn(false); + mBottomButtons.toggle(); + break; + case R.id.ll__search: + AlohaHelper.logClick(AlohaHelper.TOOLBAR_SEARCH); + showSearchIfContainsSearchIndex(); + mBottomButtons.hideButtons(); + UiUtils.hide(mFadeView); + UiUtils.clearAnimationAfterAlpha(mFadeView); + break; + case R.id.ll__bookmarks: + AlohaHelper.logClick(AlohaHelper.TOOLBAR_BOOKMARKS); + showBookmarks(); + mBottomButtons.hideButtons(); + UiUtils.hide(mFadeView); + UiUtils.clearAnimationAfterAlpha(mFadeView); + break; + case R.id.btn__myposition: + switchNextLocationState(); + break; + case R.id.yop_it: + final double[] latLon = Framework.getScreenRectCenter(); + final double zoom = Framework.getDrawScale(); + + final int locationStateMode = LocationState.INSTANCE.getLocationStateMode(); + + if (locationStateMode > LocationState.NOT_FOLLOW) + Yota.showLocation(getApplicationContext(), zoom); + else + Yota.showMap(getApplicationContext(), latLon[0], latLon[1], zoom, null, locationStateMode == LocationState.NOT_FOLLOW); + + Statistics.INSTANCE.trackBackscreenCall("Map"); + break; + default: + break; + } + } + + private void closeRouting() + { + + mLayoutRouting.setState(RoutingLayout.State.HIDDEN, true); + } + + private static void switchNextLocationState() + { + LocationState.INSTANCE.switchToNextMode(); + } + + @Override + public boolean onTouch(View view, MotionEvent event) + { + boolean result = false; + if (mPlacePage.getState() == State.DETAILS || mPlacePage.getState() == State.BOOKMARK) + { + Framework.deactivatePopup(); + hidePlacePage(); + result = true; + } + + return result || mMapFragment.onTouch(view, event); + } + + @Override + public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) + { + if (keyCode == KeyEvent.KEYCODE_MENU) + { + if (mBottomButtons.areButtonsVisible()) + mFadeView.fadeOut(false); + else + mFadeView.fadeIn(false); + mBottomButtons.toggle(); + return true; + } + return super.onKeyUp(keyCode, event); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) + { + if (resultCode == RESULT_OK && requestCode == ChooseBookmarkCategoryActivity.REQUEST_CODE_BOOKMARK_SET) + { + final Point bookmarkAndCategory = ((ParcelablePoint) data.getParcelableExtra(ChooseBookmarkCategoryActivity.BOOKMARK)).getPoint(); + final Bookmark bookmark = BookmarkManager.INSTANCE.getBookmark(bookmarkAndCategory.x, bookmarkAndCategory.y); + mPlacePage.setMapObject(bookmark); + } + super.onActivityResult(requestCode, resultCode, data); + } + + @Override + public void onRoutingEvent(final int resultCode, final Index[] missingCountries) + { + runOnUiThread(new Runnable() + { + @Override + public void run() + { + if (resultCode == RoutingResultCodesProcessor.NO_ERROR) + { + mLayoutRouting.setState(RoutingLayout.State.ROUTE_BUILT, true); + } + else + { + mLayoutRouting.setState(RoutingLayout.State.ROUTE_BUILD_ERROR, true); + final Bundle args = new Bundle(); + args.putInt(RoutingErrorDialogFragment.EXTRA_RESULT_CODE, resultCode); + args.putSerializable(RoutingErrorDialogFragment.EXTRA_MISSING_COUNTRIES, missingCountries); + final RoutingErrorDialogFragment fragment = (RoutingErrorDialogFragment) Fragment.instantiate(MwmActivity.this, RoutingErrorDialogFragment.class.getName()); + fragment.setArguments(args); + fragment.setListener(new RoutingErrorDialogFragment.RoutingDialogListener() + { + @Override + public void onDownload() + { + mLayoutRouting.setState(RoutingLayout.State.HIDDEN, false); + refreshZoomButtonsVisibility(); + ActiveCountryTree.downloadMapsForIndex(missingCountries, StorageOptions.MAP_OPTION_MAP_AND_CAR_ROUTING); + showDownloader(true); + } + + @Override + public void onCancel() + { + refreshZoomButtonsVisibility(); + } + + @Override + public void onOk() + { + if (RoutingResultCodesProcessor.isDownloadable(resultCode)) + { + mLayoutRouting.setState(RoutingLayout.State.HIDDEN, false); + refreshZoomButtonsVisibility(); + showDownloader(false); + } + } + }); + fragment.show(getSupportFragmentManager(), RoutingErrorDialogFragment.class.getName()); + } + + refreshZoomButtonsVisibility(); + } + }); + } + + @Override + public void onRouteBuildingProgress(final float progress) + { + runOnUiThread(new Runnable() + { + @Override + public void run() + { + mLayoutRouting.setRouteBuildingProgress(progress); + } + }); + } + + @Override + public void customOnNavigateUp() + { + if (popFragment()) + { + InputUtils.hideKeyboard(mBottomButtons); + mSearchController.refreshToolbar(); + } + } + + public interface MapTask extends Serializable + { + boolean run(MwmActivity target); + } + + public static class OpenUrlTask implements MapTask + { + private static final long serialVersionUID = 1L; + private final String mUrl; + + public OpenUrlTask(String url) + { + Utils.checkNotNull(url); + mUrl = url; + } + + @Override + public boolean run(MwmActivity target) + { + return target.mMapFragment.showMapForUrl(mUrl); + } + } + + public static class ShowCountryTask implements MapTask + { + private static final long serialVersionUID = 1L; + private final Index mIndex; + private final boolean mDoAutoDownload; + + public ShowCountryTask(Index index, boolean doAutoDownload) + { + mIndex = index; + mDoAutoDownload = doAutoDownload; + } + + @Override + public boolean run(MwmActivity target) + { + if (mDoAutoDownload) + { + Framework.downloadCountry(mIndex); + // set zoom level so that download process is visible + Framework.nativeShowCountry(mIndex, true); + } + else + Framework.nativeShowCountry(mIndex, false); + + return true; + } + } + + public static class UpdateCountryTask implements MapTask + { + @Override + public boolean run(final MwmActivity target) + { + target.runOnUiThread(new Runnable() + { + @Override + public void run() + { + target.showDownloader(true); + } + }); + return true; + } + } +} |