IntRangeManager.java revision 01fdbd3285be1a8ba2143a4bc11a0f5065bb68d0
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 { 550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int startId; 560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int endId; 570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // sorted by earliest start id 580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville final ArrayList<ClientRange> clients; 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) { 670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville this.startId = startId; 680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville this.endId = endId; 690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville clients = new ArrayList<ClientRange>(INITIAL_CLIENTS_ARRAY_SIZE); 700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville clients.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) { 780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville startId = clientRange.startId; 790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville endId = clientRange.endId; 800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville clients = new ArrayList<ClientRange>(INITIAL_CLIENTS_ARRAY_SIZE); 810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville clients.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) { 950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville this.startId = intRange.startId; 960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville this.endId = intRange.endId; 970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville this.clients = new ArrayList<ClientRange>(intRange.clients.size()); 980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville for (int i=0; i < numElements; i++) { 990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville this.clients.add(intRange.clients.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) { 1130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int len = clients.size(); 11401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks int insert = -1; 1150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville for (int i=0; i < len; i++) { 1160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ClientRange nextRange = clients.get(i); 1170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (range.startId <= nextRange.startId) { 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 12101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (range.startId == nextRange.startId && range.endId > nextRange.endId) { 12201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks insert = i + 1; 12301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (insert < len) { 12401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // there may be more client following with same startId 12501fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [1, 5] existing [1, 2] [1, 4] [1, 7] 12601fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks continue; 12701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 12801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks break; 12901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 1300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville clients.add(i, range); 1310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return; 1330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 13501fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (insert != -1 && insert < len) { 13601fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks clients.add(insert, range); 13701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks return; 13801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 1390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville clients.add(range); // append to end of list 1400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 1440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * The message id range for a single client. 1450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 1460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private class ClientRange { 1470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville final int startId; 1480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville final int endId; 1490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville final String client; 1500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ClientRange(int startId, int endId, String client) { 1520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville this.startId = startId; 1530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville this.endId = endId; 1540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville this.client = client; 1550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville @Override 1580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public boolean equals(Object o) { 1590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (o != null && o instanceof ClientRange) { 1600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ClientRange other = (ClientRange) o; 1610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return startId == other.startId && 1620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville endId == other.endId && 1630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville client.equals(other.client); 1640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 1650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; 1660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville @Override 1700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public int hashCode() { 1710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return (startId * 31 + endId) * 31 + client.hashCode(); 1720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 1760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * List of integer ranges, one per client, sorted by start id. 1770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 1780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private ArrayList<IntRange> mRanges = new ArrayList<IntRange>(); 1790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville protected IntRangeManager() {} 1810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 1830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Enable a range for the specified client and update ranges 1840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * if necessary. If {@link #finishUpdate} returns failure, 1850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * false is returned and the range is not added. 1860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 1870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param startId the first id included in the range 1880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param endId the last id included in the range 1890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param client the client requesting the enabled range 1900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @return true if successful, false otherwise 1910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 1920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public synchronized boolean enableRange(int startId, int endId, String client) { 1930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int len = mRanges.size(); 1940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // empty range list: add the initial IntRange 1960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (len == 0) { 19701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (tryAddRanges(startId, endId, true)) { 1980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mRanges.add(new IntRange(startId, endId, client)); 1990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 2000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 2010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; // failed to update radio 2020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 2050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville for (int startIndex = 0; startIndex < len; startIndex++) { 2060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange range = mRanges.get(startIndex); 20701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if ((startId) >= range.startId && (endId) <= range.endId) { 20801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // exact same range: new [1, 1] existing [1, 1] 20901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // range already enclosed in existing: new [3, 3], [1,3] 21001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // no radio update necessary. 21101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // duplicate "client" check is done in insert, attempt to insert. 21201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks range.insert(new ClientRange(startId, endId, client)); 21301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks return true; 21401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } else if ((startId - 1) == range.endId) { 21501fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [3, x] existing [1, 2] OR new [2, 2] existing [1, 1] 21601fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // found missing link? check if next range can be joined 21701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks int newRangeEndId = endId; 21801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks IntRange nextRange = null; 21901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if ((startIndex + 1) < len) { 22001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks nextRange = mRanges.get(startIndex + 1); 22101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if ((nextRange.startId - 1) <= endId) { 22201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [3, x] existing [1, 2] [5, 7] OR new [2 , 2] existing [1, 1] [3, 5] 22301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (endId <= nextRange.endId) { 22401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [3, 6] existing [1, 2] [5, 7] 22501fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks newRangeEndId = nextRange.startId - 1; // need to enable [3, 4] 22601fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 22701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } else { 22801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // mark nextRange to be joined as null. 22901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks nextRange = null; 23001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 23101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 23201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (tryAddRanges(startId, newRangeEndId, true)) { 23301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks range.endId = endId; 23401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks range.insert(new ClientRange(startId, endId, client)); 23501fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks 23601fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // found missing link? check if next range can be joined 23701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (nextRange != null) { 23801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (range.endId < nextRange.endId) { 23901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [3, 6] existing [1, 2] [5, 10] 24001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks range.endId = nextRange.endId; 24101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 24201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks range.clients.addAll(nextRange.clients); 24301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks mRanges.remove(nextRange); 24401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 24501fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks return true; 24601fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } else { 24701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks return false; // failed to update radio 24801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 24901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } else if (startId < range.startId) { 25001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [1, x] , existing [5, y] 2510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // test if new range completely precedes this range 2520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // note that [1, 4] and [5, 6] coalesce to [1, 6] 2530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if ((endId + 1) < range.startId) { 25401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [1, 3] existing [5, 6] non contiguous case 2550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // insert new int range before previous first range 25601fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (tryAddRanges(startId, endId, true)) { 2570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mRanges.add(startIndex, new IntRange(startId, endId, client)); 2580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 2590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 2600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; // failed to update radio 2610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else if (endId <= range.endId) { 26301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [1, 4] existing [5, 6] or new [1, 1] existing [2, 2] 2640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // extend the start of this range 26501fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (tryAddRanges(startId, range.startId - 1, true)) { 2660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville range.startId = startId; 2670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville range.clients.add(0, new ClientRange(startId, endId, client)); 2680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 2690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 2700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; // failed to update radio 2710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 2730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // find last range that can coalesce into the new combined range 2740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville for (int endIndex = startIndex+1; endIndex < len; endIndex++) { 2750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange endRange = mRanges.get(endIndex); 2760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if ((endId + 1) < endRange.startId) { 27701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [1, 10] existing [2, 3] [14, 15] 2780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // try to add entire new range 27901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (tryAddRanges(startId, endId, true)) { 2800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville range.startId = startId; 2810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville range.endId = endId; 2820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // insert new ClientRange before existing ranges 2830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville range.clients.add(0, new ClientRange(startId, endId, client)); 2840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // coalesce range with following ranges up to endIndex-1 2850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // remove each range after adding its elements, so the index 2860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // of the next range to join is always startIndex+1. 2870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // i is the index if no elements were removed: we only care 2880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // about the number of loop iterations, not the value of i. 2890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int joinIndex = startIndex + 1; 2900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville for (int i = joinIndex; i < endIndex; i++) { 29101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [1, 10] existing [2, 3] [5, 6] [14, 15] 2920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange joinRange = mRanges.get(joinIndex); 2930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville range.clients.addAll(joinRange.clients); 2940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mRanges.remove(joinRange); 2950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 2970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 2980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; // failed to update radio 2990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else if (endId <= endRange.endId) { 30101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [1, 10] existing [2, 3] [5, 15] 3020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // add range from start id to start of last overlapping range, 3030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // values from endRange.startId to endId are already enabled 30401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (tryAddRanges(startId, endRange.startId - 1, true)) { 3050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville range.startId = startId; 3060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville range.endId = endRange.endId; 3070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // insert new ClientRange before existing ranges 3080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville range.clients.add(0, new ClientRange(startId, endId, client)); 3090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // coalesce range with following ranges up to endIndex 3100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // remove each range after adding its elements, so the index 3110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // of the next range to join is always startIndex+1. 3120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // i is the index if no elements were removed: we only care 3130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // about the number of loop iterations, not the value of i. 3140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int joinIndex = startIndex + 1; 3150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville for (int i = joinIndex; i <= endIndex; i++) { 3160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange joinRange = mRanges.get(joinIndex); 3170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville range.clients.addAll(joinRange.clients); 3180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mRanges.remove(joinRange); 3190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 3210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 3220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; // failed to update radio 3230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 32701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [1, 10] existing [2, 3] 3280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // endId extends past all existing IntRanges: combine them all together 32901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (tryAddRanges(startId, endId, true)) { 3300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville range.startId = startId; 3310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville range.endId = endId; 3320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // insert new ClientRange before existing ranges 3330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville range.clients.add(0, new ClientRange(startId, endId, client)); 3340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // coalesce range with following ranges up to len-1 3350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // remove each range after adding its elements, so the index 3360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // of the next range to join is always startIndex+1. 3370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // i is the index if no elements were removed: we only care 3380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // about the number of loop iterations, not the value of i. 3390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int joinIndex = startIndex + 1; 3400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville for (int i = joinIndex; i < len; i++) { 34101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [1, 10] existing [2, 3] [5, 6] 3420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange joinRange = mRanges.get(joinIndex); 3430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville range.clients.addAll(joinRange.clients); 3440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mRanges.remove(joinRange); 3450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 3470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 3480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; // failed to update radio 3490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else if ((startId + 1) <= range.endId) { 35201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [2, x] existing [1, 4] 3530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (endId <= range.endId) { 35401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [2, 3] existing [1, 4] 3550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // completely contained in existing range; no radio changes 3560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville range.insert(new ClientRange(startId, endId, client)); 3570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 3580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 35901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [2, 5] existing [1, 4] 3600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // find last range that can coalesce into the new combined range 3610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int endIndex = startIndex; 3620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville for (int testIndex = startIndex+1; testIndex < len; testIndex++) { 3630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange testRange = mRanges.get(testIndex); 3640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if ((endId + 1) < testRange.startId) { 3650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville break; 3660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 3670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville endIndex = testIndex; 3680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // no adjacent IntRanges to combine 3710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (endIndex == startIndex) { 37201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [2, 5] existing [1, 4] 3730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // add range from range.endId+1 to endId, 3740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // values from startId to range.endId are already enabled 37501fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (tryAddRanges(range.endId + 1, endId, true)) { 3760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville range.endId = endId; 3770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville range.insert(new ClientRange(startId, endId, client)); 3780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 3790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 3800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; // failed to update radio 3810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // get last range to coalesce into start range 3840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange endRange = mRanges.get(endIndex); 3850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // Values from startId to range.endId have already been enabled. 3860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // if endId > endRange.endId, then enable range from range.endId+1 to endId, 3870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // else enable range from range.endId+1 to endRange.startId-1, because 3880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // values from endRange.startId to endId have already been added. 3890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int newRangeEndId = (endId <= endRange.endId) ? endRange.startId - 1 : endId; 39001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [2, 10] existing [1, 4] [7, 8] OR 39101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [2, 10] existing [1, 4] [7, 15] 39201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (tryAddRanges(range.endId + 1, newRangeEndId, true)) { 39301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks newRangeEndId = (endId <= endRange.endId) ? endRange.endId : endId; 39401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks range.endId = newRangeEndId; 3950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // insert new ClientRange in place 3960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville range.insert(new ClientRange(startId, endId, client)); 39701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // coalesce range with following ranges up to endIndex 3980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // remove each range after adding its elements, so the index 3990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // of the next range to join is always startIndex+1 (joinIndex). 4000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // i is the index if no elements had been removed: we only care 4010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // about the number of loop iterations, not the value of i. 4020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int joinIndex = startIndex + 1; 40301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks for (int i = joinIndex; i <= endIndex; i++) { 4040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange joinRange = mRanges.get(joinIndex); 4050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville range.clients.addAll(joinRange.clients); 4060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mRanges.remove(joinRange); 4070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 4090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 4100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; // failed to update radio 4110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 41601fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // new [5, 6], existing [1, 3] 4170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // append new range after existing IntRanges 41801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (tryAddRanges(startId, endId, true)) { 4190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mRanges.add(new IntRange(startId, endId, client)); 4200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 4210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 4220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; // failed to update radio 4230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 4260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 4270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Disable a range for the specified client and update ranges 4280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * if necessary. If {@link #finishUpdate} returns failure, 4290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * false is returned and the range is not removed. 4300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 4310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param startId the first id included in the range 4320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param endId the last id included in the range 4330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param client the client requesting to disable the range 4340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @return true if successful, false otherwise 4350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 4360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public synchronized boolean disableRange(int startId, int endId, String client) { 4370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int len = mRanges.size(); 4380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 4390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville for (int i=0; i < len; i++) { 4400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange range = mRanges.get(i); 4410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (startId < range.startId) { 4420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; // not found 4430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else if (endId <= range.endId) { 4440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // found the IntRange that encloses the client range, if any 4450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // search for it in the clients list 4460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ArrayList<ClientRange> clients = range.clients; 4470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 4480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // handle common case of IntRange containing one ClientRange 4490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int crLength = clients.size(); 4500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (crLength == 1) { 4510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ClientRange cr = clients.get(0); 4520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (cr.startId == startId && cr.endId == endId && cr.client.equals(client)) { 45301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // mRange contains only what's enabled. 45401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // remove the range from mRange then update the radio 45501fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks mRanges.remove(i); 45601fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (updateRanges()) { 4570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 4580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 45901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // failed to update radio. insert back the range 46001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks mRanges.add(i, range); 46101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks return false; 4620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 4640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; // not found 4650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 4680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // several ClientRanges: remove one, potentially splitting into many IntRanges. 4690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // Save the original start and end id for the original IntRange 4700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // in case the radio update fails and we have to revert it. If the 4710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // update succeeds, we remove the client range and insert the new IntRanges. 47201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // clients are ordered by startId then by endId, so client with largest endId 47301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // can be anywhere. Need to loop thru to find largestEndId. 4740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int largestEndId = Integer.MIN_VALUE; // largest end identifier found 4750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville boolean updateStarted = false; 4760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 47701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // crlength >= 2 4780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville for (int crIndex=0; crIndex < crLength; crIndex++) { 4790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ClientRange cr = clients.get(crIndex); 4800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (cr.startId == startId && cr.endId == endId && cr.client.equals(client)) { 4810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // found the ClientRange to remove, check if it's the last in the list 4820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (crIndex == crLength - 1) { 4830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (range.endId == largestEndId) { 48401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // remove [2, 5] from [1, 7] [2, 5] 4850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // no channels to remove from radio; return success 4860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville clients.remove(crIndex); 4870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 4880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 4890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // disable the channels at the end and lower the end id 49001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks clients.remove(crIndex); 49101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks range.endId = largestEndId; 49201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (updateRanges()) { 4930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 4940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 49501fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks clients.add(crIndex, cr); 49601fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks range.endId = cr.endId; 4970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; 4980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 5020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // copy the IntRange so that we can remove elements and modify the 5030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // start and end id's in the copy, leaving the original unmodified 5040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // until after the radio update succeeds 5050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange rangeCopy = new IntRange(range, crIndex); 5060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 5070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (crIndex == 0) { 5080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // removing the first ClientRange, so we may need to increase 5090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // the start id of the IntRange. 5100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // We know there are at least two ClientRanges in the list, 51101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // because check for just one ClientRangees case is already handled 5120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // so clients.get(1) should always succeed. 5130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int nextStartId = clients.get(1).startId; 5140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (nextStartId != range.startId) { 5150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville updateStarted = true; 5160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville rangeCopy.startId = nextStartId; 5170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // init largestEndId 5190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville largestEndId = clients.get(1).endId; 5200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 5220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // go through remaining ClientRanges, creating new IntRanges when 5230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // there is a gap in the sequence. After radio update succeeds, 5240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // remove the original IntRange and append newRanges to mRanges. 5250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // Otherwise, leave the original IntRange in mRanges and return false. 5260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ArrayList<IntRange> newRanges = new ArrayList<IntRange>(); 5270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 5280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville IntRange currentRange = rangeCopy; 5290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville for (int nextIndex = crIndex + 1; nextIndex < crLength; nextIndex++) { 5300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ClientRange nextCr = clients.get(nextIndex); 5310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (nextCr.startId > largestEndId + 1) { 53201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks updateStarted = true; 5330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville currentRange.endId = largestEndId; 5340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville newRanges.add(currentRange); 5350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville currentRange = new IntRange(nextCr); 5360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 53701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (currentRange.endId < nextCr.endId) { 53801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks currentRange.endId = nextCr.endId; 53901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 5400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville currentRange.clients.add(nextCr); 5410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (nextCr.endId > largestEndId) { 5430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville largestEndId = nextCr.endId; 5440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 5470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // remove any channels between largestEndId and endId 5480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (largestEndId < endId) { 54901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks updateStarted = true; 5500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville currentRange.endId = largestEndId; 5510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville newRanges.add(currentRange); 5530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 5540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // replace the original IntRange with newRanges 5550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mRanges.remove(i); 5560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mRanges.addAll(i, newRanges); 55701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks if (updateStarted && !updateRanges()) { 55801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // failed to update radio. revert back mRange. 55901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks mRanges.removeAll(newRanges); 56001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks mRanges.add(i, range); 56101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks return false; 56201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 56301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks 5640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 5650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 5660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // not the ClientRange to remove; save highest end ID seen so far 5670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (cr.endId > largestEndId) { 5680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville largestEndId = cr.endId; 5690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 5750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; // not found 5760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 5780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 5790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Perform a complete update operation (enable all ranges). Useful 5800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * after a radio reset. Calls {@link #startUpdate}, followed by zero or 5810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * more calls to {@link #addRange}, followed by {@link #finishUpdate}. 5820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @return true if successful, false otherwise 5830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 5840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public boolean updateRanges() { 5850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville startUpdate(); 58601fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks 58701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks populateAllRanges(); 5880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return finishUpdate(); 5890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 5910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 5920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Enable or disable a single range of message identifiers. 5930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param startId the first id included in the range 5940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param endId the last id included in the range 5950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param selected true to enable range, false to disable range 5960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @return true if successful, false otherwise 5970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 59801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks protected boolean tryAddRanges(int startId, int endId, boolean selected) { 59901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks 6000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville startUpdate(); 60101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks populateAllRanges(); 60201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // This is the new range to be enabled 60301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks addRange(startId, endId, selected); // adds to mConfigList 6040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return finishUpdate(); 6050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 6060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 6070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 6080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Returns whether the list of ranges is completely empty. 6090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @return true if there are no enabled ranges 6100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 6110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public boolean isEmpty() { 6120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return mRanges.isEmpty(); 6130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 6140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 6150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 61601fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks * Called when attempting to add a single range of message identifiers 61701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks * Populate all ranges of message identifiers. 61801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks */ 61901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks private void populateAllRanges() { 62001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks Iterator<IntRange> itr = mRanges.iterator(); 62101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks // Populate all ranges from mRanges 62201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks while (itr.hasNext()) { 62301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks IntRange currRange = (IntRange) itr.next(); 62401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks addRange(currRange.startId, currRange.endId, true); 62501fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 62601fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 62701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks 62801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks /** 62901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks * Called when attempting to add a single range of message identifiers 63001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks * Populate all ranges of message identifiers using clients' ranges. 63101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks */ 63201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks private void populateAllClientRanges() { 63301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks int len = mRanges.size(); 63401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks for (int i = 0; i < len; i++) { 63501fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks IntRange range = mRanges.get(i); 63601fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks 63701fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks int clientLen = range.clients.size(); 63801fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks for (int j=0; j < clientLen; j++) { 63901fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks ClientRange nextRange = range.clients.get(j); 64001fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks addRange(nextRange.startId, nextRange.endId, true); 64101fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 64201fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 64301fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks } 64401fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks 64501fdbd3285be1a8ba2143a4bc11a0f5065bb68d0Rika Brooks /** 6460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Called when the list of enabled ranges has changed. This will be 6470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * followed by zero or more calls to {@link #addRange} followed by 6480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * a call to {@link #finishUpdate}. 6490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 6500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville protected abstract void startUpdate(); 6510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 6520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 6530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Called after {@link #startUpdate} to indicate a range of enabled 6540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * or disabled values. 6550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 6560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param startId the first id included in the range 6570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param endId the last id included in the range 6580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param selected true to enable range, false to disable range 6590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 6600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville protected abstract void addRange(int startId, int endId, boolean selected); 6610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 6620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 6630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Called to indicate the end of a range update started by the 6640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * previous call to {@link #startUpdate}. 6650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @return true if successful, false otherwise 6660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 6670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville protected abstract boolean finishUpdate(); 6680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville} 669