mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-09 15:17:24 -05:00
#1977 P25 FQSUID handling improvements. P25 fully qualified radio/talkgroup identifiers we're being flagged as invalid when ISSI patch assigned a local address/ID of zero. Changes format of FQSUID and FQTGID to use a value of zero for the local alias when the call type is an ISSI patch and suppress display of the 0 alias value. If the identifier represents a roaming user, then the local address value is displayed with the FQSUID appended in parenthesis. (#1978)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
@@ -21,12 +21,15 @@ package io.github.dsheirer.gui.viewer;
|
||||
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.identifier.IdentifierCollection;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.util.Callback;
|
||||
|
||||
/**
|
||||
* JavaFX identifier collection viewer
|
||||
@@ -82,7 +85,19 @@ public class IdentifierCollectionViewer extends VBox
|
||||
valueColumn.setText("Value");
|
||||
valueColumn.setCellValueFactory(new PropertyValueFactory<>("value"));
|
||||
|
||||
mIdentifierTableView.getColumns().addAll(classColumn, formColumn, roleColumn, valueColumn);
|
||||
TableColumn textColumn = new TableColumn();
|
||||
textColumn.setPrefWidth(160);
|
||||
textColumn.setText("Text");
|
||||
textColumn.setCellValueFactory((Callback<TableColumn.CellDataFeatures<Identifier<?>, String>, ObservableValue>) param -> {
|
||||
if(param.getValue() != null)
|
||||
{
|
||||
return new SimpleStringProperty(param.getValue().toString());
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
mIdentifierTableView.getColumns().addAll(classColumn, formColumn, roleColumn, valueColumn, textColumn);
|
||||
}
|
||||
|
||||
return mIdentifierTableView;
|
||||
|
||||
@@ -72,12 +72,22 @@ public abstract class FullyQualifiedRadioIdentifier extends RadioIdentifier
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the radio identify is aliased with a persona value that is different from the radio ID.
|
||||
* Indicates if the radio identity is aliased with a persona value that is different from the radio ID.
|
||||
* @return true if aliased.
|
||||
*/
|
||||
public boolean isAliased()
|
||||
{
|
||||
return getValue() != mRadio;
|
||||
return getValue() != 0 && getValue() != mRadio;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the default behavior of RadioIdentifier.isValid() to allow for fully qualified SUID's with a local
|
||||
* ID of zero which indicates an ISSI patch.
|
||||
*/
|
||||
@Override
|
||||
public boolean isValid()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -71,12 +71,22 @@ public abstract class FullyQualifiedTalkgroupIdentifier extends TalkgroupIdentif
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the talkgroup identify is aliased with a persona value that is different from the talkgroup ID.
|
||||
* Indicates if the talkgroup identity is aliased with a persona value that is different from the talkgroup ID.
|
||||
* @return true if aliased.
|
||||
*/
|
||||
public boolean isAliased()
|
||||
{
|
||||
return getValue() != mTalkgroup;
|
||||
return getValue() != 0 && getValue() != mTalkgroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the default behavior of TalkgroupIdentifier.isValid() to allow for fully qualified TGID's with a local
|
||||
* ID of zero which indicates an ISSI patch.
|
||||
*/
|
||||
@Override
|
||||
public boolean isValid()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -32,7 +32,6 @@ import io.github.dsheirer.identifier.IdentifierCollection;
|
||||
import io.github.dsheirer.identifier.MutableIdentifierCollection;
|
||||
import io.github.dsheirer.identifier.encryption.EncryptionKeyIdentifier;
|
||||
import io.github.dsheirer.identifier.patch.PatchGroupPreLoadDataContent;
|
||||
import io.github.dsheirer.identifier.radio.RadioIdentifier;
|
||||
import io.github.dsheirer.identifier.scramble.ScrambleParameterIdentifier;
|
||||
import io.github.dsheirer.log.LoggingSuppressor;
|
||||
import io.github.dsheirer.message.IMessage;
|
||||
@@ -307,7 +306,7 @@ public class P25TrafficChannelManager extends TrafficChannelManager implements I
|
||||
* @param timeslot for the channel.
|
||||
* @param isIdleNull to indicate if this close event is trigged by an IDLE/NULL message
|
||||
*/
|
||||
public void closeP2CallEvent(long frequency, int timeslot, long timestamp, boolean isIdleNull)
|
||||
public void closeP2CallEvent(long frequency, int timeslot, boolean isIdleNull)
|
||||
{
|
||||
/**
|
||||
* Hack: L3Harris systems can issue a channel grant on control/TS1 which creates an event for TS2 and then the
|
||||
@@ -325,21 +324,13 @@ public class P25TrafficChannelManager extends TrafficChannelManager implements I
|
||||
|
||||
try
|
||||
{
|
||||
DecodeEvent event;
|
||||
|
||||
if(timeslot == P25P1Message.TIMESLOT_0 || timeslot == P25P1Message.TIMESLOT_1)
|
||||
{
|
||||
event = mTS1ChannelGrantEventMap.remove(frequency);
|
||||
mTS1ChannelGrantEventMap.remove(frequency);
|
||||
}
|
||||
else
|
||||
{
|
||||
event = mTS2ChannelGrantEventMap.remove(frequency);
|
||||
}
|
||||
|
||||
if(event != null)
|
||||
{
|
||||
event.end(timestamp);
|
||||
broadcast(event);
|
||||
mTS2ChannelGrantEventMap.remove(frequency);
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -1410,55 +1401,50 @@ public class P25TrafficChannelManager extends TrafficChannelManager implements I
|
||||
* Compares the TO role identifier(s) from each collection for equality. This is normally used to compare a call
|
||||
* update where we only compare the TO role.
|
||||
*
|
||||
* @param collection1 containing a TO identifier
|
||||
* @param collection2 containing a TO identifier
|
||||
* @param existingIC containing a TO identifier
|
||||
* @param nextIC containing a TO identifier
|
||||
* @return true if both collections contain a TO identifier and the TO identifiers are the same value
|
||||
*/
|
||||
private boolean isSameCallUpdate(IdentifierCollection collection1, IdentifierCollection collection2)
|
||||
private boolean isSameCallUpdate(IdentifierCollection existingIC, IdentifierCollection nextIC)
|
||||
{
|
||||
Identifier toIdentifier1 = collection1.getToIdentifier();
|
||||
Identifier toIdentifier2 = collection2.getToIdentifier();
|
||||
return toIdentifier1 != null && toIdentifier1.equals(toIdentifier2);
|
||||
Identifier existingTO = existingIC.getToIdentifier();
|
||||
Identifier nextTO = nextIC.getToIdentifier();
|
||||
return existingTO != null && existingTO.equals(nextTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the TO role identifier(s) from each collection for equality. This is normally used to compare a call
|
||||
* update where we only compare the TO role.
|
||||
*
|
||||
* @param collection1 containing a TO identifier
|
||||
* @param collection2 containing a TO identifier
|
||||
* @param existingIC for the existing/previous event containing a TO identifier
|
||||
* @param nextIC for the next event containing a TO identifier
|
||||
* @return true if both collections contain a TO identifier and the TO identifiers are the same value
|
||||
*/
|
||||
private boolean isSameCallFull(IdentifierCollection collection1, IdentifierCollection collection2)
|
||||
private boolean isSameCallFull(IdentifierCollection existingIC, IdentifierCollection nextIC)
|
||||
{
|
||||
Identifier to1 = collection1.getToIdentifier();
|
||||
Identifier to2 = collection2.getToIdentifier();
|
||||
Identifier existingTO = existingIC.getToIdentifier();
|
||||
Identifier nextTO = nextIC.getToIdentifier();
|
||||
|
||||
if(to1 != null && to1.equals(to2))
|
||||
if(existingTO != null && existingTO.equals(nextTO))
|
||||
{
|
||||
Identifier from1 = collection1.getFromIdentifier();
|
||||
Identifier existingFROM = existingIC.getFromIdentifier();
|
||||
|
||||
//If the FROM identifier hasn't yet been established, then this is the same call. We also ignore the
|
||||
//talker alias as a call identifier since on L3Harris systems they can transmit the talker alias before
|
||||
//they transmit the radio ID.
|
||||
if(from1 == null || from1.getForm() == Form.TALKER_ALIAS)
|
||||
if(existingFROM == null || existingFROM.getForm() == Form.TALKER_ALIAS)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Identifier from2 = collection2.getFromIdentifier();
|
||||
Identifier nextFROM = nextIC.getFromIdentifier();
|
||||
|
||||
if(from2 != null && from2.getForm() == Form.TALKER_ALIAS)
|
||||
if(nextFROM != null && nextFROM.getForm() == Form.TALKER_ALIAS)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if(from2 instanceof RadioIdentifier radio && radio.getValue() == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return from1.equals(from2);
|
||||
return existingFROM.equals(nextFROM);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -188,7 +188,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
protected void resetState()
|
||||
{
|
||||
super.resetState();
|
||||
closeCurrentCallEvent(System.currentTimeMillis(), true, false);
|
||||
closeCurrentCallEvent(true, false);
|
||||
mEndPttOnFacchCounter = 0;
|
||||
}
|
||||
|
||||
@@ -1274,7 +1274,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
{
|
||||
if(mac instanceof EndPushToTalk)
|
||||
{
|
||||
closeCurrentCallEvent(message.getTimestamp(), true, false);
|
||||
closeCurrentCallEvent(true, false);
|
||||
|
||||
if(message.getDataUnitID().isFACCH())
|
||||
{
|
||||
@@ -1561,7 +1561,7 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
{
|
||||
if(mac instanceof MacRelease mr)
|
||||
{
|
||||
closeCurrentCallEvent(message.getTimestamp(), true, false);
|
||||
closeCurrentCallEvent(true, false);
|
||||
broadcast(message, mac, DecodeEventType.COMMAND,
|
||||
(mr.isForcedPreemption() ? "FORCED " : "") + "CALL PREEMPTION" +
|
||||
(mr.isTalkerPreemption() ? " BY USER" : " BY CONTROLLER"));
|
||||
@@ -1882,13 +1882,12 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie
|
||||
/**
|
||||
* Ends/closes the current call event.
|
||||
*
|
||||
* @param timestamp of the message that indicates the event has ended.
|
||||
* @param resetIdentifiers to reset the FROM/TO identifiers (true) or reset just the FROM identifiers (false)
|
||||
* @param isIdleNull to indicate if the calling trigger is an IDLE/NULL message
|
||||
*/
|
||||
private void closeCurrentCallEvent(long timestamp, boolean resetIdentifiers, boolean isIdleNull)
|
||||
private void closeCurrentCallEvent(boolean resetIdentifiers, boolean isIdleNull)
|
||||
{
|
||||
mTrafficChannelManager.closeP2CallEvent(getCurrentFrequency(), getTimeslot(), timestamp, isIdleNull);
|
||||
mTrafficChannelManager.closeP2CallEvent(getCurrentFrequency(), getTimeslot(), isIdleNull);
|
||||
|
||||
if(resetIdentifiers)
|
||||
{
|
||||
|
||||
@@ -136,11 +136,11 @@ import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorol
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaGroupRegroupChannelGrantUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaGroupRegroupDeleteCommand;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaGroupRegroupExtendedFunctionCommand;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaGroupRegroupOpcode145;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaGroupRegroupTalkerAlias;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaGroupRegroupTalkerAliasContinuation;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaGroupRegroupVoiceChannelUpdate;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaGroupRegroupVoiceChannelUserAbbreviated;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaGroupRegroupVoiceChannelUserExtended;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaOpcode149;
|
||||
import io.github.dsheirer.module.decode.p25.phase2.message.mac.structure.motorola.MotorolaQueuedResponse;
|
||||
import io.github.dsheirer.module.decode.p25.reference.Vendor;
|
||||
import java.util.ArrayList;
|
||||
@@ -585,9 +585,9 @@ public class MacMessageFactory
|
||||
case MOTOROLA_89_GROUP_REGROUP_DELETE:
|
||||
return new MotorolaGroupRegroupDeleteCommand(message, offset);
|
||||
case MOTOROLA_91_GROUP_REGROUP_UNKNOWN:
|
||||
return new MotorolaGroupRegroupOpcode145(message, offset);
|
||||
return new MotorolaGroupRegroupTalkerAlias(message, offset);
|
||||
case MOTOROLA_95_UNKNOWN_149:
|
||||
return new MotorolaOpcode149(message, offset);
|
||||
return new MotorolaGroupRegroupTalkerAliasContinuation(message, offset);
|
||||
case MOTOROLA_A0_GROUP_REGROUP_VOICE_CHANNEL_USER_EXTENDED:
|
||||
return new MotorolaGroupRegroupVoiceChannelUserExtended(message, offset);
|
||||
case MOTOROLA_A3_GROUP_REGROUP_CHANNEL_GRANT_IMPLICIT:
|
||||
|
||||
@@ -30,9 +30,9 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Motorola Group Regroup Unknown Opcode 145 - 17-bytes long
|
||||
* Motorola Group Regroup Talker Alias - 17-bytes long
|
||||
*/
|
||||
public class MotorolaGroupRegroupOpcode145 extends MacStructureVendor
|
||||
public class MotorolaGroupRegroupTalkerAlias extends MacStructureVendor
|
||||
{
|
||||
private static final IntField TALKGROUP = IntField.length16(24);
|
||||
private static final IntField UNKNOWN = IntField.length32(40);
|
||||
@@ -49,7 +49,7 @@ public class MotorolaGroupRegroupOpcode145 extends MacStructureVendor
|
||||
* @param message containing the message bits
|
||||
* @param offset into the message for this structure
|
||||
*/
|
||||
public MotorolaGroupRegroupOpcode145(CorrectedBinaryMessage message, int offset)
|
||||
public MotorolaGroupRegroupTalkerAlias(CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(message, offset);
|
||||
}
|
||||
@@ -60,7 +60,7 @@ public class MotorolaGroupRegroupOpcode145 extends MacStructureVendor
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("MOTOROLA GROUP REGROUP UNKNOWN OPCODE 145 TALKGROUP:").append(getTalkgroup());
|
||||
sb.append("MOTOROLA GROUP REGROUP TALKER ALIAS TALKGROUP:").append(getTalkgroup());
|
||||
sb.append(" SOURCE SUID RADIO:").append(getRadio());
|
||||
sb.append(" UNK:").append(Integer.toHexString(getInt(UNKNOWN)).toUpperCase());
|
||||
sb.append(" MSG:").append(getMessage().get(getOffset(), getMessage().length()).toHexString());
|
||||
@@ -26,19 +26,30 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Motorola Unknown Opcode 149 (0x95)
|
||||
* Motorola Unknown Opcode 149 (0x95) Talker Alias continuation message.
|
||||
*
|
||||
* This was observed at the end of a Group Regroup call sequence during HANGTIME, so it seems more of an announcement
|
||||
* type message and less as something relevant to the call.
|
||||
* This was observed at the end of a Group Regroup call sequence during HANGTIME. Each radio doesn't know the alias
|
||||
* until it receives it once and then queues the alias for subsequent use.
|
||||
*
|
||||
* This opcode is observed following an Opcode 145 message and seems to be a continuation message.
|
||||
*
|
||||
* Examples:
|
||||
* 959011 018E58B82BAB4D3B70E9A8457F9D C67
|
||||
* 959011 0287000000000000000000000000 E26
|
||||
*
|
||||
* The opcode, vendor and length octets are consistent. The first octet seems to be an identifier, 01, 02, etc.
|
||||
* Example 2:
|
||||
* 9190110BCD02010026BEE004A403151724FD9 Opcode 145
|
||||
* 959011012436C4C022EC902A9943EDAA69E76 Opcode 149
|
||||
* 95901102298FAA77683FAE0000000000000AB Opcode 149
|
||||
* (immediately followed in the same call sequence by a slight variation)
|
||||
* 9190110BCD02010036BEE004A403151724513 Opcode 145
|
||||
* 959011013436C4C022EC902A9943EDAA699F6 Opcode 149
|
||||
* 95901102398FAA77683FAE00000000000072B Opcode 149
|
||||
*
|
||||
* The opcode, vendor and length octets are consistent. The first octet seems to be a sequence identifier, 01, 02, etc.
|
||||
* Nothing else seems to match any of the other identifiers that were active at call time.
|
||||
*/
|
||||
public class MotorolaOpcode149 extends MacStructureVendor
|
||||
public class MotorolaGroupRegroupTalkerAliasContinuation extends MacStructureVendor
|
||||
{
|
||||
private List<Identifier> mIdentifiers;
|
||||
|
||||
@@ -48,7 +59,7 @@ public class MotorolaOpcode149 extends MacStructureVendor
|
||||
* @param message containing the message bits
|
||||
* @param offset into the message for this structure
|
||||
*/
|
||||
public MotorolaOpcode149(CorrectedBinaryMessage message, int offset)
|
||||
public MotorolaGroupRegroupTalkerAliasContinuation(CorrectedBinaryMessage message, int offset)
|
||||
{
|
||||
super(message, offset);
|
||||
}
|
||||
@@ -59,7 +70,7 @@ public class MotorolaOpcode149 extends MacStructureVendor
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("MOTOROLA UNKNOWN OPCODE 149");
|
||||
sb.append("MOTOROLA TALKER ALIAS CONTINUATION");
|
||||
sb.append(" MSG:").append(getMessage().get(getOffset(), getMessage().length()).toHexString());
|
||||
return sb.toString();
|
||||
}
|
||||
@@ -227,16 +227,30 @@ public class APCO25TalkgroupFormatter extends AbstractIntegerFormatter
|
||||
{
|
||||
case DECIMAL:
|
||||
case FORMATTED:
|
||||
sb.append(toDecimal(id, RADIO_DECIMAL_WIDTH));
|
||||
sb.append("(").append(toHex(wacn, WACN_HEXADECIMAL_WIDTH));
|
||||
if(id > 0)
|
||||
{
|
||||
sb.append(toDecimal(id, RADIO_DECIMAL_WIDTH)).append(" (");
|
||||
}
|
||||
sb.append(toHex(wacn, WACN_HEXADECIMAL_WIDTH));
|
||||
sb.append(".").append(toHex(system, SYSTEM_HEXADECIMAL_WIDTH));
|
||||
sb.append(".").append(toDecimal(radio, RADIO_DECIMAL_WIDTH)).append(")");
|
||||
sb.append(".").append(toDecimal(radio, RADIO_DECIMAL_WIDTH));
|
||||
if(id > 0)
|
||||
{
|
||||
sb.append(")");
|
||||
}
|
||||
return sb.toString();
|
||||
case HEXADECIMAL:
|
||||
sb.append(toHex(id, RADIO_HEXADECIMAL_WIDTH));
|
||||
sb.append("(").append(toHex(wacn, WACN_HEXADECIMAL_WIDTH));
|
||||
if(id > 0)
|
||||
{
|
||||
sb.append(toHex(id, RADIO_HEXADECIMAL_WIDTH)).append(" (");
|
||||
}
|
||||
sb.append(toHex(wacn, WACN_HEXADECIMAL_WIDTH));
|
||||
sb.append(".").append(toHex(system, SYSTEM_HEXADECIMAL_WIDTH));
|
||||
sb.append(".").append(toHex(radio, RADIO_HEXADECIMAL_WIDTH)).append(")");
|
||||
sb.append(".").append(toHex(radio, RADIO_HEXADECIMAL_WIDTH));
|
||||
if(id > 0)
|
||||
{
|
||||
sb.append(")");
|
||||
}
|
||||
return sb.toString();
|
||||
default:
|
||||
throw new IllegalArgumentException("Unrecognized integer format: " + format);
|
||||
@@ -248,16 +262,30 @@ public class APCO25TalkgroupFormatter extends AbstractIntegerFormatter
|
||||
{
|
||||
case DECIMAL:
|
||||
case FORMATTED:
|
||||
sb.append(id);
|
||||
if(id > 0)
|
||||
{
|
||||
sb.append(id).append(" (");
|
||||
}
|
||||
sb.append("(").append(toHex(wacn, WACN_HEXADECIMAL_WIDTH));
|
||||
sb.append(".").append(toHex(system, SYSTEM_HEXADECIMAL_WIDTH));
|
||||
sb.append(".").append(radio).append(")");
|
||||
sb.append(".").append(radio);
|
||||
if(id > 0)
|
||||
{
|
||||
sb.append(")");
|
||||
}
|
||||
return sb.toString();
|
||||
case HEXADECIMAL:
|
||||
sb.append(toHex(id));
|
||||
sb.append("(").append(toHex(wacn, WACN_HEXADECIMAL_WIDTH));
|
||||
if(id > 0)
|
||||
{
|
||||
sb.append(toHex(id)).append(" (");
|
||||
}
|
||||
sb.append(toHex(wacn, WACN_HEXADECIMAL_WIDTH));
|
||||
sb.append(".").append(toHex(system, SYSTEM_HEXADECIMAL_WIDTH));
|
||||
sb.append(".").append(toHex(radio)).append(")");
|
||||
sb.append(".").append(toHex(radio));
|
||||
if(id > 0)
|
||||
{
|
||||
sb.append(")");
|
||||
}
|
||||
return sb.toString();
|
||||
default:
|
||||
throw new IllegalArgumentException("Unrecognized integer format: " + format);
|
||||
|
||||
@@ -300,15 +300,18 @@ public class FrequencyController
|
||||
*/
|
||||
public void removeSourceEventProcessor(ISourceEventProcessor processor)
|
||||
{
|
||||
mTunable.getLock().lock();
|
||||
if(mTunable != null)
|
||||
{
|
||||
mTunable.getLock().lock();
|
||||
|
||||
try
|
||||
{
|
||||
mProcessors.remove(processor);
|
||||
}
|
||||
finally
|
||||
{
|
||||
mTunable.getLock().unlock();
|
||||
try
|
||||
{
|
||||
mProcessors.remove(processor);
|
||||
}
|
||||
finally
|
||||
{
|
||||
mTunable.getLock().unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user