summaryrefslogtreecommitdiffstats
path: root/telephony/java/com/android/internal/telephony/IntRangeManager.java
diff options
context:
space:
mode:
Diffstat (limited to 'telephony/java/com/android/internal/telephony/IntRangeManager.java')
-rw-r--r--telephony/java/com/android/internal/telephony/IntRangeManager.java576
1 files changed, 0 insertions, 576 deletions
diff --git a/telephony/java/com/android/internal/telephony/IntRangeManager.java b/telephony/java/com/android/internal/telephony/IntRangeManager.java
deleted file mode 100644
index cc7774d..0000000
--- a/telephony/java/com/android/internal/telephony/IntRangeManager.java
+++ /dev/null
@@ -1,576 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-
-/**
- * Clients can enable reception of SMS-CB messages for specific ranges of
- * message identifiers (channels). This class keeps track of the currently
- * enabled message identifiers and calls abstract methods to update the
- * radio when the range of enabled message identifiers changes.
- *
- * An update is a call to {@link #startUpdate} followed by zero or more
- * calls to {@link #addRange} followed by a call to {@link #finishUpdate}.
- * Calls to {@link #enableRange} and {@link #disableRange} will perform
- * an incremental update operation if the enabled ranges have changed.
- * A full update operation (i.e. after a radio reset) can be performed
- * by a call to {@link #updateRanges}.
- *
- * Clients are identified by String (the name associated with the User ID
- * of the caller) so that a call to remove a range can be mapped to the
- * client that enabled that range (or else rejected).
- */
-public abstract class IntRangeManager {
-
- /**
- * Initial capacity for IntRange clients array list. There will be
- * few cell broadcast listeners on a typical device, so this can be small.
- */
- private static final int INITIAL_CLIENTS_ARRAY_SIZE = 4;
-
- /**
- * One or more clients forming the continuous range [startId, endId].
- * <p>When a client is added, the IntRange may merge with one or more
- * adjacent IntRanges to form a single combined IntRange.
- * <p>When a client is removed, the IntRange may divide into several
- * non-contiguous IntRanges.
- */
- private class IntRange {
- int startId;
- int endId;
- // sorted by earliest start id
- final ArrayList<ClientRange> clients;
-
- /**
- * Create a new IntRange with a single client.
- * @param startId the first id included in the range
- * @param endId the last id included in the range
- * @param client the client requesting the enabled range
- */
- IntRange(int startId, int endId, String client) {
- this.startId = startId;
- this.endId = endId;
- clients = new ArrayList<ClientRange>(INITIAL_CLIENTS_ARRAY_SIZE);
- clients.add(new ClientRange(startId, endId, client));
- }
-
- /**
- * Create a new IntRange for an existing ClientRange.
- * @param clientRange the initial ClientRange to add
- */
- IntRange(ClientRange clientRange) {
- startId = clientRange.startId;
- endId = clientRange.endId;
- clients = new ArrayList<ClientRange>(INITIAL_CLIENTS_ARRAY_SIZE);
- clients.add(clientRange);
- }
-
- /**
- * Create a new IntRange from an existing IntRange. This is used for
- * removing a ClientRange, because new IntRanges may need to be created
- * for any gaps that open up after the ClientRange is removed. A copy
- * is made of the elements of the original IntRange preceding the element
- * that is being removed. The following elements will be added to this
- * IntRange or to a new IntRange when a gap is found.
- * @param intRange the original IntRange to copy elements from
- * @param numElements the number of elements to copy from the original
- */
- IntRange(IntRange intRange, int numElements) {
- this.startId = intRange.startId;
- this.endId = intRange.endId;
- this.clients = new ArrayList<ClientRange>(intRange.clients.size());
- for (int i=0; i < numElements; i++) {
- this.clients.add(intRange.clients.get(i));
- }
- }
-
- /**
- * Insert new ClientRange in order by start id.
- * <p>If the new ClientRange is known to be sorted before or after the
- * existing ClientRanges, or at a particular index, it can be added
- * to the clients array list directly, instead of via this method.
- * <p>Note that this can be changed from linear to binary search if the
- * number of clients grows large enough that it would make a difference.
- * @param range the new ClientRange to insert
- */
- void insert(ClientRange range) {
- int len = clients.size();
- for (int i=0; i < len; i++) {
- ClientRange nextRange = clients.get(i);
- if (range.startId <= nextRange.startId) {
- // ignore duplicate ranges from the same client
- if (!range.equals(nextRange)) {
- clients.add(i, range);
- }
- return;
- }
- }
- clients.add(range); // append to end of list
- }
- }
-
- /**
- * The message id range for a single client.
- */
- private class ClientRange {
- final int startId;
- final int endId;
- final String client;
-
- ClientRange(int startId, int endId, String client) {
- this.startId = startId;
- this.endId = endId;
- this.client = client;
- }
-
- @Override
- public boolean equals(Object o) {
- if (o != null && o instanceof ClientRange) {
- ClientRange other = (ClientRange) o;
- return startId == other.startId &&
- endId == other.endId &&
- client.equals(other.client);
- } else {
- return false;
- }
- }
-
- @Override
- public int hashCode() {
- return (startId * 31 + endId) * 31 + client.hashCode();
- }
- }
-
- /**
- * List of integer ranges, one per client, sorted by start id.
- */
- private ArrayList<IntRange> mRanges = new ArrayList<IntRange>();
-
- protected IntRangeManager() {}
-
- /**
- * Enable a range for the specified client and update ranges
- * if necessary. If {@link #finishUpdate} returns failure,
- * false is returned and the range is not added.
- *
- * @param startId the first id included in the range
- * @param endId the last id included in the range
- * @param client the client requesting the enabled range
- * @return true if successful, false otherwise
- */
- public synchronized boolean enableRange(int startId, int endId, String client) {
- int len = mRanges.size();
-
- // empty range list: add the initial IntRange
- if (len == 0) {
- if (tryAddSingleRange(startId, endId, true)) {
- mRanges.add(new IntRange(startId, endId, client));
- return true;
- } else {
- return false; // failed to update radio
- }
- }
-
- for (int startIndex = 0; startIndex < len; startIndex++) {
- IntRange range = mRanges.get(startIndex);
- if (startId < range.startId) {
- // test if new range completely precedes this range
- // note that [1, 4] and [5, 6] coalesce to [1, 6]
- if ((endId + 1) < range.startId) {
- // insert new int range before previous first range
- if (tryAddSingleRange(startId, endId, true)) {
- mRanges.add(startIndex, new IntRange(startId, endId, client));
- return true;
- } else {
- return false; // failed to update radio
- }
- } else if (endId <= range.endId) {
- // extend the start of this range
- if (tryAddSingleRange(startId, range.startId - 1, true)) {
- range.startId = startId;
- range.clients.add(0, new ClientRange(startId, endId, client));
- return true;
- } else {
- return false; // failed to update radio
- }
- } else {
- // find last range that can coalesce into the new combined range
- for (int endIndex = startIndex+1; endIndex < len; endIndex++) {
- IntRange endRange = mRanges.get(endIndex);
- if ((endId + 1) < endRange.startId) {
- // try to add entire new range
- if (tryAddSingleRange(startId, endId, true)) {
- range.startId = startId;
- range.endId = endId;
- // insert new ClientRange before existing ranges
- range.clients.add(0, new ClientRange(startId, endId, client));
- // coalesce range with following ranges up to endIndex-1
- // remove each range after adding its elements, so the index
- // of the next range to join is always startIndex+1.
- // i is the index if no elements were removed: we only care
- // about the number of loop iterations, not the value of i.
- int joinIndex = startIndex + 1;
- for (int i = joinIndex; i < endIndex; i++) {
- IntRange joinRange = mRanges.get(joinIndex);
- range.clients.addAll(joinRange.clients);
- mRanges.remove(joinRange);
- }
- return true;
- } else {
- return false; // failed to update radio
- }
- } else if (endId <= endRange.endId) {
- // add range from start id to start of last overlapping range,
- // values from endRange.startId to endId are already enabled
- if (tryAddSingleRange(startId, endRange.startId - 1, true)) {
- range.startId = startId;
- range.endId = endRange.endId;
- // insert new ClientRange before existing ranges
- range.clients.add(0, new ClientRange(startId, endId, client));
- // coalesce range with following ranges up to endIndex
- // remove each range after adding its elements, so the index
- // of the next range to join is always startIndex+1.
- // i is the index if no elements were removed: we only care
- // about the number of loop iterations, not the value of i.
- int joinIndex = startIndex + 1;
- for (int i = joinIndex; i <= endIndex; i++) {
- IntRange joinRange = mRanges.get(joinIndex);
- range.clients.addAll(joinRange.clients);
- mRanges.remove(joinRange);
- }
- return true;
- } else {
- return false; // failed to update radio
- }
- }
- }
-
- // endId extends past all existing IntRanges: combine them all together
- if (tryAddSingleRange(startId, endId, true)) {
- range.startId = startId;
- range.endId = endId;
- // insert new ClientRange before existing ranges
- range.clients.add(0, new ClientRange(startId, endId, client));
- // coalesce range with following ranges up to len-1
- // remove each range after adding its elements, so the index
- // of the next range to join is always startIndex+1.
- // i is the index if no elements were removed: we only care
- // about the number of loop iterations, not the value of i.
- int joinIndex = startIndex + 1;
- for (int i = joinIndex; i < len; i++) {
- IntRange joinRange = mRanges.get(joinIndex);
- range.clients.addAll(joinRange.clients);
- mRanges.remove(joinRange);
- }
- return true;
- } else {
- return false; // failed to update radio
- }
- }
- } else if ((startId + 1) <= range.endId) {
- if (endId <= range.endId) {
- // completely contained in existing range; no radio changes
- range.insert(new ClientRange(startId, endId, client));
- return true;
- } else {
- // find last range that can coalesce into the new combined range
- int endIndex = startIndex;
- for (int testIndex = startIndex+1; testIndex < len; testIndex++) {
- IntRange testRange = mRanges.get(testIndex);
- if ((endId + 1) < testRange.startId) {
- break;
- } else {
- endIndex = testIndex;
- }
- }
- // no adjacent IntRanges to combine
- if (endIndex == startIndex) {
- // add range from range.endId+1 to endId,
- // values from startId to range.endId are already enabled
- if (tryAddSingleRange(range.endId + 1, endId, true)) {
- range.endId = endId;
- range.insert(new ClientRange(startId, endId, client));
- return true;
- } else {
- return false; // failed to update radio
- }
- }
- // get last range to coalesce into start range
- IntRange endRange = mRanges.get(endIndex);
- // Values from startId to range.endId have already been enabled.
- // if endId > endRange.endId, then enable range from range.endId+1 to endId,
- // else enable range from range.endId+1 to endRange.startId-1, because
- // values from endRange.startId to endId have already been added.
- int newRangeEndId = (endId <= endRange.endId) ? endRange.startId - 1 : endId;
- if (tryAddSingleRange(range.endId + 1, newRangeEndId, true)) {
- range.endId = endId;
- // insert new ClientRange in place
- range.insert(new ClientRange(startId, endId, client));
- // coalesce range with following ranges up to endIndex-1
- // remove each range after adding its elements, so the index
- // of the next range to join is always startIndex+1 (joinIndex).
- // i is the index if no elements had been removed: we only care
- // about the number of loop iterations, not the value of i.
- int joinIndex = startIndex + 1;
- for (int i = joinIndex; i < endIndex; i++) {
- IntRange joinRange = mRanges.get(joinIndex);
- range.clients.addAll(joinRange.clients);
- mRanges.remove(joinRange);
- }
- return true;
- } else {
- return false; // failed to update radio
- }
- }
- }
- }
-
- // append new range after existing IntRanges
- if (tryAddSingleRange(startId, endId, true)) {
- mRanges.add(new IntRange(startId, endId, client));
- return true;
- } else {
- return false; // failed to update radio
- }
- }
-
- /**
- * Disable a range for the specified client and update ranges
- * if necessary. If {@link #finishUpdate} returns failure,
- * false is returned and the range is not removed.
- *
- * @param startId the first id included in the range
- * @param endId the last id included in the range
- * @param client the client requesting to disable the range
- * @return true if successful, false otherwise
- */
- public synchronized boolean disableRange(int startId, int endId, String client) {
- int len = mRanges.size();
-
- for (int i=0; i < len; i++) {
- IntRange range = mRanges.get(i);
- if (startId < range.startId) {
- return false; // not found
- } else if (endId <= range.endId) {
- // found the IntRange that encloses the client range, if any
- // search for it in the clients list
- ArrayList<ClientRange> clients = range.clients;
-
- // handle common case of IntRange containing one ClientRange
- int crLength = clients.size();
- if (crLength == 1) {
- ClientRange cr = clients.get(0);
- if (cr.startId == startId && cr.endId == endId && cr.client.equals(client)) {
- // disable range in radio then remove the entire IntRange
- if (tryAddSingleRange(startId, endId, false)) {
- mRanges.remove(i);
- return true;
- } else {
- return false; // failed to update radio
- }
- } else {
- return false; // not found
- }
- }
-
- // several ClientRanges: remove one, potentially splitting into many IntRanges.
- // Save the original start and end id for the original IntRange
- // in case the radio update fails and we have to revert it. If the
- // update succeeds, we remove the client range and insert the new IntRanges.
- int largestEndId = Integer.MIN_VALUE; // largest end identifier found
- boolean updateStarted = false;
-
- for (int crIndex=0; crIndex < crLength; crIndex++) {
- ClientRange cr = clients.get(crIndex);
- if (cr.startId == startId && cr.endId == endId && cr.client.equals(client)) {
- // found the ClientRange to remove, check if it's the last in the list
- if (crIndex == crLength - 1) {
- if (range.endId == largestEndId) {
- // no channels to remove from radio; return success
- clients.remove(crIndex);
- return true;
- } else {
- // disable the channels at the end and lower the end id
- if (tryAddSingleRange(largestEndId + 1, range.endId, false)) {
- clients.remove(crIndex);
- range.endId = largestEndId;
- return true;
- } else {
- return false;
- }
- }
- }
-
- // copy the IntRange so that we can remove elements and modify the
- // start and end id's in the copy, leaving the original unmodified
- // until after the radio update succeeds
- IntRange rangeCopy = new IntRange(range, crIndex);
-
- if (crIndex == 0) {
- // removing the first ClientRange, so we may need to increase
- // the start id of the IntRange.
- // We know there are at least two ClientRanges in the list,
- // so clients.get(1) should always succeed.
- int nextStartId = clients.get(1).startId;
- if (nextStartId != range.startId) {
- startUpdate();
- updateStarted = true;
- addRange(range.startId, nextStartId - 1, false);
- rangeCopy.startId = nextStartId;
- }
- // init largestEndId
- largestEndId = clients.get(1).endId;
- }
-
- // go through remaining ClientRanges, creating new IntRanges when
- // there is a gap in the sequence. After radio update succeeds,
- // remove the original IntRange and append newRanges to mRanges.
- // Otherwise, leave the original IntRange in mRanges and return false.
- ArrayList<IntRange> newRanges = new ArrayList<IntRange>();
-
- IntRange currentRange = rangeCopy;
- for (int nextIndex = crIndex + 1; nextIndex < crLength; nextIndex++) {
- ClientRange nextCr = clients.get(nextIndex);
- if (nextCr.startId > largestEndId + 1) {
- if (!updateStarted) {
- startUpdate();
- updateStarted = true;
- }
- addRange(largestEndId + 1, nextCr.startId - 1, false);
- currentRange.endId = largestEndId;
- newRanges.add(currentRange);
- currentRange = new IntRange(nextCr);
- } else {
- currentRange.clients.add(nextCr);
- }
- if (nextCr.endId > largestEndId) {
- largestEndId = nextCr.endId;
- }
- }
-
- // remove any channels between largestEndId and endId
- if (largestEndId < endId) {
- if (!updateStarted) {
- startUpdate();
- updateStarted = true;
- }
- addRange(largestEndId + 1, endId, false);
- currentRange.endId = largestEndId;
- }
- newRanges.add(currentRange);
-
- if (updateStarted && !finishUpdate()) {
- return false; // failed to update radio
- }
-
- // replace the original IntRange with newRanges
- mRanges.remove(i);
- mRanges.addAll(i, newRanges);
- return true;
- } else {
- // not the ClientRange to remove; save highest end ID seen so far
- if (cr.endId > largestEndId) {
- largestEndId = cr.endId;
- }
- }
- }
- }
- }
-
- return false; // not found
- }
-
- /**
- * Perform a complete update operation (enable all ranges). Useful
- * after a radio reset. Calls {@link #startUpdate}, followed by zero or
- * more calls to {@link #addRange}, followed by {@link #finishUpdate}.
- * @return true if successful, false otherwise
- */
- public boolean updateRanges() {
- startUpdate();
- Iterator<IntRange> iterator = mRanges.iterator();
- if (iterator.hasNext()) {
- IntRange range = iterator.next();
- int start = range.startId;
- int end = range.endId;
- // accumulate ranges of [startId, endId]
- while (iterator.hasNext()) {
- IntRange nextNode = iterator.next();
- // [startIdA, endIdA], [endIdA + 1, endIdB] -> [startIdA, endIdB]
- if (nextNode.startId <= (end + 1)) {
- if (nextNode.endId > end) {
- end = nextNode.endId;
- }
- } else {
- addRange(start, end, true);
- start = nextNode.startId;
- end = nextNode.endId;
- }
- }
- // add final range
- addRange(start, end, true);
- }
- return finishUpdate();
- }
-
- /**
- * Enable or disable a single range of message identifiers.
- * @param startId the first id included in the range
- * @param endId the last id included in the range
- * @param selected true to enable range, false to disable range
- * @return true if successful, false otherwise
- */
- private boolean tryAddSingleRange(int startId, int endId, boolean selected) {
- startUpdate();
- addRange(startId, endId, selected);
- return finishUpdate();
- }
-
- /**
- * Returns whether the list of ranges is completely empty.
- * @return true if there are no enabled ranges
- */
- public boolean isEmpty() {
- return mRanges.isEmpty();
- }
-
- /**
- * Called when the list of enabled ranges has changed. This will be
- * followed by zero or more calls to {@link #addRange} followed by
- * a call to {@link #finishUpdate}.
- */
- protected abstract void startUpdate();
-
- /**
- * Called after {@link #startUpdate} to indicate a range of enabled
- * or disabled values.
- *
- * @param startId the first id included in the range
- * @param endId the last id included in the range
- * @param selected true to enable range, false to disable range
- */
- protected abstract void addRange(int startId, int endId, boolean selected);
-
- /**
- * Called to indicate the end of a range update started by the
- * previous call to {@link #startUpdate}.
- * @return true if successful, false otherwise
- */
- protected abstract boolean finishUpdate();
-}