027rainguai 发表于 2023-9-12 14:04

导航协议实现导航时悬浮显示车速

背景
某导航巡航时才能悬浮车速,导航时是不能悬浮车速的。本人不太喜欢全屏导航,因此就写了个app自己用。
原始巡航图,带车速的。

,本来导航要是有这个车速就很好,可惜官方没有。那就自己动手咯。




目前软件已开车实测500公里,无闪退问题。下面贴下核心代码。





import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;
import android.view.*;
import android.widget.TextView;
import com.hd.hdcart.amap.AMapCartReceiver;
import com.hd.hdcart.event.AMapAreaInfoMessageEvent;
import com.hd.hdcart.event.AMapFloatingWindowSettingsChangeMessageEvent;
import com.hd.hdcart.event.FloatShowEnableEvent;
import com.hd.hdcart.utils.SharedPreUtil;
import com.hd.hdcart.utils.TaskExecutor;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.util.concurrent.ScheduledFuture;

public class AMapCartService extends Service
{
    private static final String TAG = "AMapCartService";
    public static final String RECEIVE_ACTION = "AUTONAVI_STANDARD_BROADCAST_SEND";
    public static final String SEND_ACTION = "AUTONAVI_STANDARD_BROADCAST_RECV";
    public static final String KEY_TYPE = "KEY_TYPE";

    private WindowManager windowManager;
    private WindowManager.LayoutParams layoutParams;
    private View displayView;

    public int curSpeed = 0;//时速
    public String road = "";//道路
    public String sourceArea = "";//行政区

    public double ecurSpeed = 0.0d;
    public double cameraSpeed = 0.0d;
    public double limitSpeed = 0.0d;
    public final double lowerLimit = 10.0d;
    double proportion = 0.0d;

    private AMapCartReceiver aMapCartReceiver;

    public AMapCartService()
    {
    }

    @Override
    public IBinder onBind(Intent intent)
    {
      // TODO: Return the communication channel to the service.
      throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId)
    {
      if (!EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().register(this);
      }
      registerAMapReceiver();
      startSendAMapAreaInfoReceiverTask();

      windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
      if (SharedPreUtil.getBoolean("FLOATING_WINDOW_AMAP_AREA_ENABLE", false)) {
            initLayoutParams();
            showFloatView();
      }
      return super.onStartCommand(intent, flags, startId);
    }

    /**
   * 注册监听高德广播
   */
    private void registerAMapReceiver()
    {
      aMapCartReceiver = new AMapCartReceiver();
      IntentFilter intentFilter = new IntentFilter();
      intentFilter.addAction(RECEIVE_ACTION);
      intentFilter.addAction(SEND_ACTION);
      unregisterReceiver();
      registerReceiver(aMapCartReceiver, intentFilter);//再进行监听
    }

    /**
   * 请求高德行政区域信息
   *
   * @Param context
   */
    public static void sendAMapAreaInfoReceiver(Context context)
    {
      Intent intent = new Intent();
      intent.setAction(SEND_ACTION);
      intent.putExtra(KEY_TYPE, 10029);
      context.sendBroadcast(intent);
    }

    /**
   * 取消监听高德广播
   */
    private void unregisterReceiver()
    {
      try {
            if (aMapCartReceiver != null) {
                unregisterReceiver(aMapCartReceiver);//先取消监听
            }
      } catch (Exception exception) {
      }
    }

    ScheduledFuture<?> scheduledFuture;

    /**
   * 开启定时发送高德行政区域信息
   */
    public void startSendAMapAreaInfoReceiverTask()
    {
      scheduledFuture = TaskExecutor.self().repeatRun(() -> {
            sendAMapAreaInfoReceiver(this);
      }, 90 * 1000);
    }

    public void stopSendAMapAreaInfoReceiverTask()
    {
      if (scheduledFuture != null) {
            scheduledFuture.cancel(true);
      }
    }


    /**
   * 初始化悬浮窗参数
   */
    private void initLayoutParams()
    {
      layoutParams = new WindowManager.LayoutParams();

      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
      } else {
            layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
      }

      layoutParams.format = PixelFormat.RGBA_8888;
      //设置透明度
      layoutParams.alpha = 0.65f;
      layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
      layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;

