package net.osmand.plus.mapcontextmenu; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.annotation.TargetApi; import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.util.TypedValue; import android.view.GestureDetector; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.animation.DecelerateInterpolator; import android.widget.Button; import android.widget.FrameLayout; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; import net.osmand.AndroidUtils; import net.osmand.Location; import net.osmand.data.LatLon; import net.osmand.data.QuadPoint; import net.osmand.data.RotatedTileBox; import net.osmand.plus.IconsCache; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandSettings; import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.dashboard.DashLocationFragment; import net.osmand.plus.download.DownloadIndexesThread.DownloadEvents; import net.osmand.plus.mapcontextmenu.MenuController.MenuState; import net.osmand.plus.mapcontextmenu.MenuController.TitleButtonController; import net.osmand.plus.mapcontextmenu.MenuController.TitleProgressController; import net.osmand.plus.mapcontextmenu.other.MapRouteInfoMenu; import net.osmand.plus.views.AnimateDraggingMapThread; import net.osmand.plus.views.OsmandMapTileView; import net.osmand.plus.views.controls.HorizontalSwipeConfirm; import net.osmand.plus.views.controls.SingleTapConfirm; import net.osmand.util.Algorithms; import static android.util.TypedValue.COMPLEX_UNIT_DIP; import static net.osmand.plus.mapcontextmenu.MenuBuilder.SHADOW_HEIGHT_TOP_DP; public class MapContextMenuFragment extends Fragment implements DownloadEvents { public static final String TAG = "MapContextMenuFragment"; public static final float FAB_PADDING_TOP_DP = 4f; public static final float MARKER_PADDING_DP = 20f; public static final float MARKER_PADDING_X_DP = 50f; public static final float SKIP_HALF_SCREEN_STATE_KOEF = .21f; public static final int ZOOM_IN_STANDARD = 17; private View view; private View mainView; ImageView fabView; private MapContextMenu menu; private TitleButtonController leftTitleButtonController; private TitleButtonController rightTitleButtonController; private TitleButtonController topRightTitleButtonController; private TitleButtonController leftDownloadButtonController; private TitleButtonController rightDownloadButtonController; private TitleProgressController titleProgressController; private int menuTopViewHeight; private int menuTopShadowHeight; private int menuTopShadowAllHeight; private int menuTitleHeight; private int menuBottomViewHeight; private int menuFullHeight; private int menuFullHeightMax; private int menuTopViewHeightExcludingTitle; private int menuTitleTopBottomPadding; private int screenHeight; private int viewHeight; private int fabPaddingTopPx; private int markerPaddingPx; private int markerPaddingXPx; private OsmandMapTileView map; private LatLon mapCenter; private int mapZoom; private int origMarkerX; private int origMarkerY; private boolean customMapCenter; private boolean moving; private boolean nightMode; private boolean centered; private boolean initLayout = true; private boolean wasDrawerDisabled; private boolean zoomIn; private float skipHalfScreenStateLimit; private int screenOrientation; @TargetApi(Build.VERSION_CODES.HONEYCOMB) @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { screenHeight = AndroidUtils.getScreenHeight(getActivity()); skipHalfScreenStateLimit = screenHeight * SKIP_HALF_SCREEN_STATE_KOEF; viewHeight = screenHeight - AndroidUtils.getStatusBarHeight(getMapActivity()); fabPaddingTopPx = dpToPx(FAB_PADDING_TOP_DP); markerPaddingPx = dpToPx(MARKER_PADDING_DP); markerPaddingXPx = dpToPx(MARKER_PADDING_X_DP); menu = getMapActivity().getContextMenu(); view = inflater.inflate(R.layout.map_context_menu_fragment, container, false); if (!menu.isActive()) { return view; } nightMode = menu.isNightMode(); mainView = view.findViewById(R.id.context_menu_main); leftTitleButtonController = menu.getLeftTitleButtonController(); rightTitleButtonController = menu.getRightTitleButtonController(); topRightTitleButtonController = menu.getTopRightTitleButtonController(); leftDownloadButtonController = menu.getLeftDownloadButtonController(); rightDownloadButtonController = menu.getRightDownloadButtonController(); titleProgressController = menu.getTitleProgressController(); map = getMapActivity().getMapView(); RotatedTileBox box = map.getCurrentRotatedTileBox().copy(); customMapCenter = menu.getMapCenter() != null; if (!customMapCenter) { mapCenter = box.getCenterLatLon(); menu.setMapCenter(mapCenter); double markerLat = menu.getLatLon().getLatitude(); double markerLon = menu.getLatLon().getLongitude(); origMarkerX = (int) box.getPixXFromLatLon(markerLat, markerLon); origMarkerY = (int) box.getPixYFromLatLon(markerLat, markerLon); } else { mapCenter = menu.getMapCenter(); origMarkerX = box.getCenterPixelX(); origMarkerY = box.getCenterPixelY(); } mapZoom = menu.getMapZoom(); if (mapZoom == 0) { mapZoom = map.getZoom(); } IconsCache iconsCache = getMyApplication().getIconsCache(); // Left title button final Button leftTitleButton = (Button) view.findViewById(R.id.title_button); if (leftTitleButtonController != null) { leftTitleButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { leftTitleButtonController.buttonPressed(); } }); } // Right title button final Button rightTitleButton = (Button) view.findViewById(R.id.title_button_right); if (rightTitleButtonController != null) { rightTitleButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { rightTitleButtonController.buttonPressed(); } }); } // Left download button final Button leftDownloadButton = (Button) view.findViewById(R.id.download_button_left); if (leftDownloadButtonController != null) { leftDownloadButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { leftDownloadButtonController.buttonPressed(); } }); } // Right download button final Button rightDownloadButton = (Button) view.findViewById(R.id.download_button_right); if (rightDownloadButtonController != null) { rightDownloadButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { rightDownloadButtonController.buttonPressed(); } }); } // Top Right title button final Button topRightTitleButton = (Button) view.findViewById(R.id.title_button_top_right); if (topRightTitleButtonController != null) { topRightTitleButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { topRightTitleButtonController.buttonPressed(); } }); } // Progress bar if (titleProgressController != null) { final ImageView progressButton = (ImageView) view.findViewById(R.id.progressButton); progressButton.setImageDrawable(iconsCache.getIcon(R.drawable.ic_action_remove_dark, !nightMode ? R.color.icon_color : R.color.dashboard_subheader_text_dark)); progressButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { titleProgressController.buttonPressed(); } }); } menu.updateData(); updateButtonsAndProgress(); if (menu.isLandscapeLayout()) { final TypedValue typedValueAttr = new TypedValue(); getMapActivity().getTheme().resolveAttribute(R.attr.left_menu_view_bg, typedValueAttr, true); mainView.setBackgroundResource(typedValueAttr.resourceId); mainView.setLayoutParams(new FrameLayout.LayoutParams(menu.getLandscapeWidthPx(), ViewGroup.LayoutParams.MATCH_PARENT)); View fabContainer = view.findViewById(R.id.context_menu_fab_container); fabContainer.setLayoutParams(new FrameLayout.LayoutParams(menu.getLandscapeWidthPx(), ViewGroup.LayoutParams.MATCH_PARENT)); } runLayoutListener(); final GestureDetector singleTapDetector = new GestureDetector(view.getContext(), new SingleTapConfirm()); final GestureDetector swipeDetector = new GestureDetector(view.getContext(), new HorizontalSwipeConfirm(true)); final View.OnTouchListener slideTouchListener = new View.OnTouchListener() { private float dy; private float dyMain; private VelocityTracker velocity; private boolean slidingUp; private boolean slidingDown; private float velocityY; private float maxVelocityY; private boolean hasMoved; @Override public boolean onTouch(View v, MotionEvent event) { if (singleTapDetector.onTouchEvent(event)) { moving = false; if (hasMoved) { applyPosY(getViewY(), false, false, 0, 0); } openMenuHalfScreen(); return true; } if (menu.isLandscapeLayout()) { if (swipeDetector.onTouchEvent(event)) { menu.close(); } return true; } switch (event.getAction()) { case MotionEvent.ACTION_DOWN: hasMoved = false; dy = event.getY(); dyMain = getViewY(); velocity = VelocityTracker.obtain(); velocityY = 0; maxVelocityY = 0; velocity.addMovement(event); moving = true; break; case MotionEvent.ACTION_MOVE: if (moving) { hasMoved = true; float y = event.getY(); float newY = getViewY() + (y - dy); setViewY((int) newY, false, false); menuFullHeight = view.getHeight() - (int) newY + 10; if (!oldAndroid()) { ViewGroup.LayoutParams lp = mainView.getLayoutParams(); lp.height = Math.max(menuFullHeight, menuTitleHeight); mainView.setLayoutParams(lp); mainView.requestLayout(); } velocity.addMovement(event); velocity.computeCurrentVelocity(1000); velocityY = Math.abs(velocity.getYVelocity()); if (velocityY > maxVelocityY) maxVelocityY = velocityY; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: if (moving) { moving = false; int currentY = getViewY(); slidingUp = Math.abs(maxVelocityY) > 500 && (currentY - dyMain) < -50; slidingDown = Math.abs(maxVelocityY) > 500 && (currentY - dyMain) > 50; velocity.recycle(); boolean skipHalfScreenState = Math.abs(currentY - dyMain) > skipHalfScreenStateLimit; changeMenuState(currentY, skipHalfScreenState, slidingUp, slidingDown); } break; } return true; } }; View topView = view.findViewById(R.id.context_menu_top_view); topView.setOnTouchListener(slideTouchListener); View topShadowView = view.findViewById(R.id.context_menu_top_shadow); topShadowView.setOnTouchListener(slideTouchListener); View topShadowAllView = view.findViewById(R.id.context_menu_top_shadow_all); AndroidUtils.setBackground(getMapActivity(), topShadowAllView, nightMode, R.drawable.bg_map_context_menu_light, R.drawable.bg_map_context_menu_dark); topShadowAllView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getY() <= dpToPx(SHADOW_HEIGHT_TOP_DP) || event.getAction() != MotionEvent.ACTION_DOWN) return slideTouchListener.onTouch(v, event); else return false; } }); buildHeader(); AndroidUtils.setTextPrimaryColor(getMapActivity(), (TextView) view.findViewById(R.id.context_menu_line1), nightMode); View menuLine2 = view.findViewById(R.id.context_menu_line2); if (menuLine2 != null) { AndroidUtils.setTextSecondaryColor(getMapActivity(), (TextView) menuLine2, nightMode); } ((Button) view.findViewById(R.id.title_button_top_right)) .setTextColor(!nightMode ? getResources().getColor(R.color.map_widget_blue) : getResources().getColor(R.color.osmand_orange)); AndroidUtils.setTextSecondaryColor(getMapActivity(), (TextView) view.findViewById(R.id.distance), nightMode); ((Button) view.findViewById(R.id.title_button)) .setTextColor(!nightMode ? getResources().getColor(R.color.map_widget_blue) : getResources().getColor(R.color.osmand_orange)); AndroidUtils.setTextSecondaryColor(getMapActivity(), (TextView) view.findViewById(R.id.title_button_right_text), nightMode); ((Button) view.findViewById(R.id.title_button_right)) .setTextColor(!nightMode ? getResources().getColor(R.color.map_widget_blue) : getResources().getColor(R.color.osmand_orange)); AndroidUtils.setTextSecondaryColor(getMapActivity(), (TextView) view.findViewById(R.id.progressTitle), nightMode); // FAB fabView = (ImageView) view.findViewById(R.id.context_menu_fab_view); if (menu.fabVisible()) { fabView.setImageDrawable(iconsCache.getIcon(menu.getFabIconId(), 0)); if (menu.isLandscapeLayout()) { FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) fabView.getLayoutParams(); params.setMargins(0, 0, dpToPx(28f), 0); fabView.setLayoutParams(params); } fabView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { menu.fabPressed(); } }); } else { fabView.setVisibility(View.GONE); } View buttonsTopBorder = view.findViewById(R.id.buttons_top_border); AndroidUtils.setBackground(getMapActivity(), buttonsTopBorder, nightMode, R.color.dashboard_divider_light, R.color.dashboard_divider_dark); if (!menu.buttonsVisible()) { View buttons = view.findViewById(R.id.context_menu_buttons); buttonsTopBorder.setVisibility(View.GONE); buttons.setVisibility(View.GONE); } AndroidUtils.setBackground(getMapActivity(), mainView.findViewById(R.id.divider_hor_1), nightMode, R.color.dashboard_divider_light, R.color.dashboard_divider_dark); AndroidUtils.setBackground(getMapActivity(), mainView.findViewById(R.id.divider_hor_2), nightMode, R.color.dashboard_divider_light, R.color.dashboard_divider_dark); AndroidUtils.setBackground(getMapActivity(), mainView.findViewById(R.id.divider_hor_3), nightMode, R.color.dashboard_divider_light, R.color.dashboard_divider_dark); // Action buttons final ImageButton buttonFavorite = (ImageButton) view.findViewById(R.id.context_menu_fav_button); buttonFavorite.setImageDrawable(iconsCache.getIcon(menu.getFavActionIconId(), !nightMode ? R.color.icon_color : R.color.dashboard_subheader_text_dark)); AndroidUtils.setDashButtonBackground(getMapActivity(), buttonFavorite, nightMode); buttonFavorite.setContentDescription(getString(menu.getFavActionStringId())); buttonFavorite.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { menu.buttonFavoritePressed(); } }); final ImageButton buttonWaypoint = (ImageButton) view.findViewById(R.id.context_menu_route_button); if (getMyApplication().getSettings().USE_MAP_MARKERS.get()) { buttonWaypoint.setImageDrawable(iconsCache.getIcon(R.drawable.map_action_flag_dark, !nightMode ? R.color.icon_color : R.color.dashboard_subheader_text_dark)); buttonWaypoint.setContentDescription(getString(R.string.shared_string_add_to_map_markers)); } else { buttonWaypoint.setImageDrawable(iconsCache.getIcon(R.drawable.map_action_waypoint, !nightMode ? R.color.icon_color : R.color.dashboard_subheader_text_dark)); buttonWaypoint.setContentDescription(getString(R.string.context_menu_item_destination_point)); } AndroidUtils.setDashButtonBackground(getMapActivity(), buttonWaypoint, nightMode); buttonWaypoint.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { menu.buttonWaypointPressed(); } }); final ImageButton buttonShare = (ImageButton) view.findViewById(R.id.context_menu_share_button); buttonShare.setImageDrawable(iconsCache.getIcon(R.drawable.map_action_gshare_dark, !nightMode ? R.color.icon_color : R.color.dashboard_subheader_text_dark)); AndroidUtils.setDashButtonBackground(getMapActivity(), buttonShare, nightMode); buttonShare.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { menu.buttonSharePressed(); } }); final ImageButton buttonMore = (ImageButton) view.findViewById(R.id.context_menu_more_button); buttonMore.setImageDrawable(iconsCache.getIcon(R.drawable.map_overflow_menu_white, !nightMode ? R.color.icon_color : R.color.dashboard_subheader_text_dark)); AndroidUtils.setDashButtonBackground(getMapActivity(), buttonMore, nightMode); buttonMore.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { menu.buttonMorePressed(); } }); buildBottomView(); view.findViewById(R.id.context_menu_bottom_scroll).setBackgroundColor(nightMode ? getResources().getColor(R.color.ctx_menu_info_view_bg_dark) : getResources().getColor(R.color.ctx_menu_info_view_bg_light)); view.findViewById(R.id.context_menu_bottom_view).setBackgroundColor(nightMode ? getResources().getColor(R.color.ctx_menu_info_view_bg_dark) : getResources().getColor(R.color.ctx_menu_info_view_bg_light)); //getMapActivity().getMapLayers().getMapControlsLayer().setControlsClickable(false); return view; } public void openMenuFullScreen() { changeMenuState(getViewY(), true, true, false); } public void openMenuHalfScreen() { int oldMenuState = menu.getCurrentMenuState(); if (oldMenuState == MenuState.HEADER_ONLY) { changeMenuState(getViewY(), false, true, false); } else if (oldMenuState == MenuState.FULL_SCREEN && !menu.isLandscapeLayout()) { changeMenuState(getViewY(), false, false, true); } } private void changeMenuState(int currentY, boolean skipHalfScreenState, boolean slidingUp, boolean slidingDown) { boolean needCloseMenu = false; int oldMenuState = menu.getCurrentMenuState(); if (menuBottomViewHeight > 0 && slidingUp) { menu.slideUp(); if (skipHalfScreenState) { menu.slideUp(); } } else if (slidingDown) { needCloseMenu = !menu.slideDown(); if (!needCloseMenu && skipHalfScreenState) { menu.slideDown(); } } int newMenuState = menu.getCurrentMenuState(); boolean needMapAdjust = oldMenuState != newMenuState && newMenuState != MenuState.FULL_SCREEN; if (newMenuState != oldMenuState) { doBeforeMenuStateChange(oldMenuState, newMenuState); } applyPosY(currentY, needCloseMenu, needMapAdjust, oldMenuState, newMenuState); } private void applyPosY(final int currentY, final boolean needCloseMenu, boolean needMapAdjust, final int previousMenuState, final int newMenuState) { final int posY = getPosY(needCloseMenu); if (currentY != posY) { if (posY < currentY) { updateMainViewLayout(posY); } if (!oldAndroid()) { mainView.animate().y(posY) .setDuration(200) .setInterpolator(new DecelerateInterpolator()) .setListener(new AnimatorListenerAdapter() { boolean canceled = false; @Override public void onAnimationCancel(Animator animation) { canceled = true; } @Override public void onAnimationEnd(Animator animation) { if (!canceled) { if (needCloseMenu) { menu.close(); } else { updateMainViewLayout(posY); if (previousMenuState != 0 && newMenuState != 0 && previousMenuState != newMenuState) { doAfterMenuStateChange(previousMenuState, newMenuState); } } } } }) .start(); fabView.animate().y(getFabY(posY)) .setDuration(200) .setInterpolator(new DecelerateInterpolator()) .start(); if (needMapAdjust) { adjustMapPosition(posY, true, centered); } } else { setViewY(posY, false, needMapAdjust); if (needCloseMenu) { menu.close(); } else { updateMainViewLayout(posY); if (previousMenuState != 0 && newMenuState != 0 && previousMenuState != newMenuState) { doAfterMenuStateChange(previousMenuState, newMenuState); } } } } } public void updateMapCenter(LatLon mapCenter) { customMapCenter = true; menu.setMapCenter(mapCenter); this.mapCenter = mapCenter; RotatedTileBox box = map.getCurrentRotatedTileBox().copy(); origMarkerX = box.getCenterPixelX(); origMarkerY = box.getCenterPixelY(); } private void updateButtonsAndProgress() { // Title buttons boolean showTitleButtonsContainer = (leftTitleButtonController != null || rightTitleButtonController != null); final View titleButtonsContainer = view.findViewById(R.id.title_button_container); titleButtonsContainer.setVisibility(showTitleButtonsContainer ? View.VISIBLE : View.GONE); // Left title button final Button leftTitleButton = (Button) view.findViewById(R.id.title_button); final TextView titleButtonRightText = (TextView) view.findViewById(R.id.title_button_right_text); if (leftTitleButtonController != null) { leftTitleButton.setText(leftTitleButtonController.caption); leftTitleButton.setVisibility(leftTitleButtonController.visible ? View.VISIBLE : View.GONE); Drawable leftIcon = leftTitleButtonController.getLeftIcon(); if (leftIcon != null) { leftTitleButton.setCompoundDrawablesWithIntrinsicBounds(leftIcon, null, null, null); leftTitleButton.setCompoundDrawablePadding(dpToPx(4f)); } if (leftTitleButtonController.needRightText) { titleButtonRightText.setText(leftTitleButtonController.rightTextCaption); titleButtonRightText.setVisibility(View.VISIBLE); } else { titleButtonRightText.setVisibility(View.GONE); } } else { leftTitleButton.setVisibility(View.GONE); titleButtonRightText.setVisibility(View.GONE); } // Right title button final Button rightTitleButton = (Button) view.findViewById(R.id.title_button_right); if (rightTitleButtonController != null) { rightTitleButton.setText(rightTitleButtonController.caption); rightTitleButton.setVisibility(rightTitleButtonController.visible ? View.VISIBLE : View.GONE); Drawable leftIcon = rightTitleButtonController.getLeftIcon(); rightTitleButton.setCompoundDrawablesWithIntrinsicBounds(leftIcon, null, null, null); rightTitleButton.setCompoundDrawablePadding(dpToPx(4f)); } else { rightTitleButton.setVisibility(View.GONE); } // Top Right title button final Button topRightTitleButton = (Button) view.findViewById(R.id.title_button_top_right); if (topRightTitleButtonController != null) { topRightTitleButton.setText(topRightTitleButtonController.caption); topRightTitleButton.setVisibility(topRightTitleButtonController.visible ? View.VISIBLE : View.INVISIBLE); Drawable leftIcon = topRightTitleButtonController.getLeftIcon(); topRightTitleButton.setCompoundDrawablesWithIntrinsicBounds(leftIcon, null, null, null); topRightTitleButton.setCompoundDrawablePadding(dpToPx(4f)); } else { topRightTitleButton.setVisibility(View.GONE); } // Download buttons boolean showDownloadButtonsContainer = ((leftDownloadButtonController != null && leftDownloadButtonController.visible) || (rightDownloadButtonController != null && rightDownloadButtonController.visible)) && (titleProgressController == null || !titleProgressController.visible); final View downloadButtonsContainer = view.findViewById(R.id.download_buttons_container); downloadButtonsContainer.setVisibility(showDownloadButtonsContainer ? View.VISIBLE : View.GONE); if (showDownloadButtonsContainer) { view.findViewById(R.id.download_buttons_top_border).setVisibility(showTitleButtonsContainer ? View.VISIBLE : View.INVISIBLE); if (showTitleButtonsContainer) { LinearLayout.LayoutParams ll = (LinearLayout.LayoutParams) downloadButtonsContainer.getLayoutParams(); if (ll.topMargin != 0) { ll.setMargins(0, 0, 0, 0); } } } // Left download button final Button leftDownloadButton = (Button) view.findViewById(R.id.download_button_left); if (leftDownloadButtonController != null) { leftDownloadButton.setText(leftDownloadButtonController.caption); leftDownloadButton.setVisibility(leftDownloadButtonController.visible ? View.VISIBLE : View.GONE); Drawable leftIcon = leftDownloadButtonController.getLeftIcon(); if (leftIcon != null) { leftDownloadButton.setCompoundDrawablesWithIntrinsicBounds(leftIcon, null, null, null); leftDownloadButton.setCompoundDrawablePadding(dpToPx(4f)); } } else { leftDownloadButton.setVisibility(View.GONE); } // Right download button final Button rightDownloadButton = (Button) view.findViewById(R.id.download_button_right); if (rightDownloadButtonController != null) { rightDownloadButton.setText(rightDownloadButtonController.caption); rightDownloadButton.setVisibility(rightDownloadButtonController.visible ? View.VISIBLE : View.GONE); Drawable leftIcon = rightDownloadButtonController.getLeftIcon(); rightDownloadButton.setCompoundDrawablesWithIntrinsicBounds(leftIcon, null, null, null); rightDownloadButton.setCompoundDrawablePadding(dpToPx(4f)); } else { rightDownloadButton.setVisibility(View.GONE); } // Progress bar final View titleProgressContainer = view.findViewById(R.id.title_progress_container); if (titleProgressController != null) { titleProgressContainer.setVisibility(titleProgressController.visible ? View.VISIBLE : View.GONE); if (titleProgressController.visible && showTitleButtonsContainer) { LinearLayout.LayoutParams ll = (LinearLayout.LayoutParams) titleProgressContainer.getLayoutParams(); if (ll.topMargin != 0) { ll.setMargins(0, 0, 0, 0); } } final ProgressBar progressBar = (ProgressBar) view.findViewById(R.id.progressBar); final TextView progressTitle = (TextView) view.findViewById(R.id.progressTitle); progressTitle.setText(titleProgressController.caption); progressBar.setIndeterminate(titleProgressController.indeterminate); progressBar.setProgress(titleProgressController.progress); final ImageView progressButton = (ImageView) view.findViewById(R.id.progressButton); progressButton.setVisibility(titleProgressController.buttonVisible ? View.VISIBLE : View.GONE); } else { titleProgressContainer.setVisibility(View.GONE); } } private void buildHeader() { OsmandApplication app = getMyApplication(); if (app != null) { IconsCache iconsCache = app.getIconsCache(); final View iconLayout = view.findViewById(R.id.context_menu_icon_layout); final ImageView iconView = (ImageView) view.findViewById(R.id.context_menu_icon_view); Drawable icon = menu.getLeftIcon(); int iconId = menu.getLeftIconId(); if (icon != null) { iconView.setImageDrawable(icon); iconLayout.setVisibility(View.VISIBLE); } else if (iconId != 0) { iconView.setImageDrawable(iconsCache.getIcon(iconId, !nightMode ? R.color.osmand_orange : R.color.osmand_orange_dark)); iconLayout.setVisibility(View.VISIBLE); } else { iconLayout.setVisibility(View.GONE); } setAddressLocation(); } } private void buildBottomView() { View bottomView = view.findViewById(R.id.context_menu_bottom_view); if (menu.isExtended()) { bottomView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return true; } }); menu.build(bottomView); } } @Override public void onResume() { super.onResume(); if (!menu.isActive() || MapRouteInfoMenu.isVisible()) { dismissMenu(); return; } screenOrientation = DashLocationFragment.getScreenOrientation(getActivity()); getMapActivity().getMapViewTrackingUtilities().setContextMenu(menu); getMapActivity().getMapViewTrackingUtilities().setMapLinkedToLocation(false); wasDrawerDisabled = getMapActivity().isDrawerDisabled(); if (!wasDrawerDisabled) { getMapActivity().disableDrawer(); } } @Override public void onPause() { getMapActivity().getMapViewTrackingUtilities().setContextMenu(null); getMapActivity().getMapViewTrackingUtilities().setMapLinkedToLocation(false); if (!wasDrawerDisabled) { getMapActivity().enableDrawer(); } super.onPause(); } @Override public void onDestroyView() { super.onDestroyView(); if (!menu.isActive()) { if (mapCenter != null) { if (mapZoom == 0) { mapZoom = map.getZoom(); } //map.setLatLon(mapCenter.getLatitude(), mapCenter.getLongitude()); //map.setIntZoom(mapZoom); AnimateDraggingMapThread thread = map.getAnimatedDraggingThread(); thread.startMoving(mapCenter.getLatitude(), mapCenter.getLongitude(), mapZoom, true); } } menu.setMapCenter(null); menu.setMapZoom(0); } public void rebuildMenu() { OsmandApplication app = getMyApplication(); if (app != null) { IconsCache iconsCache = app.getIconsCache(); final ImageButton buttonFavorite = (ImageButton) view.findViewById(R.id.context_menu_fav_button); buttonFavorite.setImageDrawable(iconsCache.getIcon(menu.getFavActionIconId(), !nightMode ? R.color.icon_color : R.color.dashboard_subheader_text_dark)); buttonFavorite.setContentDescription(getString(menu.getFavActionStringId())); buildHeader(); LinearLayout bottomLayout = (LinearLayout) view.findViewById(R.id.context_menu_bottom_view); bottomLayout.removeAllViews(); buildBottomView(); runLayoutListener(); } } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) private void runLayoutListener() { ViewTreeObserver vto = view.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { ViewTreeObserver obs = view.getViewTreeObserver(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { obs.removeOnGlobalLayoutListener(this); } else { obs.removeGlobalOnLayoutListener(this); } if (getActivity() == null) { return; } int newMenuTopViewHeight = view.findViewById(R.id.context_menu_top_view).getHeight(); menuTopShadowHeight = view.findViewById(R.id.context_menu_top_shadow).getHeight(); int newMenuTopShadowAllHeight = view.findViewById(R.id.context_menu_top_shadow_all).getHeight(); menuFullHeight = view.findViewById(R.id.context_menu_main).getHeight(); int dy = 0; if (!menu.isLandscapeLayout()) { TextView line1 = (TextView) view.findViewById(R.id.context_menu_line1); TextView line2 = (TextView) view.findViewById(R.id.context_menu_line2); int line2LineCount = 0; int line2LineHeight = 0; int line2MeasuredHeight = 0; if (line2 != null) { line2LineCount = line2.getLineCount(); line2LineHeight = line2.getLineHeight(); line2MeasuredHeight = line2.getMeasuredHeight(); } if (menuTopViewHeight != 0) { int titleHeight = line1.getLineCount() * line1.getLineHeight() + line2LineCount * line2LineHeight + menuTitleTopBottomPadding; if (titleHeight < line1.getMeasuredHeight() + line2MeasuredHeight) { titleHeight = line1.getMeasuredHeight() + line2MeasuredHeight; } newMenuTopViewHeight = menuTopViewHeightExcludingTitle + titleHeight; dy = Math.max(0, newMenuTopViewHeight - menuTopViewHeight - (newMenuTopShadowAllHeight - menuTopShadowAllHeight)); } else { menuTopViewHeightExcludingTitle = newMenuTopViewHeight - line1.getMeasuredHeight() - line2MeasuredHeight; menuTitleTopBottomPadding = (line1.getMeasuredHeight() - line1.getLineCount() * line1.getLineHeight()) + (line2MeasuredHeight - line2LineCount * line2LineHeight); } } menuTopViewHeight = newMenuTopViewHeight; menuTopShadowAllHeight = newMenuTopShadowAllHeight; menuTitleHeight = menuTopShadowHeight + menuTopShadowAllHeight + dy; menuBottomViewHeight = view.findViewById(R.id.context_menu_bottom_view).getHeight(); menuFullHeightMax = menuTitleHeight + menuBottomViewHeight; if (origMarkerX == 0 && origMarkerY == 0) { origMarkerX = view.getWidth() / 2; origMarkerY = view.getHeight() / 2; } if (initLayout && centered) { centerMarkerLocation(); } if (!moving) { doLayoutMenu(); } initLayout = false; } }); } public void centerMarkerLocation() { centered = true; showOnMap(menu.getLatLon(), true, true, false); } private int getZoom() { int zoom; if (zoomIn) { zoom = ZOOM_IN_STANDARD; } else { zoom = menu.getMapZoom(); } if (zoom == 0) { zoom = map.getZoom(); } return zoom; } private LatLon calculateCenterLatLon(LatLon latLon, int zoom, boolean updateOrigXY) { double flat = latLon.getLatitude(); double flon = latLon.getLongitude(); RotatedTileBox cp = map.getCurrentRotatedTileBox().copy(); cp.setCenterLocation(0.5f, map.getMapPosition() == OsmandSettings.BOTTOM_CONSTANT ? 0.15f : 0.5f); cp.setLatLonCenter(flat, flon); cp.setZoom(zoom); flat = cp.getLatFromPixel(cp.getPixWidth() / 2, cp.getPixHeight() / 2); flon = cp.getLonFromPixel(cp.getPixWidth() / 2, cp.getPixHeight() / 2); if (updateOrigXY) { origMarkerX = cp.getCenterPixelX(); origMarkerY = cp.getCenterPixelY(); } return new LatLon(flat, flon); } private void showOnMap(LatLon latLon, boolean updateCoords, boolean needMove, boolean alreadyAdjusted) { AnimateDraggingMapThread thread = map.getAnimatedDraggingThread(); int fZoom = getZoom(); LatLon calcLatLon = calculateCenterLatLon(latLon, fZoom, updateCoords); if (updateCoords) { mapCenter = calcLatLon; menu.setMapCenter(mapCenter); } if (!alreadyAdjusted) { calcLatLon = getAdjustedMarkerLocation(getPosY(), calcLatLon, true, fZoom); } if (needMove) { thread.startMoving(calcLatLon.getLatitude(), calcLatLon.getLongitude(), fZoom, true); } } private void setAddressLocation() { // Text line 1 TextView line1 = (TextView) view.findViewById(R.id.context_menu_line1); line1.setText(menu.getTitleStr()); // Text line 2 LinearLayout line2layout = (LinearLayout) view.findViewById(R.id.context_menu_line2_layout); TextView line2 = (TextView) view.findViewById(R.id.context_menu_line2); if (menu.hasCustomAddressLine()) { line2layout.removeAllViews(); menu.buildCustomAddressLine(line2layout); } else { String typeStr = menu.getTypeStr(); String streetStr = menu.getStreetStr(); StringBuilder line2Str = new StringBuilder(); if (!Algorithms.isEmpty(typeStr)) { line2Str.append(typeStr); Drawable icon = menu.getTypeIcon(); line2.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null); line2.setCompoundDrawablePadding(dpToPx(5f)); } if (!Algorithms.isEmpty(streetStr) && !menu.displayStreetNameInTitle()) { if (line2Str.length() > 0) { line2Str.append(": "); } line2Str.append(streetStr); } line2.setText(line2Str.toString()); } updateCompassVisibility(); } private void updateCompassVisibility() { OsmandApplication app = getMyApplication(); if (app != null) { View compassView = view.findViewById(R.id.compass_layout); Location ll = app.getLocationProvider().getLastKnownLocation(); boolean gpsFixed = ll != null && System.currentTimeMillis() - ll.getTime() < 1000 * 60 * 60 * 20; if (gpsFixed && menu.displayDistanceDirection() && menu.getCurrentMenuState() != MenuState.FULL_SCREEN) { updateDistanceDirection(); compassView.setVisibility(View.VISIBLE); } else { if (!menu.displayDistanceDirection()) { compassView.setVisibility(View.GONE); } else { compassView.setVisibility(View.INVISIBLE); } } } } private void updateDistanceDirection() { OsmandApplication app = getMyApplication(); FragmentActivity activity = getActivity(); if (app != null && activity != null) { TextView distanceText = (TextView) view.findViewById(R.id.distance); ImageView direction = (ImageView) view.findViewById(R.id.direction); float myHeading = menu.getHeading() == null ? 0f : menu.getHeading(); DashLocationFragment.updateLocationView(false, menu.getMyLocation(), myHeading, direction, distanceText, menu.getLatLon().getLatitude(), menu.getLatLon().getLongitude(), screenOrientation, app, activity); } } private int getPosY() { return getPosY(false); } private int getPosY(boolean needCloseMenu) { if (needCloseMenu) { return screenHeight; } int destinationState; int minHalfY; if (menu.isExtended()) { destinationState = menu.getCurrentMenuState(); minHalfY = viewHeight - (int) (viewHeight * menu.getHalfScreenMaxHeightKoef()); } else { destinationState = MenuState.HEADER_ONLY; minHalfY = viewHeight; } int posY = 0; switch (destinationState) { case MenuState.HEADER_ONLY: posY = viewHeight - menuTitleHeight; break; case MenuState.HALF_SCREEN: posY = viewHeight - menuFullHeightMax; posY = Math.max(posY, minHalfY); break; case MenuState.FULL_SCREEN: posY = -menuTopShadowHeight - dpToPx(SHADOW_HEIGHT_TOP_DP); break; default: break; } return posY; } private void updateMainViewLayout(int posY) { menuFullHeight = view.getHeight() - posY; if (!oldAndroid()) { ViewGroup.LayoutParams lp = mainView.getLayoutParams(); lp.height = Math.max(menuFullHeight, menuTitleHeight); mainView.setLayoutParams(lp); mainView.requestLayout(); } } private int getViewY() { if (!oldAndroid()) { return (int) mainView.getY(); } else { return mainView.getPaddingTop(); } } private void setViewY(int y, boolean animated, boolean adjustMapPos) { if (!oldAndroid()) { mainView.setY(y); fabView.setY(getFabY(y)); } else { mainView.setPadding(0, y, 0, 0); fabView.setPadding(0, getFabY(y), 0, 0); } if (!customMapCenter) { if (adjustMapPos) { adjustMapPosition(y, animated, centered); } } else { customMapCenter = false; } } private void adjustMapPosition(int y, boolean animated, boolean center) { map.getAnimatedDraggingThread().stopAnimatingSync(); LatLon latlon = getAdjustedMarkerLocation(y, menu.getLatLon(), center, getZoom()); if (map.getLatitude() == latlon.getLatitude() && map.getLongitude() == latlon.getLongitude()) { return; } if (animated) { showOnMap(latlon, false, true, true); } else { map.setLatLon(latlon.getLatitude(), latlon.getLongitude()); } } private LatLon getAdjustedMarkerLocation(int y, LatLon reqMarkerLocation, boolean center, int zoom) { double markerLat = reqMarkerLocation.getLatitude(); double markerLon = reqMarkerLocation.getLongitude(); RotatedTileBox box = map.getCurrentRotatedTileBox().copy(); box.setCenterLocation(0.5f, map.getMapPosition() == OsmandSettings.BOTTOM_CONSTANT ? 0.15f : 0.5f); box.setZoom(zoom); int markerMapCenterX = (int) box.getPixXFromLatLon(mapCenter.getLatitude(), mapCenter.getLongitude()); int markerMapCenterY = (int) box.getPixYFromLatLon(mapCenter.getLatitude(), mapCenter.getLongitude()); float cpyOrig = box.getCenterPixelPoint().y; box.setCenterLocation(0.5f, 0.5f); int markerX = (int) box.getPixXFromLatLon(markerLat, markerLon); int markerY = (int) box.getPixYFromLatLon(markerLat, markerLon); QuadPoint cp = box.getCenterPixelPoint(); float cpx = cp.x; float cpy = cp.y; float cpyDelta = menu.isLandscapeLayout() ? 0 : cpyOrig - cpy; markerY += cpyDelta; y += cpyDelta; float origMarkerY = this.origMarkerY + cpyDelta; LatLon latlon; if (center) { latlon = reqMarkerLocation; } else { latlon = box.getLatLonFromPixel(markerMapCenterX, markerMapCenterY); } if (menu.isLandscapeLayout()) { int x = menu.getLandscapeWidthPx(); if (markerX - markerPaddingXPx < x || markerX > origMarkerX) { int dx = (x + markerPaddingXPx) - markerX; int dy = 0; if (center) { dy = (int) cpy - markerY; } else { cpy = cpyOrig; } if (dx >= 0 || center) { latlon = box.getLatLonFromPixel(cpx - dx, cpy - dy); } } } else { if (markerY + markerPaddingPx > y || markerY < origMarkerY) { int dx = 0; int dy = markerY - (y - markerPaddingPx); if (markerY - dy <= origMarkerY) { if (center) { dx = markerX - (int) cpx; } latlon = box.getLatLonFromPixel(cpx + dx, cpy + dy); } } } return latlon; } private int getFabY(int y) { int fabY = y + fabPaddingTopPx; if (fabY < fabPaddingTopPx) { fabY = fabPaddingTopPx; } return fabY; } private boolean oldAndroid() { return (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH); } private void doLayoutMenu() { final int posY = getPosY(); setViewY(posY, true, !initLayout || !centered); updateMainViewLayout(posY); } public void dismissMenu() { FragmentActivity activity = getActivity(); if (activity != null) { try { activity.getSupportFragmentManager().popBackStack(TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE); } catch (Exception e) { } } } public void refreshTitle() { setAddressLocation(); runLayoutListener(); } public void setFragmentVisibility(boolean visible) { if (visible) { view.setVisibility(View.VISIBLE); if (mapCenter != null) { map.setLatLon(mapCenter.getLatitude(), mapCenter.getLongitude()); } adjustMapPosition(getPosY(), true, false); } else { view.setVisibility(View.GONE); } } public OsmandApplication getMyApplication() { if (getActivity() == null) { return null; } return (OsmandApplication) getActivity().getApplication(); } public static boolean showInstance(final MapContextMenu menu, final MapActivity mapActivity, final boolean centered) { try { if (menu.getLatLon() == null || mapActivity.isActivityDestroyed()) { return false; } int slideInAnim = R.anim.slide_in_bottom; int slideOutAnim = R.anim.slide_out_bottom; if (menu.isExtended()) { slideInAnim = menu.getSlideInAnimation(); slideOutAnim = menu.getSlideOutAnimation(); } MapContextMenuFragment fragment = new MapContextMenuFragment(); fragment.centered = centered; mapActivity.getSupportFragmentManager().beginTransaction() .setCustomAnimations(slideInAnim, slideOutAnim, slideInAnim, slideOutAnim) .add(R.id.fragmentContainer, fragment, TAG) .addToBackStack(TAG).commitAllowingStateLoss(); return true; } catch (RuntimeException e) { return false; } } //DownloadEvents @Override public void newDownloadIndexes() { updateOnDownload(); } @Override public void downloadInProgress() { updateOnDownload(); } @Override public void downloadHasFinished() { updateOnDownload(); if (menu != null && menu.isVisible() && menu.isMapDownloaded()) { rebuildMenu(); } } private void updateOnDownload() { if (menu != null) { boolean wasProgressVisible = menu.getTitleProgressController() != null && menu.getTitleProgressController().visible; menu.updateData(); boolean progressVisible = menu.getTitleProgressController() != null && menu.getTitleProgressController().visible; updateButtonsAndProgress(); if (wasProgressVisible != progressVisible) { runLayoutListener(); } } } public void updateMenu() { menu.updateData(); updateButtonsAndProgress(); runLayoutListener(); } private MapActivity getMapActivity() { return (MapActivity) getActivity(); } private int dpToPx(float dp) { Resources r = getActivity().getResources(); return (int) TypedValue.applyDimension( COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics() ); } public void updateLocation(boolean centerChanged, boolean locationChanged, boolean compassChanged) { updateDistanceDirection(); } private void doBeforeMenuStateChange(int previousState, int newState) { if (newState == MenuState.HALF_SCREEN) { centered = true; if (!zoomIn && menu.supportZoomIn()) { if (getZoom() < ZOOM_IN_STANDARD) { zoomIn = true; } } calculateCenterLatLon(menu.getLatLon(), getZoom(), true); } } private void doAfterMenuStateChange(int previousState, int newState) { updateCompassVisibility(); } }