10825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/* 20825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Copyright (C) 2011 The Android Open Source Project 30825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 40825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Licensed under the Apache License, Version 2.0 (the "License"); 50825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * you may not use this file except in compliance with the License. 60825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * You may obtain a copy of the License at 70825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 80825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * http://www.apache.org/licenses/LICENSE-2.0 90825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Unless required by applicable law or agreed to in writing, software 110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * distributed under the License is distributed on an "AS IS" BASIS, 120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * See the License for the specific language governing permissions and 140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * limitations under the License. 150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 170825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepackage com.android.internal.telephony; 180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 190825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.ArrayList; 200825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.Iterator; 210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/** 230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Clients can enable reception of SMS-CB messages for specific ranges of 240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * message identifiers (channels). This class keeps track of the currently 250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * enabled message identifiers and calls abstract methods to update the 260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * radio when the range of enabled message identifiers changes. 270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * An update is a call to {@link #startUpdate} followed by zero or more 290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * calls to {@link #addRange} followed by a call to {@link #finishUpdate}. 300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Calls to {@link #enableRange} and {@link #disableRange} will perform 310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * an incremental update operation if the enabled ranges have changed. 320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * A full update operation (i.e. after a radio reset) can be performed 330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * by a call to {@link #updateRanges}. 340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Clients are identified by String (the name associated with the User ID 360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * of the caller) so that a call to remove a range can be mapped to the 370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * client that enabled that range (or else rejected). 380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 390825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepublic abstract class IntRangeManager { 400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Initial capacity for IntRange clients array list. There will be 430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * few cell broadcast listeners on a typical device, so this can be small. 440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static final int INITIAL_CLIENTS_ARRAY_SIZE = 4; 460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * One or more clients forming the continuous range [startId, endId]. 490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * <p>When a client is added, the IntRange may merge with one or more 500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * adjacent IntRanges to form a single combined IntRange. 510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * <p>When a client is removed, the IntRange may divide into several 520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * non-contiguous IntRanges. 530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private class IntRange { 5522d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville int mStartId; 5622d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville int mEndId; 570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // sorted by earliest start id 5822d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville final ArrayList<ClientRange> mClients; 590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Create a new IntRange with a single client. 620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param startId the first id included in the range 630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param endId the last id included in the range 640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param client the client requesting the enabled range 650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange(int startId, int endId, String client) { 6722d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mStartId = startId; 6822d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mEndId = endId; 6922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mClients = new ArrayList<ClientRange>(INITIAL_CLIENTS_ARRAY_SIZE); 7022d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mClients.add(new ClientRange(startId, endId, client)); 710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Create a new IntRange for an existing ClientRange. 750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param clientRange the initial ClientRange to add 760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange(ClientRange clientRange) { 7822d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mStartId = clientRange.mStartId; 7922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mEndId = clientRange.mEndId; 8022d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mClients = new ArrayList<ClientRange>(INITIAL_CLIENTS_ARRAY_SIZE); 8122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mClients.add(clientRange); 820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Create a new IntRange from an existing IntRange. This is used for 860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * removing a ClientRange, because new IntRanges may need to be created 870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * for any gaps that open up after the ClientRange is removed. A copy 880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * is made of the elements of the original IntRange preceding the element 890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * that is being removed. The following elements will be added to this 900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * IntRange or to a new IntRange when a gap is found. 910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param intRange the original IntRange to copy elements from 920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param numElements the number of elements to copy from the original 930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange(IntRange intRange, int numElements) { 9522d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mStartId = intRange.mStartId; 9622d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mEndId = intRange.mEndId; 9722d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mClients = new ArrayList<ClientRange>(intRange.mClients.size()); 980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville for (int i=0; i < numElements; i++) { 9922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mClients.add(intRange.mClients.get(i)); 1000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 10401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks * Insert new ClientRange in order by start id, then by end id 1050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * <p>If the new ClientRange is known to be sorted before or after the 1060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * existing ClientRanges, or at a particular index, it can be added 1070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * to the clients array list directly, instead of via this method. 1080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * <p>Note that this can be changed from linear to binary search if the 1090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * number of clients grows large enough that it would make a difference. 1100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param range the new ClientRange to insert 1110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 1120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville void insert(ClientRange range) { 11322d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville int len = mClients.size(); 11401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks int insert = -1; 1150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville for (int i=0; i < len; i++) { 11622d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville ClientRange nextRange = mClients.get(i); 11722d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if (range.mStartId <= nextRange.mStartId) { 1180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // ignore duplicate ranges from the same client 1190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (!range.equals(nextRange)) { 12001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // check if same startId, then order by endId 1214e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby if (range.mStartId == nextRange.mStartId 1224e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby && range.mEndId > nextRange.mEndId) { 12301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks insert = i + 1; 12401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (insert < len) { 12501fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // there may be more client following with same startId 12601fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [1, 5] existing [1, 2] [1, 4] [1, 7] 12701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks continue; 12801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 12901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks break; 13001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 13122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mClients.add(i, range); 1320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return; 1340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 13601fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (insert != -1 && insert < len) { 1374e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby mClients.add(insert, range); 13801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks return; 13901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 14022d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mClients.add(range); // append to end of list 1410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 1450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * The message id range for a single client. 1460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 1470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private class ClientRange { 14822d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville final int mStartId; 14922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville final int mEndId; 15022d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville final String mClient; 1510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ClientRange(int startId, int endId, String client) { 15322d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mStartId = startId; 15422d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mEndId = endId; 15522d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mClient = client; 1560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville @Override 1590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public boolean equals(Object o) { 1600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (o != null && o instanceof ClientRange) { 1610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ClientRange other = (ClientRange) o; 16222d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville return mStartId == other.mStartId && 16322d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mEndId == other.mEndId && 16422d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville mClient.equals(other.mClient); 1650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 1660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; 1670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville @Override 1710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public int hashCode() { 17222d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville return (mStartId * 31 + mEndId) * 31 + mClient.hashCode(); 1730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 1770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * List of integer ranges, one per client, sorted by start id. 1780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 1790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private ArrayList<IntRange> mRanges = new ArrayList<IntRange>(); 1800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville protected IntRangeManager() {} 1820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 1840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Enable a range for the specified client and update ranges 1850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * if necessary. If {@link #finishUpdate} returns failure, 1860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * false is returned and the range is not added. 1870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 1880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param startId the first id included in the range 1890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param endId the last id included in the range 1900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param client the client requesting the enabled range 1910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @return true if successful, false otherwise 1920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 1930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public synchronized boolean enableRange(int startId, int endId, String client) { 1940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int len = mRanges.size(); 1950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // empty range list: add the initial IntRange 1970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (len == 0) { 19801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (tryAddRanges(startId, endId, true)) { 1990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mRanges.add(new IntRange(startId, endId, client)); 2000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 2010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 2020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; // failed to update radio 2030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 2060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville for (int startIndex = 0; startIndex < len; startIndex++) { 2070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange range = mRanges.get(startIndex); 2084e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby if ((startId) >= range.mStartId && (endId) <= range.mEndId) { 20901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // exact same range: new [1, 1] existing [1, 1] 21001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // range already enclosed in existing: new [3, 3], [1,3] 21101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // no radio update necessary. 21201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // duplicate "client" check is done in insert, attempt to insert. 21301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks range.insert(new ClientRange(startId, endId, client)); 21401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks return true; 2154e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby } else if ((startId - 1) == range.mEndId) { 21601fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [3, x] existing [1, 2] OR new [2, 2] existing [1, 1] 21701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // found missing link? check if next range can be joined 21801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks int newRangeEndId = endId; 21901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks IntRange nextRange = null; 22001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if ((startIndex + 1) < len) { 22101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks nextRange = mRanges.get(startIndex + 1); 2224e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby if ((nextRange.mStartId - 1) <= endId) { 22301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [3, x] existing [1, 2] [5, 7] OR new [2 , 2] existing [1, 1] [3, 5] 2244e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby if (endId <= nextRange.mEndId) { 22501fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [3, 6] existing [1, 2] [5, 7] 2264e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby newRangeEndId = nextRange.mStartId - 1; // need to enable [3, 4] 22701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 22801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } else { 22901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // mark nextRange to be joined as null. 23001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks nextRange = null; 23101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 23201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 23301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (tryAddRanges(startId, newRangeEndId, true)) { 2344e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby range.mEndId = endId; 23501fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks range.insert(new ClientRange(startId, endId, client)); 23601fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks 23701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // found missing link? check if next range can be joined 23801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (nextRange != null) { 2394e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby if (range.mEndId < nextRange.mEndId) { 24001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [3, 6] existing [1, 2] [5, 10] 2414e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby range.mEndId = nextRange.mEndId; 24201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 2434e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby range.mClients.addAll(nextRange.mClients); 24401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks mRanges.remove(nextRange); 24501fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 24601fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks return true; 24701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } else { 24801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks return false; // failed to update radio 24901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 2504e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby } else if (startId < range.mStartId) { 25101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [1, x] , existing [5, y] 2520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // test if new range completely precedes this range 2530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // note that [1, 4] and [5, 6] coalesce to [1, 6] 25422d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if ((endId + 1) < range.mStartId) { 25501fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [1, 3] existing [5, 6] non contiguous case 2560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // insert new int range before previous first range 25701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (tryAddRanges(startId, endId, true)) { 2580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mRanges.add(startIndex, new IntRange(startId, endId, client)); 2590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 2600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 2610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; // failed to update radio 2620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 26322d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville } else if (endId <= range.mEndId) { 26401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [1, 4] existing [5, 6] or new [1, 1] existing [2, 2] 2650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // extend the start of this range 2664e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby if (tryAddRanges(startId, range.mStartId - 1, true)) { 26722d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville range.mStartId = startId; 26822d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville range.mClients.add(0, new ClientRange(startId, endId, client)); 2690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 2700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 2710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; // failed to update radio 2720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 2740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // find last range that can coalesce into the new combined range 2750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville for (int endIndex = startIndex+1; endIndex < len; endIndex++) { 2760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange endRange = mRanges.get(endIndex); 27722d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if ((endId + 1) < endRange.mStartId) { 27801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [1, 10] existing [2, 3] [14, 15] 2790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // try to add entire new range 28001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (tryAddRanges(startId, endId, true)) { 28122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville range.mStartId = startId; 28222d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville range.mEndId = endId; 2830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // insert new ClientRange before existing ranges 28422d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville range.mClients.add(0, new ClientRange(startId, endId, client)); 2850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // coalesce range with following ranges up to endIndex-1 2860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // remove each range after adding its elements, so the index 2870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // of the next range to join is always startIndex+1. 2880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // i is the index if no elements were removed: we only care 2890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // about the number of loop iterations, not the value of i. 2900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int joinIndex = startIndex + 1; 2910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville for (int i = joinIndex; i < endIndex; i++) { 29201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [1, 10] existing [2, 3] [5, 6] [14, 15] 2930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange joinRange = mRanges.get(joinIndex); 29422d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville range.mClients.addAll(joinRange.mClients); 2950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mRanges.remove(joinRange); 2960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 2980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 2990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; // failed to update radio 3000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 30122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville } else if (endId <= endRange.mEndId) { 30201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [1, 10] existing [2, 3] [5, 15] 3030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // add range from start id to start of last overlapping range, 3040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // values from endRange.startId to endId are already enabled 3054e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby if (tryAddRanges(startId, endRange.mStartId - 1, true)) { 30622d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville range.mStartId = startId; 30722d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville range.mEndId = endRange.mEndId; 3080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // insert new ClientRange before existing ranges 30922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville range.mClients.add(0, new ClientRange(startId, endId, client)); 3100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // coalesce range with following ranges up to endIndex 3110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // remove each range after adding its elements, so the index 3120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // of the next range to join is always startIndex+1. 3130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // i is the index if no elements were removed: we only care 3140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // about the number of loop iterations, not the value of i. 3150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int joinIndex = startIndex + 1; 3160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville for (int i = joinIndex; i <= endIndex; i++) { 3170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange joinRange = mRanges.get(joinIndex); 31822d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville range.mClients.addAll(joinRange.mClients); 3190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mRanges.remove(joinRange); 3200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 3220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 3230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; // failed to update radio 3240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 32801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [1, 10] existing [2, 3] 3290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // endId extends past all existing IntRanges: combine them all together 33001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (tryAddRanges(startId, endId, true)) { 33122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville range.mStartId = startId; 33222d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville range.mEndId = endId; 3330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // insert new ClientRange before existing ranges 33422d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville range.mClients.add(0, new ClientRange(startId, endId, client)); 3350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // coalesce range with following ranges up to len-1 3360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // remove each range after adding its elements, so the index 3370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // of the next range to join is always startIndex+1. 3380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // i is the index if no elements were removed: we only care 3390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // about the number of loop iterations, not the value of i. 3400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int joinIndex = startIndex + 1; 3410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville for (int i = joinIndex; i < len; i++) { 34201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [1, 10] existing [2, 3] [5, 6] 3430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange joinRange = mRanges.get(joinIndex); 34422d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville range.mClients.addAll(joinRange.mClients); 3450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mRanges.remove(joinRange); 3460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 3480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 3490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; // failed to update radio 3500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 35222d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville } else if ((startId + 1) <= range.mEndId) { 35301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [2, x] existing [1, 4] 35422d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if (endId <= range.mEndId) { 35501fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [2, 3] existing [1, 4] 3560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // completely contained in existing range; no radio changes 3570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville range.insert(new ClientRange(startId, endId, client)); 3580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 3590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 36001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [2, 5] existing [1, 4] 3610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // find last range that can coalesce into the new combined range 3620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int endIndex = startIndex; 3630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville for (int testIndex = startIndex+1; testIndex < len; testIndex++) { 3640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange testRange = mRanges.get(testIndex); 36522d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if ((endId + 1) < testRange.mStartId) { 3660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville break; 3670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 3680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville endIndex = testIndex; 3690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // no adjacent IntRanges to combine 3720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (endIndex == startIndex) { 37301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [2, 5] existing [1, 4] 3740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // add range from range.endId+1 to endId, 3750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // values from startId to range.endId are already enabled 3764e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby if (tryAddRanges(range.mEndId + 1, endId, true)) { 37722d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville range.mEndId = endId; 3780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville range.insert(new ClientRange(startId, endId, client)); 3790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 3800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 3810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; // failed to update radio 3820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // get last range to coalesce into start range 3850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange endRange = mRanges.get(endIndex); 3860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // Values from startId to range.endId have already been enabled. 3870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // if endId > endRange.endId, then enable range from range.endId+1 to endId, 3880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // else enable range from range.endId+1 to endRange.startId-1, because 3890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // values from endRange.startId to endId have already been added. 39022d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville int newRangeEndId = (endId <= endRange.mEndId) ? endRange.mStartId - 1 : endId; 39101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [2, 10] existing [1, 4] [7, 8] OR 39201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [2, 10] existing [1, 4] [7, 15] 3934e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby if (tryAddRanges(range.mEndId + 1, newRangeEndId, true)) { 3944e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby newRangeEndId = (endId <= endRange.mEndId) ? endRange.mEndId : endId; 3954e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby range.mEndId = newRangeEndId; 3960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // insert new ClientRange in place 3970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville range.insert(new ClientRange(startId, endId, client)); 39801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // coalesce range with following ranges up to endIndex 3990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // remove each range after adding its elements, so the index 4000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // of the next range to join is always startIndex+1 (joinIndex). 4010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // i is the index if no elements had been removed: we only care 4020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // about the number of loop iterations, not the value of i. 4030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int joinIndex = startIndex + 1; 40401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks for (int i = joinIndex; i <= endIndex; i++) { 4050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange joinRange = mRanges.get(joinIndex); 40622d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville range.mClients.addAll(joinRange.mClients); 4070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mRanges.remove(joinRange); 4080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 4100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 4110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; // failed to update radio 4120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 41701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [5, 6], existing [1, 3] 4180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // append new range after existing IntRanges 41901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (tryAddRanges(startId, endId, true)) { 4200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mRanges.add(new IntRange(startId, endId, client)); 4210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 4220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 4230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; // failed to update radio 4240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 4270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 4280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Disable a range for the specified client and update ranges 4290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * if necessary. If {@link #finishUpdate} returns failure, 4300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * false is returned and the range is not removed. 4310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 4320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param startId the first id included in the range 4330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param endId the last id included in the range 4340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param client the client requesting to disable the range 4350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @return true if successful, false otherwise 4360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 4370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public synchronized boolean disableRange(int startId, int endId, String client) { 4380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int len = mRanges.size(); 4390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 4400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville for (int i=0; i < len; i++) { 4410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange range = mRanges.get(i); 44222d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if (startId < range.mStartId) { 4430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; // not found 44422d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville } else if (endId <= range.mEndId) { 4450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // found the IntRange that encloses the client range, if any 4460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // search for it in the clients list 44722d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville ArrayList<ClientRange> clients = range.mClients; 4480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 4490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // handle common case of IntRange containing one ClientRange 4500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int crLength = clients.size(); 4510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (crLength == 1) { 4520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ClientRange cr = clients.get(0); 45322d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if (cr.mStartId == startId && cr.mEndId == endId && cr.mClient.equals(client)) { 45401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // mRange contains only what's enabled. 45501fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // remove the range from mRange then update the radio 45601fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks mRanges.remove(i); 45701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (updateRanges()) { 4580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 4590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 46001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // failed to update radio. insert back the range 46101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks mRanges.add(i, range); 46201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks return false; 4630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 4650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; // not found 4660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 4690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // several ClientRanges: remove one, potentially splitting into many IntRanges. 4700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // Save the original start and end id for the original IntRange 4710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // in case the radio update fails and we have to revert it. If the 4720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // update succeeds, we remove the client range and insert the new IntRanges. 47301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // clients are ordered by startId then by endId, so client with largest endId 47401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // can be anywhere. Need to loop thru to find largestEndId. 4750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int largestEndId = Integer.MIN_VALUE; // largest end identifier found 4760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville boolean updateStarted = false; 4770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 47801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // crlength >= 2 4790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville for (int crIndex=0; crIndex < crLength; crIndex++) { 4800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ClientRange cr = clients.get(crIndex); 48122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if (cr.mStartId == startId && cr.mEndId == endId && cr.mClient.equals(client)) { 4820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // found the ClientRange to remove, check if it's the last in the list 4830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (crIndex == crLength - 1) { 48422d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if (range.mEndId == largestEndId) { 48501fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // remove [2, 5] from [1, 7] [2, 5] 4860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // no channels to remove from radio; return success 4870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville clients.remove(crIndex); 4880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 4890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 4900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // disable the channels at the end and lower the end id 49101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks clients.remove(crIndex); 4924e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby range.mEndId = largestEndId; 49301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (updateRanges()) { 4940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 4950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 49601fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks clients.add(crIndex, cr); 4974e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby range.mEndId = cr.mEndId; 4980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; 4990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 5030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // copy the IntRange so that we can remove elements and modify the 5040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // start and end id's in the copy, leaving the original unmodified 5050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // until after the radio update succeeds 5060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange rangeCopy = new IntRange(range, crIndex); 5070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 5080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (crIndex == 0) { 5090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // removing the first ClientRange, so we may need to increase 5100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // the start id of the IntRange. 5110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // We know there are at least two ClientRanges in the list, 5124e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby // because check for just one ClientRanges case is already handled 5130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // so clients.get(1) should always succeed. 51422d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville int nextStartId = clients.get(1).mStartId; 51522d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if (nextStartId != range.mStartId) { 5160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville updateStarted = true; 51722d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville rangeCopy.mStartId = nextStartId; 5180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // init largestEndId 52022d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville largestEndId = clients.get(1).mEndId; 5210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 5230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // go through remaining ClientRanges, creating new IntRanges when 5240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // there is a gap in the sequence. After radio update succeeds, 5250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // remove the original IntRange and append newRanges to mRanges. 5260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // Otherwise, leave the original IntRange in mRanges and return false. 5270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ArrayList<IntRange> newRanges = new ArrayList<IntRange>(); 5280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 5290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange currentRange = rangeCopy; 5300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville for (int nextIndex = crIndex + 1; nextIndex < crLength; nextIndex++) { 5310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ClientRange nextCr = clients.get(nextIndex); 53222d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if (nextCr.mStartId > largestEndId + 1) { 53301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks updateStarted = true; 53422d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville currentRange.mEndId = largestEndId; 5350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville newRanges.add(currentRange); 5360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville currentRange = new IntRange(nextCr); 5370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 5384e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby if (currentRange.mEndId < nextCr.mEndId) { 5394e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby currentRange.mEndId = nextCr.mEndId; 54001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 54122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville currentRange.mClients.add(nextCr); 5420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 54322d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if (nextCr.mEndId > largestEndId) { 54422d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville largestEndId = nextCr.mEndId; 5450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 5480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // remove any channels between largestEndId and endId 5490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (largestEndId < endId) { 55001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks updateStarted = true; 55122d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville currentRange.mEndId = largestEndId; 5520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville newRanges.add(currentRange); 5540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 5550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // replace the original IntRange with newRanges 5560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mRanges.remove(i); 5570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mRanges.addAll(i, newRanges); 55801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (updateStarted && !updateRanges()) { 55901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // failed to update radio. revert back mRange. 56001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks mRanges.removeAll(newRanges); 56101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks mRanges.add(i, range); 56201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks return false; 56301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 56401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks 5650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 5660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 5670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // not the ClientRange to remove; save highest end ID seen so far 56822d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville if (cr.mEndId > largestEndId) { 56922d85a8e3a575a6d01d2c788587971657dfe20c6Wink Saville largestEndId = cr.mEndId; 5700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 5760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; // not found 5770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 5790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 5800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Perform a complete update operation (enable all ranges). Useful 5810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * after a radio reset. Calls {@link #startUpdate}, followed by zero or 5820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * more calls to {@link #addRange}, followed by {@link #finishUpdate}. 5830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @return true if successful, false otherwise 5840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 5850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public boolean updateRanges() { 5860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville startUpdate(); 58701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks 58801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks populateAllRanges(); 5890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return finishUpdate(); 5900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 5920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 5930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Enable or disable a single range of message identifiers. 5940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param startId the first id included in the range 5950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param endId the last id included in the range 5960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param selected true to enable range, false to disable range 5970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @return true if successful, false otherwise 5980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 59901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks protected boolean tryAddRanges(int startId, int endId, boolean selected) { 60001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks 6010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville startUpdate(); 60201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks populateAllRanges(); 60301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // This is the new range to be enabled 60401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks addRange(startId, endId, selected); // adds to mConfigList 6050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return finishUpdate(); 6060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 6070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 6080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 6090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Returns whether the list of ranges is completely empty. 6100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @return true if there are no enabled ranges 6110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 6120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public boolean isEmpty() { 6130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return mRanges.isEmpty(); 6140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 6150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 6160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 61701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks * Called when attempting to add a single range of message identifiers 61801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks * Populate all ranges of message identifiers. 61901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks */ 62001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks private void populateAllRanges() { 62101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks Iterator<IntRange> itr = mRanges.iterator(); 62201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // Populate all ranges from mRanges 62301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks while (itr.hasNext()) { 62401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks IntRange currRange = (IntRange) itr.next(); 6254e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby addRange(currRange.mStartId, currRange.mEndId, true); 62601fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 62701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 62801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks 62901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks /** 63001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks * Called when attempting to add a single range of message identifiers 63101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks * Populate all ranges of message identifiers using clients' ranges. 63201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks */ 63301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks private void populateAllClientRanges() { 63401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks int len = mRanges.size(); 63501fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks for (int i = 0; i < len; i++) { 63601fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks IntRange range = mRanges.get(i); 63701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks 6384e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby int clientLen = range.mClients.size(); 63901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks for (int j=0; j < clientLen; j++) { 6404e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby ClientRange nextRange = range.mClients.get(j); 6414e9ed0410d72180872d59b14cb375c1c2ed94788Jake Hamby addRange(nextRange.mStartId, nextRange.mEndId, true); 64201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 64301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 64401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 64501fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks 64601fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks /** 6470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Called when the list of enabled ranges has changed. This will be 6480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * followed by zero or more calls to {@link #addRange} followed by 6490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * a call to {@link #finishUpdate}. 6500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 6510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville protected abstract void startUpdate(); 6520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 6530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 6540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Called after {@link #startUpdate} to indicate a range of enabled 6550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * or disabled values. 6560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 6570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param startId the first id included in the range 6580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param endId the last id included in the range 6590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param selected true to enable range, false to disable range 6600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 6610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville protected abstract void addRange(int startId, int endId, boolean selected); 6620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 6630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 6640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Called to indicate the end of a range update started by the 6650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * previous call to {@link #startUpdate}. 6660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @return true if successful, false otherwise 6670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 6680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville protected abstract boolean finishUpdate(); 6690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville} 670