      layoutParams.width = SharedPreUtil.getInteger("FLOATING_WINDOW_AMAP_AREA_CONTAINER_WIDTH", 424);
      layoutParams.height = SharedPreUtil.getInteger("FLOATING_WINDOW_AMAP_AREA_CONTAINER_HEIGHT", 162);
      layoutParams.x = SharedPreUtil.getInteger("FLOATING_WINDOW_AMAP_AREA_CONTAINER_X", 300);
      layoutParams.y = SharedPreUtil.getInteger("FLOATING_WINDOW_AMAP_AREA_CONTAINER_Y", 300);
    }

    /**
   * 显示悬浮窗
   */
    private void showFloatView()
    {
      LayoutInflater layoutInflater = LayoutInflater.from(this);
      displayView = layoutInflater.inflate(R.layout.amap_area_floating_window, null);
      if (layoutParams == null) {
            initLayoutParams();
      }

      displayView.setOnTouchListener(new View.OnTouchListener()
      {
            @Override
            public boolean onTouch(View v, MotionEvent event)
            {
                if (layoutParams != null) {
                  layoutParams.x = (int) event.getRawX() - displayView.getMeasuredWidth() / 2;
                  layoutParams.y = (int) event.getRawY() - displayView.getMeasuredHeight() / 2;
                  SharedPreUtil.saveInteger("FLOATING_WINDOW_AMAP_AREA_CONTAINER_X", layoutParams.x);
                  SharedPreUtil.saveInteger("FLOATING_WINDOW_AMAP_AREA_CONTAINER_Y", layoutParams.y);
                  windowManager.updateViewLayout(displayView, layoutParams);
                }
                return false;
            }
      });


      TextView txtCurSpeed = (TextView) displayView.findViewById(R.id.txtCurSpeed);
      txtCurSpeed.setText(curSpeed+ " km/h");
      txtCurSpeed.setTextSize(SharedPreUtil.getInteger("FLOATING_WINDOW_AMAP_SD_FONT_SIZE", 40));

      TextView txtArea = (TextView) displayView.findViewById(R.id.txtArea);
      if (sourceArea != null && !sourceArea.equals("")) {
            txtArea.setText(sourceArea);
      } else {
            txtArea.setText("waiting...");
      }
      txtArea.setTextSize(SharedPreUtil.getInteger("FLOATING_WINDOW_AMAP_AREA_FONT_SIZE", 20));

      TextView txtRoad = (TextView) displayView.findViewById(R.id.txtRoad);
      txtRoad.setText(road);

      txtRoad.setTextSize(SharedPreUtil.getInteger("FLOATING_WINDOW_AMAP_AREA_FONT_SIZE", 20));


      windowManager.addView(displayView, layoutParams);
    }


    /**
   * 接收高德行政区域信息
   *
   * @param event
   */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onAMapAreaInfoMessageEvent(AMapAreaInfoMessageEvent event)
    {
      if (event.getType().equals("10030")) {
            if (!sourceArea.equals(event.toString())) {
                updateFloatViewContent(event.toString());
                sourceArea = event.toString();
            }
      } else if (event.getType().equals("10065")) {
            TextView txtCcurSpeed = (TextView) displayView.findViewById(R.id.txtCurSpeed);
            txtCcurSpeed.setText(event.getCurSpeed() + " km/h");
      }else {
            updateFloatViewcurSpeed(event);
      }

    }

    /**
   * 更新悬浮窗文本内容
   *
   * @param content
   */
    private void updateFloatViewContent(String content)
    {
      if (displayView != null) {
            TextView txtArea = (TextView) displayView.findViewById(R.id.txtArea);
            txtArea.setText(content);
      }
    }


    /**
   * 更新悬浮窗的车速
   *
   * @param event
   */
    private void updateFloatViewcurSpeed(AMapAreaInfoMessageEvent event)
    {
      ecurSpeed = Double.valueOf(event.getCurSpeed());
      cameraSpeed = Double.valueOf(event.getCameraSpeed());
      limitSpeed = Double.valueOf(event.getLimitedSpeed());

      curSpeed = event.getCurSpeed();

      if (displayView != null) {
            TextView txtCcurSpeed = (TextView) displayView.findViewById(R.id.txtCurSpeed);
            txtCcurSpeed.setText(curSpeed + " km/h");

            TextView txtRoad = (TextView) displayView.findViewById(R.id.txtRoad);

            if (cameraSpeed <= 0) {
                cameraSpeed = limitSpeed;
            }

            proportion = (ecurSpeed - cameraSpeed) / cameraSpeed * 100;


            String tempStr = event.getCurRoadName() + " 无限速 ";
            txtCcurSpeed.setTextColor(Color.WHITE);

            if (cameraSpeed > 0 && proportion < lowerLimit) {
                txtCcurSpeed.setTextColor(Color.MAGENTA); //无测速
                tempStr = event.getCurRoadName() + " 限速 " + cameraSpeed + "km/h ";
            } else if (cameraSpeed > 0 && proportion >= lowerLimit) {
                String num = String.format("%.0f", proportion);
                tempStr = event.getCurRoadName() + " 限速 " + cameraSpeed + " km/h 已超速" + num + "%";
                txtCcurSpeed.setTextColor(Color.RED); //有测速
            }

            txtRoad.setText(tempStr);
            road = tempStr;


      }
    }

    /**
   * 接收悬浮窗设置变化
   *
   * @param event
   */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void updateFloatView(AMapFloatingWindowSettingsChangeMessageEvent event)
    {
      if (layoutParams != null && displayView != null) {
            layoutParams.width = SharedPreUtil.getInteger("FLOATING_WINDOW_AMAP_AREA_CONTAINER_WIDTH", 424);
            layoutParams.height = SharedPreUtil.getInteger("FLOATING_WINDOW_AMAP_AREA_CONTAINER_HEIGHT", 162);
            layoutParams.x = SharedPreUtil.getInteger("FLOATING_WINDOW_AMAP_AREA_CONTAINER_X", 300);
            layoutParams.y = SharedPreUtil.getInteger("FLOATING_WINDOW_AMAP_AREA_CONTAINER_Y", 300);

//            GradientDrawable drawable = (GradientDrawable) displayView.getBackground();
//            drawable.setColor(SharedPreUtil.getInteger("FLOATING_WINDOW_AMAP_AREA_CONTAINER_BACKGROUND_COLOR", Color.parseColor("#060E19")));
//            displayView.setBackground(drawable);

            //当前车速
            TextView curSpeed = displayView.findViewById(R.id.txtCurSpeed);
            curSpeed.setTextSize(SharedPreUtil.getInteger("FLOATING_WINDOW_AMAP_SD_FONT_SIZE", 40));
//
            TextView txtArea = displayView.findViewById(R.id.txtArea);
            txtArea.setTextSize(SharedPreUtil.getInteger("FLOATING_WINDOW_AMAP_AREA_FONT_SIZE", 20));


            windowManager.updateViewLayout(displayView, layoutParams);
      }
    }

    /**
   * 隐藏悬浮窗
   */
    private void hideFloatView()
    {
      if (displayView != null) {
            windowManager.removeView(displayView);
      }
    }

    //FloatShowEnableEvent
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onFloatShowEnableEvent(FloatShowEnableEvent event)
    {
      if (event.isEnable()) {
            showFloatView();
      } else {
            hideFloatView();
      }
    }


    @Override
    public void onDestroy()
    {
      if (!EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().unregister(this);
      }

      unregisterReceiver();
      stopSendAMapAreaInfoReceiverTask();
      hideFloatView();
    }
}

