Android - realizing the navigation of calculating routes in APP

Effect video

Jump to Baidu map for route calculation and navigation

Route calculation and navigation in APP

Function realization

Jump mode implementation

Function Description: by initializing Baidu map API, obtain the longitude and latitude of the current position as the starting point, and the entered address as the destination, then package it into Uri format, use implicit Intent to call Baidu map APP, and finally realize routing navigation.

Permission statement

Declare the permissions required for navigation, such as network permissions, location permissions, etc

private void InitPermission(){
        List<String> PermissionList = new ArrayList<>();
        //Judge whether the permission is authorized
        if (ContextCompat.checkSelfPermission( Function.this, Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED) {
            PermissionList.add( Manifest.permission.ACCESS_FINE_LOCATION );
        }
        if (ContextCompat.checkSelfPermission( Function.this, Manifest.permission.READ_PHONE_STATE ) != PackageManager.PERMISSION_GRANTED) {
            PermissionList.add( Manifest.permission.READ_PHONE_STATE );
        }
        if (ContextCompat.checkSelfPermission( Function.this, Manifest.permission.WRITE_EXTERNAL_STORAGE ) != PackageManager.PERMISSION_GRANTED) {
            PermissionList.add( Manifest.permission.WRITE_EXTERNAL_STORAGE );
        }
        if (!PermissionList.isEmpty()) {
            String[] Permissions = PermissionList.toArray( new String[PermissionList.size()] );//Convert to array
            ActivityCompat.requestPermissions( Function.this, Permissions, 1 );//One time application authority
        } else {
            /*****************If the permissions have been declared, start configuring parameters*****************/
            requestLocation();
        }
    }

Determine whether Baidu map is installed in the mobile phone

Baidu map package name

 public static final String BAIDUMAPPACKAGE = "com.baidu.BaiduMap"; // Baidu map package name

By taking the baidu map package name as the index, find out whether the application exists in the mobile phone, and return the boolean value

   public static boolean isBaiduMapInstalled(){
        return isInstallPackage(BAIDUMAPPACKAGE);
    }
    private static boolean isInstallPackage(String packageName) {
        return new File("/data/data/" + packageName).exists();
    }

Jump to Baidu map

Take the longitude and latitude obtained as the navigation starting point and the entered address as the navigation ending point. Finally, evoke Baidu map APP through Intent implicit jump

 public  void  Navigation(String EndAddress){
 Uri uri = Uri.parse( "baidumap://map/direction?origin=" + Latitude + "," + Longitude + "&" + "destination=" + EndAddress + "&mode=driving&package=com.baidu.BaiduMap;end" );
 startActivity( new Intent( Intent.ACTION_VIEW, uri ) );
    }

Non jump mode implementation

Function Description: first, convert the input address into latitude and longitude, then calculate the routing node through Baidu map navigation API, and then complete the navigation planning

UI design

background

Create a file in the drawable directory and implement a rounded rectangle
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
 <solid android:color="#ffffff"/>
    <corners android:radius="10dp"/>
</shape>

Dot

Create a file in the drawable directory and implement a solid circle
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
<solid android:color="#4CAF50"/>
    <size android:height="10dp" android:width="10dp"/>

Layout code

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Activity.SelectNodeActivity"
    android:orientation="vertical"
    android:background="#F1EDED">
    <include layout="@layout/titlebar"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:background="@drawable/white_radiu_bg">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/grey_radiu_bg"
            android:layout_margin="20dp"
            android:padding="10dp">
        <LinearLayout
            android:layout_width="0dp"
            android:layout_weight="7"
            android:layout_height="wrap_content"
            android:orientation="vertical">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal"
                android:padding="@dimen/navi_dimens_5dp">
                <View
                    android:layout_width="10dp"
                    android:layout_height="10dp"
                    android:background="@drawable/green_point"
                    android:layout_gravity="center"
                    android:layout_marginRight="5dp"/>
                <EditText
                    android:id="@+id/startAddress"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:hint="please enter starting point"
                    android:textColor="#000000"
                    android:textSize="15sp"
                    android:layout_gravity="center"
                    android:layout_marginLeft="5dp"
                    android:background="@null"/>
            </LinearLayout>
            <!--Split line-->
            <View
                android:layout_width="match_parent"
                android:layout_height="1dp"
                android:background="#DBCACA"
                android:layout_marginTop="5dp"
                android:layout_marginBottom="5dp"/>
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal"
                android:padding="@dimen/navi_dimens_5dp">
                <View
                    android:layout_width="10dp"
                    android:layout_height="10dp"
                    android:background="@drawable/red_point"
                    android:layout_gravity="center"
                    android:layout_marginRight="5dp"/>
                <EditText
                    android:id="@+id/endAddress"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:hint="please enter ending point"
                    android:textColor="#000000"
                    android:textSize="15sp"
                    android:layout_marginLeft="5dp"
                    android:background="@null"
                    android:layout_gravity="center"/>
            </LinearLayout>
        </LinearLayout>
            <LinearLayout
                android:id="@+id/exchangeStr"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:layout_gravity="center"
                android:layout_marginLeft="10dp"
                android:onClick="ExchangeStr">
                <ImageView
                    android:layout_width="25dp"
                    android:layout_height="25dp"
                    android:src="@drawable/icon_exchange"
                    android:layout_gravity="center"/>
            </LinearLayout>
        </LinearLayout>
    </LinearLayout>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="50dp">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/white_radiu_bg"
        android:layout_margin="10dp"
        android:padding="10dp"
        android:layout_alignParentBottom="true">
        <Button
            android:id="@+id/exeProcess"
            android:layout_width="match_parent"
            android:layout_height="30dp"
            android:background="@drawable/green_radiu_bg"
            android:text="Start Navigation"
            android:textAllCaps="false"
            android:textColor="#ffffff"
            android:layout_margin="10dp"
            android:onClick="ExeProcess"/>
    </LinearLayout>
    </RelativeLayout>
</LinearLayout>

Function realization

Before introducing the function, first introduce two concepts, namely geocoding and anti geocoding
For details, please jump to the official website of Baidu map

Geocoding:Converting address information to geographic coordinates(Longitude and latitude)
Anti geocoding:Geographical coordinates(Longitude and latitude)Convert to address information

Permission statement

List the required declared permissions as an array

    private static final String[] authBaseArr = {
            Manifest.permission.RECORD_AUDIO,
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS,
            Manifest.permission.WRITE_EXTERNAL_STORAGE
    };

Traverse the array to determine whether the permission is declared, and return the boolean value as the judgment identifier

    private void InitPermission() {
        // Apply for permission
        if (Build.VERSION.SDK_INT >= 23) {
            if (!hasBasePhoneAuth()) {
                requestPermissions(authBaseArr, authBaseRequestCode);
            }
        }
    }
    private boolean hasBasePhoneAuth() {
        PackageManager pm = this.getPackageManager();
        for (String auth : authBaseArr) {
            if (pm.checkPermission(auth, this.getPackageName()) != PackageManager
                    .PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

Initialize BroadCast

    private void InitBroadCastReceiver() {
        IntentFilter filter = new IntentFilter();
        filter.addAction("com.navi.ready");
        mReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                BNDemoFactory.getInstance().initCarInfo();
                BNDemoFactory.getInstance().initRoutePlanNode();
            }
        };
        registerReceiver(mReceiver, filter);
    }
Initialize vehicle information

If the vehicle information is not modified manually, it shall be based on the following information

    public void initCarInfo() {
        // Driving license plate setting
        // BaiduNaviManagerFactory.getCommonSettingManager().setCarNum("Jing A88888");
        // Truck information
        BNTruckInfo truckInfo = new BNTruckInfo.Builder()
                .plate("Beijing A88888")
                .axlesNumber(2)
                .axlesWeight(1)
                .emissionLimit(VehicleConstant.EmissionStandard.S3)
                .length(5)
                .weight(2)
                .loadWeight(1)
                .oilCost("40000")
                .plateType(VehicleConstant.PlateType.BLUE)
                .powerType(VehicleConstant.PowerType.OIL)
                .truckType(VehicleConstant.TruckType.HEAVY)
                .height(2)
                .width(2.5f)
                .build();
        // The interface will be locally persistent and can be set once in the application
        BaiduNaviManagerFactory.getCommonSettingManager().setTruckInfo(truckInfo);
        // Motorcycle information
        BNMotorInfo motorInfo = new BNMotorInfo.Builder()
                .plate("Beijing A88888")
                .plateType(VehicleConstant.PlateType.BLUE)
                .motorType(VehicleConstant.MotorType.OIL)
                .displacement("")
                .build();
        // The interface will be locally persistent and can be set once in the application
        BaiduNaviManagerFactory.getCommonSettingManager().setMotorInfo(motorInfo);
        // BaiduNaviManagerFactory.getCommonSettingManager().setTestEnvironment(false);
        BaiduNaviManagerFactory.getCommonSettingManager().setNodeClick(true);
    }
Initialize node information

If the path node information is not modified manually, it is based on the following information

    public void initRoutePlanNode() {
        startNode = new BNRoutePlanNode.Builder()
                .latitude(40.041690)
                .longitude(116.306333)
                .name("Baidu building")
                .description("Baidu building")
                .build();
        endNode = new BNRoutePlanNode.Builder()
                .latitude(39.908560)
                .longitude(116.397609)
                .name("Beijing Tiananmen")
                .description("Beijing Tiananmen")
                .build();
    }

Node information exchange

That is, the start address information and the end address information are exchanged, and a temporary variable is used to store one party's data to complete the exchange

    public void ExchangeStr(View view) {
        String Start = startAddress.getText().toString().trim();
        String End = endAddress.getText().toString().trim();
        startAddress.setText( End );
        endAddress.setText( Start );
    }

Address information to geographic information (longitude and latitude)

Geocoder provides an API for the mutual conversion of address information and geographic information for Baidu map

geocoder = new Geocoder( SelectNodeActivity.this );

The Address information entered by the user is converted by getFromLocationName() method and an Address object is returned; It should be noted that the Address information entered should be more accurate, such as xxx land, xxx District, xxx city, xxx Province, so that the accuracy of the converted geographic information will not shift too much

private String GetNodeValue(String Address){
        builder = new StringBuilder(  );
        try {
            List<android.location.Address> addresses = geocoder.getFromLocationName(Address,1 );
            double start_latitude = addresses.get( 0 ).getLatitude();//latitude
            double start_longitude = addresses.get( 0 ).getLongitude();//longitude
            builder.append( start_longitude ).append( "," ).append( start_latitude );
        } catch (IOException e) {
            Toast.makeText( SelectNodeActivity.this,"error",Toast.LENGTH_SHORT).show();
            e.printStackTrace();
        }
        return builder.toString();
    }

Save geographic information

Save the converted geographic information (latitude and longitude) by using a simple factory singleton class

    private void AddrToCoordinate(){
        boolean flag = Geocoder.isPresent();
        if (!flag)
            Toast.makeText( SelectNodeActivity.this,"error",Toast.LENGTH_SHORT ).show();
        else {
            String start = GetNodeValue(startAddress.getText().toString().trim());
            String end = GetNodeValue(endAddress.getText().toString().trim());
            //TODO sets the latitude and longitude of the starting point
            if (!TextUtils.isEmpty(start)) {
                BNDemoFactory.getInstance().setStartNode(this, start);
                Log.d( "start:",start );
            }
            //TODO sets the latitude and longitude of the end point
            if (!TextUtils.isEmpty(end)) {
                BNDemoFactory.getInstance().setEndNode(this, end);
                Log.d( "end:",end );
            }
        }
    }

Routing navigation

    private void routePlanToNavi(final Bundle bundle) {
        List<BNRoutePlanNode> list = new ArrayList<>();
        //TODO obtains the longitude and latitude in the main function and starts the route calculation and navigation
        list.add(BNDemoFactory.getInstance().getStartNode(this));
        list.add(BNDemoFactory.getInstance().getEndNode(this));

        // Turn off the electronic dog
        if (BaiduNaviManagerFactory.getCruiserManager().isCruiserStarted()) {
            BaiduNaviManagerFactory.getCruiserManager().stopCruise();
        }
        BaiduNaviManagerFactory.getRoutePlanManager().routePlanToNavi(
                list,
                IBNRoutePlanManager.RoutePlanPreference.ROUTE_PLAN_PREFERENCE_DEFAULT,
                bundle, handler);
    }

Node computing requires a lot of memory space and time, so the use of asynchronous communication does not affect the distribution of the main thread and the refresh of the UI

private Handler handler = new Handler( Looper.getMainLooper()) {
        @Override
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what) {
                case IBNRoutePlanManager.MSG_NAVI_ROUTE_PLAN_START:
                    Toast.makeText(SelectNodeActivity.this, "Start of road calculation", Toast.LENGTH_SHORT).show();
                    ControlBoardWindow.getInstance().showControl("Start of road calculation");
                    break;
                case IBNRoutePlanManager.MSG_NAVI_ROUTE_PLAN_SUCCESS:
                    Toast.makeText(SelectNodeActivity.this, "Successful routing", Toast.LENGTH_SHORT).show();
                    ControlBoardWindow.getInstance().showControl("Calculate the road successfully");
                    // Avoid restricted messages
                    Bundle infoBundle = (Bundle) msg.obj;
                    if (infoBundle != null) {
                        String info = infoBundle
                                .getString( BNaviCommonParams.BNRouteInfoKey.TRAFFIC_LIMIT_INFO);
                        Log.e("OnSdkDemo", "info = " + info);
                    }
                    break;
                case IBNRoutePlanManager.MSG_NAVI_ROUTE_PLAN_FAILED:
                    ControlBoardWindow.getInstance().showControl("Routing failure");
                    Toast.makeText(SelectNodeActivity.this.getApplicationContext(),
                            "Routing failure", Toast.LENGTH_SHORT).show();
                    break;
                case IBNRoutePlanManager.MSG_NAVI_ROUTE_PLAN_TO_NAVI:
                    Toast.makeText(SelectNodeActivity.this.getApplicationContext(),
                            "Calculate the route successfully and prepare to enter the navigation", Toast.LENGTH_SHORT).show();
                    ControlBoardWindow.getInstance().showControl("Calculate the route successfully and prepare to enter the navigation");
                    switch (mPageType) {
                        case BNDemoUtils.NORMAL:
                            BNDemoUtils.gotoNavi(SelectNodeActivity.this);
                            break;
                        case BNDemoUtils.ANALOG:
                            BNDemoUtils.gotoAnalog(SelectNodeActivity.this);
                            break;
                        case BNDemoUtils.EXTGPS:
                            BNDemoUtils.gotoExtGps(SelectNodeActivity.this);
                            break;
                        default:
                            break;
                    }
                    break;
                default:
                    break;
            }
        }
    };

Destroy

After using, you should put the destructable contents into onDestroy to avoid the waste of memory space

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(mReceiver);
        stopService(new Intent(this, ForegroundService.class));
    }

Keywords: Java Android Android Studio Apache

Added by bobbuilder on Sat, 19 Feb 2022 11:13:56 +0200