Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e7d2554f authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Update CSIP base uuid devie set into a single device detail preference"

parents e731e209 c32061b8
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.settingslib.bluetooth;

import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHearingAid;
@@ -351,8 +352,10 @@ public class BluetoothEventManager {
            cachedDevice.onBondingStateChanged(bondState);

            if (bondState == BluetoothDevice.BOND_NONE) {
                /* Check if we need to remove other Hearing Aid devices */
                if (cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID) {
                // Check if we need to remove other Coordinated set member devices / Hearing Aid
                // devices
                if (cachedDevice.getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID
                        || cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID) {
                    mDeviceManager.onDeviceUnpaired(cachedDevice);
                }
                int reason = intent.getIntExtra(BluetoothDevice.EXTRA_REASON,
+73 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.settingslib.bluetooth;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothProfile;
@@ -41,7 +42,9 @@ import com.android.settingslib.Utils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;

/**
@@ -66,6 +69,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
    private final Object mProfileLock = new Object();
    BluetoothDevice mDevice;
    private long mHiSyncId;
    private int mGroupId;
    // Need this since there is no method for getting RSSI
    short mRssi;
    // mProfiles and mRemovedProfiles does not do swap() between main and sub device. It is
@@ -100,6 +104,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
    private boolean mIsA2dpProfileConnectedFail = false;
    private boolean mIsHeadsetProfileConnectedFail = false;
    private boolean mIsHearingAidProfileConnectedFail = false;
    // Group member devices for the coordinated set
    private Set<CachedBluetoothDevice> mMemberDevices = new HashSet<CachedBluetoothDevice>();
    // Group second device for Hearing Aid
    private CachedBluetoothDevice mSubDevice;

@@ -133,6 +139,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
        mDevice = device;
        fillData();
        mHiSyncId = BluetoothHearingAid.HI_SYNC_ID_INVALID;
        mGroupId = BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
    }

    /**
@@ -317,6 +324,24 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
        return mIsCoordinatedSetMember;
    }

    /**
    * Get the coordinated set group id.
    *
    * @return the group id.
    */
    public int getGroupId() {
        return mGroupId;
    }

    /**
    * Set the coordinated set group id.
    *
    * @param id the group id from the CSIP.
    */
    public void setGroupId(int id) {
        mGroupId = id;
    }

    void onBondingDockConnect() {
        // Attempt to connect if UUIDs are available. Otherwise,
        // we will connect when the ACTION_UUID intent arrives.
@@ -1191,4 +1216,52 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
        mSubDevice.mJustDiscovered = tmpJustDiscovered;
        fetchActiveDevices();
    }

    /**
     * @return a set of member devices that are in the same coordinated set with this device.
     */
    public Set<CachedBluetoothDevice> getMemberDevice() {
        return mMemberDevices;
    }

    /**
     * Store the member devices that are in the same coordinated set.
     */
    public void setMemberDevice(CachedBluetoothDevice memberDevice) {
        mMemberDevices.add(memberDevice);
    }

    /**
     * Remove a device from the member device sets.
     */
    public void removeMemberDevice(CachedBluetoothDevice memberDevice) {
        mMemberDevices.remove(memberDevice);
    }

    /**
     * In order to show the preference for the whole group, we always set the main device as the
     * first connected device in the coordinated set, and then switch the content of the main
     * device and member devices.
     *
     * @param prevMainDevice the previous Main device, it will be added into the member device set.
     * @param newMainDevie the new Main device, it will be removed from the member device set.
     */
    public void switchMemberDeviceContent(CachedBluetoothDevice prevMainDevice,
            CachedBluetoothDevice newMainDevie) {
        // Backup from main device
        final BluetoothDevice tmpDevice = mDevice;
        final short tmpRssi = mRssi;
        final boolean tmpJustDiscovered = mJustDiscovered;
        // Set main device from sub device
        mDevice = newMainDevie.mDevice;
        mRssi = newMainDevie.mRssi;
        mJustDiscovered = newMainDevie.mJustDiscovered;
        setMemberDevice(prevMainDevice);
        mMemberDevices.remove(newMainDevie);
        // Set sub device from backup
        newMainDevie.mDevice = tmpDevice;
        newMainDevie.mRssi = tmpRssi;
        newMainDevie.mJustDiscovered = tmpJustDiscovered;
        fetchActiveDevices();
    }
}
+103 −14
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.settingslib.bluetooth;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.util.Log;

@@ -26,6 +27,7 @@ import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

/**
 * CachedBluetoothDeviceManager manages the set of remote Bluetooth devices.
@@ -41,11 +43,14 @@ public class CachedBluetoothDeviceManager {
    final List<CachedBluetoothDevice> mCachedDevices = new ArrayList<CachedBluetoothDevice>();
    @VisibleForTesting
    HearingAidDeviceManager mHearingAidDeviceManager;
    @VisibleForTesting
    CsipDeviceManager mCsipDeviceManager;

    CachedBluetoothDeviceManager(Context context, LocalBluetoothManager localBtManager) {
        mContext = context;
        mBtManager = localBtManager;
        mHearingAidDeviceManager = new HearingAidDeviceManager(localBtManager, mCachedDevices);
        mCsipDeviceManager = new CsipDeviceManager(localBtManager, mCachedDevices);
    }

    public synchronized Collection<CachedBluetoothDevice> getCachedDevicesCopy() {
@@ -79,7 +84,16 @@ public class CachedBluetoothDeviceManager {
            if (cachedDevice.getDevice().equals(device)) {
                return cachedDevice;
            }
            // Check sub devices if it exists
            // Check the member devices for the coordinated set if it exists
            final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
            if (memberDevices != null) {
                for (CachedBluetoothDevice memberDevice : memberDevices) {
                    if (memberDevice.getDevice().equals(device)) {
                        return memberDevice;
                    }
                }
            }
            // Check sub devices for hearing aid if it exists
            CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
            if (subDevice != null && subDevice.getDevice().equals(device)) {
                return subDevice;
@@ -102,8 +116,10 @@ public class CachedBluetoothDeviceManager {
            newDevice = findDevice(device);
            if (newDevice == null) {
                newDevice = new CachedBluetoothDevice(mContext, profileManager, device);
                mCsipDeviceManager.initCsipDeviceIfNeeded(newDevice);
                mHearingAidDeviceManager.initHearingAidDeviceIfNeeded(newDevice);
                if (!mHearingAidDeviceManager.setSubDeviceIfNeeded(newDevice)) {
                if (!mCsipDeviceManager.setMemberDeviceIfNeeded(newDevice)
                        && !mHearingAidDeviceManager.setSubDeviceIfNeeded(newDevice)) {
                    mCachedDevices.add(newDevice);
                    mBtManager.getEventManager().dispatchDeviceAdded(newDevice);
                }
@@ -114,13 +130,23 @@ public class CachedBluetoothDeviceManager {
    }

    /**
     * Returns device summary of the pair of the hearing aid passed as the parameter.
     * Returns device summary of the pair of the hearing aid / CSIP passed as the parameter.
     *
     * @param CachedBluetoothDevice device
     * @return Device summary, or if the pair does not exist or if it is not a hearing aid,
     * then {@code null}.
     * @return Device summary, or if the pair does not exist or if it is not a hearing aid or
     * a CSIP set member, then {@code null}.
     */
    public synchronized String getSubDeviceSummary(CachedBluetoothDevice device) {
        final Set<CachedBluetoothDevice> memberDevices = device.getMemberDevice();
        if (memberDevices != null) {
            for (CachedBluetoothDevice memberDevice : memberDevices) {
                if (!memberDevice.isConnected()) {
                    return null;
                }
            }

            return device.getConnectionSummary();
        }
        CachedBluetoothDevice subDevice = device.getSubDevice();
        if (subDevice != null && subDevice.isConnected()) {
            return subDevice.getConnectionSummary();
@@ -132,12 +158,22 @@ public class CachedBluetoothDeviceManager {
     * Search for existing sub device {@link CachedBluetoothDevice}.
     *
     * @param device the address of the Bluetooth device
     * @return true for found sub device or false.
     * @return true for found sub / member device or false.
     */
    public synchronized boolean isSubDevice(BluetoothDevice device) {
        for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
            if (!cachedDevice.getDevice().equals(device)) {
                // Check sub devices if it exists
                // Check the member devices of the coordinated set if it exists
                Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
                if (memberDevices != null) {
                    for (CachedBluetoothDevice memberDevice : memberDevices) {
                        if (memberDevice.getDevice().equals(device)) {
                            return true;
                        }
                    }
                    continue;
                }
                // Check sub devices of hearing aid if it exists
                CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
                if (subDevice != null && subDevice.getDevice().equals(device)) {
                    return true;
@@ -156,6 +192,14 @@ public class CachedBluetoothDeviceManager {
        mHearingAidDeviceManager.updateHearingAidsDevices();
    }

    /**
     * Updates the Csip devices; specifically the GroupId's. This routine is called when the
     * CSIS is connected and the GroupId's are now available.
     */
    public synchronized void updateCsipDevices() {
        mCsipDeviceManager.updateCsipDevices();
    }

    /**
     * Attempts to get the name of a remote device, otherwise returns the address.
     *
@@ -185,6 +229,16 @@ public class CachedBluetoothDeviceManager {
    private void clearNonBondedSubDevices() {
        for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
            CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
            final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
            if (memberDevices != null) {
                for (CachedBluetoothDevice memberDevice : memberDevices) {
                    // Member device exists and it is not bonded
                    if (memberDevice.getDevice().getBondState() == BluetoothDevice.BOND_NONE) {
                        cachedDevice.removeMemberDevice(memberDevice);
                    }
                }
                return;
            }
            CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
            if (subDevice != null
                    && subDevice.getDevice().getBondState() == BluetoothDevice.BOND_NONE) {
@@ -201,6 +255,13 @@ public class CachedBluetoothDeviceManager {
        for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
            CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
            cachedDevice.setJustDiscovered(false);
            final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
            if (memberDevices != null) {
                for (CachedBluetoothDevice memberDevice : memberDevices) {
                    memberDevice.setJustDiscovered(false);
                }
                return;
            }
            final CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
            if (subDevice != null) {
                subDevice.setJustDiscovered(false);
@@ -214,12 +275,21 @@ public class CachedBluetoothDeviceManager {
        if (bluetoothState == BluetoothAdapter.STATE_TURNING_OFF) {
            for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
                CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
                final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
                if (memberDevices != null) {
                    for (CachedBluetoothDevice memberDevice : memberDevices) {
                        if (memberDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
                            cachedDevice.removeMemberDevice(memberDevice);
                        }
                    }
                } else {
                    CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
                    if (subDevice != null) {
                        if (subDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
                            cachedDevice.setSubDevice(null);
                        }
                    }
                }
                if (cachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
                    cachedDevice.setJustDiscovered(false);
                    mCachedDevices.remove(i);
@@ -229,13 +299,32 @@ public class CachedBluetoothDeviceManager {
    }

    public synchronized boolean onProfileConnectionStateChangedIfProcessed(CachedBluetoothDevice
            cachedDevice, int state) {
            cachedDevice, int state, int profileId) {
        if (profileId == BluetoothProfile.HEARING_AID) {
            return mHearingAidDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
                state);
        }
        if (profileId == BluetoothProfile.CSIP_SET_COORDINATOR) {
            return mCsipDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
                state);
        }
        return false;
    }

    public synchronized void onDeviceUnpaired(CachedBluetoothDevice device) {
        CachedBluetoothDevice mainDevice = mHearingAidDeviceManager.findMainDevice(device);
        CachedBluetoothDevice mainDevice = mCsipDeviceManager.findMainDevice(device);
        final Set<CachedBluetoothDevice> memberDevices = device.getMemberDevice();
        if (memberDevices != null) {
            // Main device is unpaired, to unpair the member device
            for (CachedBluetoothDevice memberDevice : memberDevices) {
                memberDevice.unpair();
                device.removeMemberDevice(memberDevice);
            }
        } else if (mainDevice != null) {
            // the member device unpaired, to unpair main device
            mainDevice.unpair();
        }
        mainDevice = mHearingAidDeviceManager.findMainDevice(device);
        CachedBluetoothDevice subDevice = device.getSubDevice();
        if (subDevice != null) {
            // Main device is unpaired, to unpair sub device
+247 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.settingslib.bluetooth;

import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.os.ParcelUuid;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * CsipDeviceManager manages the set of remote CSIP Bluetooth devices.
 */
public class CsipDeviceManager {
    private static final String TAG = "CsipDeviceManager";
    private static final boolean DEBUG = BluetoothUtils.D;

    private final LocalBluetoothManager mBtManager;
    private final List<CachedBluetoothDevice> mCachedDevices;

    CsipDeviceManager(LocalBluetoothManager localBtManager,
            List<CachedBluetoothDevice> cachedDevices) {
        mBtManager = localBtManager;
        mCachedDevices = cachedDevices;
    };

    void initCsipDeviceIfNeeded(CachedBluetoothDevice newDevice) {
        // Current it only supports the base uuid for CSIP and group this set in UI.
        final int groupId = getBaseGroupId(newDevice.getDevice());
        if (isValidGroupId(groupId)) {
            log("initCsipDeviceIfNeeded: " + newDevice + " (group: " + groupId + ")");
            // Once groupId is valid, assign groupId
            newDevice.setGroupId(groupId);
        }
    }

    private int getBaseGroupId(BluetoothDevice device) {
        final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
        final CsipSetCoordinatorProfile profileProxy = profileManager
                .getCsipSetCoordinatorProfile();
        if (profileProxy != null) {
            final Map<Integer, ParcelUuid> groupIdMap = profileProxy
                    .getGroupUuidMapByDevice(device);
            if (groupIdMap == null) {
                return BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
            }

            for (Map.Entry<Integer, ParcelUuid> entry: groupIdMap.entrySet()) {
                if (entry.getValue().equals(BluetoothUuid.BASE_UUID)) {
                    return entry.getKey();
                }
            }
        }
        return BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
    }

    boolean setMemberDeviceIfNeeded(CachedBluetoothDevice newDevice) {
        final int groupId = newDevice.getGroupId();
        if (isValidGroupId(groupId)) {
            final CachedBluetoothDevice CsipDevice = getCachedDevice(groupId);
            log("setMemberDeviceIfNeeded, main: " + CsipDevice + ", member: " + newDevice);
            // Just add one of the coordinated set from a pair in the list that is shown in the UI.
            // Once there is other devices with the same groupId, to add new device as member
            // devices.
            if (CsipDevice != null) {
                CsipDevice.setMemberDevice(newDevice);
                newDevice.setName(CsipDevice.getName());
                return true;
            }
        }
        return false;
    }

    private boolean isValidGroupId(int groupId) {
        return groupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
    }

    private CachedBluetoothDevice getCachedDevice(int groupId) {
        for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
            CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
            if (cachedDevice.getGroupId() == groupId) {
                return cachedDevice;
            }
        }
        return null;
    }

    // To collect all set member devices and call #onGroupIdChanged to group device by GroupId
    void updateCsipDevices() {
        final Set<Integer> newGroupIdSet = new HashSet<Integer>();
        for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
            // Do nothing if GroupId has been assigned
            if (!isValidGroupId(cachedDevice.getGroupId())) {
                final int newGroupId = getBaseGroupId(cachedDevice.getDevice());
                // Do nothing if there is no GroupId on Bluetooth device
                if (isValidGroupId(newGroupId)) {
                    cachedDevice.setGroupId(newGroupId);
                    newGroupIdSet.add(newGroupId);
                }
            }
        }
        for (int groupId : newGroupIdSet) {
            onGroupIdChanged(groupId);
        }
    }

    // Group devices by groupId
    @VisibleForTesting
    void onGroupIdChanged(int groupId) {
        int firstMatchedIndex = -1;
        CachedBluetoothDevice mainDevice = null;

        for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
            final CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
            if (cachedDevice.getGroupId() != groupId) {
                continue;
            }

            if (firstMatchedIndex == -1) {
                // Found the first one
                firstMatchedIndex = i;
                mainDevice = cachedDevice;
                continue;
            }

            log("onGroupIdChanged: removed from UI device =" + cachedDevice
                    + ", with groupId=" + groupId + " firstMatchedIndex=" + firstMatchedIndex);

            mainDevice.setMemberDevice(cachedDevice);
            mCachedDevices.remove(i);
            mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice);
            break;
        }
    }

    // @return {@code true}, the event is processed inside the method. It is for updating
    // le audio device on group relationship when receiving connected or disconnected.
    // @return {@code false}, it is not le audio device or to process it same as other profiles
    boolean onProfileConnectionStateChangedIfProcessed(CachedBluetoothDevice cachedDevice,
            int state) {
        log("onProfileConnectionStateChangedIfProcessed: " + cachedDevice + ", state: " + state);
        switch (state) {
            case BluetoothProfile.STATE_CONNECTED:
                onGroupIdChanged(cachedDevice.getGroupId());
                CachedBluetoothDevice mainDevice = findMainDevice(cachedDevice);
                if (mainDevice != null) {
                    if (mainDevice.isConnected()) {
                        // When main device exists and in connected state, receiving member device
                        // connection. To refresh main device UI
                        mainDevice.refresh();
                        return true;
                    } else {
                        // When both LE Audio devices are disconnected, receiving member device
                        // connection. To switch content and dispatch to notify UI change
                        mBtManager.getEventManager().dispatchDeviceRemoved(mainDevice);
                        mainDevice.switchMemberDeviceContent(mainDevice, cachedDevice);
                        mainDevice.refresh();
                        // It is necessary to do remove and add for updating the mapping on
                        // preference and device
                        mBtManager.getEventManager().dispatchDeviceAdded(mainDevice);
                        return true;
                    }
                }
                break;
            case BluetoothProfile.STATE_DISCONNECTED:
                mainDevice = findMainDevice(cachedDevice);
                if (mainDevice != null) {
                    // When main device exists, receiving sub device disconnection
                    // To update main device UI
                    mainDevice.refresh();
                    return true;
                }
                final Set<CachedBluetoothDevice> memberSet = cachedDevice.getMemberDevice();
                if (memberSet == null) {
                    break;
                }

                for (CachedBluetoothDevice device: memberSet) {
                    if (device.isConnected()) {
                        // Main device is disconnected and sub device is connected
                        // To copy data from sub device to main device
                        mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice);
                        cachedDevice.switchMemberDeviceContent(device, cachedDevice);
                        cachedDevice.refresh();
                        // It is necessary to do remove and add for updating the mapping on
                        // preference and device
                        mBtManager.getEventManager().dispatchDeviceAdded(cachedDevice);
                        return true;
                    }
                }
                break;
            default:
                // Do not handle this state.
        }
        return false;
    }

    CachedBluetoothDevice findMainDevice(CachedBluetoothDevice device) {
        if (device == null || mCachedDevices == null) {
            return null;
        }

        for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
            if (isValidGroupId(cachedDevice.getGroupId())) {
                Set<CachedBluetoothDevice> memberSet = cachedDevice.getMemberDevice();
                if (memberSet == null) {
                    continue;
                }

                for (CachedBluetoothDevice memberDevice: memberSet) {
                    if (memberDevice != null && memberDevice.equals(device)) {
                        return cachedDevice;
                    }
                }
            }
        }
        return null;
    }

    private void log(String msg) {
        if (DEBUG) {
            Log.d(TAG, msg);
        }
    }
}
+15 −0

File changed.

Preview size limit exceeded, changes collapsed.

Loading