woshilizibenren 发表于 2024-3-28 08:51

027rainguai 发表于 2024-2-22 09:38
必须可以,但是这个玩意是调用了高德的私有广播接口,不方便提供成品,大厂不敢搞它

:lol这个倒没问题的,我自己修改了高德6.5.5的渠道版本变成全功能版,然后询问过高德产品经理,产品经理说只要不拿来盈利,分享完全没问题,后来发到了高德车机官方论坛里,已经回帖30多页了,搜索引擎搜到的6.5.5修改版,就是我发布的:lol

梦毁他城 发表于 2024-2-23 12:39

027rainguai 发表于 2024-2-22 09:37
好像有成品吧,有个博主叫沉默,他搞过

是的,市面上的悬浮基本都是chemo大佬的,我就是想知道,除了地图包,还有没有其他要支持的,比如什么协议之类的,我是别克车型,直接用飞屏的包不成功,只有原厂的百度可以三指飞屏

Kls673M 发表于 2023-9-12 14:19

这个!! 搞个HUD比这个好吧

to0716 发表于 2023-9-12 14:22

有些车型方向盘遮挡仪表没发看见时速      导航时速又小很   不错

smaxlyb 发表于 2023-9-12 14:33

牛逼啊,自己动手,丰衣足食

huaibeilifei 发表于 2023-9-12 14:55

怎么用啊?

ouzhenwei 发表于 2023-9-12 14:55

这个不错

Wapj0018 发表于 2023-9-12 15:17

谢谢大佬

cl19980429 发表于 2023-9-12 15:18

大佬江夏的啊, 我也是江夏的

027rainguai 发表于 2023-9-12 15:27

cl19980429 发表于 2023-9-12 15:18
大佬江夏的啊, 我也是江夏的

嗯呢,江夏的。

熊猫咖啡 发表于 2023-9-12 18:25

楼主幸福安康,可惜不会用
页: [1] 2 3 4 5
查看完整版本: 导航协议实现导航时悬浮显示车速