diff options
Diffstat (limited to 'dom/system/gonk')
164 files changed, 0 insertions, 74269 deletions
diff --git a/dom/system/gonk/AudioChannelManager.cpp b/dom/system/gonk/AudioChannelManager.cpp deleted file mode 100644 index 977715a29..000000000 --- a/dom/system/gonk/AudioChannelManager.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsIDocument.h" -#include "nsIDOMClassInfo.h" -#include "nsIDOMEvent.h" -#include "nsIDOMEventListener.h" -#include "nsPIDOMWindow.h" -#include "nsIDocShell.h" -#include "nsIPermissionManager.h" -#include "nsIInterfaceRequestorUtils.h" -#include "AudioChannelManager.h" -#include "mozilla/dom/AudioChannelManagerBinding.h" -#include "mozilla/dom/nsBrowserElement.h" -#include "mozilla/Services.h" - -namespace mozilla { -namespace dom { -namespace system { - -NS_IMPL_QUERY_INTERFACE_INHERITED(AudioChannelManager, DOMEventTargetHelper, - nsIDOMEventListener) -NS_IMPL_ADDREF_INHERITED(AudioChannelManager, DOMEventTargetHelper) -NS_IMPL_RELEASE_INHERITED(AudioChannelManager, DOMEventTargetHelper) - -AudioChannelManager::AudioChannelManager() - : mVolumeChannel(-1) -{ - hal::RegisterSwitchObserver(hal::SWITCH_HEADPHONES, this); -} - -AudioChannelManager::~AudioChannelManager() -{ - hal::UnregisterSwitchObserver(hal::SWITCH_HEADPHONES, this); - - nsCOMPtr<EventTarget> target = do_QueryInterface(GetOwner()); - NS_ENSURE_TRUE_VOID(target); - - target->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"), - this, - /* useCapture = */ true); -} - -void -AudioChannelManager::Init(nsPIDOMWindowInner* aWindow) -{ - BindToOwner(aWindow); - - nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetOwner()); - NS_ENSURE_TRUE_VOID(target); - - target->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"), - this, - /* useCapture = */ true, - /* wantsUntrusted = */ false); -} - -JSObject* -AudioChannelManager::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) -{ - return AudioChannelManagerBinding::Wrap(aCx, this, aGivenProto); -} - -void -AudioChannelManager::Notify(const hal::SwitchEvent& aEvent) -{ - mState = Some(aEvent.status()); - - DispatchTrustedEvent(NS_LITERAL_STRING("headphoneschange")); -} - -bool -AudioChannelManager::SetVolumeControlChannel(const nsAString& aChannel) -{ - if (aChannel.EqualsASCII("publicnotification")) { - return false; - } - - AudioChannel newChannel = AudioChannelService::GetAudioChannel(aChannel); - - // Only normal channel doesn't need permission. - if (newChannel != AudioChannel::Normal) { - nsCOMPtr<nsIPermissionManager> permissionManager = - services::GetPermissionManager(); - if (!permissionManager) { - return false; - } - uint32_t perm = nsIPermissionManager::UNKNOWN_ACTION; - permissionManager->TestPermissionFromWindow(GetOwner(), - nsCString(NS_LITERAL_CSTRING("audio-channel-") + - NS_ConvertUTF16toUTF8(aChannel)).get(), &perm); - if (perm != nsIPermissionManager::ALLOW_ACTION) { - return false; - } - } - - if (mVolumeChannel == (int32_t)newChannel) { - return true; - } - - mVolumeChannel = (int32_t)newChannel; - - NotifyVolumeControlChannelChanged(); - return true; -} - -bool -AudioChannelManager::GetVolumeControlChannel(nsAString & aChannel) -{ - if (mVolumeChannel >= 0) { - AudioChannelService::GetAudioChannelString( - static_cast<AudioChannel>(mVolumeChannel), - aChannel); - } else { - aChannel.AssignASCII(""); - } - - return true; -} - -void -AudioChannelManager::NotifyVolumeControlChannelChanged() -{ - nsCOMPtr<nsIDocShell> docshell = do_GetInterface(GetOwner()); - NS_ENSURE_TRUE_VOID(docshell); - - bool isActive = false; - docshell->GetIsActive(&isActive); - - RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate(); - if (!service) { - return; - } - - if (isActive) { - service->SetDefaultVolumeControlChannel(mVolumeChannel, isActive); - } else { - service->SetDefaultVolumeControlChannel(-1, isActive); - } -} - -NS_IMETHODIMP -AudioChannelManager::HandleEvent(nsIDOMEvent* aEvent) -{ - nsAutoString type; - aEvent->GetType(type); - - if (type.EqualsLiteral("visibilitychange")) { - NotifyVolumeControlChannelChanged(); - } - return NS_OK; -} - -void -AudioChannelManager::GetAllowedAudioChannels( - nsTArray<RefPtr<BrowserElementAudioChannel>>& aAudioChannels, - ErrorResult& aRv) -{ - MOZ_ASSERT(aAudioChannels.IsEmpty()); - - // Only main process is supported. - if (XRE_GetProcessType() != GeckoProcessType_Default) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } - - nsCOMPtr<nsPIDOMWindowInner> window = GetOwner(); - if (NS_WARN_IF(!window)) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } - - nsBrowserElement::GenerateAllowedAudioChannels(window, nullptr, nullptr, - aAudioChannels, aRv); - NS_WARNING_ASSERTION(!aRv.Failed(), "GenerateAllowedAudioChannels failed"); -} - -} // namespace system -} // namespace dom -} // namespace mozilla diff --git a/dom/system/gonk/AudioChannelManager.h b/dom/system/gonk/AudioChannelManager.h deleted file mode 100644 index a460651e7..000000000 --- a/dom/system/gonk/AudioChannelManager.h +++ /dev/null @@ -1,87 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_dom_system_AudioChannelManager_h -#define mozilla_dom_system_AudioChannelManager_h - -#include "mozilla/dom/BrowserElementAudioChannel.h" -#include "mozilla/DOMEventTargetHelper.h" -#include "mozilla/Hal.h" -#include "mozilla/HalTypes.h" -#include "mozilla/Maybe.h" -#include "AudioChannelService.h" - -namespace mozilla { -namespace hal { -class SwitchEvent; -typedef Observer<SwitchEvent> SwitchObserver; -} // namespace hal - -namespace dom { -namespace system { - -class AudioChannelManager final - : public DOMEventTargetHelper - , public hal::SwitchObserver - , public nsIDOMEventListener -{ -public: - AudioChannelManager(); - - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_NSIDOMEVENTLISTENER - - void Notify(const hal::SwitchEvent& aEvent); - - void Init(nsPIDOMWindowInner* aWindow); - - /** - * WebIDL Interface - */ - - nsPIDOMWindowInner* GetParentObject() const - { - return GetOwner(); - } - - virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; - - bool Headphones() - { - // Bug 929139 - Remove the assert check for SWITCH_STATE_UNKNOWN. - // If any devices (ex: emulator) didn't have the corresponding sys node for - // headset switch state then GonkSwitch will report the unknown state. - // So it is possible to get unknown state here. - if (mState.isNothing()) { - mState = Some(hal::GetCurrentSwitchState(hal::SWITCH_HEADPHONES)); - } - return mState.value() != hal::SWITCH_STATE_OFF && - mState.value() != hal::SWITCH_STATE_UNKNOWN; - } - - bool SetVolumeControlChannel(const nsAString& aChannel); - - bool GetVolumeControlChannel(nsAString& aChannel); - - IMPL_EVENT_HANDLER(headphoneschange) - - void GetAllowedAudioChannels( - nsTArray<RefPtr<mozilla::dom::BrowserElementAudioChannel>>& aAudioChannels, - mozilla::ErrorResult& aRv); - -protected: - virtual ~AudioChannelManager(); - -private: - void NotifyVolumeControlChannelChanged(); - - Maybe<hal::SwitchState> mState; - int32_t mVolumeChannel; -}; - -} // namespace system -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_system_AudioChannelManager_h diff --git a/dom/system/gonk/AudioManager.cpp b/dom/system/gonk/AudioManager.cpp deleted file mode 100644 index 88dff13f7..000000000 --- a/dom/system/gonk/AudioManager.cpp +++ /dev/null @@ -1,1412 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include <android/log.h> -#include <cutils/properties.h> -#include <binder/IServiceManager.h> - -#include "AudioChannelService.h" -#include "AudioManager.h" - -#include "nsIObserverService.h" -#include "nsISettingsService.h" -#include "nsPrintfCString.h" - -#include "mozilla/Hal.h" -#include "mozilla/Services.h" -#include "mozilla/StaticPtr.h" -#include "mozilla/ClearOnShutdown.h" -#include "mozilla/MozPromise.h" -#include "mozilla/dom/ScriptSettings.h" -#include "base/message_loop.h" - -#include "BluetoothCommon.h" -#include "BluetoothHfpManagerBase.h" - -#include "nsJSUtils.h" -#include "nsThreadUtils.h" -#include "nsServiceManagerUtils.h" -#include "nsComponentManagerUtils.h" -#include "nsContentUtils.h" -#include "nsXULAppAPI.h" -#include "mozilla/dom/BindingUtils.h" -#include "mozilla/dom/SettingChangeNotificationBinding.h" - -using namespace mozilla::dom; -using namespace mozilla::dom::gonk; -using namespace android; -using namespace mozilla; -using namespace mozilla::dom::bluetooth; - -#undef LOG -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "AudioManager" , ## args) - -#define HEADPHONES_STATUS_HEADSET u"headset" -#define HEADPHONES_STATUS_HEADPHONE u"headphone" -#define HEADPHONES_STATUS_OFF u"off" -#define HEADPHONES_STATUS_UNKNOWN u"unknown" -#define HEADPHONES_STATUS_CHANGED "headphones-status-changed" -#define MOZ_SETTINGS_CHANGE_ID "mozsettings-changed" -#define AUDIO_CHANNEL_PROCESS_CHANGED "audio-channel-process-changed" -#define AUDIO_POLICY_SERVICE_NAME "media.audio_policy" -#define SETTINGS_SERVICE "@mozilla.org/settingsService;1" - -// Refer AudioService.java from Android -static const uint32_t sMaxStreamVolumeTbl[AUDIO_STREAM_CNT] = { - 5, // voice call - 15, // system - 15, // ring - 15, // music - 15, // alarm - 15, // notification - 15, // BT SCO - 15, // enforced audible - 15, // DTMF - 15, // TTS -#if ANDROID_VERSION < 19 - 15, // FM -#endif -}; - -static const uint32_t sDefaultStreamVolumeTbl[AUDIO_STREAM_CNT] = { - 3, // voice call - 8, // system - 8, // ring - 8, // music - 8, // alarm - 8, // notification - 8, // BT SCO - 15, // enforced audible // XXX Handle as fixed maximum audio setting - 8, // DTMF - 8, // TTS -#if ANDROID_VERSION < 19 - 8, // FM -#endif -}; - -static const int32_t sStreamVolumeAliasTbl[AUDIO_STREAM_CNT] = { - AUDIO_STREAM_VOICE_CALL, // voice call - AUDIO_STREAM_NOTIFICATION, // system - AUDIO_STREAM_NOTIFICATION, // ring - AUDIO_STREAM_MUSIC, // music - AUDIO_STREAM_ALARM, // alarm - AUDIO_STREAM_NOTIFICATION, // notification - AUDIO_STREAM_BLUETOOTH_SCO, // BT SCO - AUDIO_STREAM_ENFORCED_AUDIBLE,// enforced audible - AUDIO_STREAM_DTMF, // DTMF - AUDIO_STREAM_TTS, // TTS -#if ANDROID_VERSION < 19 - AUDIO_STREAM_MUSIC, // FM -#endif -}; - -static const uint32_t sChannelStreamTbl[NUMBER_OF_AUDIO_CHANNELS] = { - AUDIO_STREAM_MUSIC, // AudioChannel::Normal - AUDIO_STREAM_MUSIC, // AudioChannel::Content - AUDIO_STREAM_NOTIFICATION, // AudioChannel::Notification - AUDIO_STREAM_ALARM, // AudioChannel::Alarm - AUDIO_STREAM_VOICE_CALL, // AudioChannel::Telephony - AUDIO_STREAM_RING, // AudioChannel::Ringer - AUDIO_STREAM_ENFORCED_AUDIBLE,// AudioChannel::Publicnotification - AUDIO_STREAM_SYSTEM, // AudioChannel::System -}; - - -struct AudioDeviceInfo { - /** The string the value maps to */ - const char* tag; - /** The enum value that maps to this string */ - uint32_t value; -}; - -// Mappings audio output devices to strings. -static const AudioDeviceInfo kAudioDeviceInfos[] = { - { "earpiece", AUDIO_DEVICE_OUT_EARPIECE }, - { "speaker", AUDIO_DEVICE_OUT_SPEAKER }, - { "wired_headset", AUDIO_DEVICE_OUT_WIRED_HEADSET }, - { "wired_headphone", AUDIO_DEVICE_OUT_WIRED_HEADPHONE }, - { "bt_scoheadset", AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET }, - { "bt_a2dp", AUDIO_DEVICE_OUT_BLUETOOTH_A2DP }, -}; - -static const int kBtSampleRate = 8000; - -typedef MozPromise<bool, const char*, true> VolumeInitPromise; - -namespace mozilla { -namespace dom { -namespace gonk { - -/** - * We have five sound volume settings from UX spec, - * You can see more informations in Bug1068219. - * (1) Media : music, video, FM ... - * (2) Notification : ringer, notification ... - * (3) Alarm : alarm - * (4) Telephony : GSM call, WebRTC call - * (5) Bluetooth SCO : SCO call - **/ -struct VolumeData { - const char* mChannelName; - int32_t mStreamType; -}; - -static const VolumeData gVolumeData[] = { - {"audio.volume.content", AUDIO_STREAM_MUSIC}, - {"audio.volume.notification", AUDIO_STREAM_NOTIFICATION}, - {"audio.volume.alarm", AUDIO_STREAM_ALARM}, - {"audio.volume.telephony", AUDIO_STREAM_VOICE_CALL}, - {"audio.volume.bt_sco", AUDIO_STREAM_BLUETOOTH_SCO} -}; - -class RunnableCallTask : public Runnable -{ -public: - explicit RunnableCallTask(nsIRunnable* aRunnable) - : mRunnable(aRunnable) {} - - NS_IMETHOD Run() override - { - return mRunnable->Run(); - } -protected: - nsCOMPtr<nsIRunnable> mRunnable; -}; - -nsCOMPtr<nsISettingsServiceLock> -GetSettingServiceLock() -{ - nsresult rv; - nsCOMPtr<nsISettingsService> service = do_GetService(SETTINGS_SERVICE, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) { - return nullptr; - } - - nsCOMPtr<nsISettingsServiceLock> lock; - rv = service->CreateLock(nullptr, getter_AddRefs(lock)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return nullptr; - } - return lock.forget(); -} - -#if ANDROID_VERSION >= 21 -class GonkAudioPortCallback : public AudioSystem::AudioPortCallback -{ -public: - virtual void onAudioPortListUpdate() - { - nsCOMPtr<nsIRunnable> runnable = - NS_NewRunnableFunction([]() { - MOZ_ASSERT(NS_IsMainThread()); - RefPtr<AudioManager> audioManager = AudioManager::GetInstance(); - NS_ENSURE_TRUE(audioManager.get(), ); - audioManager->UpdateCachedActiveDevicesForStreams(); - audioManager->MaybeUpdateVolumeSettingToDatabase(); - }); - NS_DispatchToMainThread(runnable); - } - virtual void onAudioPatchListUpdate() { } - virtual void onServiceDied() { } -}; -#endif - -void -AudioManager::HandleAudioFlingerDied() -{ - //Disable volume change notification - mIsVolumeInited = false; - - uint32_t attempt; - for (attempt = 0; attempt < 50; attempt++) { - if (defaultServiceManager()->checkService(String16(AUDIO_POLICY_SERVICE_NAME)) != 0) { - break; - } - LOG("AudioPolicyService is dead! attempt=%d", attempt); - usleep(1000 * 200); - } - - MOZ_RELEASE_ASSERT(attempt < 50); - - // Indicate to audio HAL that we start the reconfiguration phase after a media - // server crash - AudioSystem::setParameters(0, String8("restarting=true")); - - // Restore device connection states - SetAllDeviceConnectionStates(); - - // Restore call state -#if ANDROID_VERSION < 17 - AudioSystem::setPhoneState(mPhoneState); -#else - AudioSystem::setPhoneState(static_cast<audio_mode_t>(mPhoneState)); -#endif - - // Restore master volume - AudioSystem::setMasterVolume(1.0); - - // Restore stream volumes - for (uint32_t streamType = 0; streamType < AUDIO_STREAM_CNT; ++streamType) { - mStreamStates[streamType]->InitStreamVolume(); - mStreamStates[streamType]->RestoreVolumeIndexToAllDevices(); - } - - // Indicate the end of reconfiguration phase to audio HAL - AudioSystem::setParameters(0, String8("restarting=true")); - - // Enable volume change notification - mIsVolumeInited = true; - mAudioOutDevicesUpdated = 0; - MaybeUpdateVolumeSettingToDatabase(true); -} - -class VolumeInitCallback final : public nsISettingsServiceCallback -{ -public: - NS_DECL_ISUPPORTS - - VolumeInitCallback() - : mInitCounter(0) - { - mPromise = mPromiseHolder.Ensure(__func__); - } - - RefPtr<VolumeInitPromise> GetPromise() const - { - return mPromise; - } - - NS_IMETHOD Handle(const nsAString& aName, JS::Handle<JS::Value> aResult) - { - RefPtr<AudioManager> audioManager = AudioManager::GetInstance(); - MOZ_ASSERT(audioManager); - for (uint32_t idx = 0; idx < MOZ_ARRAY_LENGTH(gVolumeData); ++idx) { - NS_ConvertASCIItoUTF16 volumeType(gVolumeData[idx].mChannelName); - if (StringBeginsWith(aName, volumeType)) { - uint32_t device = GetDeviceFromSettingName(aName); - MOZ_ASSERT(device != AUDIO_DEVICE_NONE); - if (aResult.isInt32()) { - int32_t stream = gVolumeData[idx].mStreamType; - uint32_t volIndex = aResult.toInt32(); - nsresult rv = audioManager->ValidateVolumeIndex(stream, volIndex); - if (NS_WARN_IF(NS_FAILED(rv))) { - mPromiseHolder.Reject("Error : invalid volume index.", __func__); - return rv; - } - audioManager->SetStreamVolumeForDevice(stream, volIndex, device); - } - - if (++mInitCounter == MOZ_ARRAY_LENGTH(kAudioDeviceInfos) * MOZ_ARRAY_LENGTH(gVolumeData)) { - mPromiseHolder.Resolve(true, __func__); - } - return NS_OK; - } - } - mPromiseHolder.Reject("Error : unexpected audio init event.", __func__); - return NS_OK; - } - - NS_IMETHOD HandleError(const nsAString& aName) - { - mPromiseHolder.Reject(NS_ConvertUTF16toUTF8(aName).get(), __func__); - return NS_OK; - } - -protected: - ~VolumeInitCallback() {} - - uint32_t GetDeviceFromSettingName(const nsAString& aName) const - { - for (uint32_t idx = 0; idx < MOZ_ARRAY_LENGTH(kAudioDeviceInfos); ++idx) { - NS_ConvertASCIItoUTF16 device(kAudioDeviceInfos[idx].tag); - if (StringEndsWith(aName, device)) { - return kAudioDeviceInfos[idx].value; - } - } - return AUDIO_DEVICE_NONE; - } - - RefPtr<VolumeInitPromise> mPromise; - MozPromiseHolder<VolumeInitPromise> mPromiseHolder; - uint32_t mInitCounter; -}; - -NS_IMPL_ISUPPORTS(VolumeInitCallback, nsISettingsServiceCallback) - -static void -BinderDeadCallback(status_t aErr) -{ - if (aErr != DEAD_OBJECT) { - return; - } - - nsCOMPtr<nsIRunnable> runnable = - NS_NewRunnableFunction([]() { - MOZ_ASSERT(NS_IsMainThread()); - RefPtr<AudioManager> audioManager = AudioManager::GetInstance(); - NS_ENSURE_TRUE(audioManager.get(), ); - audioManager->HandleAudioFlingerDied(); - }); - - NS_DispatchToMainThread(runnable); -} - -bool -AudioManager::IsFmOutConnected() -{ - return mConnectedDevices.Get(AUDIO_DEVICE_OUT_FM, nullptr); -} - -NS_IMPL_ISUPPORTS(AudioManager, nsIAudioManager, nsIObserver) - -void -AudioManager::AudioOutDeviceUpdated(uint32_t aDevice) -{ - MOZ_ASSERT(audio_is_output_device(aDevice)); - mAudioOutDevicesUpdated |= aDevice; -} - -void -AudioManager::UpdateHeadsetConnectionState(hal::SwitchState aState) -{ - bool headphoneConnected = mConnectedDevices.Get(AUDIO_DEVICE_OUT_WIRED_HEADPHONE, - nullptr); - bool headsetConnected = mConnectedDevices.Get(AUDIO_DEVICE_OUT_WIRED_HEADSET, - nullptr); - if (aState == hal::SWITCH_STATE_HEADSET) { - UpdateDeviceConnectionState(true, - AUDIO_DEVICE_OUT_WIRED_HEADSET, - NS_LITERAL_CSTRING("")); - } else if (aState == hal::SWITCH_STATE_HEADPHONE) { - UpdateDeviceConnectionState(true, - AUDIO_DEVICE_OUT_WIRED_HEADPHONE, - NS_LITERAL_CSTRING("")); - } else if (aState == hal::SWITCH_STATE_OFF) { - if (headsetConnected) { - UpdateDeviceConnectionState(false, - AUDIO_DEVICE_OUT_WIRED_HEADSET, - NS_LITERAL_CSTRING("")); - } - if (headphoneConnected) { - UpdateDeviceConnectionState(false, - AUDIO_DEVICE_OUT_WIRED_HEADPHONE, - NS_LITERAL_CSTRING("")); - } - } -} - -void -AudioManager::UpdateDeviceConnectionState(bool aIsConnected, uint32_t aDevice, const nsCString& aDeviceName) -{ -#if ANDROID_VERSION >= 15 - bool isConnected = mConnectedDevices.Get(aDevice, nullptr); - if (isConnected && !aIsConnected) { - AudioSystem::setDeviceConnectionState(static_cast<audio_devices_t>(aDevice), - AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, - aDeviceName.get()); - mConnectedDevices.Remove(aDevice); - } else if(!isConnected && aIsConnected) { - AudioSystem::setDeviceConnectionState(static_cast<audio_devices_t>(aDevice), - AUDIO_POLICY_DEVICE_STATE_AVAILABLE, - aDeviceName.get()); - mConnectedDevices.Put(aDevice, aDeviceName); - } -#if ANDROID_VERSION < 21 - // Manually call it, since AudioPortCallback is not supported. - // Current volumes might be changed by updating active devices in android - // AudioPolicyManager. - MaybeUpdateVolumeSettingToDatabase(); -#endif -#else - NS_NOTREACHED("Doesn't support audio routing on GB version"); -#endif -} - -void -AudioManager::SetAllDeviceConnectionStates() -{ - for (auto iter = mConnectedDevices.Iter(); !iter.Done(); iter.Next()) { - const uint32_t& device = iter.Key(); - nsCString& deviceAddress = iter.Data(); - AudioSystem::setDeviceConnectionState(static_cast<audio_devices_t>(device), - AUDIO_POLICY_DEVICE_STATE_AVAILABLE, - deviceAddress.get()); - } -#if ANDROID_VERSION < 21 - // Manually call it, since AudioPortCallback is not supported. - // Current volumes might be changed by updating active devices in android - // AudioPolicyManager. - MaybeUpdateVolumeSettingToDatabase(true); -#endif -} - -void -AudioManager::HandleBluetoothStatusChanged(nsISupports* aSubject, - const char* aTopic, - const nsCString aAddress) -{ -#ifdef MOZ_B2G_BT - bool isConnected = false; - if (!strcmp(aTopic, BLUETOOTH_SCO_STATUS_CHANGED_ID)) { - BluetoothHfpManagerBase* hfp = - static_cast<BluetoothHfpManagerBase*>(aSubject); - isConnected = hfp->IsScoConnected(); - } else { - BluetoothProfileManagerBase* profile = - static_cast<BluetoothProfileManagerBase*>(aSubject); - isConnected = profile->IsConnected(); - } - - if (!strcmp(aTopic, BLUETOOTH_SCO_STATUS_CHANGED_ID)) { - if (isConnected) { - String8 cmd; - cmd.appendFormat("bt_samplerate=%d", kBtSampleRate); - AudioSystem::setParameters(0, cmd); - SetForceForUse(nsIAudioManager::USE_COMMUNICATION, nsIAudioManager::FORCE_BT_SCO); - } else { - int32_t force; - GetForceForUse(nsIAudioManager::USE_COMMUNICATION, &force); - if (force == nsIAudioManager::FORCE_BT_SCO) { - SetForceForUse(nsIAudioManager::USE_COMMUNICATION, nsIAudioManager::FORCE_NONE); - } - } - } else if (!strcmp(aTopic, BLUETOOTH_A2DP_STATUS_CHANGED_ID)) { - if (!isConnected && mA2dpSwitchDone) { - RefPtr<AudioManager> self = this; - nsCOMPtr<nsIRunnable> runnable = - NS_NewRunnableFunction([self, isConnected, aAddress]() { - if (self->mA2dpSwitchDone) { - return; - } - self->UpdateDeviceConnectionState(isConnected, - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, - aAddress); - - String8 cmd("bluetooth_enabled=false"); - AudioSystem::setParameters(0, cmd); - cmd.setTo("A2dpSuspended=true"); - AudioSystem::setParameters(0, cmd); - self->mA2dpSwitchDone = true; - }); - MessageLoop::current()->PostDelayedTask( - MakeAndAddRef<RunnableCallTask>(runnable), 1000); - - mA2dpSwitchDone = false; - } else { - UpdateDeviceConnectionState(isConnected, - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, - aAddress); - String8 cmd("bluetooth_enabled=true"); - AudioSystem::setParameters(0, cmd); - cmd.setTo("A2dpSuspended=false"); - AudioSystem::setParameters(0, cmd); - mA2dpSwitchDone = true; -#if ANDROID_VERSION >= 17 - if (AudioSystem::getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) == AUDIO_POLICY_FORCE_NO_BT_A2DP) { - SetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, AUDIO_POLICY_FORCE_NONE); - } -#endif - } - mBluetoothA2dpEnabled = isConnected; - } else if (!strcmp(aTopic, BLUETOOTH_HFP_STATUS_CHANGED_ID)) { - UpdateDeviceConnectionState(isConnected, - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, - aAddress); - UpdateDeviceConnectionState(isConnected, - AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, - aAddress); - } else if (!strcmp(aTopic, BLUETOOTH_HFP_NREC_STATUS_CHANGED_ID)) { - String8 cmd; - BluetoothHfpManagerBase* hfp = - static_cast<BluetoothHfpManagerBase*>(aSubject); - if (hfp->IsNrecEnabled()) { - cmd.setTo("bt_headset_name=<unknown>;bt_headset_nrec=on"); - AudioSystem::setParameters(0, cmd); - } else { - cmd.setTo("bt_headset_name=<unknown>;bt_headset_nrec=off"); - AudioSystem::setParameters(0, cmd); - } - } -#endif -} - -void -AudioManager::HandleAudioChannelProcessChanged() -{ - // Note: If the user answers a VoIP call (e.g. WebRTC calls) during the - // telephony call (GSM/CDMA calls) the audio manager won't set the - // PHONE_STATE_IN_COMMUNICATION audio state. Once the telephony call finishes - // the RIL plumbing sets the PHONE_STATE_NORMAL audio state. This seems to be - // an issue for the VoIP call but it is not. Once the RIL plumbing sets the - // the PHONE_STATE_NORMAL audio state the AudioManager::mPhoneAudioAgent - // member will call the NotifyStoppedPlaying() method causing that this function will - // be called again and therefore the audio manager sets the - // PHONE_STATE_IN_COMMUNICATION audio state. - - if ((mPhoneState == PHONE_STATE_IN_CALL) || - (mPhoneState == PHONE_STATE_RINGTONE)) { - return; - } - - RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate(); - bool telephonyChannelIsActive = service && service->TelephonyChannelIsActive(); - telephonyChannelIsActive ? SetPhoneState(PHONE_STATE_IN_COMMUNICATION) : - SetPhoneState(PHONE_STATE_NORMAL); -} - -nsresult -AudioManager::Observe(nsISupports* aSubject, - const char* aTopic, - const char16_t* aData) -{ - if ((strcmp(aTopic, BLUETOOTH_SCO_STATUS_CHANGED_ID) == 0) || - (strcmp(aTopic, BLUETOOTH_HFP_STATUS_CHANGED_ID) == 0) || - (strcmp(aTopic, BLUETOOTH_HFP_NREC_STATUS_CHANGED_ID) == 0) || - (strcmp(aTopic, BLUETOOTH_A2DP_STATUS_CHANGED_ID) == 0)) { - nsCString address = NS_ConvertUTF16toUTF8(nsDependentString(aData)); - if (address.IsEmpty()) { - NS_WARNING(nsPrintfCString("Invalid address of %s", aTopic).get()); - return NS_ERROR_FAILURE; - } - - HandleBluetoothStatusChanged(aSubject, aTopic, address); - return NS_OK; - } - - else if (!strcmp(aTopic, AUDIO_CHANNEL_PROCESS_CHANGED)) { - HandleAudioChannelProcessChanged(); - return NS_OK; - } - - // To process the volume control on each volume categories according to - // change of settings - else if (!strcmp(aTopic, MOZ_SETTINGS_CHANGE_ID)) { - RootedDictionary<dom::SettingChangeNotification> setting(RootingCx()); - if (!WrappedJSToDictionary(aSubject, setting)) { - return NS_OK; - } - if (!StringBeginsWith(setting.mKey, NS_LITERAL_STRING("audio.volume."))) { - return NS_OK; - } - if (!setting.mValue.isNumber()) { - return NS_OK; - } - - uint32_t volIndex = setting.mValue.toNumber(); - for (uint32_t idx = 0; idx < MOZ_ARRAY_LENGTH(gVolumeData); ++idx) { - if (setting.mKey.EqualsASCII(gVolumeData[idx].mChannelName)) { - SetStreamVolumeIndex(gVolumeData[idx].mStreamType, volIndex); - return NS_OK; - } - } - } - - NS_WARNING("Unexpected topic in AudioManager"); - return NS_ERROR_FAILURE; -} - -static void -NotifyHeadphonesStatus(hal::SwitchState aState) -{ - nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); - if (obs) { - if (aState == hal::SWITCH_STATE_HEADSET) { - obs->NotifyObservers(nullptr, HEADPHONES_STATUS_CHANGED, HEADPHONES_STATUS_HEADSET); - } else if (aState == hal::SWITCH_STATE_HEADPHONE) { - obs->NotifyObservers(nullptr, HEADPHONES_STATUS_CHANGED, HEADPHONES_STATUS_HEADPHONE); - } else if (aState == hal::SWITCH_STATE_OFF) { - obs->NotifyObservers(nullptr, HEADPHONES_STATUS_CHANGED, HEADPHONES_STATUS_OFF); - } else { - obs->NotifyObservers(nullptr, HEADPHONES_STATUS_CHANGED, HEADPHONES_STATUS_UNKNOWN); - } - } -} - -class HeadphoneSwitchObserver : public hal::SwitchObserver -{ -public: - void Notify(const hal::SwitchEvent& aEvent) { - RefPtr<AudioManager> audioManager = AudioManager::GetInstance(); - MOZ_ASSERT(audioManager); - audioManager->HandleHeadphoneSwitchEvent(aEvent); - } -}; - -void -AudioManager::HandleHeadphoneSwitchEvent(const hal::SwitchEvent& aEvent) -{ - NotifyHeadphonesStatus(aEvent.status()); - // When user pulled out the headset, a delay of routing here can avoid the leakage of audio from speaker. - if (aEvent.status() == hal::SWITCH_STATE_OFF && mSwitchDone) { - - RefPtr<AudioManager> self = this; - nsCOMPtr<nsIRunnable> runnable = - NS_NewRunnableFunction([self]() { - if (self->mSwitchDone) { - return; - } - self->UpdateHeadsetConnectionState(hal::SWITCH_STATE_OFF); - self->mSwitchDone = true; - }); - MessageLoop::current()->PostDelayedTask( - MakeAndAddRef<RunnableCallTask>(runnable), 1000); - mSwitchDone = false; - } else if (aEvent.status() != hal::SWITCH_STATE_OFF) { - UpdateHeadsetConnectionState(aEvent.status()); - mSwitchDone = true; - } - // Handle the coexistence of a2dp / headset device, latest one wins. -#if ANDROID_VERSION >= 17 - int32_t forceUse = 0; - GetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, &forceUse); - if (aEvent.status() != hal::SWITCH_STATE_OFF && mBluetoothA2dpEnabled) { - SetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, AUDIO_POLICY_FORCE_NO_BT_A2DP); - } else if (forceUse == AUDIO_POLICY_FORCE_NO_BT_A2DP) { - SetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, AUDIO_POLICY_FORCE_NONE); - } -#endif -} - -AudioManager::AudioManager() - : mPhoneState(PHONE_STATE_CURRENT) - , mIsVolumeInited(false) - , mAudioOutDevicesUpdated(0) - , mSwitchDone(true) -#if defined(MOZ_B2G_BT) || ANDROID_VERSION >= 17 - , mBluetoothA2dpEnabled(false) -#endif -#ifdef MOZ_B2G_BT - , mA2dpSwitchDone(true) -#endif - , mObserver(new HeadphoneSwitchObserver()) -{ - for (uint32_t idx = 0; idx < MOZ_ARRAY_LENGTH(kAudioDeviceInfos); ++idx) { - mAudioDeviceTableIdMaps.Put(kAudioDeviceInfos[idx].value, idx); - } - - AudioSystem::setErrorCallback(BinderDeadCallback); -#if ANDROID_VERSION >= 21 - android::sp<GonkAudioPortCallback> callback = new GonkAudioPortCallback(); - AudioSystem::setAudioPortCallback(callback); -#endif - - // Create VolumeStreamStates - for (uint32_t loop = 0; loop < AUDIO_STREAM_CNT; ++loop) { - VolumeStreamState* streamState = - new VolumeStreamState(*this, static_cast<audio_stream_type_t>(loop)); - mStreamStates.AppendElement(streamState); - } - // Initialize stream volumes with default values - for (int32_t streamType = 0; streamType < AUDIO_STREAM_MAX; streamType++) { - uint32_t volIndex = sDefaultStreamVolumeTbl[streamType]; - SetStreamVolumeForDevice(streamType, volIndex, AUDIO_DEVICE_OUT_DEFAULT); - } - UpdateCachedActiveDevicesForStreams(); - - RegisterSwitchObserver(hal::SWITCH_HEADPHONES, mObserver); - // Initialize headhone/heaset status - UpdateHeadsetConnectionState(hal::GetCurrentSwitchState(hal::SWITCH_HEADPHONES)); - NotifyHeadphonesStatus(hal::GetCurrentSwitchState(hal::SWITCH_HEADPHONES)); - - // Get the initial volume index from settings DB during boot up. - InitVolumeFromDatabase(); - - // Gecko only control stream volume not master so set to default value - // directly. - AudioSystem::setMasterVolume(1.0); - - nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); - NS_ENSURE_TRUE_VOID(obs); - if (NS_FAILED(obs->AddObserver(this, BLUETOOTH_SCO_STATUS_CHANGED_ID, false))) { - NS_WARNING("Failed to add bluetooth sco status changed observer!"); - } - if (NS_FAILED(obs->AddObserver(this, BLUETOOTH_A2DP_STATUS_CHANGED_ID, false))) { - NS_WARNING("Failed to add bluetooth a2dp status changed observer!"); - } - if (NS_FAILED(obs->AddObserver(this, BLUETOOTH_HFP_STATUS_CHANGED_ID, false))) { - NS_WARNING("Failed to add bluetooth hfp status changed observer!"); - } - if (NS_FAILED(obs->AddObserver(this, BLUETOOTH_HFP_NREC_STATUS_CHANGED_ID, false))) { - NS_WARNING("Failed to add bluetooth hfp NREC status changed observer!"); - } - if (NS_FAILED(obs->AddObserver(this, MOZ_SETTINGS_CHANGE_ID, false))) { - NS_WARNING("Failed to add mozsettings-changed observer!"); - } - if (NS_FAILED(obs->AddObserver(this, AUDIO_CHANNEL_PROCESS_CHANGED, false))) { - NS_WARNING("Failed to add audio-channel-process-changed observer!"); - } - -} - -AudioManager::~AudioManager() { - AudioSystem::setErrorCallback(nullptr); -#if ANDROID_VERSION >= 21 - AudioSystem::setAudioPortCallback(nullptr); -#endif - hal::UnregisterSwitchObserver(hal::SWITCH_HEADPHONES, mObserver); - - nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); - NS_ENSURE_TRUE_VOID(obs); - if (NS_FAILED(obs->RemoveObserver(this, BLUETOOTH_SCO_STATUS_CHANGED_ID))) { - NS_WARNING("Failed to remove bluetooth sco status changed observer!"); - } - if (NS_FAILED(obs->RemoveObserver(this, BLUETOOTH_A2DP_STATUS_CHANGED_ID))) { - NS_WARNING("Failed to remove bluetooth a2dp status changed observer!"); - } - if (NS_FAILED(obs->RemoveObserver(this, BLUETOOTH_HFP_STATUS_CHANGED_ID))) { - NS_WARNING("Failed to remove bluetooth hfp status changed observer!"); - } - if (NS_FAILED(obs->RemoveObserver(this, BLUETOOTH_HFP_NREC_STATUS_CHANGED_ID))) { - NS_WARNING("Failed to remove bluetooth hfp NREC status changed observer!"); - } - if (NS_FAILED(obs->RemoveObserver(this, MOZ_SETTINGS_CHANGE_ID))) { - NS_WARNING("Failed to remove mozsettings-changed observer!"); - } - if (NS_FAILED(obs->RemoveObserver(this, AUDIO_CHANNEL_PROCESS_CHANGED))) { - NS_WARNING("Failed to remove audio-channel-process-changed!"); - } -} - -static StaticRefPtr<AudioManager> sAudioManager; - -already_AddRefed<AudioManager> -AudioManager::GetInstance() -{ - // Avoid createing AudioManager from content process. - if (!XRE_IsParentProcess()) { - MOZ_CRASH("Non-chrome processes should not get here."); - } - - // Avoid createing multiple AudioManager instance inside main process. - if (!sAudioManager) { - sAudioManager = new AudioManager(); - ClearOnShutdown(&sAudioManager); - } - - RefPtr<AudioManager> audioMgr = sAudioManager.get(); - return audioMgr.forget(); -} - -NS_IMETHODIMP -AudioManager::GetMicrophoneMuted(bool* aMicrophoneMuted) -{ - - if (AudioSystem::isMicrophoneMuted(aMicrophoneMuted)) { - return NS_ERROR_FAILURE; - } - return NS_OK; -} - -NS_IMETHODIMP -AudioManager::SetMicrophoneMuted(bool aMicrophoneMuted) -{ - if (!AudioSystem::muteMicrophone(aMicrophoneMuted)) { - return NS_OK; - } - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -AudioManager::GetPhoneState(int32_t* aState) -{ - *aState = mPhoneState; - return NS_OK; -} - -NS_IMETHODIMP -AudioManager::SetPhoneState(int32_t aState) -{ - if (mPhoneState == aState) { - return NS_OK; - } - - nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); - if (obs) { - nsString state; - state.AppendInt(aState); - obs->NotifyObservers(nullptr, "phone-state-changed", state.get()); - } - -#if ANDROID_VERSION < 17 - if (AudioSystem::setPhoneState(aState)) { -#else - if (AudioSystem::setPhoneState(static_cast<audio_mode_t>(aState))) { -#endif - return NS_ERROR_FAILURE; - } - -#if ANDROID_VERSION < 21 - // Manually call it, since AudioPortCallback is not supported. - // Current volumes might be changed by updating active devices in android - // AudioPolicyManager. - MaybeUpdateVolumeSettingToDatabase(); -#endif - mPhoneState = aState; - return NS_OK; -} - -NS_IMETHODIMP -AudioManager::SetForceForUse(int32_t aUsage, int32_t aForce) -{ -#if ANDROID_VERSION >= 15 - status_t status = AudioSystem::setForceUse( - (audio_policy_force_use_t)aUsage, - (audio_policy_forced_cfg_t)aForce); -#if ANDROID_VERSION < 21 - // Manually call it, since AudioPortCallback is not supported. - // Current volumes might be changed by updating active devices in android - // AudioPolicyManager. - MaybeUpdateVolumeSettingToDatabase(); -#endif - return status ? NS_ERROR_FAILURE : NS_OK; -#else - NS_NOTREACHED("Doesn't support force routing on GB version"); - return NS_ERROR_UNEXPECTED; -#endif -} - -NS_IMETHODIMP -AudioManager::GetForceForUse(int32_t aUsage, int32_t* aForce) { -#if ANDROID_VERSION >= 15 - *aForce = AudioSystem::getForceUse((audio_policy_force_use_t)aUsage); - return NS_OK; -#else - NS_NOTREACHED("Doesn't support force routing on GB version"); - return NS_ERROR_UNEXPECTED; -#endif -} - -NS_IMETHODIMP -AudioManager::SetAudioChannelVolume(uint32_t aChannel, uint32_t aIndex) -{ - if (aChannel >= NUMBER_OF_AUDIO_CHANNELS) { - return NS_ERROR_INVALID_ARG; - } - - return SetStreamVolumeIndex(sChannelStreamTbl[aChannel], aIndex); -} - -NS_IMETHODIMP -AudioManager::GetAudioChannelVolume(uint32_t aChannel, uint32_t* aIndex) -{ - if (aChannel >= NUMBER_OF_AUDIO_CHANNELS) { - return NS_ERROR_INVALID_ARG; - } - - if (!aIndex) { - return NS_ERROR_NULL_POINTER; - } - - return GetStreamVolumeIndex(sChannelStreamTbl[aChannel], aIndex); -} - -NS_IMETHODIMP -AudioManager::GetMaxAudioChannelVolume(uint32_t aChannel, uint32_t* aMaxIndex) -{ - if (aChannel >= NUMBER_OF_AUDIO_CHANNELS) { - return NS_ERROR_INVALID_ARG; - } - - if (!aMaxIndex) { - return NS_ERROR_NULL_POINTER; - } - - *aMaxIndex = mStreamStates[sChannelStreamTbl[aChannel]]->GetMaxIndex(); - return NS_OK; -} - -nsresult -AudioManager::ValidateVolumeIndex(int32_t aStream, uint32_t aIndex) const -{ - if (aStream <= AUDIO_STREAM_DEFAULT || aStream >= AUDIO_STREAM_MAX) { - return NS_ERROR_INVALID_ARG; - } - - uint32_t maxIndex = mStreamStates[aStream]->GetMaxIndex(); - if (aIndex > maxIndex) { - return NS_ERROR_FAILURE; - } - return NS_OK; -} - -nsresult -AudioManager::SetStreamVolumeForDevice(int32_t aStream, - uint32_t aIndex, - uint32_t aDevice) -{ - if (aStream <= AUDIO_STREAM_DEFAULT || aStream >= AUDIO_STREAM_MAX) { - return NS_ERROR_INVALID_ARG; - } - - int32_t streamAlias = sStreamVolumeAliasTbl[aStream]; - VolumeStreamState* streamState = mStreamStates[streamAlias].get(); - return streamState->SetVolumeIndexToAliasStreams(aIndex, aDevice); -} - -nsresult -AudioManager::SetStreamVolumeIndex(int32_t aStream, uint32_t aIndex) -{ - if (aStream <= AUDIO_STREAM_DEFAULT || aStream >= AUDIO_STREAM_MAX) { - return NS_ERROR_INVALID_ARG; - } - - int32_t streamAlias = sStreamVolumeAliasTbl[aStream]; - - nsresult rv; - for (int32_t streamType = 0; streamType < AUDIO_STREAM_MAX; streamType++) { - if (streamAlias == sStreamVolumeAliasTbl[streamType]) { - rv = mStreamStates[streamType]->SetVolumeIndexToActiveDevices(aIndex); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - } - } - - // AUDIO_STREAM_FM is not used on recent gonk. - // AUDIO_STREAM_MUSIC is used for FM radio volume control. -#if ANDROID_VERSION < 19 - if (streamAlias == AUDIO_STREAM_MUSIC && IsFmOutConnected()) { - rv = mStreamStates[AUDIO_STREAM_FM]-> - SetVolumeIndex(aIndex, AUDIO_DEVICE_OUT_FM); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - } -#endif - - MaybeUpdateVolumeSettingToDatabase(); - return NS_OK; -} - -nsresult -AudioManager::GetStreamVolumeIndex(int32_t aStream, uint32_t *aIndex) -{ - if (!aIndex) { - return NS_ERROR_INVALID_ARG; - } - - if (aStream <= AUDIO_STREAM_DEFAULT || aStream >= AUDIO_STREAM_MAX) { - return NS_ERROR_INVALID_ARG; - } - - *aIndex = mStreamStates[aStream]->GetVolumeIndex(); - return NS_OK; -} - -nsAutoCString -AudioManager::AppendDeviceToVolumeSetting(const char* aName, uint32_t aDevice) -{ - nsAutoCString topic; - topic.Assign(aName); - topic.Append("."); - uint32_t index = 0; - DebugOnly<bool> exist = mAudioDeviceTableIdMaps.Get(aDevice, &index); - MOZ_ASSERT(exist); - topic.Append(kAudioDeviceInfos[index].tag); - return topic; -} - -void -AudioManager::InitVolumeFromDatabase() -{ - nsresult rv; - nsCOMPtr<nsISettingsService> service = do_GetService(SETTINGS_SERVICE, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - - nsCOMPtr<nsISettingsServiceLock> lock; - rv = service->CreateLock(nullptr, getter_AddRefs(lock)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - - RefPtr<VolumeInitCallback> callback = new VolumeInitCallback(); - MOZ_ASSERT(callback); - callback->GetPromise()->Then(AbstractThread::MainThread(), __func__, this, - &AudioManager::InitDeviceVolumeSucceeded, - &AudioManager::InitDeviceVolumeFailed); - - for (uint32_t idx = 0; idx < MOZ_ARRAY_LENGTH(gVolumeData); ++idx) { - for (uint32_t idx2 = 0; idx2 < MOZ_ARRAY_LENGTH(kAudioDeviceInfos); ++idx2) { - lock->Get(AppendDeviceToVolumeSetting(gVolumeData[idx].mChannelName, - kAudioDeviceInfos[idx2].value).get(), - callback); - } - } -} - -void -AudioManager::InitDeviceVolumeSucceeded() -{ - mIsVolumeInited = true; - MaybeUpdateVolumeSettingToDatabase(true); -} - -void -AudioManager::InitDeviceVolumeFailed(const char* aError) -{ - // Default volume of AUDIO_DEVICE_OUT_DEFAULT is already set. - mIsVolumeInited = true; - MaybeUpdateVolumeSettingToDatabase(true); - NS_WARNING(aError); -} - -void -AudioManager::MaybeUpdateVolumeSettingToDatabase(bool aForce) -{ - if (!mIsVolumeInited) { - return; - } - - nsCOMPtr<nsISettingsServiceLock> lock = GetSettingServiceLock(); - if (NS_WARN_IF(!lock)) { - return; - } - - // Send events to update the Gaia volumes - JS::Rooted<JS::Value> value(RootingCx()); - uint32_t volume = 0; - for (uint32_t idx = 0; idx < MOZ_ARRAY_LENGTH(gVolumeData); ++idx) { - int32_t streamType = gVolumeData[idx].mStreamType; - VolumeStreamState* streamState = mStreamStates[streamType].get(); - if(!aForce && !streamState->IsDevicesChanged()) { - continue; - } - // Get volume index of active device. - volume = streamState->GetVolumeIndex(); - value.setInt32(volume); - lock->Set(gVolumeData[idx].mChannelName, value, nullptr, nullptr); - } - - // For reducing the code dependency, Gaia doesn't need to know the - // device volume, it only need to care about different volume categories. - // However, we need to send the setting volume to the permanent database, - // so that we can store the volume setting even if the phone reboots. - - for (uint32_t idx = 0; idx < MOZ_ARRAY_LENGTH(gVolumeData); ++idx) { - int32_t streamType = gVolumeData[idx].mStreamType; - VolumeStreamState* streamState = mStreamStates[streamType].get(); - - if(!streamState->IsVolumeIndexesChanged()) { - continue; - } - - uint32_t remainingDevices = mAudioOutDevicesUpdated; - for (uint32_t i = 0; remainingDevices != 0; i++) { - uint32_t device = (1 << i); - if ((device & remainingDevices) == 0) { - continue; - } - remainingDevices &= ~device; - if (!mAudioDeviceTableIdMaps.Get(device, nullptr)) { - continue; - } - volume = streamState->GetVolumeIndex(device); - value.setInt32(volume); - lock->Set(AppendDeviceToVolumeSetting(gVolumeData[idx].mChannelName, - device).get(), - value, nullptr, nullptr); - } - } - - // Clear changed flags - for (uint32_t idx = 0; idx < MOZ_ARRAY_LENGTH(gVolumeData); ++idx) { - int32_t streamType = gVolumeData[idx].mStreamType; - mStreamStates[streamType]->ClearDevicesChanged(); - mStreamStates[streamType]->ClearVolumeIndexesChanged(); - } - // Clear mAudioOutDevicesUpdated - mAudioOutDevicesUpdated = 0; -} - -void -AudioManager::UpdateCachedActiveDevicesForStreams() -{ - // This function updates cached active devices for streams. - // It is used for optimization of GetDevicesForStream() since L. - // AudioManager could know when active devices - // are changed in AudioPolicyManager by onAudioPortListUpdate(). - // Except it, AudioManager normally do not need to ask AuidoPolicyManager - // about current active devices of streams and could use cached values. - // Before L, onAudioPortListUpdate() does not exist and GetDevicesForStream() - // does not use the cache. Therefore this function do nothing. -#if ANDROID_VERSION >= 21 - for (int32_t streamType = 0; streamType < AUDIO_STREAM_MAX; streamType++) { - // Update cached active devices of stream - mStreamStates[streamType]->IsDevicesChanged(false /* aFromCache */); - } -#endif -} - -uint32_t -AudioManager::GetDevicesForStream(int32_t aStream, bool aFromCache) -{ -#if ANDROID_VERSION >= 21 - // Since Lollipop, devices update could be notified by AudioPortCallback. - // Cached values can be used if there is no update. - if (aFromCache) { - return mStreamStates[aStream]->GetLastDevices(); - } -#endif - -#if ANDROID_VERSION >= 17 - audio_devices_t devices = - AudioSystem::getDevicesForStream(static_cast<audio_stream_type_t>(aStream)); - - return static_cast<uint32_t>(devices); -#else - // Per audio out device volume is not supported. - // Use AUDIO_DEVICE_OUT_SPEAKER just to store audio volume to DB. - return AUDIO_DEVICE_OUT_SPEAKER; -#endif -} - -uint32_t -AudioManager::GetDeviceForStream(int32_t aStream) -{ - uint32_t devices = - GetDevicesForStream(static_cast<audio_stream_type_t>(aStream)); - uint32_t device = SelectDeviceFromDevices(devices); - return device; -} - -/* static */ uint32_t -AudioManager::SelectDeviceFromDevices(uint32_t aOutDevices) -{ - uint32_t device = aOutDevices; - - // See android AudioService.getDeviceForStream(). - // AudioPolicyManager expects it. - // See also android AudioPolicyManager::getDeviceForVolume(). - if ((device & (device - 1)) != 0) { - // Multiple device selection. - if ((device & AUDIO_DEVICE_OUT_SPEAKER) != 0) { - device = AUDIO_DEVICE_OUT_SPEAKER; -#if ANDROID_VERSION >= 21 - } else if ((device & AUDIO_DEVICE_OUT_HDMI_ARC) != 0) { - device = AUDIO_DEVICE_OUT_HDMI_ARC; - } else if ((device & AUDIO_DEVICE_OUT_SPDIF) != 0) { - device = AUDIO_DEVICE_OUT_SPDIF; - } else if ((device & AUDIO_DEVICE_OUT_AUX_LINE) != 0) { - device = AUDIO_DEVICE_OUT_AUX_LINE; -#endif - } else { - device &= AUDIO_DEVICE_OUT_ALL_A2DP; - } - } - MOZ_ASSERT(audio_is_output_device(device)); - return device; -} -AudioManager::VolumeStreamState::VolumeStreamState(AudioManager& aManager, - int32_t aStreamType) - : mManager(aManager) - , mStreamType(aStreamType) - , mLastDevices(0) - , mIsDevicesChanged(true) - , mIsVolumeIndexesChanged(true) -{ - InitStreamVolume(); -} - -bool -AudioManager::VolumeStreamState::IsDevicesChanged(bool aFromCache) -{ - uint32_t devices = mManager.GetDevicesForStream(mStreamType, aFromCache); - if (devices != mLastDevices) { - mLastDevices = devices; - mIsDevicesChanged = true; - } - return mIsDevicesChanged; -} - -void -AudioManager::VolumeStreamState::ClearDevicesChanged() -{ - mIsDevicesChanged = false; -} - -bool -AudioManager::VolumeStreamState::IsVolumeIndexesChanged() -{ - return mIsVolumeIndexesChanged; -} - -void -AudioManager::VolumeStreamState::ClearVolumeIndexesChanged() -{ - mIsVolumeIndexesChanged = false; -} - -void -AudioManager::VolumeStreamState::InitStreamVolume() -{ - AudioSystem::initStreamVolume(static_cast<audio_stream_type_t>(mStreamType), - 0, - GetMaxIndex()); -} - -uint32_t -AudioManager::VolumeStreamState::GetMaxIndex() -{ - return sMaxStreamVolumeTbl[mStreamType]; -} - -uint32_t -AudioManager::VolumeStreamState::GetDefaultIndex() -{ - return sDefaultStreamVolumeTbl[mStreamType]; -} - -uint32_t -AudioManager::VolumeStreamState::GetVolumeIndex() -{ - uint32_t device = mManager.GetDeviceForStream(mStreamType); - return GetVolumeIndex(device); -} - -uint32_t -AudioManager::VolumeStreamState::GetVolumeIndex(uint32_t aDevice) -{ - uint32_t index = 0; - bool ret = mVolumeIndexes.Get(aDevice, &index); - if (!ret) { - index = mVolumeIndexes.Get(AUDIO_DEVICE_OUT_DEFAULT); - } - return index; -} - -nsresult -AudioManager::VolumeStreamState::SetVolumeIndexToActiveDevices(uint32_t aIndex) -{ - uint32_t device = mManager.GetDeviceForStream(mStreamType); - - // Update volume index for device - uint32_t oldVolumeIndex = 0; - bool exist = mVolumeIndexes.Get(device, &oldVolumeIndex); - if (exist && aIndex == oldVolumeIndex) { - // No update - return NS_OK; - } - - // AudioPolicyManager::setStreamVolumeIndex() set volumes of all active - // devices for stream. - nsresult rv; - rv = SetVolumeIndexToConsistentDeviceIfNeeded(aIndex, device); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - return NS_OK; -} - -nsresult -AudioManager::VolumeStreamState::SetVolumeIndexToAliasStreams(uint32_t aIndex, - uint32_t aDevice) -{ - uint32_t oldVolumeIndex = 0; - bool exist = mVolumeIndexes.Get(aDevice, &oldVolumeIndex); - if (exist && aIndex == oldVolumeIndex) { - // No update - return NS_OK; - } - - nsresult rv = SetVolumeIndexToConsistentDeviceIfNeeded(aIndex, aDevice); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - for (int32_t streamType = 0; streamType < AUDIO_STREAM_MAX; streamType++) { - if ((streamType != mStreamType) && - sStreamVolumeAliasTbl[streamType] == mStreamType) { - // Rescaling of index is not necessary. - rv = mManager.mStreamStates[streamType]-> - SetVolumeIndexToAliasStreams(aIndex, aDevice); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - } - } - - return NS_OK; -} - -nsresult -AudioManager::VolumeStreamState::SetVolumeIndexToConsistentDeviceIfNeeded(uint32_t aIndex, uint32_t aDevice) -{ - nsresult rv; - if (aDevice == AUDIO_DEVICE_OUT_SPEAKER || aDevice == AUDIO_DEVICE_OUT_EARPIECE) { - // Set AUDIO_DEVICE_OUT_SPEAKER and AUDIO_DEVICE_OUT_EARPIECE to same volume. - rv = SetVolumeIndex(aIndex, AUDIO_DEVICE_OUT_SPEAKER); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - rv = SetVolumeIndex(aIndex, AUDIO_DEVICE_OUT_EARPIECE); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - } else { - // No alias device - rv = SetVolumeIndex(aIndex, aDevice); - } - return rv; -} - -nsresult -AudioManager::VolumeStreamState::SetVolumeIndex(uint32_t aIndex, - uint32_t aDevice, - bool aUpdateCache) -{ - status_t rv; -#if ANDROID_VERSION >= 17 - if (aUpdateCache) { - mVolumeIndexes.Put(aDevice, aIndex); - mIsVolumeIndexesChanged = true; - mManager.AudioOutDeviceUpdated(aDevice); - } - - rv = AudioSystem::setStreamVolumeIndex( - static_cast<audio_stream_type_t>(mStreamType), - aIndex, - aDevice); - return rv ? NS_ERROR_FAILURE : NS_OK; -#else - if (aUpdateCache) { - // Per audio out device volume is not supported. - // Use AUDIO_DEVICE_OUT_SPEAKER just to store audio volume to DB. - mVolumeIndexes.Put(AUDIO_DEVICE_OUT_SPEAKER, aIndex); - mIsVolumeIndexesChanged = true; - mManager.AudioOutDeviceUpdated(AUDIO_DEVICE_OUT_SPEAKER); - } - rv = AudioSystem::setStreamVolumeIndex( - static_cast<audio_stream_type_t>(mStreamType), - aIndex); - return rv ? NS_ERROR_FAILURE : NS_OK; -#endif -} - -void -AudioManager::VolumeStreamState::RestoreVolumeIndexToAllDevices() -{ - for (auto iter = mVolumeIndexes.Iter(); !iter.Done(); iter.Next()) { - const uint32_t& key = iter.Key(); - uint32_t& index = iter.Data(); - SetVolumeIndex(key, index, /* aUpdateCache */ false); - } -} - -} /* namespace gonk */ -} /* namespace dom */ -} /* namespace mozilla */ diff --git a/dom/system/gonk/AudioManager.h b/dom/system/gonk/AudioManager.h deleted file mode 100644 index f56eaad6c..000000000 --- a/dom/system/gonk/AudioManager.h +++ /dev/null @@ -1,180 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef mozilla_dom_system_b2g_audiomanager_h__ -#define mozilla_dom_system_b2g_audiomanager_h__ - -#include "mozilla/HalTypes.h" -#include "mozilla/Observer.h" -#include "mozilla/UniquePtr.h" -#include "nsAutoPtr.h" -#include "nsDataHashtable.h" -#include "nsIAudioManager.h" -#include "nsIObserver.h" -#include "android_audio/AudioSystem.h" - -// {b2b51423-502d-4d77-89b3-7786b562b084} -#define NS_AUDIOMANAGER_CID {0x94f6fd70, 0x7615, 0x4af9, \ - {0x89, 0x10, 0xf9, 0x3c, 0x55, 0xe6, 0x62, 0xec}} -#define NS_AUDIOMANAGER_CONTRACTID "@mozilla.org/telephony/audiomanager;1" - -class nsISettingsServiceLock; - -namespace mozilla { -namespace hal { -class SwitchEvent; -typedef Observer<SwitchEvent> SwitchObserver; -} // namespace hal - -namespace dom { -namespace gonk { - -class VolumeInitCallback; - -class AudioManager final : public nsIAudioManager - , public nsIObserver -{ -public: - static already_AddRefed<AudioManager> GetInstance(); - - NS_DECL_ISUPPORTS - NS_DECL_NSIAUDIOMANAGER - NS_DECL_NSIOBSERVER - - // Validate whether the volume index is within the range - nsresult ValidateVolumeIndex(int32_t aStream, uint32_t aIndex) const; - - // Called when android AudioFlinger in mediaserver is died - void HandleAudioFlingerDied(); - - void HandleHeadphoneSwitchEvent(const hal::SwitchEvent& aEvent); - - class VolumeStreamState { - public: - explicit VolumeStreamState(AudioManager& aManager, int32_t aStreamType); - int32_t GetStreamType() - { - return mStreamType; - } - bool IsDevicesChanged(bool aFromCache = true); - void ClearDevicesChanged(); - uint32_t GetLastDevices() - { - return mLastDevices; - } - bool IsVolumeIndexesChanged(); - void ClearVolumeIndexesChanged(); - void InitStreamVolume(); - uint32_t GetMaxIndex(); - uint32_t GetDefaultIndex(); - uint32_t GetVolumeIndex(); - uint32_t GetVolumeIndex(uint32_t aDevice); - void ClearCurrentVolumeUpdated(); - // Set volume index to all active devices. - // Active devices are chosen by android AudioPolicyManager. - nsresult SetVolumeIndexToActiveDevices(uint32_t aIndex); - // Set volume index to all alias streams for device. Alias streams have same volume. - nsresult SetVolumeIndexToAliasStreams(uint32_t aIndex, uint32_t aDevice); - nsresult SetVolumeIndexToConsistentDeviceIfNeeded(uint32_t aIndex, uint32_t aDevice); - nsresult SetVolumeIndex(uint32_t aIndex, uint32_t aDevice, bool aUpdateCache = true); - // Restore volume index to all devices. Called when AudioFlinger is restarted. - void RestoreVolumeIndexToAllDevices(); - private: - AudioManager& mManager; - const int32_t mStreamType; - uint32_t mLastDevices; - bool mIsDevicesChanged; - bool mIsVolumeIndexesChanged; - nsDataHashtable<nsUint32HashKey, uint32_t> mVolumeIndexes; - }; - -protected: - int32_t mPhoneState; - - bool mIsVolumeInited; - - // A bitwise variable for volume update of audio output devices, - // clear it after store the value into database. - uint32_t mAudioOutDevicesUpdated; - - // Connected devices that are controlled by setDeviceConnectionState() - nsDataHashtable<nsUint32HashKey, nsCString> mConnectedDevices; - - nsDataHashtable<nsUint32HashKey, uint32_t> mAudioDeviceTableIdMaps; - - bool mSwitchDone; - -#if defined(MOZ_B2G_BT) || ANDROID_VERSION >= 17 - bool mBluetoothA2dpEnabled; -#endif -#ifdef MOZ_B2G_BT - bool mA2dpSwitchDone; -#endif - nsTArray<UniquePtr<VolumeStreamState> > mStreamStates; - uint32_t mLastChannelVolume[AUDIO_STREAM_CNT]; - - bool IsFmOutConnected(); - - nsresult SetStreamVolumeForDevice(int32_t aStream, - uint32_t aIndex, - uint32_t aDevice); - nsresult SetStreamVolumeIndex(int32_t aStream, uint32_t aIndex); - nsresult GetStreamVolumeIndex(int32_t aStream, uint32_t* aIndex); - - void UpdateCachedActiveDevicesForStreams(); - uint32_t GetDevicesForStream(int32_t aStream, bool aFromCache = true); - uint32_t GetDeviceForStream(int32_t aStream); - // Choose one device as representative of active devices. - static uint32_t SelectDeviceFromDevices(uint32_t aOutDevices); - -private: - nsAutoPtr<mozilla::hal::SwitchObserver> mObserver; - - void HandleBluetoothStatusChanged(nsISupports* aSubject, - const char* aTopic, - const nsCString aAddress); - void HandleAudioChannelProcessChanged(); - - // Append the audio output device to the volume setting string. - nsAutoCString AppendDeviceToVolumeSetting(const char* aName, - uint32_t aDevice); - - // We store the volume setting in the database, these are related functions. - void InitVolumeFromDatabase(); - void MaybeUpdateVolumeSettingToDatabase(bool aForce = false); - - // Promise functions. - void InitDeviceVolumeSucceeded(); - void InitDeviceVolumeFailed(const char* aError); - - void AudioOutDeviceUpdated(uint32_t aDevice); - - void UpdateHeadsetConnectionState(hal::SwitchState aState); - void UpdateDeviceConnectionState(bool aIsConnected, uint32_t aDevice, const nsCString& aDeviceName); - void SetAllDeviceConnectionStates(); - - AudioManager(); - ~AudioManager(); - - friend class VolumeInitCallback; - friend class VolumeStreamState; - friend class GonkAudioPortCallback; -}; - -} /* namespace gonk */ -} /* namespace dom */ -} /* namespace mozilla */ - -#endif // mozilla_dom_system_b2g_audiomanager_h__ diff --git a/dom/system/gonk/AutoMounter.cpp b/dom/system/gonk/AutoMounter.cpp deleted file mode 100644 index 52c4554fb..000000000 --- a/dom/system/gonk/AutoMounter.cpp +++ /dev/null @@ -1,1496 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include <errno.h> -#include <fcntl.h> -#include <pthread.h> -#include <signal.h> -#include <string.h> -#include <strings.h> -#include <unistd.h> -#include <sys/statfs.h> - -#include <arpa/inet.h> -#include <linux/types.h> -#include <linux/netlink.h> -#include <netinet/in.h> -#include <sys/socket.h> -#include <android/log.h> -#include <cutils/properties.h> - -#include "AutoMounter.h" -#include "nsVolumeService.h" -#include "AutoMounterSetting.h" -#include "base/message_loop.h" -#include "base/task.h" -#include "mozilla/AutoRestore.h" -#include "mozilla/FileUtils.h" -#include "mozilla/Hal.h" -#include "mozilla/StaticPtr.h" -#include "MozMtpServer.h" -#include "MozMtpStorage.h" -#include "nsCharSeparatedTokenizer.h" -#include "nsMemory.h" -#include "nsString.h" -#include "nsThreadUtils.h" -#include "nsXULAppAPI.h" -#include "OpenFileFinder.h" -#include "Volume.h" -#include "VolumeManager.h" -#include "nsIStatusReporter.h" - -USING_MTP_NAMESPACE - -/************************************************************************** -* -* The following "switch" files are available for monitoring usb -* connections: -* -* /sys/devices/virtual/switch/usb_connected/state -* /sys/devices/virtual/switch/usb_configuration/state -* -* Under gingerbread, only the usb_configuration seems to be available. -* Starting with honeycomb, usb_connected was also added. -* -* When a cable insertion/removal occurs, then a uevent similar to the -* following will be generted: -* -* change@/devices/virtual/switch/usb_configuration -* ACTION=change -* DEVPATH=/devices/virtual/switch/usb_configuration -* SUBSYSTEM=switch -* SWITCH_NAME=usb_configuration -* SWITCH_STATE=0 -* SEQNUM=5038 -* -* SWITCH_STATE will be 0 after a removal and 1 after an insertion -* -**************************************************************************/ - -#define USB_CONFIGURATION_SWITCH_NAME NS_LITERAL_STRING("usb_configuration") - -#define GB_SYS_UMS_ENABLE "/sys/devices/virtual/usb_composite/usb_mass_storage/enable" -#define GB_SYS_USB_CONFIGURED "/sys/devices/virtual/switch/usb_configuration/state" - -#define ICS_SYS_USB_FUNCTIONS "/sys/devices/virtual/android_usb/android0/functions" -#define ICS_SYS_UMS_DIRECTORY "/sys/devices/virtual/android_usb/android0/f_mass_storage" -#define ICS_SYS_MTP_DIRECTORY "/sys/devices/virtual/android_usb/android0/f_mtp" -#define ICS_SYS_USB_STATE "/sys/devices/virtual/android_usb/android0/state" - -#undef USE_DEBUG // MozMtpDatabase.h also defines USE_DEBUG -#define USE_DEBUG 0 - -#undef LOG -#undef LOGW -#undef ERR -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "AutoMounter", ## args) -#define LOGW(args...) __android_log_print(ANDROID_LOG_WARN, "AutoMounter", ## args) -#define ERR(args...) __android_log_print(ANDROID_LOG_ERROR, "AutoMounter", ## args) - -#undef DBG -#if USE_DEBUG -#define DBG(args...) __android_log_print(ANDROID_LOG_DEBUG, "AutoMounter" , ## args) -#else -#define DBG(args...) -#endif - -namespace mozilla { -namespace system { - -#define SYS_USB_CONFIG "sys.usb.config" -#define PERSIST_SYS_USB_CONFIG "persist.sys.usb.config" - -#define USB_FUNC_ADB "adb" -#define USB_FUNC_MTP "mtp" -#define USB_FUNC_NONE "none" -#define USB_FUNC_RNDIS "rndis" -#define USB_FUNC_UMS "mass_storage" -#define USB_FUNC_DEFAULT "default" - -class AutoMounter; - -static void SetAutoMounterStatus(int32_t aStatus); - -/***************************************************************************/ - -inline const char* SwitchStateStr(const hal::SwitchEvent& aEvent) -{ - return aEvent.status() == hal::SWITCH_STATE_ON ? "plugged" : "unplugged"; -} - -/***************************************************************************/ - -static bool -IsUsbCablePluggedIn() -{ -#if 0 - // Use this code when bug 745078 gets fixed (or use whatever the - // appropriate method is) - return GetCurrentSwitchEvent(SWITCH_USB) == hal::SWITCH_STATE_ON; -#else - // Until then, just go read the file directly - if (access(ICS_SYS_USB_STATE, F_OK) == 0) { - char usbState[20]; - if (ReadSysFile(ICS_SYS_USB_STATE, usbState, sizeof(usbState))) { - DBG("IsUsbCablePluggedIn: state = '%s'", usbState); - return strcmp(usbState, "CONFIGURED") == 0 || - strcmp(usbState, "CONNECTED") == 0; - } - ERR("Error reading file '%s': %s", ICS_SYS_USB_STATE, strerror(errno)); - return false; - } - bool configured; - if (ReadSysFile(GB_SYS_USB_CONFIGURED, &configured)) { - return configured; - } - ERR("Error reading file '%s': %s", GB_SYS_USB_CONFIGURED, strerror(errno)); - return false; -#endif -} - -static bool -IsUsbConfigured() -{ - if (access(ICS_SYS_USB_STATE, F_OK) == 0) { - char usbState[20]; - if (ReadSysFile(ICS_SYS_USB_STATE, usbState, sizeof(usbState))) { - DBG("IsUsbConfigured: state = '%s'", usbState); - return strcmp(usbState, "CONFIGURED") == 0; - } - ERR("Error reading file '%s': %s", ICS_SYS_USB_STATE, strerror(errno)); - return false; - } - bool configured; - if (ReadSysFile(GB_SYS_USB_CONFIGURED, &configured)) { - return configured; - } - ERR("Error reading file '%s': %s", GB_SYS_USB_CONFIGURED, strerror(errno)); - return false; -} - -/***************************************************************************/ - -// The AutoVolumeManagerStateObserver allows the AutoMounter to know when -// the volume manager changes state (i.e. it has finished initialization) -class AutoVolumeManagerStateObserver : public VolumeManager::StateObserver -{ -public: - virtual void Notify(const VolumeManager::StateChangedEvent& aEvent); -}; - -// The AutoVolumeEventObserver allows the AutoMounter to know about card -// insertion and removal, as well as state changes in the volume. -class AutoVolumeEventObserver : public Volume::EventObserver -{ -public: - virtual void Notify(Volume* const& aEvent); -}; - -class AutoMounterResponseCallback : public VolumeResponseCallback -{ -public: - AutoMounterResponseCallback() - : mErrorCount(0) - { - } - -protected: - virtual void ResponseReceived(const VolumeCommand* aCommand); - -private: - const static int kMaxErrorCount = 3; // Max number of errors before we give up - - int mErrorCount; -}; - -/***************************************************************************/ - -class AutoMounter -{ -public: - NS_INLINE_DECL_REFCOUNTING(AutoMounter) - - typedef nsTArray<RefPtr<Volume>> VolumeArray; - - AutoMounter() - : mState(STATE_IDLE), - mResponseCallback(new AutoMounterResponseCallback), - mMode(AUTOMOUNTER_DISABLE) - { - VolumeManager::RegisterStateObserver(&mVolumeManagerStateObserver); - Volume::RegisterVolumeObserver(&mVolumeEventObserver, "AutoMounter"); - - // It's possible that the VolumeManager is already in the READY state, - // so we call CheckVolumeSettings here to cover that case. Otherwise, - // we'll pick it up when the VolumeManage state changes to VOLUMES_READY. - CheckVolumeSettings(); - - DBG("Calling UpdateState from constructor"); - UpdateState(); - } - - void CheckVolumeSettings() - { - if (VolumeManager::State() != VolumeManager::VOLUMES_READY) { - DBG("CheckVolumeSettings: VolumeManager is NOT READY yet"); - return; - } - DBG("CheckVolumeSettings: VolumeManager is READY"); - - // The VolumeManager knows about all of the volumes from vold. We now - // know the names of all of the volumes, so we can find out what the - // initial sharing settings are set to. - - VolumeManager::VolumeArray::size_type numVolumes = VolumeManager::NumVolumes(); - VolumeManager::VolumeArray::index_type i; - for (i = 0; i < numVolumes; i++) { - RefPtr<Volume> vol = VolumeManager::GetVolume(i); - if (vol) { - // We need to pick up the intial value of the - // ums.volume.NAME.enabled setting. - AutoMounterSetting::CheckVolumeSettings(vol->Name()); - - // Note: eventually CheckVolumeSettings will call - // AutoMounter::SetSharingMode, which will in turn call - // UpdateState if needed. - } - } - } - - void UpdateState(); - void GetStatus(bool& umsAvail, bool& umsConfigured, bool& umsEnabled, bool& mtpAvail, - bool& mtpConfigured, bool& mtpEnabled, bool& rndisConfigured); - - nsresult Dump(nsACString& desc); - - void ConfigureUsbFunction(const char* aUsbFunc); - - bool StartMtpServer(); - void StopMtpServer(); - - void StartUmsSharing(); - void StopUmsSharing(); - - - const char* ModeStr(int32_t aMode) - { - switch (aMode) { - case AUTOMOUNTER_DISABLE: return "Disable"; - case AUTOMOUNTER_ENABLE_UMS: return "Enable-UMS"; - case AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED: return "DisableWhenUnplugged"; - case AUTOMOUNTER_ENABLE_MTP: return "Enable-MTP"; - } - return "??? Unknown ???"; - } - - bool IsModeEnabled(int32_t aMode) - { - return aMode == AUTOMOUNTER_ENABLE_MTP || - aMode == AUTOMOUNTER_ENABLE_UMS; - } - - void SetMode(int32_t aMode) - { - if ((aMode == AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED) && - (mMode == AUTOMOUNTER_DISABLE)) { - // If it's already disabled, then leave it as disabled. - // AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED implies "enabled until unplugged" - aMode = AUTOMOUNTER_DISABLE; - } - - if (aMode == AUTOMOUNTER_DISABLE && - mMode == AUTOMOUNTER_ENABLE_UMS && IsUsbCablePluggedIn()) { - // On many devices (esp non-Samsung), we can't force the disable, so we - // need to defer until the USB cable is actually unplugged. - // See bug 777043. - // - // Otherwise our attempt to disable it will fail, and we'll wind up in a bad - // state where the AutoMounter thinks that Sharing has been turned off, but - // the files are actually still being Shared because the attempt to unshare - // failed. - LOG("Attempting to disable UMS. Deferring until USB cable is unplugged."); - aMode = AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED; - } - - if (aMode != mMode) { - LOG("Changing mode from '%s' to '%s'", ModeStr(mMode), ModeStr(aMode)); - mMode = aMode; - DBG("Calling UpdateState due to mode set to %d", mMode); - UpdateState(); - } - } - - void SetSharingMode(const nsACString& aVolumeName, bool aAllowSharing) - { - RefPtr<Volume> vol = VolumeManager::FindVolumeByName(aVolumeName); - if (!vol) { - return; - } - if (vol->IsSharingEnabled() == aAllowSharing) { - return; - } - vol->SetUnmountRequested(false); - vol->SetMountRequested(false); - vol->SetSharingEnabled(aAllowSharing); - DBG("Calling UpdateState due to volume %s sharing set to %d", - vol->NameStr(), (int)aAllowSharing); - UpdateState(); - } - - void FormatVolume(const nsACString& aVolumeName) - { - RefPtr<Volume> vol = VolumeManager::FindVolumeByName(aVolumeName); - if (!vol) { - return; - } - if (vol->IsFormatRequested()) { - return; - } - vol->SetUnmountRequested(false); - vol->SetMountRequested(false); - vol->SetFormatRequested(true); - DBG("Calling UpdateState due to volume %s formatting set to %d", - vol->NameStr(), (int)vol->IsFormatRequested()); - UpdateState(); - } - - void MountVolume(const nsACString& aVolumeName) - { - RefPtr<Volume> vol = VolumeManager::FindVolumeByName(aVolumeName); - if (!vol) { - return; - } - vol->SetUnmountRequested(false); - if (vol->IsMountRequested() || vol->mState == nsIVolume::STATE_MOUNTED) { - return; - } - vol->SetMountRequested(true); - DBG("Calling UpdateState due to volume %s mounting set to %d", - vol->NameStr(), (int)vol->IsMountRequested()); - UpdateState(); - } - - void UnmountVolume(const nsACString& aVolumeName) - { - RefPtr<Volume> vol = VolumeManager::FindVolumeByName(aVolumeName); - if (!vol) { - return; - } - if (vol->IsUnmountRequested()) { - return; - } - vol->SetMountRequested(false); - vol->SetUnmountRequested(true); - DBG("Calling UpdateState due to volume %s unmounting set to %d", - vol->NameStr(), (int)vol->IsUnmountRequested()); - UpdateState(); - } - -protected: - ~AutoMounter() - { - Volume::UnregisterVolumeObserver(&mVolumeEventObserver, "AutoMounter"); - VolumeManager::UnregisterStateObserver(&mVolumeManagerStateObserver); - } - -private: - - enum STATE - { - // IDLE - Nothing is being shared - STATE_IDLE, - - // We've detected that conditions are right to enable mtp. So we've - // set sys.usb.config to include mtp, and we're waiting for the USB - // subsystem to be "configured". Once mtp shows up in - // then we know - // that its been configured and we can open /dev/mtp_usb - STATE_MTP_CONFIGURING, - - // mtp has been configured (i.e. mtp now shows up in - // /sys/devices/virtual/android_usb/android0/functions so we can start - // the mtp server. - STATE_MTP_STARTED, - - // The mtp server has reported sessionStarted. We'll leave this state - // when we receive sessionEnded. - STATE_MTP_CONNECTED, - - // We've added mass_storage (aka UMS) to sys.usb.config and we're waiting for - // mass_storage to appear in /sys/devices/virtual/android_usb/android0/functions - STATE_UMS_CONFIGURING, - - // mass_storage has been configured and we can start sharing once the user - // enables it. - STATE_UMS_CONFIGURED, - - // USB Tethering is enabled - STATE_RNDIS_CONFIGURED, - }; - - const char *StateStr(STATE aState) - { - switch (aState) { - case STATE_IDLE: return "IDLE"; - case STATE_MTP_CONFIGURING: return "MTP_CONFIGURING"; - case STATE_MTP_CONNECTED: return "MTP_CONNECTED"; - case STATE_MTP_STARTED: return "MTP_STARTED"; - case STATE_UMS_CONFIGURING: return "UMS_CONFIGURING"; - case STATE_UMS_CONFIGURED: return "UMS_CONFIGURED"; - case STATE_RNDIS_CONFIGURED: return "RNDIS_CONFIGURED"; - } - return "STATE_???"; - } - - void SetState(STATE aState) - { - const char *oldStateStr = StateStr(mState); - mState = aState; - const char *newStateStr = StateStr(mState); - LOG("AutoMounter state changed from %s to %s", oldStateStr, newStateStr); - } - - STATE mState; - - AutoVolumeEventObserver mVolumeEventObserver; - AutoVolumeManagerStateObserver mVolumeManagerStateObserver; - RefPtr<VolumeResponseCallback> mResponseCallback; - int32_t mMode; - MozMtpStorage::Array mMozMtpStorage; -}; - -static StaticRefPtr<AutoMounter> sAutoMounter; -static StaticRefPtr<MozMtpServer> sMozMtpServer; - -// The following is for status reporter -enum STATE_REPORTER_STATE -{ - REPORTER_UNREGISTERED, - REPORTER_REGISTERED -}; - -static int status_reporter_progress = REPORTER_UNREGISTERED; -nsresult getState(nsACString &desc) -{ - sAutoMounter->Dump(desc); - return NS_OK; -} -NS_STATUS_REPORTER_IMPLEMENT(AutoMounter, "AutoMounter", getState); - -/***************************************************************************/ - -void -AutoVolumeManagerStateObserver::Notify(const VolumeManager::StateChangedEvent &) -{ - LOG("VolumeManager state changed event: %s", VolumeManager::StateStr()); - - if (!sAutoMounter) { - return; - } - - // In the event that the VolumeManager just entered the VOLUMES_READY state, - // we call CheckVolumeSettings here (it's possible that this method never - // gets called if the VolumeManager was already in the VOLUMES_READY state - // by the time the AutoMounter was constructed). - sAutoMounter->CheckVolumeSettings(); - - DBG("Calling UpdateState due to VolumeManagerStateObserver"); - sAutoMounter->UpdateState(); -} - -void -AutoVolumeEventObserver::Notify(Volume * const &) -{ - if (!sAutoMounter) { - return; - } - DBG("Calling UpdateState due to VolumeEventStateObserver"); - sAutoMounter->UpdateState(); -} - -void -AutoMounterResponseCallback::ResponseReceived(const VolumeCommand* aCommand) -{ - - if (WasSuccessful()) { - DBG("Calling UpdateState due to Volume::OnSuccess"); - mErrorCount = 0; - sAutoMounter->UpdateState(); - return; - } - ERR("Command '%s' failed: %d '%s'", - aCommand->CmdStr(), ResponseCode(), ResponseStr().get()); - - if (++mErrorCount < kMaxErrorCount) { - DBG("Calling UpdateState due to VolumeResponseCallback::OnError"); - sAutoMounter->UpdateState(); - } -} - -static bool -IsUsbFunctionEnabled(const char* aConfig, const char* aUsbFunc) -{ - nsAutoCString config(aConfig); - nsCCharSeparatedTokenizer tokenizer(config, ','); - - while (tokenizer.hasMoreTokens()) { - nsAutoCString token(tokenizer.nextToken()); - if (token.Equals(aUsbFunc)) { - DBG("IsUsbFunctionEnabled('%s', '%s'): returning true", aConfig, aUsbFunc); - return true; - } - } - DBG("IsUsbFunctionEnabled('%s', '%s'): returning false", aConfig, aUsbFunc); - return false; -} - -static void -SetUsbFunction(const char* aUsbFunc) -{ - char oldSysUsbConfig[PROPERTY_VALUE_MAX]; - property_get(SYS_USB_CONFIG, oldSysUsbConfig, ""); - - if (strcmp(oldSysUsbConfig, USB_FUNC_NONE) == 0) { - // It's quite possible that sys.usb.config may have the value "none". We - // convert that to an empty string here, and at the end we convert the - // empty string back to "none". - oldSysUsbConfig[0] = '\0'; - } - - if (IsUsbFunctionEnabled(oldSysUsbConfig, aUsbFunc)) { - // The function is already configured. Nothing else to do. - DBG("SetUsbFunction('%s') - already set - nothing to do", aUsbFunc); - return; - } - - char newSysUsbConfig[PROPERTY_VALUE_MAX]; - - if (strcmp(aUsbFunc, USB_FUNC_MTP) == 0) { - // We're enabling MTP. For this we'll wind up using mtp, or mtp,adb - strlcpy(newSysUsbConfig, USB_FUNC_MTP, sizeof(newSysUsbConfig)); - } else if (strcmp(aUsbFunc, USB_FUNC_UMS) == 0) { - // We're enabling UMS. For this we make the assumption that the persisted - // property has mass_storage enabled. - property_get(PERSIST_SYS_USB_CONFIG, newSysUsbConfig, ""); - } else if (strcmp(aUsbFunc, USB_FUNC_DEFAULT) == 0) { - // Set the property as PERSIST_SYS_USB_CONFIG - property_get(PERSIST_SYS_USB_CONFIG, newSysUsbConfig, ""); - } else { - printf_stderr("AutoMounter::SetUsbFunction Unrecognized aUsbFunc '%s'\n", aUsbFunc); - MOZ_ASSERT(0); - return; - } - - // Make sure the new value that we write into sys.usb.config keeps the adb - // (or non-adb) of the current string. - - if (IsUsbFunctionEnabled(oldSysUsbConfig, USB_FUNC_ADB)) { - // ADB was turned on - keep it on. - if (!IsUsbFunctionEnabled(newSysUsbConfig, USB_FUNC_ADB)) { - // Add adb to the new string - strlcat(newSysUsbConfig, ",", sizeof(newSysUsbConfig)); - strlcat(newSysUsbConfig, USB_FUNC_ADB, sizeof(newSysUsbConfig)); - } - } else { - // ADB was turned off - keep it off - if (IsUsbFunctionEnabled(newSysUsbConfig, USB_FUNC_ADB)) { - // Remove ADB from the new string. - if (strcmp(newSysUsbConfig, USB_FUNC_ADB) == 0) { - newSysUsbConfig[0] = '\0'; - } else { - nsAutoCString withoutAdb(newSysUsbConfig); - withoutAdb.ReplaceSubstring( "," USB_FUNC_ADB, ""); - strlcpy(newSysUsbConfig, withoutAdb.get(), sizeof(newSysUsbConfig)); - } - } - } - - // If the persisted function didn't have mass_storage (this happens on - // the nexus 4/5, then we can get to here and have oldSysUsbConfig equal - // to newSysUsbConfig. So we need to check for that. - - if (strcmp(oldSysUsbConfig, newSysUsbConfig) == 0) { - DBG("SetUsbFunction('%s') %s is already set to '%s' - nothing to do", - aUsbFunc, SYS_USB_CONFIG, newSysUsbConfig); - return; - } - - if (newSysUsbConfig[0] == '\0') { - // Convert the empty string back to the string "none" - strlcpy(newSysUsbConfig, USB_FUNC_NONE, sizeof(newSysUsbConfig)); - } - LOG("SetUsbFunction(%s) %s from '%s' to '%s'", aUsbFunc, SYS_USB_CONFIG, - oldSysUsbConfig, newSysUsbConfig); - property_set(SYS_USB_CONFIG, newSysUsbConfig); -} - -bool -AutoMounter::StartMtpServer() -{ - if (sMozMtpServer) { - // Mtp Server is already running - nothing to do - return true; - } - LOG("Starting MtpServer"); - - // For debugging, Change the #if 0 to #if 1, and then attach gdb during - // the 5 second interval below. Otherwise, configuring MTP will cause adb - // (and thus gdb) to get bounced. -#if 0 - LOG("Sleeping"); - PRTime now = PR_Now(); - PRTime stopTime = now + 5000000; - while (PR_Now() < stopTime) { - LOG("Sleeping..."); - sleep(1); - } - LOG("Sleep done"); -#endif - - sMozMtpServer = new MozMtpServer(); - if (!sMozMtpServer->Init()) { - sMozMtpServer = nullptr; - return false; - } - - VolumeArray::index_type volIndex; - VolumeArray::size_type numVolumes = VolumeManager::NumVolumes(); - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr<Volume> vol = VolumeManager::GetVolume(volIndex); - RefPtr<MozMtpStorage> storage = new MozMtpStorage(vol, sMozMtpServer); - mMozMtpStorage.AppendElement(storage); - } - - sMozMtpServer->Run(); - return true; -} - -void -AutoMounter::StopMtpServer() -{ - LOG("Stopping MtpServer"); - - mMozMtpStorage.Clear(); - sMozMtpServer = nullptr; -} - -/***************************************************************************/ - -void -AutoMounter::UpdateState() -{ - static bool inUpdateState = false; - if (inUpdateState) { - // When UpdateState calls SetISharing, this causes a volume state - // change to occur, which would normally cause UpdateState to be called - // again. We want the volume state change to go out (so that device - // storage will see the change in sharing state), but since we're - // already in UpdateState we just want to prevent recursion from screwing - // things up. - return; - } - AutoRestore<bool> inUpdateStateDetector(inUpdateState); - inUpdateState = true; - - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - // If the following preconditions are met: - // - UMS is available (i.e. compiled into the kernel) - // - UMS is enabled - // - AutoMounter is enabled - // - USB cable is plugged in - // then we will try to unmount and share - // otherwise we will try to unshare and mount. - - if (VolumeManager::State() != VolumeManager::VOLUMES_READY) { - // The volume manager isn't in a ready state, so there - // isn't anything else that we can do. - LOG("UpdateState: VolumeManager not ready yet"); - return; - } - - if (mResponseCallback->IsPending()) { - // We only deal with one outstanding volume command at a time, - // so we need to wait for it to finish. - return; - } - - // Calling setprop sys.usb.config mtp,adb (or adding mass_storage) will - // cause /sys/devices/virtual/android_usb/android0/state to go: - // CONFIGURED -> DISCONNECTED -> CONNECTED -> CONFIGURED - // - // Since IsUsbCablePluggedIn returns state == CONFIGURED, it will look - // like a cable pull and replugin. - bool umsAvail, umsConfigured, umsEnabled; - bool mtpAvail, mtpConfigured, mtpEnabled; - bool rndisConfigured; - bool usbCablePluggedIn = IsUsbCablePluggedIn(); - GetStatus(umsAvail, umsConfigured, umsEnabled, mtpAvail, - mtpConfigured, mtpEnabled, rndisConfigured); - bool enabled = mtpEnabled || umsEnabled; - - if (mMode == AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED) { - // DISABLE_WHEN_UNPLUGGED implies already enabled. - enabled = usbCablePluggedIn; - if (!usbCablePluggedIn) { - mMode = AUTOMOUNTER_DISABLE; - mtpEnabled = false; - umsEnabled = false; - } - } - - DBG("UpdateState: ums:A%dC%dE%d mtp:A%dC%dE%d rndis:%d mode:%d usb:%d mState:%s", - umsAvail, umsConfigured, umsEnabled, - mtpAvail, mtpConfigured, mtpEnabled, rndisConfigured, - mMode, usbCablePluggedIn, StateStr(mState)); - - switch (mState) { - - case STATE_IDLE: - if (!usbCablePluggedIn) { - // Stay in the IDLE state. We'll get a CONNECTED or CONFIGURED - // UEvent when the usb cable is plugged in. - break; - } - if (rndisConfigured) { - // USB Tethering uses RNDIS. We'll just wait until its turned off. - SetState(STATE_RNDIS_CONFIGURED); - break; - } - if (mtpEnabled) { - if (mtpConfigured) { - // The USB layer has already been configured. Now we can go ahead - // and start the MTP server. This particular codepath will not - // normally be taken, but it could happen if you stop and restart - // b2g while sys.usb.config is set to enable mtp. - if (StartMtpServer()) { - SetState(STATE_MTP_STARTED); - } else { - if (umsAvail) { - // Unable to start MTP. Go back to UMS. - LOG("UpdateState: StartMtpServer failed, switch to UMS"); - SetUsbFunction(USB_FUNC_UMS); - SetState(STATE_UMS_CONFIGURING); - } else { - LOG("UpdateState: StartMtpServer failed, keep idle state"); - SetUsbFunction(USB_FUNC_DEFAULT); - } - } - } else { - // We need to configure USB to use mtp. Wait for it to be configured - // before we start the MTP server. - SetUsbFunction(USB_FUNC_MTP); - SetState(STATE_MTP_CONFIGURING); - } - } else if (umsConfigured) { - // UMS is already configured. - SetState(STATE_UMS_CONFIGURED); - } else if (umsAvail) { - // We do this whether or not UMS is enabled. With UMS, it's the - // sharing of the volume which is significant. What is important - // is that we don't leave it in MTP mode when MTP isn't enabled. - SetUsbFunction(USB_FUNC_UMS); - SetState(STATE_UMS_CONFIGURING); - } - break; - - case STATE_MTP_CONFIGURING: - // While configuring, the USB configuration state will change from - // CONFIGURED -> CONNECTED -> DISCONNECTED -> CONNECTED -> CONFIGURED - // so we don't check for cable unplugged here. - if (mtpEnabled && mtpConfigured) { - // The USB layer has been configured. Now we can go ahead and start - // the MTP server. - if (StartMtpServer()) { - SetState(STATE_MTP_STARTED); - } else { - // Unable to start MTP. Go back to UMS. - SetUsbFunction(USB_FUNC_UMS); - SetState(STATE_UMS_CONFIGURING); - } - break; - } - if (rndisConfigured) { - SetState(STATE_RNDIS_CONFIGURED); - break; - } - break; - - case STATE_MTP_STARTED: - if (usbCablePluggedIn && mtpConfigured && mtpEnabled) { - // Everything is still good. Leave the MTP server running - break; - } - DBG("STATE_MTP_STARTED: About to StopMtpServer " - "mtpConfigured = %d mtpEnabled = %d usbCablePluggedIn: %d", - mtpConfigured, mtpEnabled, usbCablePluggedIn); - StopMtpServer(); - if (rndisConfigured) { - SetState(STATE_RNDIS_CONFIGURED); - break; - } - if (umsAvail) { - // Switch back to UMS - SetUsbFunction(USB_FUNC_UMS); - SetState(STATE_UMS_CONFIGURING); - break; - } - - // if ums/rndis is not available and mtp is disable, - // restore the usb function as PERSIST_SYS_USB_CONFIG. - SetUsbFunction(USB_FUNC_DEFAULT); - SetState(STATE_IDLE); - break; - - case STATE_UMS_CONFIGURING: - if (mtpEnabled) { - // MTP was enabled. Start reconfiguring. - SetState(STATE_MTP_CONFIGURING); - SetUsbFunction(USB_FUNC_MTP); - break; - } - if (rndisConfigured) { - SetState(STATE_RNDIS_CONFIGURED); - break; - } - // While configuring, the USB configuration state will change from - // CONFIGURED -> CONNECTED -> DISCONNECTED -> CONNECTED -> CONFIGURED - // so we don't check for cable unplugged here. However, having said - // that, we'll often sit in this state while the cable is unplugged, - // since we might not get any events until the cable gets plugged back - // in. This is why we need to check for mtpEnabled once we get the - // configured event. - if (umsConfigured) { - SetState(STATE_UMS_CONFIGURED); - } - break; - - case STATE_UMS_CONFIGURED: - if (usbCablePluggedIn) { - if (mtpEnabled) { - // MTP was enabled. Start reconfiguring. - SetState(STATE_MTP_CONFIGURING); - SetUsbFunction(USB_FUNC_MTP); - break; - } - if (umsConfigured && umsEnabled) { - // This is the normal state when UMS is enabled. - break; - } - } - if (rndisConfigured) { - SetState(STATE_RNDIS_CONFIGURED); - break; - } - SetState(STATE_IDLE); - break; - - case STATE_RNDIS_CONFIGURED: - if (usbCablePluggedIn && rndisConfigured) { - // Normal state when RNDIS is enabled. - break; - } - SetState(STATE_IDLE); - break; - - default: - SetState(STATE_IDLE); - break; - } - - bool tryToShare = umsEnabled && usbCablePluggedIn; - LOG("UpdateState: ums:A%dC%dE%d mtp:A%dC%dE%d mode:%d usb:%d tryToShare:%d state:%s", - umsAvail, umsConfigured, umsEnabled, - mtpAvail, mtpConfigured, mtpEnabled, - mMode, usbCablePluggedIn, tryToShare, StateStr(mState)); - - bool filesOpen = false; - static unsigned filesOpenDelayCount = 0; - VolumeArray::index_type volIndex; - VolumeArray::size_type numVolumes = VolumeManager::NumVolumes(); - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr<Volume> vol = VolumeManager::GetVolume(volIndex); - Volume::STATE volState = vol->State(); - - if (vol->State() == nsIVolume::STATE_MOUNTED) { - LOG("UpdateState: Volume %s is %s and %s @ %s gen %d locked %d sharing %s", - vol->NameStr(), vol->StateStr(), - vol->MediaPresent() ? "inserted" : "missing", - vol->MountPoint().get(), vol->MountGeneration(), - (int)vol->IsMountLocked(), - vol->CanBeShared() ? (vol->IsSharingEnabled() ? - (vol->IsSharing() ? "en-y" : "en-n") : "dis") : "x"); - if (vol->IsSharing() && !usbCablePluggedIn) { - // We call SetIsSharing(true) below to indicate intent to share. This - // causes a state change which notifys apps, and they'll close any - // open files, which will initiate the change away from the mounted - // state and into the sharing state. Normally, when the volume - // transitions back to the mounted state, then vol->mIsSharing gets set - // to false. However, if the user pulls the USB cable before we - // actually start sharing, then the volume never actually leaves - // the mounted state (and hence never transitions from - // sharing -> mounted), and mIsSharing never gets set back to false. - // So we clear mIsSharing here. - vol->SetIsSharing(false); - } - } else { - LOG("UpdateState: Volume %s is %s and %s", vol->NameStr(), vol->StateStr(), - vol->MediaPresent() ? "inserted" : "missing"); - } - if (!vol->MediaPresent()) { - // No media - nothing we can do - continue; - } - - if (vol->State() == nsIVolume::STATE_CHECKMNT) { - // vold reports the volume is "Mounted". Need to check if the volume is - // accessible by statfs(). Once it can be accessed, set the volume as - // STATE_MOUNTED, otherwise, post a delay task of UpdateState to check it - // again. - struct statfs fsbuf; - int rc = MOZ_TEMP_FAILURE_RETRY(statfs(vol->MountPoint().get(), &fsbuf)); - if (rc == -1) { - // statfs() failed. Stay in STATE_CHECKMNT. Any failures here - // are probably non-recoverable, so we need to wait until - // something else changes the state back to IDLE/UNMOUNTED, etc. - ERR("statfs failed for '%s': errno = %d (%s)", vol->NameStr(), errno, strerror(errno)); - continue; - } - static int delay = 250; - if (fsbuf.f_blocks == 0) { - if (delay <= 4000) { - LOG("UpdateState: Volume '%s' is inaccessible, checking again in %d msec", vol->NameStr(), delay); - MessageLoopForIO::current()-> - PostDelayedTask(NewRunnableMethod(this, &AutoMounter::UpdateState), - delay); - delay *= 2; - } else { - LOG("UpdateState: Volume '%s' is inaccessible, giving up", vol->NameStr()); - } - continue; - } else { - delay = 250; - vol->SetState(nsIVolume::STATE_MOUNTED); - } - } - - if ((tryToShare && vol->IsSharingEnabled()) || - vol->IsFormatRequested() || - vol->IsUnmountRequested()) { - switch (volState) { - // We're going to try to unmount the volume - case nsIVolume::STATE_MOUNTED: { - if (vol->IsMountLocked()) { - // The volume is currently locked, so leave it in the mounted - // state. - LOGW("UpdateState: Mounted volume %s is locked, not sharing or formatting", - vol->NameStr()); - break; - } - - // Mark the volume as if we've started sharing/formatting/unmmounting. - // This will cause apps which watch device storage notifications to see - // the volume go into the different state, and prompt them to close any - // open files that they might have. - if (tryToShare && vol->IsSharingEnabled()) { - vol->SetIsSharing(true); - } else if (vol->IsFormatRequested()){ - vol->SetIsFormatting(true); - } else if (vol->IsUnmountRequested()){ - vol->SetIsUnmounting(true); - } - - // Check to see if there are any open files on the volume and - // don't initiate the unmount while there are open files. - OpenFileFinder::Info fileInfo; - OpenFileFinder fileFinder(vol->MountPoint()); - if (fileFinder.First(&fileInfo)) { - LOGW("The following files are open under '%s'", - vol->MountPoint().get()); - do { - LOGW(" PID: %d file: '%s' app: '%s' comm: '%s' exe: '%s'\n", - fileInfo.mPid, - fileInfo.mFileName.get(), - fileInfo.mAppName.get(), - fileInfo.mComm.get(), - fileInfo.mExe.get()); - } while (fileFinder.Next(&fileInfo)); - LOGW("UpdateState: Mounted volume %s has open files, not sharing or formatting", - vol->NameStr()); - - // Check again in a few seconds to see if the files are closed. - // Since we're trying to share the volume, this implies that we're - // plugged into the PC via USB and this in turn implies that the - // battery is charging, so we don't need to be too concerned about - // wasting battery here. - // - // If we just detected that there were files open, then we use - // a short timer. We will have told the apps that we're trying - // trying to share, and they'll be closing their files. This makes - // the sharing more responsive. If after a few seconds, the apps - // haven't closed their files, then we back off. - - int delay = 1000; - if (filesOpenDelayCount > 10) { - delay = 5000; - } - MessageLoopForIO::current()-> - PostDelayedTask(NewRunnableMethod(this, &AutoMounter::UpdateState), - delay); - filesOpen = true; - break; - } - - // Volume is mounted, we need to unmount before - // we can share. - LOG("UpdateState: Unmounting %s", vol->NameStr()); - vol->StartUnmount(mResponseCallback); - return; // UpdateState will be called again when the Unmount command completes - } - case nsIVolume::STATE_IDLE: - case nsIVolume::STATE_MOUNT_FAIL: { - LOG("UpdateState: Volume %s is %s", vol->NameStr(), vol->StateStr()); - if (vol->IsFormatting() && !vol->IsFormatRequested()) { - vol->SetFormatRequested(false); - if (!(tryToShare && vol->IsSharingEnabled()) && volState == nsIVolume::STATE_IDLE) { - LOG("UpdateState: Mounting %s", vol->NameStr()); - vol->StartMount(mResponseCallback); - break; - } - } - - // If there are format and share requests in the same time, - // we should do format first then share. - if (vol->IsFormatRequested()) { - // Volume is unmounted. We can go ahead and format. - LOG("UpdateState: Formatting %s", vol->NameStr()); - vol->StartFormat(mResponseCallback); - } else if (tryToShare && vol->IsSharingEnabled() && volState == nsIVolume::STATE_IDLE) { - // Volume is unmounted. We can go ahead and share. - LOG("UpdateState: Sharing %s", vol->NameStr()); - vol->StartShare(mResponseCallback); - } - return; // UpdateState will be called again when the Share/Format command completes - } - default: { - // Not in a state that we can do anything about. - break; - } - } - } else { - // We're going to try and unshare and remount the volumes - switch (volState) { - case nsIVolume::STATE_SHARED: { - // Volume is shared. We can go ahead and unshare. - LOG("UpdateState: Unsharing %s", vol->NameStr()); - vol->StartUnshare(mResponseCallback); - return; // UpdateState will be called again when the Unshare command completes - } - case nsIVolume::STATE_IDLE: { - if (!vol->IsUnmountRequested()) { - // Volume is unmounted and mount-requested, try to mount. - - LOG("UpdateState: Mounting %s", vol->NameStr()); - vol->StartMount(mResponseCallback); - } - return; // UpdateState will be called again when Mount command completes - } - default: { - // Not in a state that we can do anything about. - break; - } - } - } - } - - int32_t status = AUTOMOUNTER_STATUS_DISABLED; - if (filesOpen) { - filesOpenDelayCount++; - status = AUTOMOUNTER_STATUS_FILES_OPEN; - } else if (enabled) { - filesOpenDelayCount = 0; - status = AUTOMOUNTER_STATUS_ENABLED; - } - SetAutoMounterStatus(status); -} - -/***************************************************************************/ - -void AutoMounter::GetStatus(bool& umsAvail, bool& umsConfigured, bool& umsEnabled, - bool& mtpAvail, bool& mtpConfigured, bool& mtpEnabled, - bool& rndisConfigured) -{ - umsAvail = false; - umsConfigured = false; - umsEnabled = false; - mtpAvail = false; - mtpConfigured = false; - mtpEnabled = false; - rndisConfigured = false; - - if (access(ICS_SYS_USB_FUNCTIONS, F_OK) != 0) { - return; - } - - char functionsStr[60]; - if (!ReadSysFile(ICS_SYS_USB_FUNCTIONS, functionsStr, sizeof(functionsStr))) { - ERR("Error reading file '%s': %s", ICS_SYS_USB_FUNCTIONS, strerror(errno)); - functionsStr[0] = '\0'; - } - DBG("GetStatus: USB functions: '%s'", functionsStr); - - bool usbConfigured = IsUsbConfigured(); - - // On the Nexus 4/5, it advertises that the UMS usb function is available, - // but we have a further requirement that mass_storage be in the - // persist.sys.usb.config property. - char persistSysUsbConfig[PROPERTY_VALUE_MAX]; - property_get(PERSIST_SYS_USB_CONFIG, persistSysUsbConfig, ""); - if (IsUsbFunctionEnabled(persistSysUsbConfig, USB_FUNC_UMS)) { - umsAvail = (access(ICS_SYS_UMS_DIRECTORY, F_OK) == 0); - } - if (umsAvail) { - umsConfigured = usbConfigured && strstr(functionsStr, USB_FUNC_UMS) != nullptr; - umsEnabled = (mMode == AUTOMOUNTER_ENABLE_UMS) || - ((mMode == AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED) && umsConfigured); - } else { - umsConfigured = false; - umsEnabled = false; - } - - mtpAvail = (access(ICS_SYS_MTP_DIRECTORY, F_OK) == 0); - if (mtpAvail) { - mtpConfigured = usbConfigured && strstr(functionsStr, USB_FUNC_MTP) != nullptr; - mtpEnabled = (mMode == AUTOMOUNTER_ENABLE_MTP) || - ((mMode == AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED) && mtpConfigured); - } else { - mtpConfigured = false; - mtpEnabled = false; - } - - rndisConfigured = strstr(functionsStr, USB_FUNC_RNDIS) != nullptr; -} - - -nsresult AutoMounter::Dump(nsACString& desc) -{ - DBG("GetState!"); - bool umsAvail, umsConfigured, umsEnabled; - bool mtpAvail, mtpConfigured, mtpEnabled; - bool rndisConfigured; - GetStatus(umsAvail, umsConfigured, umsEnabled, mtpAvail, - mtpConfigured, mtpEnabled, rndisConfigured); - if (mMode == AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED) { - // DISABLE_WHEN_UNPLUGGED implies already enabled. - if (!IsUsbCablePluggedIn()) { - mMode = AUTOMOUNTER_DISABLE; - mtpEnabled = false; - umsEnabled = false; - } - } - - // Automounter information - desc += "Current Mode:"; - desc += ModeStr(mMode); - desc += "|"; - - - desc += "Current State:"; - desc += StateStr(mState); - desc += "|"; - - desc += "UMS Status:"; - if (umsAvail) { - desc += "Available"; - } else { - desc += "UnAvailable"; - } - desc += ","; - if (umsConfigured) { - desc += "Configured"; - } else { - desc += "Un-Configured"; - } - desc += ","; - if (umsEnabled) { - desc += "Enabled"; - } else { - desc += "Disabled"; - } - desc += "|"; - - - desc += "MTP Status:"; - if (mtpAvail) { - desc += "Available"; - } else { - desc += "UnAvailable"; - } - desc += ","; - if (mtpConfigured) { - desc += "Configured"; - } else { - desc += "Un-Configured"; - } - desc += ","; - if (mtpEnabled) { - desc += "Enabled"; - } else { - desc += "Disabled"; - } - - - // Volume information - VolumeArray::index_type volIndex; - VolumeArray::size_type numVolumes = VolumeManager::NumVolumes(); - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr<Volume> vol = VolumeManager::GetVolume(volIndex); - - desc += "|"; - desc += vol->NameStr(); - desc += ":"; - desc += vol->StateStr(); - desc += "@"; - desc += vol->MountPoint().get(); - - if (!vol->MediaPresent()) { - continue; - } - - if (vol->CanBeShared()) { - desc += ",CanBeShared"; - } - if (vol->CanBeFormatted()) { - desc += ",CanBeFormatted"; - } - if (vol->CanBeMounted()) { - desc += ",CanBeMounted"; - } - if (vol->IsRemovable()) { - desc += ",Removable"; - } - if (vol->IsHotSwappable()) { - desc += ",HotSwappable"; - } - } - - return NS_OK; -} - - -static void -InitAutoMounterIOThread() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - MOZ_ASSERT(!sAutoMounter); - - sAutoMounter = new AutoMounter(); -} - -static void -ShutdownAutoMounterIOThread() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - sAutoMounter = nullptr; - ShutdownVolumeManager(); -} - -static void -SetAutoMounterModeIOThread(const int32_t& aMode) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - MOZ_ASSERT(sAutoMounter); - - sAutoMounter->SetMode(aMode); -} - -static void -SetAutoMounterSharingModeIOThread(const nsCString& aVolumeName, const bool& aAllowSharing) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - MOZ_ASSERT(sAutoMounter); - - sAutoMounter->SetSharingMode(aVolumeName, aAllowSharing); -} - -static void -AutoMounterFormatVolumeIOThread(const nsCString& aVolumeName) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - MOZ_ASSERT(sAutoMounter); - - sAutoMounter->FormatVolume(aVolumeName); -} - -static void -AutoMounterMountVolumeIOThread(const nsCString& aVolumeName) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - MOZ_ASSERT(sAutoMounter); - - sAutoMounter->MountVolume(aVolumeName); -} - -static void -AutoMounterUnmountVolumeIOThread(const nsCString& aVolumeName) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - MOZ_ASSERT(sAutoMounter); - - sAutoMounter->UnmountVolume(aVolumeName); -} - -static void -UsbCableEventIOThread() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - if (!sAutoMounter) { - return; - } - DBG("Calling UpdateState due to USBCableEvent"); - sAutoMounter->UpdateState(); -} - -/************************************************************************** -* -* Public API -* -* Since the AutoMounter runs in IO Thread context, we need to switch -* to IOThread context before we can do anything. -* -**************************************************************************/ - -class UsbCableObserver final : public hal::SwitchObserver -{ - ~UsbCableObserver() - { - hal::UnregisterSwitchObserver(hal::SWITCH_USB, this); - } - -public: - NS_INLINE_DECL_REFCOUNTING(UsbCableObserver) - - UsbCableObserver() - { - hal::RegisterSwitchObserver(hal::SWITCH_USB, this); - } - - virtual void Notify(const hal::SwitchEvent& aEvent) - { - DBG("UsbCable switch device: %d state: %s\n", - aEvent.device(), SwitchStateStr(aEvent)); - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(UsbCableEventIOThread)); - } -}; - -static StaticRefPtr<UsbCableObserver> sUsbCableObserver; -static StaticRefPtr<AutoMounterSetting> sAutoMounterSetting; - -void -InitAutoMounter() -{ - InitVolumeManager(); - sAutoMounterSetting = new AutoMounterSetting(); - - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(InitAutoMounterIOThread)); - - // Switch Observers need to run on the main thread, so we need to - // start it here and have it send events to the AutoMounter running - // on the IO Thread. - sUsbCableObserver = new UsbCableObserver(); - - // Register status reporter into reporter manager - if(status_reporter_progress == REPORTER_UNREGISTERED) { - NS_RegisterStatusReporter(new NS_STATUS_REPORTER_NAME(AutoMounter)); - } - status_reporter_progress = REPORTER_REGISTERED; -} - -int32_t -GetAutoMounterStatus() -{ - if (sAutoMounterSetting) { - return sAutoMounterSetting->GetStatus(); - } - return AUTOMOUNTER_STATUS_DISABLED; -} - -//static -void -SetAutoMounterStatus(int32_t aStatus) -{ - if (sAutoMounterSetting) { - sAutoMounterSetting->SetStatus(aStatus); - } -} - -void -SetAutoMounterMode(int32_t aMode) -{ - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(SetAutoMounterModeIOThread, aMode)); -} - -void -SetAutoMounterSharingMode(const nsCString& aVolumeName, bool aAllowSharing) -{ - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(SetAutoMounterSharingModeIOThread, - aVolumeName, aAllowSharing)); -} - -void -AutoMounterFormatVolume(const nsCString& aVolumeName) -{ - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(AutoMounterFormatVolumeIOThread, - aVolumeName)); -} - -void -AutoMounterMountVolume(const nsCString& aVolumeName) -{ - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(AutoMounterMountVolumeIOThread, - aVolumeName)); -} - -void -AutoMounterUnmountVolume(const nsCString& aVolumeName) -{ - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(AutoMounterUnmountVolumeIOThread, - aVolumeName)); -} - -void -ShutdownAutoMounter() -{ - if (sAutoMounter) { - DBG("ShutdownAutoMounter: About to StopMtpServer"); - sAutoMounter->StopMtpServer(); - // Unregister status reporter into reporter manager - if(status_reporter_progress == REPORTER_REGISTERED) { - NS_UnregisterStatusReporter(new NS_STATUS_REPORTER_NAME(AutoMounter)); - } - status_reporter_progress = REPORTER_UNREGISTERED; - } - sAutoMounterSetting = nullptr; - sUsbCableObserver = nullptr; - - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(ShutdownAutoMounterIOThread)); -} - -} // system -} // mozilla diff --git a/dom/system/gonk/AutoMounter.h b/dom/system/gonk/AutoMounter.h deleted file mode 100644 index ea98cadf1..000000000 --- a/dom/system/gonk/AutoMounter.h +++ /dev/null @@ -1,101 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_automounter_h__ -#define mozilla_system_automounter_h__ - -#include <stdint.h> - -class nsCString; - -namespace mozilla { -namespace system { - -// AutoMounter modes -#define AUTOMOUNTER_DISABLE 0 -#define AUTOMOUNTER_ENABLE_UMS 1 -#define AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED 2 -#define AUTOMOUNTER_ENABLE_MTP 3 - -// Automounter statuses -#define AUTOMOUNTER_STATUS_DISABLED 0 -#define AUTOMOUNTER_STATUS_ENABLED 1 -#define AUTOMOUNTER_STATUS_FILES_OPEN 2 - -/** - * Initialize the automounter. This causes some of the phone's - * directories to show up on the host when the phone is plugged - * into the host via USB. - * - * When the AutoMounter starts, it will poll the current state - * of affairs (usb cable plugged in, automounter enabled, etc) - * and try to make the state of the volumes match. - */ -void -InitAutoMounter(); - -/** - * Sets the enabled state of the automounter. - * - * This will in turn cause the automounter to re-evaluate - * whether it should mount/unmount/share/unshare volumes. - */ -void -SetAutoMounterMode(int32_t aMode); - -/** - * Reports the status of the automounter. - */ -int32_t -GetAutoMounterStatus(); - -/** - * Sets the sharing mode of an individual volume. - * - * If a volume is enabled for sharing, and the autmounter - * is in a state to share, then the volume will be shared - * with the PC. - */ -void -SetAutoMounterSharingMode(const nsCString& aVolumeName, bool aAllowSharing); - -/** - * Formats the volume with specified volume name. - * - * If the volume is ready to format, automounter - * will unmount it, format it and then mount it again. - */ -void -AutoMounterFormatVolume(const nsCString& aVolumeName); - -/** - * Mounts the volume with specified volume name. - * - * If the volume is already unmounted, automounter - * will mount it. Otherwise automounter will skip this. - */ -void -AutoMounterMountVolume(const nsCString& aVolumeName); - -/** - * Unmounts the volume with specified volume name. - * - * If the volume is already mounted, automounter - * will unmount it. Otherwise automounter will skip this. - */ -void -AutoMounterUnmountVolume(const nsCString& aVolumeName); - -/** - * Shuts down the automounter. - * - * This leaves the volumes in whatever state they're in. - */ -void -ShutdownAutoMounter(); - -} // system -} // mozilla - -#endif // mozilla_system_automounter_h__ diff --git a/dom/system/gonk/AutoMounterSetting.cpp b/dom/system/gonk/AutoMounterSetting.cpp deleted file mode 100644 index 606bcce04..000000000 --- a/dom/system/gonk/AutoMounterSetting.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "AutoMounter.h" -#include "AutoMounterSetting.h" - -#include "base/message_loop.h" -#include "jsapi.h" -#include "mozilla/Services.h" -#include "nsCOMPtr.h" -#include "nsContentUtils.h" -#include "nsDebug.h" -#include "nsIObserverService.h" -#include "nsISettingsService.h" -#include "nsJSUtils.h" -#include "nsPrintfCString.h" -#include "nsServiceManagerUtils.h" -#include "nsString.h" -#include "nsThreadUtils.h" -#include "xpcpublic.h" -#include "mozilla/dom/ScriptSettings.h" -#include "mozilla/Attributes.h" -#include "mozilla/dom/BindingUtils.h" -#include "mozilla/dom/SettingChangeNotificationBinding.h" - -#undef LOG -#undef ERR -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "AutoMounterSetting" , ## args) -#define ERR(args...) __android_log_print(ANDROID_LOG_ERROR, "AutoMounterSetting" , ## args) - -#define UMS_MODE "ums.mode" -#define UMS_STATUS "ums.status" -#define UMS_VOLUME_ENABLED_PREFIX "ums.volume." -#define UMS_VOLUME_ENABLED_SUFFIX ".enabled" -#define MOZSETTINGS_CHANGED "mozsettings-changed" - -using namespace mozilla::dom; - -namespace mozilla { -namespace system { - -class SettingsServiceCallback final : public nsISettingsServiceCallback -{ -public: - NS_DECL_THREADSAFE_ISUPPORTS - - SettingsServiceCallback() {} - - NS_IMETHOD Handle(const nsAString& aName, JS::Handle<JS::Value> aResult) - { - if (aResult.isInt32()) { - int32_t mode = aResult.toInt32(); - SetAutoMounterMode(mode); - } - return NS_OK; - } - - NS_IMETHOD HandleError(const nsAString& aName) - { - ERR("SettingsCallback::HandleError: %s\n", NS_LossyConvertUTF16toASCII(aName).get()); - return NS_OK; - } - -protected: - ~SettingsServiceCallback() {} -}; - -NS_IMPL_ISUPPORTS(SettingsServiceCallback, nsISettingsServiceCallback) - -class CheckVolumeSettingsCallback final : public nsISettingsServiceCallback -{ -public: - NS_DECL_THREADSAFE_ISUPPORTS - - CheckVolumeSettingsCallback(const nsACString& aVolumeName) - : mVolumeName(aVolumeName) {} - - NS_IMETHOD Handle(const nsAString& aName, JS::Handle<JS::Value> aResult) - { - if (aResult.isBoolean()) { - bool isSharingEnabled = aResult.toBoolean(); - SetAutoMounterSharingMode(mVolumeName, isSharingEnabled); - } - return NS_OK; - } - - NS_IMETHOD HandleError(const nsAString& aName) - { - ERR("CheckVolumeSettingsCallback::HandleError: %s\n", NS_LossyConvertUTF16toASCII(aName).get()); - return NS_OK; - } - -protected: - ~CheckVolumeSettingsCallback() {} - -private: - nsCString mVolumeName; -}; - -NS_IMPL_ISUPPORTS(CheckVolumeSettingsCallback, nsISettingsServiceCallback) - -AutoMounterSetting::AutoMounterSetting() - : mStatus(AUTOMOUNTER_STATUS_DISABLED) -{ - MOZ_ASSERT(NS_IsMainThread()); - - // Setup an observer to watch changes to the setting - nsCOMPtr<nsIObserverService> observerService = - mozilla::services::GetObserverService(); - if (!observerService) { - ERR("GetObserverService failed"); - return; - } - nsresult rv; - rv = observerService->AddObserver(this, MOZSETTINGS_CHANGED, false); - if (NS_FAILED(rv)) { - ERR("AddObserver failed"); - return; - } - - // Force ums.mode to be 0 initially. We do this because settings are persisted. - // We don't want UMS to be enabled until such time as the phone is unlocked, - // and gaia/apps/system/js/storage.js takes care of detecting when the phone - // becomes unlocked and changes ums.mode appropriately. - nsCOMPtr<nsISettingsService> settingsService = - do_GetService("@mozilla.org/settingsService;1"); - if (!settingsService) { - ERR("Failed to get settingsLock service!"); - return; - } - nsCOMPtr<nsISettingsServiceLock> lock; - settingsService->CreateLock(nullptr, getter_AddRefs(lock)); - nsCOMPtr<nsISettingsServiceCallback> callback = new SettingsServiceCallback(); - JS::Rooted<JS::Value> value(RootingCx()); - value.setInt32(AUTOMOUNTER_DISABLE); - lock->Set(UMS_MODE, value, callback, nullptr); - value.setInt32(mStatus); - lock->Set(UMS_STATUS, value, nullptr, nullptr); -} - -AutoMounterSetting::~AutoMounterSetting() -{ - nsCOMPtr<nsIObserverService> observerService = - mozilla::services::GetObserverService(); - if (observerService) { - observerService->RemoveObserver(this, MOZSETTINGS_CHANGED); - } -} - -NS_IMPL_ISUPPORTS(AutoMounterSetting, nsIObserver) - -const char * -AutoMounterSetting::StatusStr(int32_t aStatus) -{ - switch (aStatus) { - case AUTOMOUNTER_STATUS_DISABLED: return "Disabled"; - case AUTOMOUNTER_STATUS_ENABLED: return "Enabled"; - case AUTOMOUNTER_STATUS_FILES_OPEN: return "FilesOpen"; - } - return "??? Unknown ???"; -} - -class CheckVolumeSettingsRunnable : public Runnable -{ -public: - CheckVolumeSettingsRunnable(const nsACString& aVolumeName) - : mVolumeName(aVolumeName) {} - - NS_IMETHOD Run() override - { - MOZ_ASSERT(NS_IsMainThread()); - nsCOMPtr<nsISettingsService> settingsService = - do_GetService("@mozilla.org/settingsService;1"); - NS_ENSURE_TRUE(settingsService, NS_ERROR_FAILURE); - nsCOMPtr<nsISettingsServiceLock> lock; - settingsService->CreateLock(nullptr, getter_AddRefs(lock)); - nsCOMPtr<nsISettingsServiceCallback> callback = - new CheckVolumeSettingsCallback(mVolumeName); - nsPrintfCString setting(UMS_VOLUME_ENABLED_PREFIX "%s" UMS_VOLUME_ENABLED_SUFFIX, - mVolumeName.get()); - lock->Get(setting.get(), callback); - return NS_OK; - } - -private: - nsCString mVolumeName; -}; - -//static -void -AutoMounterSetting::CheckVolumeSettings(const nsACString& aVolumeName) -{ - NS_DispatchToMainThread(new CheckVolumeSettingsRunnable(aVolumeName)); -} - -class SetStatusRunnable : public Runnable -{ -public: - SetStatusRunnable(int32_t aStatus) : mStatus(aStatus) {} - - NS_IMETHOD Run() override - { - MOZ_ASSERT(NS_IsMainThread()); - nsCOMPtr<nsISettingsService> settingsService = - do_GetService("@mozilla.org/settingsService;1"); - NS_ENSURE_TRUE(settingsService, NS_ERROR_FAILURE); - nsCOMPtr<nsISettingsServiceLock> lock; - settingsService->CreateLock(nullptr, getter_AddRefs(lock)); - // lock may be null if this gets called during shutdown. - if (lock) { - JS::Rooted<JS::Value> value(RootingCx(), - JS::Int32Value(mStatus)); - lock->Set(UMS_STATUS, value, nullptr, nullptr); - } - return NS_OK; - } - -private: - int32_t mStatus; -}; - -//static -void -AutoMounterSetting::SetStatus(int32_t aStatus) -{ - if (aStatus != mStatus) { - LOG("Changing status from '%s' to '%s'", - StatusStr(mStatus), StatusStr(aStatus)); - mStatus = aStatus; - NS_DispatchToMainThread(new SetStatusRunnable(aStatus)); - } -} - -NS_IMETHODIMP -AutoMounterSetting::Observe(nsISupports* aSubject, - const char* aTopic, - const char16_t* aData) -{ - if (strcmp(aTopic, MOZSETTINGS_CHANGED) != 0) { - return NS_OK; - } - - // Note that this function gets called for any and all settings changes, - // so we need to carefully check if we have the one we're interested in. - // - // The string that we're interested in will be a JSON string that looks like: - // {"key":"ums.autoMount","value":true} - - RootedDictionary<SettingChangeNotification> setting(RootingCx()); - if (!WrappedJSToDictionary(aSubject, setting)) { - return NS_OK; - } - - // Check for ums.mode changes - if (setting.mKey.EqualsASCII(UMS_MODE)) { - if (!setting.mValue.isInt32()) { - return NS_OK; - } - int32_t mode = setting.mValue.toInt32(); - SetAutoMounterMode(mode); - return NS_OK; - } - - // Check for ums.volume.NAME.enabled - if (StringBeginsWith(setting.mKey, NS_LITERAL_STRING(UMS_VOLUME_ENABLED_PREFIX)) && - StringEndsWith(setting.mKey, NS_LITERAL_STRING(UMS_VOLUME_ENABLED_SUFFIX))) { - if (!setting.mValue.isBoolean()) { - return NS_OK; - } - const size_t prefixLen = sizeof(UMS_VOLUME_ENABLED_PREFIX) - 1; - const size_t suffixLen = sizeof(UMS_VOLUME_ENABLED_SUFFIX) - 1; - nsDependentSubstring volumeName = - Substring(setting.mKey, prefixLen, setting.mKey.Length() - prefixLen - suffixLen); - bool isSharingEnabled = setting.mValue.toBoolean(); - SetAutoMounterSharingMode(NS_LossyConvertUTF16toASCII(volumeName), isSharingEnabled); - return NS_OK; - } - - return NS_OK; -} - -} // namespace system -} // namespace mozilla diff --git a/dom/system/gonk/AutoMounterSetting.h b/dom/system/gonk/AutoMounterSetting.h deleted file mode 100644 index 7972de379..000000000 --- a/dom/system/gonk/AutoMounterSetting.h +++ /dev/null @@ -1,38 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_automountersetting_h__ -#define mozilla_system_automountersetting_h__ - -#include "nsIObserver.h" - -namespace mozilla { -namespace system { - -class AutoMounterSetting : public nsIObserver -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER - - AutoMounterSetting(); - - static void CheckVolumeSettings(const nsACString& aVolumeName); - - int32_t GetStatus() { return mStatus; } - void SetStatus(int32_t aStatus); - const char *StatusStr(int32_t aStatus); - -protected: - virtual ~AutoMounterSetting(); - -private: - int32_t mStatus; -}; - -} // namespace system -} // namespace mozilla - -#endif // mozilla_system_automountersetting_h__ - diff --git a/dom/system/gonk/DataCallInterfaceService.js b/dom/system/gonk/DataCallInterfaceService.js deleted file mode 100644 index 0f0e7101c..000000000 --- a/dom/system/gonk/DataCallInterfaceService.js +++ /dev/null @@ -1,276 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -const DATACALLINTERFACE_CONTRACTID = "@mozilla.org/datacall/interface;1"; -const DATACALLINTERFACESERVICE_CONTRACTID = - "@mozilla.org/datacall/interfaceservice;1"; -const DATACALLINTERFACE_CID = - Components.ID("{ff669306-4390-462a-989b-ba37fc42153f}"); -const DATACALLINTERFACESERVICE_CID = - Components.ID("{e23e9337-592d-40b9-8cef-7bd47c28b72e}"); - -const TOPIC_XPCOM_SHUTDOWN = "xpcom-shutdown"; -const TOPIC_PREF_CHANGED = "nsPref:changed"; -const PREF_RIL_DEBUG_ENABLED = "ril.debugging.enabled"; - -XPCOMUtils.defineLazyGetter(this, "RIL", function () { - let obj = {}; - Cu.import("resource://gre/modules/ril_consts.js", obj); - return obj; -}); - -XPCOMUtils.defineLazyServiceGetter(this, "gRil", - "@mozilla.org/ril;1", - "nsIRadioInterfaceLayer"); - -XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService", - "@mozilla.org/mobileconnection/mobileconnectionservice;1", - "nsIMobileConnectionService"); - -var DEBUG = RIL.DEBUG_RIL; - -function updateDebugFlag() { - // Read debug setting from pref - let debugPref; - try { - debugPref = Services.prefs.getBoolPref(PREF_RIL_DEBUG_ENABLED); - } catch (e) { - debugPref = false; - } - DEBUG = debugPref || RIL.DEBUG_RIL; -} -updateDebugFlag(); - -function DataCall(aAttributes) { - for (let key in aAttributes) { - if (key === "pdpType") { - // Convert pdp type into constant int value. - this[key] = RIL.RIL_DATACALL_PDP_TYPES.indexOf(aAttributes[key]); - continue; - } - - this[key] = aAttributes[key]; - } -} -DataCall.prototype = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCall]), - - failCause: Ci.nsIDataCallInterface.DATACALL_FAIL_NONE, - suggestedRetryTime: -1, - cid: -1, - active: -1, - pdpType: -1, - ifname: null, - addreses: null, - dnses: null, - gateways: null, - pcscf: null, - mtu: -1 -}; - -function DataCallInterfaceService() { - this._dataCallInterfaces = []; - - let numClients = gRil.numRadioInterfaces; - for (let i = 0; i < numClients; i++) { - this._dataCallInterfaces.push(new DataCallInterface(i)); - } - - Services.obs.addObserver(this, TOPIC_XPCOM_SHUTDOWN, false); - Services.prefs.addObserver(PREF_RIL_DEBUG_ENABLED, this, false); -} -DataCallInterfaceService.prototype = { - classID: DATACALLINTERFACESERVICE_CID, - classInfo: XPCOMUtils.generateCI({ - classID: DATACALLINTERFACESERVICE_CID, - contractID: DATACALLINTERFACESERVICE_CONTRACTID, - classDescription: "Data Call Interface Service", - interfaces: [Ci.nsIDataCallInterfaceService, - Ci.nsIGonkDataCallInterfaceService] - }), - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallInterfaceService, - Ci.nsIGonkDataCallInterfaceService], - Ci.nsIObserver), - - // An array of DataCallInterface instances. - _dataCallInterfaces: null, - - debug: function(aMessage) { - dump("-*- DataCallInterfaceService: " + aMessage + "\n"); - }, - - // nsIDataCallInterfaceService - - getDataCallInterface: function(aClientId) { - let dataCallInterface = this._dataCallInterfaces[aClientId]; - if (!dataCallInterface) { - throw Cr.NS_ERROR_UNEXPECTED; - } - - return dataCallInterface; - }, - - // nsIGonkDataCallInterfaceService - - notifyDataCallListChanged: function(aClientId, aCount, aDataCalls) { - let dataCallInterface = this.getDataCallInterface(aClientId); - dataCallInterface.handleDataCallListChanged(aCount, aDataCalls); - }, - - // nsIObserver - - observe: function(aSubject, aTopic, aData) { - switch (aTopic) { - case TOPIC_PREF_CHANGED: - if (aData === PREF_RIL_DEBUG_ENABLED) { - updateDebugFlag(); - } - break; - case TOPIC_XPCOM_SHUTDOWN: - Services.prefs.removeObserver(PREF_RIL_DEBUG_ENABLED, this); - Services.obs.removeObserver(this, TOPIC_XPCOM_SHUTDOWN); - break; - } - }, -}; - -function DataCallInterface(aClientId) { - this._clientId = aClientId; - this._radioInterface = gRil.getRadioInterface(aClientId); - this._listeners = []; - - if (DEBUG) this.debug("DataCallInterface: " + aClientId); -} -DataCallInterface.prototype = { - classID: DATACALLINTERFACE_CID, - classInfo: XPCOMUtils.generateCI({classID: DATACALLINTERFACE_CID, - contractID: DATACALLINTERFACE_CONTRACTID, - classDescription: "Data Call Interface", - interfaces: [Ci.nsIDataCallInterface]}), - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallInterface]), - - debug: function(aMessage) { - dump("-*- DataCallInterface[" + this._clientId + "]: " + aMessage + "\n"); - }, - - _clientId: -1, - - _radioInterface: null, - - _listeners: null, - - // nsIDataCallInterface - - setupDataCall: function(aApn, aUsername, aPassword, aAuthType, aPdpType, - aCallback) { - let connection = - gMobileConnectionService.getItemByServiceId(this._clientId); - let dataInfo = connection && connection.data; - let radioTechType = dataInfo.type; - let radioTechnology = RIL.GECKO_RADIO_TECH.indexOf(radioTechType); - // Convert pdp type into string value. - let pdpType = RIL.RIL_DATACALL_PDP_TYPES[aPdpType]; - - this._radioInterface.sendWorkerMessage("setupDataCall", { - radioTech: radioTechnology, - apn: aApn, - user: aUsername, - passwd: aPassword, - chappap: aAuthType, - pdptype: pdpType - }, (aResponse) => { - if (aResponse.errorMsg) { - aCallback.notifyError(aResponse.errorMsg); - } else { - let dataCall = new DataCall(aResponse); - aCallback.notifySetupDataCallSuccess(dataCall); - } - }); - }, - - deactivateDataCall: function(aCid, aReason, aCallback) { - this._radioInterface.sendWorkerMessage("deactivateDataCall", { - cid: aCid, - reason: aReason - }, (aResponse) => { - if (aResponse.errorMsg) { - aCallback.notifyError(aResponse.errorMsg); - } else { - aCallback.notifySuccess(); - } - }); - }, - - getDataCallList: function(aCallback) { - this._radioInterface.sendWorkerMessage("getDataCallList", null, - (aResponse) => { - if (aResponse.errorMsg) { - aCallback.notifyError(aResponse.errorMsg); - } else { - let dataCalls = aResponse.datacalls.map( - dataCall => new DataCall(dataCall)); - aCallback.notifyGetDataCallListSuccess(dataCalls.length, dataCalls); - } - }); - }, - - setDataRegistration: function(aAttach, aCallback) { - this._radioInterface.sendWorkerMessage("setDataRegistration", { - attach: aAttach - }, (aResponse) => { - if (aResponse.errorMsg) { - aCallback.notifyError(aResponse.errorMsg); - } else { - aCallback.notifySuccess(); - } - }); - }, - - handleDataCallListChanged: function(aCount, aDataCalls) { - this._notifyAllListeners("notifyDataCallListChanged", [aCount, aDataCalls]); - }, - - _notifyAllListeners: function(aMethodName, aArgs) { - let listeners = this._listeners.slice(); - for (let listener of listeners) { - if (this._listeners.indexOf(listener) == -1) { - // Listener has been unregistered in previous run. - continue; - } - - let handler = listener[aMethodName]; - try { - handler.apply(listener, aArgs); - } catch (e) { - if (DEBUG) { - this.debug("listener for " + aMethodName + " threw an exception: " + e); - } - } - } - }, - - registerListener: function(aListener) { - if (this._listeners.indexOf(aListener) >= 0) { - return; - } - - this._listeners.push(aListener); - }, - - unregisterListener: function(aListener) { - let index = this._listeners.indexOf(aListener); - if (index >= 0) { - this._listeners.splice(index, 1); - } - }, -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DataCallInterfaceService]);
\ No newline at end of file diff --git a/dom/system/gonk/DataCallInterfaceService.manifest b/dom/system/gonk/DataCallInterfaceService.manifest deleted file mode 100644 index bf062c7e9..000000000 --- a/dom/system/gonk/DataCallInterfaceService.manifest +++ /dev/null @@ -1,6 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -component {e23e9337-592d-40b9-8cef-7bd47c28b72e} DataCallInterfaceService.js -contract @mozilla.org/datacall/interfaceservice;1 {e23e9337-592d-40b9-8cef-7bd47c28b72e}
\ No newline at end of file diff --git a/dom/system/gonk/DataCallManager.js b/dom/system/gonk/DataCallManager.js deleted file mode 100644 index 5411987cd..000000000 --- a/dom/system/gonk/DataCallManager.js +++ /dev/null @@ -1,1726 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/systemlibs.js"); - -XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService", - "@mozilla.org/settingsService;1", - "nsISettingsService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager", - "@mozilla.org/network/manager;1", - "nsINetworkManager"); - -XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService", - "@mozilla.org/mobileconnection/mobileconnectionservice;1", - "nsIMobileConnectionService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gIccService", - "@mozilla.org/icc/iccservice;1", - "nsIIccService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gDataCallInterfaceService", - "@mozilla.org/datacall/interfaceservice;1", - "nsIDataCallInterfaceService"); - -XPCOMUtils.defineLazyGetter(this, "RIL", function() { - let obj = {}; - Cu.import("resource://gre/modules/ril_consts.js", obj); - return obj; -}); - -// Ril quirk to attach data registration on demand. -var RILQUIRKS_DATA_REGISTRATION_ON_DEMAND = - libcutils.property_get("ro.moz.ril.data_reg_on_demand", "false") == "true"; - -// Ril quirk to control the uicc/data subscription. -var RILQUIRKS_SUBSCRIPTION_CONTROL = - libcutils.property_get("ro.moz.ril.subscription_control", "false") == "true"; - -// Ril quirk to enable IPv6 protocol/roaming protocol in APN settings. -var RILQUIRKS_HAVE_IPV6 = - libcutils.property_get("ro.moz.ril.ipv6", "false") == "true"; - -const DATACALLMANAGER_CID = - Components.ID("{35b9efa2-e42c-45ce-8210-0a13e6f4aadc}"); -const DATACALLHANDLER_CID = - Components.ID("{132b650f-c4d8-4731-96c5-83785cb31dee}"); -const RILNETWORKINTERFACE_CID = - Components.ID("{9574ee84-5d0d-4814-b9e6-8b279e03dcf4}"); -const RILNETWORKINFO_CID = - Components.ID("{dd6cf2f0-f0e3-449f-a69e-7c34fdcb8d4b}"); - -const TOPIC_XPCOM_SHUTDOWN = "xpcom-shutdown"; -const TOPIC_MOZSETTINGS_CHANGED = "mozsettings-changed"; -const TOPIC_PREF_CHANGED = "nsPref:changed"; -const TOPIC_DATA_CALL_ERROR = "data-call-error"; -const PREF_RIL_DEBUG_ENABLED = "ril.debugging.enabled"; - -const NETWORK_TYPE_UNKNOWN = Ci.nsINetworkInfo.NETWORK_TYPE_UNKNOWN; -const NETWORK_TYPE_WIFI = Ci.nsINetworkInfo.NETWORK_TYPE_WIFI; -const NETWORK_TYPE_MOBILE = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE; -const NETWORK_TYPE_MOBILE_MMS = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_MMS; -const NETWORK_TYPE_MOBILE_SUPL = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_SUPL; -const NETWORK_TYPE_MOBILE_IMS = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_IMS; -const NETWORK_TYPE_MOBILE_DUN = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN; -const NETWORK_TYPE_MOBILE_FOTA = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_FOTA; - -const NETWORK_STATE_UNKNOWN = Ci.nsINetworkInfo.NETWORK_STATE_UNKNOWN; -const NETWORK_STATE_CONNECTING = Ci.nsINetworkInfo.NETWORK_STATE_CONNECTING; -const NETWORK_STATE_CONNECTED = Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED; -const NETWORK_STATE_DISCONNECTING = Ci.nsINetworkInfo.NETWORK_STATE_DISCONNECTING; -const NETWORK_STATE_DISCONNECTED = Ci.nsINetworkInfo.NETWORK_STATE_DISCONNECTED; - -const INT32_MAX = 2147483647; - -// set to true in ril_consts.js to see debug messages -var DEBUG = RIL.DEBUG_RIL; - -function updateDebugFlag() { - // Read debug setting from pref - let debugPref; - try { - debugPref = Services.prefs.getBoolPref(PREF_RIL_DEBUG_ENABLED); - } catch (e) { - debugPref = false; - } - DEBUG = debugPref || RIL.DEBUG_RIL; -} -updateDebugFlag(); - -function DataCallManager() { - this._connectionHandlers = []; - - let numRadioInterfaces = gMobileConnectionService.numItems; - for (let clientId = 0; clientId < numRadioInterfaces; clientId++) { - this._connectionHandlers.push(new DataCallHandler(clientId)); - } - - let lock = gSettingsService.createLock(); - // Read the APN data from the settings DB. - lock.get("ril.data.apnSettings", this); - // Read the data enabled setting from DB. - lock.get("ril.data.enabled", this); - lock.get("ril.data.roaming_enabled", this); - // Read the default client id for data call. - lock.get("ril.data.defaultServiceId", this); - - Services.obs.addObserver(this, TOPIC_XPCOM_SHUTDOWN, false); - Services.obs.addObserver(this, TOPIC_MOZSETTINGS_CHANGED, false); - Services.prefs.addObserver(PREF_RIL_DEBUG_ENABLED, this, false); -} -DataCallManager.prototype = { - classID: DATACALLMANAGER_CID, - classInfo: XPCOMUtils.generateCI({classID: DATACALLMANAGER_CID, - classDescription: "Data Call Manager", - interfaces: [Ci.nsIDataCallManager]}), - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallManager, - Ci.nsIObserver, - Ci.nsISettingsServiceCallback]), - - _connectionHandlers: null, - - // Flag to determine the data state to start with when we boot up. It - // corresponds to the 'ril.data.enabled' setting from the UI. - _dataEnabled: false, - - // Flag to record the default client id for data call. It corresponds to - // the 'ril.data.defaultServiceId' setting from the UI. - _dataDefaultClientId: -1, - - // Flag to record the current default client id for data call. - // It differs from _dataDefaultClientId in that it is set only when - // the switch of client id process is done. - _currentDataClientId: -1, - - // Pending function to execute when we are notified that another data call has - // been disconnected. - _pendingDataCallRequest: null, - - debug: function(aMsg) { - dump("-*- DataCallManager: " + aMsg + "\n"); - }, - - get dataDefaultServiceId() { - return this._dataDefaultClientId; - }, - - getDataCallHandler: function(aClientId) { - let handler = this._connectionHandlers[aClientId] - if (!handler) { - throw Cr.NS_ERROR_UNEXPECTED; - } - - return handler; - }, - - _setDataRegistration: function(aDataCallInterface, aAttach) { - return new Promise(function(aResolve, aReject) { - let callback = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallCallback]), - notifySuccess: function() { - aResolve(); - }, - notifyError: function(aErrorMsg) { - aReject(aErrorMsg); - } - }; - - aDataCallInterface.setDataRegistration(aAttach, callback); - }); - }, - - _handleDataClientIdChange: function(aNewClientId) { - if (this._dataDefaultClientId === aNewClientId) { - return; - } - this._dataDefaultClientId = aNewClientId; - - // This is to handle boot up stage. - if (this._currentDataClientId == -1) { - this._currentDataClientId = this._dataDefaultClientId; - let connHandler = this._connectionHandlers[this._currentDataClientId]; - let dcInterface = connHandler.dataCallInterface; - if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND || - RILQUIRKS_SUBSCRIPTION_CONTROL) { - this._setDataRegistration(dcInterface, true); - } - if (this._dataEnabled) { - let settings = connHandler.dataCallSettings; - settings.oldEnabled = settings.enabled; - settings.enabled = true; - connHandler.updateRILNetworkInterface(); - } - return; - } - - let oldConnHandler = this._connectionHandlers[this._currentDataClientId]; - let oldIface = oldConnHandler.dataCallInterface; - let oldSettings = oldConnHandler.dataCallSettings; - let newConnHandler = this._connectionHandlers[this._dataDefaultClientId]; - let newIface = newConnHandler.dataCallInterface; - let newSettings = newConnHandler.dataCallSettings; - - let applyPendingDataSettings = () => { - if (DEBUG) { - this.debug("Apply pending data registration and settings."); - } - - if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND || - RILQUIRKS_SUBSCRIPTION_CONTROL) { - this._setDataRegistration(oldIface, false).then(() => { - if (this._dataEnabled) { - newSettings.oldEnabled = newSettings.enabled; - newSettings.enabled = true; - } - this._currentDataClientId = this._dataDefaultClientId; - - this._setDataRegistration(newIface, true).then(() => { - newConnHandler.updateRILNetworkInterface(); - }); - }); - return; - } - - if (this._dataEnabled) { - newSettings.oldEnabled = newSettings.enabled; - newSettings.enabled = true; - } - - this._currentDataClientId = this._dataDefaultClientId; - newConnHandler.updateRILNetworkInterface(); - }; - - if (this._dataEnabled) { - oldSettings.oldEnabled = oldSettings.enabled; - oldSettings.enabled = false; - } - - oldConnHandler.deactivateDataCallsAndWait().then(() => { - applyPendingDataSettings(); - }); - }, - - _shutdown: function() { - for (let handler of this._connectionHandlers) { - handler.shutdown(); - } - this._connectionHandlers = null; - Services.prefs.removeObserver(PREF_RIL_DEBUG_ENABLED, this); - Services.obs.removeObserver(this, TOPIC_XPCOM_SHUTDOWN); - Services.obs.removeObserver(this, TOPIC_MOZSETTINGS_CHANGED); - }, - - /** - * nsISettingsServiceCallback - */ - handle: function(aName, aResult) { - switch (aName) { - case "ril.data.apnSettings": - if (DEBUG) { - this.debug("'ril.data.apnSettings' is now " + - JSON.stringify(aResult)); - } - if (!aResult) { - break; - } - for (let clientId in this._connectionHandlers) { - let handler = this._connectionHandlers[clientId]; - let apnSetting = aResult[clientId]; - if (handler && apnSetting) { - handler.updateApnSettings(apnSetting); - } - } - break; - case "ril.data.enabled": - if (DEBUG) { - this.debug("'ril.data.enabled' is now " + aResult); - } - if (this._dataEnabled === aResult) { - break; - } - this._dataEnabled = aResult; - - if (DEBUG) { - this.debug("Default id for data call: " + this._dataDefaultClientId); - } - if (this._dataDefaultClientId === -1) { - // We haven't got the default id for data from db. - break; - } - - let connHandler = this._connectionHandlers[this._dataDefaultClientId]; - let settings = connHandler.dataCallSettings; - settings.oldEnabled = settings.enabled; - settings.enabled = aResult; - connHandler.updateRILNetworkInterface(); - break; - case "ril.data.roaming_enabled": - if (DEBUG) { - this.debug("'ril.data.roaming_enabled' is now " + aResult); - this.debug("Default id for data call: " + this._dataDefaultClientId); - } - for (let clientId = 0; clientId < this._connectionHandlers.length; clientId++) { - let connHandler = this._connectionHandlers[clientId]; - let settings = connHandler.dataCallSettings; - settings.roamingEnabled = Array.isArray(aResult) ? aResult[clientId] - : aResult; - } - if (this._dataDefaultClientId === -1) { - // We haven't got the default id for data from db. - break; - } - this._connectionHandlers[this._dataDefaultClientId].updateRILNetworkInterface(); - break; - case "ril.data.defaultServiceId": - aResult = aResult || 0; - if (DEBUG) { - this.debug("'ril.data.defaultServiceId' is now " + aResult); - } - this._handleDataClientIdChange(aResult); - break; - } - }, - - handleError: function(aErrorMessage) { - if (DEBUG) { - this.debug("There was an error while reading RIL settings."); - } - }, - - /** - * nsIObserver interface methods. - */ - observe: function(aSubject, aTopic, aData) { - switch (aTopic) { - case TOPIC_MOZSETTINGS_CHANGED: - if ("wrappedJSObject" in aSubject) { - aSubject = aSubject.wrappedJSObject; - } - this.handle(aSubject.key, aSubject.value); - break; - case TOPIC_PREF_CHANGED: - if (aData === PREF_RIL_DEBUG_ENABLED) { - updateDebugFlag(); - } - break; - case TOPIC_XPCOM_SHUTDOWN: - this._shutdown(); - break; - } - }, -}; - -function DataCallHandler(aClientId) { - // Initial owning attributes. - this.clientId = aClientId; - this.dataCallSettings = { - oldEnabled: false, - enabled: false, - roamingEnabled: false - }; - this._dataCalls = []; - this._listeners = []; - - // This map is used to collect all the apn types and its corresponding - // RILNetworkInterface. - this.dataNetworkInterfaces = new Map(); - - this.dataCallInterface = gDataCallInterfaceService.getDataCallInterface(aClientId); - this.dataCallInterface.registerListener(this); - - let mobileConnection = gMobileConnectionService.getItemByServiceId(aClientId); - mobileConnection.registerListener(this); - - this._dataInfo = { - state: mobileConnection.data.state, - type: mobileConnection.data.type, - roaming: mobileConnection.data.roaming - } -} -DataCallHandler.prototype = { - classID: DATACALLHANDLER_CID, - classInfo: XPCOMUtils.generateCI({classID: DATACALLHANDLER_CID, - classDescription: "Data Call Handler", - interfaces: [Ci.nsIDataCallHandler]}), - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallHandler, - Ci.nsIDataCallInterfaceListener, - Ci.nsIMobileConnectionListener]), - - clientId: 0, - dataCallInterface: null, - dataCallSettings: null, - dataNetworkInterfaces: null, - _dataCalls: null, - _dataInfo: null, - - // Apn settings to be setup after data call are cleared. - _pendingApnSettings: null, - - debug: function(aMsg) { - dump("-*- DataCallHandler[" + this.clientId + "]: " + aMsg + "\n"); - }, - - shutdown: function() { - // Shutdown all RIL network interfaces - this.dataNetworkInterfaces.forEach(function(networkInterface) { - gNetworkManager.unregisterNetworkInterface(networkInterface); - networkInterface.shutdown(); - networkInterface = null; - }); - this.dataNetworkInterfaces.clear(); - this._dataCalls = []; - this.clientId = null; - - this.dataCallInterface.unregisterListener(this); - this.dataCallInterface = null; - - let mobileConnection = - gMobileConnectionService.getItemByServiceId(this.clientId); - mobileConnection.unregisterListener(this); - }, - - /** - * Check if we get all necessary APN data. - */ - _validateApnSetting: function(aApnSetting) { - return (aApnSetting && - aApnSetting.apn && - aApnSetting.types && - aApnSetting.types.length); - }, - - _convertApnType: function(aApnType) { - switch (aApnType) { - case "default": - return NETWORK_TYPE_MOBILE; - case "mms": - return NETWORK_TYPE_MOBILE_MMS; - case "supl": - return NETWORK_TYPE_MOBILE_SUPL; - case "ims": - return NETWORK_TYPE_MOBILE_IMS; - case "dun": - return NETWORK_TYPE_MOBILE_DUN; - case "fota": - return NETWORK_TYPE_MOBILE_FOTA; - default: - return NETWORK_TYPE_UNKNOWN; - } - }, - - _compareDataCallOptions: function(aDataCall, aNewDataCall) { - return aDataCall.apnProfile.apn == aNewDataCall.apnProfile.apn && - aDataCall.apnProfile.user == aNewDataCall.apnProfile.user && - aDataCall.apnProfile.password == aNewDataCall.apnProfile.passwd && - aDataCall.apnProfile.authType == aNewDataCall.apnProfile.authType && - aDataCall.apnProfile.protocol == aNewDataCall.apnProfile.protocol && - aDataCall.apnProfile.roaming_protocol == aNewDataCall.apnProfile.roaming_protocol; - }, - - /** - * This function will do the following steps: - * 1. Clear the cached APN settings in the RIL. - * 2. Combine APN, user name, and password as the key of |byApn| object to - * refer to the corresponding APN setting. - * 3. Use APN type as the index of |byType| object to refer to the - * corresponding APN setting. - * 4. Create RilNetworkInterface for each APN setting created at step 2. - */ - _setupApnSettings: function(aNewApnSettings) { - if (!aNewApnSettings) { - return; - } - if (DEBUG) this.debug("setupApnSettings: " + JSON.stringify(aNewApnSettings)); - - // Shutdown all network interfaces and clear data calls. - this.dataNetworkInterfaces.forEach(function(networkInterface) { - gNetworkManager.unregisterNetworkInterface(networkInterface); - networkInterface.shutdown(); - networkInterface = null; - }); - this.dataNetworkInterfaces.clear(); - this._dataCalls = []; - - // Cache the APN settings by APNs and by types in the RIL. - for (let inputApnSetting of aNewApnSettings) { - if (!this._validateApnSetting(inputApnSetting)) { - continue; - } - - // Use APN type as the key of dataNetworkInterfaces to refer to the - // corresponding RILNetworkInterface. - for (let i = 0; i < inputApnSetting.types.length; i++) { - let apnType = inputApnSetting.types[i]; - let networkType = this._convertApnType(apnType); - if (networkType === NETWORK_TYPE_UNKNOWN) { - if (DEBUG) this.debug("Invalid apn type: " + apnType); - continue; - } - - if (DEBUG) this.debug("Preparing RILNetworkInterface for type: " + apnType); - // Create DataCall for RILNetworkInterface or reuse one that is shareable. - let dataCall; - for (let i = 0; i < this._dataCalls.length; i++) { - if (this._dataCalls[i].canHandleApn(inputApnSetting)) { - if (DEBUG) this.debug("Found shareable DataCall, reusing it."); - dataCall = this._dataCalls[i]; - break; - } - } - - if (!dataCall) { - if (DEBUG) this.debug("No shareable DataCall found, creating one."); - dataCall = new DataCall(this.clientId, inputApnSetting, this); - this._dataCalls.push(dataCall); - } - - try { - let networkInterface = new RILNetworkInterface(this, networkType, - inputApnSetting, - dataCall); - gNetworkManager.registerNetworkInterface(networkInterface); - this.dataNetworkInterfaces.set(networkType, networkInterface); - } catch (e) { - if (DEBUG) { - this.debug("Error setting up RILNetworkInterface for type " + - apnType + ": " + e); - } - } - } - } - }, - - /** - * Check if all data is disconnected. - */ - allDataDisconnected: function() { - for (let i = 0; i < this._dataCalls.length; i++) { - let dataCall = this._dataCalls[i]; - if (dataCall.state != NETWORK_STATE_UNKNOWN && - dataCall.state != NETWORK_STATE_DISCONNECTED) { - return false; - } - } - return true; - }, - - deactivateDataCallsAndWait: function() { - return new Promise((aResolve, aReject) => { - this.deactivateDataCalls({ - notifyDataCallsDisconnected: function() { - aResolve(); - } - }); - }); - }, - - updateApnSettings: function(aNewApnSettings) { - if (!aNewApnSettings) { - return; - } - if (this._pendingApnSettings) { - // Change of apn settings in process, just update to the newest. - this._pengingApnSettings = aNewApnSettings; - return; - } - - this._pendingApnSettings = aNewApnSettings; - this.deactivateDataCallsAndWait().then(() => { - this._setupApnSettings(this._pendingApnSettings); - this._pendingApnSettings = null; - this.updateRILNetworkInterface(); - }); - }, - - updateRILNetworkInterface: function() { - let networkInterface = this.dataNetworkInterfaces.get(NETWORK_TYPE_MOBILE); - if (!networkInterface) { - if (DEBUG) { - this.debug("No network interface for default data."); - } - return; - } - - let connection = - gMobileConnectionService.getItemByServiceId(this.clientId); - - // This check avoids data call connection if the radio is not ready - // yet after toggling off airplane mode. - let radioState = connection && connection.radioState; - if (radioState != Ci.nsIMobileConnection.MOBILE_RADIO_STATE_ENABLED) { - if (DEBUG) { - this.debug("RIL is not ready for data connection: radio's not ready"); - } - return; - } - - // We only watch at "ril.data.enabled" flag changes for connecting or - // disconnecting the data call. If the value of "ril.data.enabled" is - // true and any of the remaining flags change the setting application - // should turn this flag to false and then to true in order to reload - // the new values and reconnect the data call. - if (this.dataCallSettings.oldEnabled === this.dataCallSettings.enabled) { - if (DEBUG) { - this.debug("No changes for ril.data.enabled flag. Nothing to do."); - } - return; - } - - let dataInfo = connection && connection.data; - let isRegistered = - dataInfo && - dataInfo.state == RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED; - let haveDataConnection = - dataInfo && - dataInfo.type != RIL.GECKO_MOBILE_CONNECTION_STATE_UNKNOWN; - if (!isRegistered || !haveDataConnection) { - if (DEBUG) { - this.debug("RIL is not ready for data connection: Phone's not " + - "registered or doesn't have data connection."); - } - return; - } - let wifi_active = false; - if (gNetworkManager.activeNetworkInfo && - gNetworkManager.activeNetworkInfo.type == NETWORK_TYPE_WIFI) { - wifi_active = true; - } - - let defaultDataCallConnected = networkInterface.connected; - - // We have moved part of the decision making into DataCall, the rest will be - // moved after Bug 904514 - [meta] NetworkManager enhancement. - if (networkInterface.enabled && - (!this.dataCallSettings.enabled || - (dataInfo.roaming && !this.dataCallSettings.roamingEnabled))) { - if (DEBUG) { - this.debug("Data call settings: disconnect data call."); - } - networkInterface.disconnect(); - return; - } - - if (networkInterface.enabled && wifi_active) { - if (DEBUG) { - this.debug("Disconnect data call when Wifi is connected."); - } - networkInterface.disconnect(); - return; - } - - if (!this.dataCallSettings.enabled || defaultDataCallConnected) { - if (DEBUG) { - this.debug("Data call settings: nothing to do."); - } - return; - } - if (dataInfo.roaming && !this.dataCallSettings.roamingEnabled) { - if (DEBUG) { - this.debug("We're roaming, but data roaming is disabled."); - } - return; - } - if (wifi_active) { - if (DEBUG) { - this.debug("Don't connect data call when Wifi is connected."); - } - return; - } - if (this._pendingApnSettings) { - if (DEBUG) this.debug("We're changing apn settings, ignore any changes."); - return; - } - - if (this._deactivatingDataCalls) { - if (DEBUG) this.debug("We're deactivating all data calls, ignore any changes."); - return; - } - - if (DEBUG) { - this.debug("Data call settings: connect data call."); - } - networkInterface.connect(); - }, - - _isMobileNetworkType: function(aNetworkType) { - if (aNetworkType === NETWORK_TYPE_MOBILE || - aNetworkType === NETWORK_TYPE_MOBILE_MMS || - aNetworkType === NETWORK_TYPE_MOBILE_SUPL || - aNetworkType === NETWORK_TYPE_MOBILE_IMS || - aNetworkType === NETWORK_TYPE_MOBILE_DUN || - aNetworkType === NETWORK_TYPE_MOBILE_FOTA) { - return true; - } - - return false; - }, - - getDataCallStateByType: function(aNetworkType) { - if (!this._isMobileNetworkType(aNetworkType)) { - if (DEBUG) this.debug(aNetworkType + " is not a mobile network type!"); - throw Cr.NS_ERROR_INVALID_ARG; - } - - let networkInterface = this.dataNetworkInterfaces.get(aNetworkType); - if (!networkInterface) { - return NETWORK_STATE_UNKNOWN; - } - return networkInterface.info.state; - }, - - setupDataCallByType: function(aNetworkType) { - if (DEBUG) { - this.debug("setupDataCallByType: " + aNetworkType); - } - - if (!this._isMobileNetworkType(aNetworkType)) { - if (DEBUG) this.debug(aNetworkType + " is not a mobile network type!"); - throw Cr.NS_ERROR_INVALID_ARG; - } - - let networkInterface = this.dataNetworkInterfaces.get(aNetworkType); - if (!networkInterface) { - if (DEBUG) { - this.debug("No network interface for type: " + aNetworkType); - } - return; - } - - networkInterface.connect(); - }, - - deactivateDataCallByType: function(aNetworkType) { - if (DEBUG) { - this.debug("deactivateDataCallByType: " + aNetworkType); - } - - if (!this._isMobileNetworkType(aNetworkType)) { - if (DEBUG) this.debug(aNetworkType + " is not a mobile network type!"); - throw Cr.NS_ERROR_INVALID_ARG; - } - - let networkInterface = this.dataNetworkInterfaces.get(aNetworkType); - if (!networkInterface) { - if (DEBUG) { - this.debug("No network interface for type: " + aNetworkType); - } - return; - } - - networkInterface.disconnect(); - }, - - _deactivatingDataCalls: false, - - deactivateDataCalls: function(aCallback) { - let dataDisconnecting = false; - this.dataNetworkInterfaces.forEach(function(networkInterface) { - if (networkInterface.enabled) { - if (networkInterface.info.state != NETWORK_STATE_UNKNOWN && - networkInterface.info.state != NETWORK_STATE_DISCONNECTED) { - dataDisconnecting = true; - } - networkInterface.disconnect(); - } - }); - - this._deactivatingDataCalls = dataDisconnecting; - if (!dataDisconnecting) { - aCallback.notifyDataCallsDisconnected(); - return; - } - - let callback = { - notifyAllDataDisconnected: () => { - this._unregisterListener(callback); - aCallback.notifyDataCallsDisconnected(); - } - }; - this._registerListener(callback); - }, - - _listeners: null, - - _notifyListeners: function(aMethodName, aArgs) { - let listeners = this._listeners.slice(); - for (let listener of listeners) { - if (this._listeners.indexOf(listener) == -1) { - // Listener has been unregistered in previous run. - continue; - } - - let handler = listener[aMethodName]; - try { - handler.apply(listener, aArgs); - } catch (e) { - this.debug("listener for " + aMethodName + " threw an exception: " + e); - } - } - }, - - _registerListener: function(aListener) { - if (this._listeners.indexOf(aListener) >= 0) { - return; - } - - this._listeners.push(aListener); - }, - - _unregisterListener: function(aListener) { - let index = this._listeners.indexOf(aListener); - if (index >= 0) { - this._listeners.splice(index, 1); - } - }, - - _findDataCallByCid: function(aCid) { - if (aCid === undefined || aCid < 0) { - return -1; - } - - for (let i = 0; i < this._dataCalls.length; i++) { - let datacall = this._dataCalls[i]; - if (datacall.linkInfo.cid != null && - datacall.linkInfo.cid == aCid) { - return i; - } - } - - return -1; - }, - - /** - * Notify about data call setup error, called from DataCall. - */ - notifyDataCallError: function(aDataCall, aErrorMsg) { - // Notify data call error only for data APN - let networkInterface = this.dataNetworkInterfaces.get(NETWORK_TYPE_MOBILE); - if (networkInterface && networkInterface.enabled) { - let dataCall = networkInterface.dataCall; - if (this._compareDataCallOptions(dataCall, aDataCall)) { - Services.obs.notifyObservers(networkInterface.info, - TOPIC_DATA_CALL_ERROR, aErrorMsg); - } - } - }, - - /** - * Notify about data call changed, called from DataCall. - */ - notifyDataCallChanged: function(aUpdatedDataCall) { - // Process pending radio power off request after all data calls - // are disconnected. - if (aUpdatedDataCall.state == NETWORK_STATE_DISCONNECTED || - aUpdatedDataCall.state == NETWORK_STATE_UNKNOWN && - this.allDataDisconnected() && this._deactivatingDataCalls) { - this._deactivatingDataCalls = false; - this._notifyListeners("notifyAllDataDisconnected", { - clientId: this.clientId - }); - } - }, - - // nsIDataCallInterfaceListener - - notifyDataCallListChanged: function(aCount, aDataCallList) { - let currentDataCalls = this._dataCalls.slice(); - for (let i = 0; i < aDataCallList.length; i++) { - let dataCall = aDataCallList[i]; - let index = this._findDataCallByCid(dataCall.cid); - if (index == -1) { - if (DEBUG) { - this.debug("Unexpected new data call: " + JSON.stringify(dataCall)); - } - continue; - } - currentDataCalls[index].onDataCallChanged(dataCall); - currentDataCalls[index] = null; - } - - // If there is any CONNECTED DataCall left in currentDataCalls, means that - // it is missing in dataCallList, we should send a DISCONNECTED event to - // notify about this. - for (let i = 0; i < currentDataCalls.length; i++) { - let currentDataCall = currentDataCalls[i]; - if (currentDataCall && currentDataCall.linkInfo.cid != null && - currentDataCall.state == NETWORK_STATE_CONNECTED) { - if (DEBUG) { - this.debug("Expected data call missing: " + JSON.stringify( - currentDataCall.apnProfile) + ", must have been DISCONNECTED."); - } - currentDataCall.onDataCallChanged({ - state: NETWORK_STATE_DISCONNECTED - }); - } - } - }, - - // nsIMobileConnectionListener - - notifyVoiceChanged: function() {}, - - notifyDataChanged: function () { - let connection = gMobileConnectionService.getItemByServiceId(this.clientId); - let newDataInfo = connection.data; - - if (this._dataInfo.state == newDataInfo.state && - this._dataInfo.type == newDataInfo.type && - this._dataInfo.roaming == newDataInfo.roaming) { - return; - } - - this._dataInfo.state = newDataInfo.state; - this._dataInfo.type = newDataInfo.type; - this._dataInfo.roaming = newDataInfo.roaming; - this.updateRILNetworkInterface(); - }, - - notifyDataError: function (aMessage) {}, - - notifyCFStateChanged: function(aAction, aReason, aNumber, aTimeSeconds, aServiceClass) {}, - - notifyEmergencyCbModeChanged: function(aActive, aTimeoutMs) {}, - - notifyOtaStatusChanged: function(aStatus) {}, - - notifyRadioStateChanged: function() {}, - - notifyClirModeChanged: function(aMode) {}, - - notifyLastKnownNetworkChanged: function() {}, - - notifyLastKnownHomeNetworkChanged: function() {}, - - notifyNetworkSelectionModeChanged: function() {}, - - notifyDeviceIdentitiesChanged: function() {} -}; - -function DataCall(aClientId, aApnSetting, aDataCallHandler) { - this.clientId = aClientId; - this.dataCallHandler = aDataCallHandler; - this.apnProfile = { - apn: aApnSetting.apn, - user: aApnSetting.user, - password: aApnSetting.password, - authType: aApnSetting.authtype, - protocol: aApnSetting.protocol, - roaming_protocol: aApnSetting.roaming_protocol - }; - this.linkInfo = { - cid: null, - ifname: null, - addresses: [], - dnses: [], - gateways: [], - pcscf: [], - mtu: null - }; - this.state = NETWORK_STATE_UNKNOWN; - this.requestedNetworkIfaces = []; -} -DataCall.prototype = { - /** - * Standard values for the APN connection retry process - * Retry funcion: time(secs) = A * numer_of_retries^2 + B - */ - NETWORK_APNRETRY_FACTOR: 8, - NETWORK_APNRETRY_ORIGIN: 3, - NETWORK_APNRETRY_MAXRETRIES: 10, - - dataCallHandler: null, - - // Event timer for connection retries - timer: null, - - // APN failed connections. Retry counter - apnRetryCounter: 0, - - // Array to hold RILNetworkInterfaces that requested this DataCall. - requestedNetworkIfaces: null, - - /** - * @return "deactivate" if <ifname> changes or one of the aCurrentDataCall - * addresses is missing in updatedDataCall, or "identical" if no - * changes found, or "changed" otherwise. - */ - _compareDataCallLink: function(aUpdatedDataCall, aCurrentDataCall) { - // If network interface is changed, report as "deactivate". - if (aUpdatedDataCall.ifname != aCurrentDataCall.ifname) { - return "deactivate"; - } - - // If any existing address is missing, report as "deactivate". - for (let i = 0; i < aCurrentDataCall.addresses.length; i++) { - let address = aCurrentDataCall.addresses[i]; - if (aUpdatedDataCall.addresses.indexOf(address) < 0) { - return "deactivate"; - } - } - - if (aCurrentDataCall.addresses.length != aUpdatedDataCall.addresses.length) { - // Since now all |aCurrentDataCall.addresses| are found in - // |aUpdatedDataCall.addresses|, this means one or more new addresses are - // reported. - return "changed"; - } - - let fields = ["gateways", "dnses"]; - for (let i = 0; i < fields.length; i++) { - // Compare <datacall>.<field>. - let field = fields[i]; - let lhs = aUpdatedDataCall[field], rhs = aCurrentDataCall[field]; - if (lhs.length != rhs.length) { - return "changed"; - } - for (let i = 0; i < lhs.length; i++) { - if (lhs[i] != rhs[i]) { - return "changed"; - } - } - } - - if (aCurrentDataCall.mtu != aUpdatedDataCall.mtu) { - return "changed"; - } - - return "identical"; - }, - - _getGeckoDataCallState:function (aDataCall) { - if (aDataCall.active == Ci.nsIDataCallInterface.DATACALL_STATE_ACTIVE_UP || - aDataCall.active == Ci.nsIDataCallInterface.DATACALL_STATE_ACTIVE_DOWN) { - return NETWORK_STATE_CONNECTED; - } - - return NETWORK_STATE_DISCONNECTED; - }, - - onSetupDataCallResult: function(aDataCall) { - this.debug("onSetupDataCallResult: " + JSON.stringify(aDataCall)); - let errorMsg = aDataCall.errorMsg; - if (aDataCall.failCause && - aDataCall.failCause != Ci.nsIDataCallInterface.DATACALL_FAIL_NONE) { - errorMsg = - RIL.RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[aDataCall.failCause]; - } - - if (errorMsg) { - if (DEBUG) { - this.debug("SetupDataCall error for apn " + this.apnProfile.apn + ": " + - errorMsg + " (" + aDataCall.failCause + "), retry time: " + - aDataCall.suggestedRetryTime); - } - - this.state = NETWORK_STATE_DISCONNECTED; - - if (this.requestedNetworkIfaces.length === 0) { - if (DEBUG) this.debug("This DataCall is not requested anymore."); - return; - } - - // Let DataCallHandler notify MobileConnectionService - this.dataCallHandler.notifyDataCallError(this, errorMsg); - - // For suggestedRetryTime, the value of INT32_MAX(0x7fffffff) means no retry. - if (aDataCall.suggestedRetryTime === INT32_MAX || - this.isPermanentFail(aDataCall.failCause, errorMsg)) { - if (DEBUG) this.debug("Data call error: no retry needed."); - return; - } - - this.retry(aDataCall.suggestedRetryTime); - return; - } - - this.apnRetryCounter = 0; - this.linkInfo.cid = aDataCall.cid; - - if (this.requestedNetworkIfaces.length === 0) { - if (DEBUG) { - this.debug("State is connected, but no network interface requested" + - " this DataCall"); - } - this.deactivate(); - return; - } - - this.linkInfo.ifname = aDataCall.ifname; - this.linkInfo.addresses = aDataCall.addresses ? aDataCall.addresses.split(" ") : []; - this.linkInfo.gateways = aDataCall.gateways ? aDataCall.gateways.split(" ") : []; - this.linkInfo.dnses = aDataCall.dnses ? aDataCall.dnses.split(" ") : []; - this.linkInfo.pcscf = aDataCall.pcscf ? aDataCall.pcscf.split(" ") : []; - this.linkInfo.mtu = aDataCall.mtu > 0 ? aDataCall.mtu : 0; - this.state = this._getGeckoDataCallState(aDataCall); - - // Notify DataCallHandler about data call connected. - this.dataCallHandler.notifyDataCallChanged(this); - - for (let i = 0; i < this.requestedNetworkIfaces.length; i++) { - this.requestedNetworkIfaces[i].notifyRILNetworkInterface(); - } - }, - - onDeactivateDataCallResult: function() { - if (DEBUG) this.debug("onDeactivateDataCallResult"); - - this.reset(); - - if (this.requestedNetworkIfaces.length > 0) { - if (DEBUG) { - this.debug("State is disconnected/unknown, but this DataCall is" + - " requested."); - } - this.setup(); - return; - } - - // Notify DataCallHandler about data call disconnected. - this.dataCallHandler.notifyDataCallChanged(this); - }, - - onDataCallChanged: function(aUpdatedDataCall) { - if (DEBUG) { - this.debug("onDataCallChanged: " + JSON.stringify(aUpdatedDataCall)); - } - - if (this.state == NETWORK_STATE_CONNECTING || - this.state == NETWORK_STATE_DISCONNECTING) { - if (DEBUG) { - this.debug("We are in connecting/disconnecting state, ignore any " + - "unsolicited event for now."); - } - return; - } - - let dataCallState = this._getGeckoDataCallState(aUpdatedDataCall); - if (this.state == dataCallState && - dataCallState != NETWORK_STATE_CONNECTED) { - return; - } - - let newLinkInfo = { - ifname: aUpdatedDataCall.ifname, - addresses: aUpdatedDataCall.addresses ? aUpdatedDataCall.addresses.split(" ") : [], - dnses: aUpdatedDataCall.dnses ? aUpdatedDataCall.dnses.split(" ") : [], - gateways: aUpdatedDataCall.gateways ? aUpdatedDataCall.gateways.split(" ") : [], - pcscf: aUpdatedDataCall.pcscf ? aUpdatedDataCall.pcscf.split(" ") : [], - mtu: aUpdatedDataCall.mtu > 0 ? aUpdatedDataCall.mtu : 0 - }; - - switch (dataCallState) { - case NETWORK_STATE_CONNECTED: - if (this.state == NETWORK_STATE_CONNECTED) { - let result = - this._compareDataCallLink(newLinkInfo, this.linkInfo); - - if (result == "identical") { - if (DEBUG) this.debug("No changes in data call."); - return; - } - if (result == "deactivate") { - if (DEBUG) this.debug("Data link changed, cleanup."); - this.deactivate(); - return; - } - // Minor change, just update and notify. - if (DEBUG) { - this.debug("Data link minor change, just update and notify."); - } - - this.linkInfo.addresses = newLinkInfo.addresses.slice(); - this.linkInfo.gateways = newLinkInfo.gateways.slice(); - this.linkInfo.dnses = newLinkInfo.dnses.slice(); - this.linkInfo.pcscf = newLinkInfo.pcscf.slice(); - this.linkInfo.mtu = newLinkInfo.mtu; - } - break; - case NETWORK_STATE_DISCONNECTED: - case NETWORK_STATE_UNKNOWN: - if (this.state == NETWORK_STATE_CONNECTED) { - // Notify first on unexpected data call disconnection. - this.state = dataCallState; - for (let i = 0; i < this.requestedNetworkIfaces.length; i++) { - this.requestedNetworkIfaces[i].notifyRILNetworkInterface(); - } - } - this.reset(); - - if (this.requestedNetworkIfaces.length > 0) { - if (DEBUG) { - this.debug("State is disconnected/unknown, but this DataCall is" + - " requested."); - } - this.setup(); - return; - } - break; - } - - this.state = dataCallState; - - // Notify DataCallHandler about data call changed. - this.dataCallHandler.notifyDataCallChanged(this); - - for (let i = 0; i < this.requestedNetworkIfaces.length; i++) { - this.requestedNetworkIfaces[i].notifyRILNetworkInterface(); - } - }, - - // Helpers - - debug: function(aMsg) { - dump("-*- DataCall[" + this.clientId + ":" + this.apnProfile.apn + "]: " + - aMsg + "\n"); - }, - - get connected() { - return this.state == NETWORK_STATE_CONNECTED; - }, - - isPermanentFail: function(aDataFailCause, aErrorMsg) { - // Check ril.h for 'no retry' data call fail causes. - if (aErrorMsg === RIL.GECKO_ERROR_RADIO_NOT_AVAILABLE || - aErrorMsg === RIL.GECKO_ERROR_INVALID_PARAMETER || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_OPERATOR_BARRED || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_MISSING_UKNOWN_APN || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_UNKNOWN_PDP_ADDRESS_TYPE || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_USER_AUTHENTICATION || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_ACTIVATION_REJECT_GGSN || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_SERVICE_OPTION_NOT_SUPPORTED || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_NSAPI_IN_USE || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_ONLY_IPV4_ALLOWED || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_ONLY_IPV6_ALLOWED || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_PROTOCOL_ERRORS || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_RADIO_POWER_OFF || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_TETHERED_CALL_ACTIVE) { - return true; - } - - return false; - }, - - inRequestedTypes: function(aType) { - for (let i = 0; i < this.requestedNetworkIfaces.length; i++) { - if (this.requestedNetworkIfaces[i].info.type == aType) { - return true; - } - } - return false; - }, - - canHandleApn: function(aApnSetting) { - let isIdentical = this.apnProfile.apn == aApnSetting.apn && - (this.apnProfile.user || '') == (aApnSetting.user || '') && - (this.apnProfile.password || '') == (aApnSetting.password || '') && - (this.apnProfile.authType || '') == (aApnSetting.authtype || ''); - - if (RILQUIRKS_HAVE_IPV6) { - isIdentical = isIdentical && - (this.apnProfile.protocol || '') == (aApnSetting.protocol || '') && - (this.apnProfile.roaming_protocol || '') == (aApnSetting.roaming_protocol || ''); - } - - return isIdentical; - }, - - resetLinkInfo: function() { - this.linkInfo.cid = null; - this.linkInfo.ifname = null; - this.linkInfo.addresses = []; - this.linkInfo.dnses = []; - this.linkInfo.gateways = []; - this.linkInfo.pcscf = []; - this.linkInfo.mtu = null; - }, - - reset: function() { - this.resetLinkInfo(); - - this.state = NETWORK_STATE_UNKNOWN; - }, - - connect: function(aNetworkInterface) { - if (DEBUG) this.debug("connect: " + aNetworkInterface.info.type); - - if (this.requestedNetworkIfaces.indexOf(aNetworkInterface) == -1) { - this.requestedNetworkIfaces.push(aNetworkInterface); - } - - if (this.state == NETWORK_STATE_CONNECTING || - this.state == NETWORK_STATE_DISCONNECTING) { - return; - } - if (this.state == NETWORK_STATE_CONNECTED) { - // This needs to run asynchronously, to behave the same way as the case of - // non-shared apn, see bug 1059110. - Services.tm.currentThread.dispatch(() => { - // Do not notify if state changed while this event was being dispatched, - // the state probably was notified already or need not to be notified. - if (aNetworkInterface.info.state == RIL.GECKO_NETWORK_STATE_CONNECTED) { - aNetworkInterface.notifyRILNetworkInterface(); - } - }, Ci.nsIEventTarget.DISPATCH_NORMAL); - return; - } - - // If retry mechanism is running on background, stop it since we are going - // to setup data call now. - if (this.timer) { - this.timer.cancel(); - } - - this.setup(); - }, - - setup: function() { - if (DEBUG) { - this.debug("Going to set up data connection with APN " + - this.apnProfile.apn); - } - - let connection = - gMobileConnectionService.getItemByServiceId(this.clientId); - let dataInfo = connection && connection.data; - if (dataInfo == null || - dataInfo.state != RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED || - dataInfo.type == RIL.GECKO_MOBILE_CONNECTION_STATE_UNKNOWN) { - return; - } - - let radioTechType = dataInfo.type; - let radioTechnology = RIL.GECKO_RADIO_TECH.indexOf(radioTechType); - let authType = RIL.RIL_DATACALL_AUTH_TO_GECKO.indexOf(this.apnProfile.authType); - // Use the default authType if the value in database is invalid. - // For the case that user might not select the authentication type. - if (authType == -1) { - if (DEBUG) { - this.debug("Invalid authType '" + this.apnProfile.authtype + - "', using '" + RIL.GECKO_DATACALL_AUTH_DEFAULT + "'"); - } - authType = RIL.RIL_DATACALL_AUTH_TO_GECKO.indexOf(RIL.GECKO_DATACALL_AUTH_DEFAULT); - } - - let pdpType = Ci.nsIDataCallInterface.DATACALL_PDP_TYPE_IPV4; - if (RILQUIRKS_HAVE_IPV6) { - pdpType = !dataInfo.roaming - ? RIL.RIL_DATACALL_PDP_TYPES.indexOf(this.apnProfile.protocol) - : RIL.RIL_DATACALL_PDP_TYPES.indexOf(this.apnProfile.roaming_protocol); - if (pdpType == -1) { - if (DEBUG) { - this.debug("Invalid pdpType '" + (!dataInfo.roaming - ? this.apnProfile.protocol - : this.apnProfile.roaming_protocol) + - "', using '" + RIL.GECKO_DATACALL_PDP_TYPE_DEFAULT + "'"); - } - pdpType = RIL.RIL_DATACALL_PDP_TYPES.indexOf(RIL.GECKO_DATACALL_PDP_TYPE_DEFAULT); - } - } - - let dcInterface = this.dataCallHandler.dataCallInterface; - dcInterface.setupDataCall( - this.apnProfile.apn, this.apnProfile.user, this.apnProfile.password, - authType, pdpType, { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallCallback]), - notifySetupDataCallSuccess: (aDataCall) => { - this.onSetupDataCallResult(aDataCall); - }, - notifyError: (aErrorMsg) => { - this.onSetupDataCallResult({errorMsg: aErrorMsg}); - } - }); - this.state = NETWORK_STATE_CONNECTING; - }, - - retry: function(aSuggestedRetryTime) { - let apnRetryTimer; - - // We will retry the connection in increasing times - // based on the function: time = A * numer_of_retries^2 + B - if (this.apnRetryCounter >= this.NETWORK_APNRETRY_MAXRETRIES) { - this.apnRetryCounter = 0; - this.timer = null; - if (DEBUG) this.debug("Too many APN Connection retries - STOP retrying"); - return; - } - - // If there is a valid aSuggestedRetryTime, override the retry timer. - if (aSuggestedRetryTime !== undefined && aSuggestedRetryTime >= 0) { - apnRetryTimer = aSuggestedRetryTime / 1000; - } else { - apnRetryTimer = this.NETWORK_APNRETRY_FACTOR * - (this.apnRetryCounter * this.apnRetryCounter) + - this.NETWORK_APNRETRY_ORIGIN; - } - this.apnRetryCounter++; - if (DEBUG) { - this.debug("Data call - APN Connection Retry Timer (secs-counter): " + - apnRetryTimer + "-" + this.apnRetryCounter); - } - - if (this.timer == null) { - // Event timer for connection retries - this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - } - this.timer.initWithCallback(this, apnRetryTimer * 1000, - Ci.nsITimer.TYPE_ONE_SHOT); - }, - - disconnect: function(aNetworkInterface) { - if (DEBUG) this.debug("disconnect: " + aNetworkInterface.info.type); - - let index = this.requestedNetworkIfaces.indexOf(aNetworkInterface); - if (index != -1) { - this.requestedNetworkIfaces.splice(index, 1); - - if (this.state == NETWORK_STATE_DISCONNECTED || - this.state == NETWORK_STATE_UNKNOWN) { - if (this.timer) { - this.timer.cancel(); - } - this.reset(); - return; - } - - // Notify the DISCONNECTED event immediately after network interface is - // removed from requestedNetworkIfaces, to make the DataCall, shared or - // not, to have the same behavior. - Services.tm.currentThread.dispatch(() => { - // Do not notify if state changed while this event was being dispatched, - // the state probably was notified already or need not to be notified. - if (aNetworkInterface.info.state == RIL.GECKO_NETWORK_STATE_DISCONNECTED) { - aNetworkInterface.notifyRILNetworkInterface(); - - // Clear link info after notifying NetworkManager. - if (this.requestedNetworkIfaces.length === 0) { - this.resetLinkInfo(); - } - } - }, Ci.nsIEventTarget.DISPATCH_NORMAL); - } - - // Only deactivate data call if no more network interface needs this - // DataCall and if state is CONNECTED, for other states, we simply remove - // the network interface from requestedNetworkIfaces. - if (this.requestedNetworkIfaces.length > 0 || - this.state != NETWORK_STATE_CONNECTED) { - return; - } - - this.deactivate(); - }, - - deactivate: function() { - let reason = Ci.nsIDataCallInterface.DATACALL_DEACTIVATE_NO_REASON; - if (DEBUG) { - this.debug("Going to disconnect data connection cid " + this.linkInfo.cid); - } - - let dcInterface = this.dataCallHandler.dataCallInterface; - dcInterface.deactivateDataCall(this.linkInfo.cid, reason, { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallCallback]), - notifySuccess: () => { - this.onDeactivateDataCallResult(); - }, - notifyError: (aErrorMsg) => { - this.onDeactivateDataCallResult(); - } - }); - - this.state = NETWORK_STATE_DISCONNECTING; - }, - - // Entry method for timer events. Used to reconnect to a failed APN - notify: function(aTimer) { - this.setup(); - }, - - shutdown: function() { - if (this.timer) { - this.timer.cancel(); - this.timer = null; - } - } -}; - -function RILNetworkInfo(aClientId, aType, aNetworkInterface) -{ - this.serviceId = aClientId; - this.type = aType; - - this.networkInterface = aNetworkInterface; -} -RILNetworkInfo.prototype = { - classID: RILNETWORKINFO_CID, - classInfo: XPCOMUtils.generateCI({classID: RILNETWORKINFO_CID, - classDescription: "RILNetworkInfo", - interfaces: [Ci.nsINetworkInfo, - Ci.nsIRilNetworkInfo]}), - QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInfo, - Ci.nsIRilNetworkInfo]), - - networkInterface: null, - - getDataCall: function() { - return this.networkInterface.dataCall; - }, - - getApnSetting: function() { - return this.networkInterface.apnSetting; - }, - - debug: function(aMsg) { - dump("-*- RILNetworkInfo[" + this.serviceId + ":" + this.type + "]: " + - aMsg + "\n"); - }, - - /** - * nsINetworkInfo Implementation - */ - get state() { - let dataCall = this.getDataCall(); - if (!dataCall.inRequestedTypes(this.type)) { - return NETWORK_STATE_DISCONNECTED; - } - return dataCall.state; - }, - - type: null, - - get name() { - return this.getDataCall().linkInfo.ifname; - }, - - getAddresses: function(aIps, aPrefixLengths) { - let addresses = this.getDataCall().linkInfo.addresses; - - let ips = []; - let prefixLengths = []; - for (let i = 0; i < addresses.length; i++) { - let [ip, prefixLength] = addresses[i].split("/"); - ips.push(ip); - prefixLengths.push(prefixLength); - } - - aIps.value = ips.slice(); - aPrefixLengths.value = prefixLengths.slice(); - - return ips.length; - }, - - getGateways: function(aCount) { - let linkInfo = this.getDataCall().linkInfo; - - if (aCount) { - aCount.value = linkInfo.gateways.length; - } - - return linkInfo.gateways.slice(); - }, - - getDnses: function(aCount) { - let linkInfo = this.getDataCall().linkInfo; - - if (aCount) { - aCount.value = linkInfo.dnses.length; - } - - return linkInfo.dnses.slice(); - }, - - /** - * nsIRilNetworkInfo Implementation - */ - - serviceId: 0, - - get iccId() { - let icc = gIccService.getIccByServiceId(this.serviceId); - let iccInfo = icc && icc.iccInfo; - - return iccInfo && iccInfo.iccid; - }, - - get mmsc() { - if (this.type != NETWORK_TYPE_MOBILE_MMS) { - if (DEBUG) this.debug("Error! Only MMS network can get MMSC."); - throw Cr.NS_ERROR_UNEXPECTED; - } - - return this.getApnSetting().mmsc || ""; - }, - - get mmsProxy() { - if (this.type != NETWORK_TYPE_MOBILE_MMS) { - if (DEBUG) this.debug("Error! Only MMS network can get MMS proxy."); - throw Cr.NS_ERROR_UNEXPECTED; - } - - return this.getApnSetting().mmsproxy || ""; - }, - - get mmsPort() { - if (this.type != NETWORK_TYPE_MOBILE_MMS) { - if (DEBUG) this.debug("Error! Only MMS network can get MMS port."); - throw Cr.NS_ERROR_UNEXPECTED; - } - - // Note: Port 0 is reserved, so we treat it as invalid as well. - // See http://www.iana.org/assignments/port-numbers - return this.getApnSetting().mmsport || -1; - }, - - getPcscf: function(aCount) { - if (this.type != NETWORK_TYPE_MOBILE_IMS) { - if (DEBUG) this.debug("Error! Only IMS network can get pcscf."); - throw Cr.NS_ERROR_UNEXPECTED; - } - - let linkInfo = this.getDataCall().linkInfo; - - if (aCount) { - aCount.value = linkInfo.pcscf.length; - } - return linkInfo.pcscf.slice(); - }, -}; - -function RILNetworkInterface(aDataCallHandler, aType, aApnSetting, aDataCall) { - if (!aDataCall) { - throw new Error("No dataCall for RILNetworkInterface: " + type); - } - - this.dataCallHandler = aDataCallHandler; - this.enabled = false; - this.dataCall = aDataCall; - this.apnSetting = aApnSetting; - - this.info = new RILNetworkInfo(aDataCallHandler.clientId, aType, this); -} - -RILNetworkInterface.prototype = { - classID: RILNETWORKINTERFACE_CID, - classInfo: XPCOMUtils.generateCI({classID: RILNETWORKINTERFACE_CID, - classDescription: "RILNetworkInterface", - interfaces: [Ci.nsINetworkInterface]}), - QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInterface]), - - // If this RILNetworkInterface type is enabled or not. - enabled: null, - - apnSetting: null, - - dataCall: null, - - /** - * nsINetworkInterface Implementation - */ - - info: null, - - get httpProxyHost() { - return this.apnSetting.proxy || ""; - }, - - get httpProxyPort() { - return this.apnSetting.port || ""; - }, - - get mtu() { - // Value provided by network has higher priority than apn settings. - return this.dataCall.linkInfo.mtu || this.apnSetting.mtu || -1; - }, - - // Helpers - - debug: function(aMsg) { - dump("-*- RILNetworkInterface[" + this.dataCallHandler.clientId + ":" + - this.info.type + "]: " + aMsg + "\n"); - }, - - get connected() { - return this.info.state == NETWORK_STATE_CONNECTED; - }, - - notifyRILNetworkInterface: function() { - if (DEBUG) { - this.debug("notifyRILNetworkInterface type: " + this.info.type + - ", state: " + this.info.state); - } - - gNetworkManager.updateNetworkInterface(this); - }, - - connect: function() { - this.enabled = true; - - this.dataCall.connect(this); - }, - - disconnect: function() { - if (!this.enabled) { - return; - } - this.enabled = false; - - this.dataCall.disconnect(this); - }, - - shutdown: function() { - this.dataCall.shutdown(); - this.dataCall = null; - } -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DataCallManager]);
\ No newline at end of file diff --git a/dom/system/gonk/DataCallManager.manifest b/dom/system/gonk/DataCallManager.manifest deleted file mode 100644 index 2a982415e..000000000 --- a/dom/system/gonk/DataCallManager.manifest +++ /dev/null @@ -1,4 +0,0 @@ -# DataCallManager.js -component {35b9efa2-e42c-45ce-8210-0a13e6f4aadc} DataCallManager.js -contract @mozilla.org/datacall/manager;1 {35b9efa2-e42c-45ce-8210-0a13e6f4aadc} -category profile-after-change DataCallManager @mozilla.org/datacall/manager;1
\ No newline at end of file diff --git a/dom/system/gonk/GeolocationUtil.cpp b/dom/system/gonk/GeolocationUtil.cpp deleted file mode 100644 index 99d484a19..000000000 --- a/dom/system/gonk/GeolocationUtil.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "GeolocationUtil.h" - -double CalculateDeltaInMeter(double aLat, double aLon, double aLastLat, double aLastLon) -{ - // Use spherical law of cosines to calculate difference - // Not quite as correct as the Haversine but simpler and cheaper - const double radsInDeg = M_PI / 180.0; - const double rNewLat = aLat * radsInDeg; - const double rNewLon = aLon * radsInDeg; - const double rOldLat = aLastLat * radsInDeg; - const double rOldLon = aLastLon * radsInDeg; - // WGS84 equatorial radius of earth = 6378137m - double cosDelta = (sin(rNewLat) * sin(rOldLat)) + - (cos(rNewLat) * cos(rOldLat) * cos(rOldLon - rNewLon)); - if (cosDelta > 1.0) { - cosDelta = 1.0; - } else if (cosDelta < -1.0) { - cosDelta = -1.0; - } - return acos(cosDelta) * 6378137; -} - diff --git a/dom/system/gonk/GeolocationUtil.h b/dom/system/gonk/GeolocationUtil.h deleted file mode 100644 index fde337fb8..000000000 --- a/dom/system/gonk/GeolocationUtil.h +++ /dev/null @@ -1,13 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef GEOLOCATIONUTIL_H -#define GEOLOCATIONUTIL_H - -double CalculateDeltaInMeter(double aLat, double aLon, double aLastLat, double aLastLon); - -#endif - diff --git a/dom/system/gonk/GonkGPSGeolocationProvider.cpp b/dom/system/gonk/GonkGPSGeolocationProvider.cpp deleted file mode 100644 index 9ce6ce2e5..000000000 --- a/dom/system/gonk/GonkGPSGeolocationProvider.cpp +++ /dev/null @@ -1,706 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include "GonkGPSGeolocationProvider.h" - -#include <cmath> -#include <pthread.h> -#include <hardware/gps.h> - -#include "base/task.h" -#include "GeolocationUtil.h" -#include "mozstumbler/MozStumbler.h" -#include "mozilla/Preferences.h" -#include "mozilla/Services.h" -#include "nsContentUtils.h" -#include "nsGeoPosition.h" -#include "nsIInterfaceRequestorUtils.h" -#include "nsINetworkInterface.h" -#include "nsIObserverService.h" -#include "nsJSUtils.h" -#include "nsPrintfCString.h" -#include "nsServiceManagerUtils.h" -#include "nsThreadUtils.h" -#include "prtime.h" -#include "mozilla/dom/BindingUtils.h" -#include "mozilla/dom/ScriptSettings.h" -#include "mozilla/dom/SettingChangeNotificationBinding.h" - -#ifdef AGPS_TYPE_INVALID -#define AGPS_HAVE_DUAL_APN -#endif - -#define FLUSH_AIDE_DATA 0 - -#undef LOG -#undef ERR -#undef DBG -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GonkGPSGeolocationProvider", ## args) -#define ERR(args...) __android_log_print(ANDROID_LOG_ERROR, "GonkGPSGeolocationProvider", ## args) -#define DBG(args...) __android_log_print(ANDROID_LOG_DEBUG, "GonkGPSGeolocationProvider" , ## args) - -using namespace mozilla; -using namespace mozilla::dom; - -static const int kDefaultPeriod = 1000; // ms -static bool gDebug_isLoggingEnabled = false; -static bool gDebug_isGPSLocationIgnored = false; -static const char* kMozSettingsChangedTopic = "mozsettings-changed"; -// Both of these settings can be toggled in the Gaia Developer settings screen. -static const char* kSettingDebugEnabled = "geolocation.debugging.enabled"; -static const char* kSettingDebugGpsIgnored = "geolocation.debugging.gps-locations-ignored"; - -// While most methods of GonkGPSGeolocationProvider should only be -// called from main thread, we deliberately put the Init and ShutdownGPS -// methods off main thread to avoid blocking. -NS_IMPL_ISUPPORTS(GonkGPSGeolocationProvider, - nsIGeolocationProvider, - nsIObserver, - nsISettingsServiceCallback) - -/* static */ GonkGPSGeolocationProvider* GonkGPSGeolocationProvider::sSingleton = nullptr; -GpsCallbacks GonkGPSGeolocationProvider::mCallbacks; - - -void -GonkGPSGeolocationProvider::LocationCallback(GpsLocation* location) -{ - if (gDebug_isGPSLocationIgnored) { - return; - } - - class UpdateLocationEvent : public Runnable { - public: - UpdateLocationEvent(nsGeoPosition* aPosition) - : mPosition(aPosition) - {} - NS_IMETHOD Run() override { - RefPtr<GonkGPSGeolocationProvider> provider = - GonkGPSGeolocationProvider::GetSingleton(); - nsCOMPtr<nsIGeolocationUpdate> callback = provider->mLocationCallback; - provider->mLastGPSPosition = mPosition; - if (callback) { - callback->Update(mPosition); - } - return NS_OK; - } - private: - RefPtr<nsGeoPosition> mPosition; - }; - - MOZ_ASSERT(location); - - const float kImpossibleAccuracy_m = 0.001; - if (location->accuracy < kImpossibleAccuracy_m) { - return; - } - - RefPtr<nsGeoPosition> somewhere = new nsGeoPosition(location->latitude, - location->longitude, - location->altitude, - location->accuracy, - location->accuracy, - location->bearing, - location->speed, - PR_Now() / PR_USEC_PER_MSEC); - // Note above: Can't use location->timestamp as the time from the satellite is a - // minimum of 16 secs old (see http://leapsecond.com/java/gpsclock.htm). - // All code from this point on expects the gps location to be timestamped with the - // current time, most notably: the geolocation service which respects maximumAge - // set in the DOM JS. - - if (gDebug_isLoggingEnabled) { - DBG("geo: GPS got a fix (%f, %f). accuracy: %f", - location->latitude, - location->longitude, - location->accuracy); - } - - RefPtr<UpdateLocationEvent> event = new UpdateLocationEvent(somewhere); - NS_DispatchToMainThread(event); - -} - -class NotifyObserversGPSTask final : public Runnable -{ -public: - explicit NotifyObserversGPSTask(const char16_t* aData) - : mData(aData) - {} - NS_IMETHOD Run() override { - RefPtr<nsIGeolocationProvider> provider = - GonkGPSGeolocationProvider::GetSingleton(); - nsCOMPtr<nsIObserverService> obsService = services::GetObserverService(); - obsService->NotifyObservers(provider, "geolocation-device-events", mData); - return NS_OK; - } -private: - const char16_t* mData; -}; - -void -GonkGPSGeolocationProvider::StatusCallback(GpsStatus* status) -{ - const char* msgStream=0; - switch (status->status) { - case GPS_STATUS_NONE: - msgStream = "geo: GPS_STATUS_NONE\n"; - break; - case GPS_STATUS_SESSION_BEGIN: - msgStream = "geo: GPS_STATUS_SESSION_BEGIN\n"; - break; - case GPS_STATUS_SESSION_END: - msgStream = "geo: GPS_STATUS_SESSION_END\n"; - break; - case GPS_STATUS_ENGINE_ON: - msgStream = "geo: GPS_STATUS_ENGINE_ON\n"; - NS_DispatchToMainThread(new NotifyObserversGPSTask(u"GPSStarting")); - break; - case GPS_STATUS_ENGINE_OFF: - msgStream = "geo: GPS_STATUS_ENGINE_OFF\n"; - NS_DispatchToMainThread(new NotifyObserversGPSTask(u"GPSShutdown")); - break; - default: - msgStream = "geo: Unknown GPS status\n"; - break; - } - if (gDebug_isLoggingEnabled){ - DBG("%s", msgStream); - } -} - -void -GonkGPSGeolocationProvider::SvStatusCallback(GpsSvStatus* sv_info) -{ - if (gDebug_isLoggingEnabled) { - static int numSvs = 0; - static uint32_t numEphemeris = 0; - static uint32_t numAlmanac = 0; - static uint32_t numUsedInFix = 0; - - unsigned int i = 1; - uint32_t svAlmanacCount = 0; - for (i = 1; i > 0; i <<= 1) { - if (i & sv_info->almanac_mask) { - svAlmanacCount++; - } - } - - uint32_t svEphemerisCount = 0; - for (i = 1; i > 0; i <<= 1) { - if (i & sv_info->ephemeris_mask) { - svEphemerisCount++; - } - } - - uint32_t svUsedCount = 0; - for (i = 1; i > 0; i <<= 1) { - if (i & sv_info->used_in_fix_mask) { - svUsedCount++; - } - } - - // Log the message only if the the status changed. - if (sv_info->num_svs != numSvs || - svAlmanacCount != numAlmanac || - svEphemerisCount != numEphemeris || - svUsedCount != numUsedInFix) { - - LOG( - "geo: Number of SVs have (visibility, almanac, ephemeris): (%d, %d, %d)." - " %d of these SVs were used in fix.\n", - sv_info->num_svs, svAlmanacCount, svEphemerisCount, svUsedCount); - - numSvs = sv_info->num_svs; - numAlmanac = svAlmanacCount; - numEphemeris = svEphemerisCount; - numUsedInFix = svUsedCount; - } - } -} - -void -GonkGPSGeolocationProvider::NmeaCallback(GpsUtcTime timestamp, const char* nmea, int length) -{ - if (gDebug_isLoggingEnabled) { - DBG("NMEA: timestamp:\t%lld, length: %d, %s", timestamp, length, nmea); - } -} - -void -GonkGPSGeolocationProvider::SetCapabilitiesCallback(uint32_t capabilities) -{ - class UpdateCapabilitiesEvent : public Runnable { - public: - UpdateCapabilitiesEvent(uint32_t aCapabilities) - : mCapabilities(aCapabilities) - {} - NS_IMETHOD Run() override { - RefPtr<GonkGPSGeolocationProvider> provider = - GonkGPSGeolocationProvider::GetSingleton(); - - provider->mSupportsScheduling = mCapabilities & GPS_CAPABILITY_SCHEDULING; - provider->mSupportsSingleShot = mCapabilities & GPS_CAPABILITY_SINGLE_SHOT; -#ifdef GPS_CAPABILITY_ON_DEMAND_TIME - provider->mSupportsTimeInjection = mCapabilities & GPS_CAPABILITY_ON_DEMAND_TIME; -#endif - return NS_OK; - } - private: - uint32_t mCapabilities; - }; - - NS_DispatchToMainThread(new UpdateCapabilitiesEvent(capabilities)); -} - -void -GonkGPSGeolocationProvider::AcquireWakelockCallback() -{ -} - -void -GonkGPSGeolocationProvider::ReleaseWakelockCallback() -{ -} - -typedef void *(*pthread_func)(void *); - -/** Callback for creating a thread that can call into the JS codes. - */ -pthread_t -GonkGPSGeolocationProvider::CreateThreadCallback(const char* name, void (*start)(void *), void* arg) -{ - pthread_t thread; - pthread_attr_t attr; - - pthread_attr_init(&attr); - - /* Unfortunately pthread_create and the callback disagreed on what - * start function should return. - */ - pthread_create(&thread, &attr, reinterpret_cast<pthread_func>(start), arg); - - return thread; -} - -void -GonkGPSGeolocationProvider::RequestUtcTimeCallback() -{ -} - -GonkGPSGeolocationProvider::GonkGPSGeolocationProvider() - : mStarted(false) - , mSupportsScheduling(false) - , mObservingSettingsChange(false) - , mSupportsSingleShot(false) - , mSupportsTimeInjection(false) - , mGpsInterface(nullptr) -{ -} - -GonkGPSGeolocationProvider::~GonkGPSGeolocationProvider() -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(!mStarted, "Must call Shutdown before destruction"); - - sSingleton = nullptr; -} - -already_AddRefed<GonkGPSGeolocationProvider> -GonkGPSGeolocationProvider::GetSingleton() -{ - MOZ_ASSERT(NS_IsMainThread()); - - if (!sSingleton) - sSingleton = new GonkGPSGeolocationProvider(); - - RefPtr<GonkGPSGeolocationProvider> provider = sSingleton; - return provider.forget(); -} - -const GpsInterface* -GonkGPSGeolocationProvider::GetGPSInterface() -{ - hw_module_t* module; - - if (hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module)) - return nullptr; - - hw_device_t* device; - if (module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device)) - return nullptr; - - gps_device_t* gps_device = (gps_device_t *)device; - const GpsInterface* result = gps_device->get_gps_interface(gps_device); - - if (result->size != sizeof(GpsInterface)) { - return nullptr; - } - return result; -} - -void -GonkGPSGeolocationProvider::RequestSettingValue(const char* aKey) -{ - MOZ_ASSERT(aKey); - nsCOMPtr<nsISettingsService> ss = do_GetService("@mozilla.org/settingsService;1"); - if (!ss) { - MOZ_ASSERT(ss); - return; - } - - nsCOMPtr<nsISettingsServiceLock> lock; - nsresult rv = ss->CreateLock(nullptr, getter_AddRefs(lock)); - if (NS_FAILED(rv)) { - ERR("error while createLock setting '%s': %d\n", aKey, uint32_t(rv)); - return; - } - - rv = lock->Get(aKey, this); - if (NS_FAILED(rv)) { - ERR("error while get setting '%s': %d\n", aKey, uint32_t(rv)); - return; - } -} - -void -GonkGPSGeolocationProvider::InjectLocation(double latitude, - double longitude, - float accuracy) -{ - if (gDebug_isLoggingEnabled) { - DBG("injecting location (%f, %f) accuracy: %f", latitude, longitude, accuracy); - } - - MOZ_ASSERT(NS_IsMainThread()); - if (!mGpsInterface) { - return; - } - - mGpsInterface->inject_location(latitude, longitude, accuracy); -} - -void -GonkGPSGeolocationProvider::Init() -{ - // Must not be main thread. Some GPS driver's first init takes very long. - MOZ_ASSERT(!NS_IsMainThread()); - - mGpsInterface = GetGPSInterface(); - if (!mGpsInterface) { - return; - } - - if (!mCallbacks.size) { - mCallbacks.size = sizeof(GpsCallbacks); - mCallbacks.location_cb = LocationCallback; - mCallbacks.status_cb = StatusCallback; - mCallbacks.sv_status_cb = SvStatusCallback; - mCallbacks.nmea_cb = NmeaCallback; - mCallbacks.set_capabilities_cb = SetCapabilitiesCallback; - mCallbacks.acquire_wakelock_cb = AcquireWakelockCallback; - mCallbacks.release_wakelock_cb = ReleaseWakelockCallback; - mCallbacks.create_thread_cb = CreateThreadCallback; - -#ifdef GPS_CAPABILITY_ON_DEMAND_TIME - mCallbacks.request_utc_time_cb = RequestUtcTimeCallback; -#endif - - } - - if (mGpsInterface->init(&mCallbacks) != 0) { - return; - } - - NS_DispatchToMainThread(NewRunnableMethod(this, &GonkGPSGeolocationProvider::StartGPS)); -} - -void -GonkGPSGeolocationProvider::StartGPS() -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(mGpsInterface); - - int32_t update = Preferences::GetInt("geo.default.update", kDefaultPeriod); - - int positionMode = GPS_POSITION_MODE_STANDALONE; - - if (!mSupportsScheduling) { - update = kDefaultPeriod; - } - - mGpsInterface->set_position_mode(positionMode, - GPS_POSITION_RECURRENCE_PERIODIC, - update, 0, 0); -#if FLUSH_AIDE_DATA - // Delete cached data - mGpsInterface->delete_aiding_data(GPS_DELETE_ALL); -#endif - - mGpsInterface->start(); -} - - -NS_IMPL_ISUPPORTS(GonkGPSGeolocationProvider::NetworkLocationUpdate, - nsIGeolocationUpdate) - -NS_IMETHODIMP -GonkGPSGeolocationProvider::NetworkLocationUpdate::Update(nsIDOMGeoPosition *position) -{ - RefPtr<GonkGPSGeolocationProvider> provider = - GonkGPSGeolocationProvider::GetSingleton(); - - nsCOMPtr<nsIDOMGeoPositionCoords> coords; - position->GetCoords(getter_AddRefs(coords)); - if (!coords) { - return NS_ERROR_FAILURE; - } - - double lat, lon, acc; - coords->GetLatitude(&lat); - coords->GetLongitude(&lon); - coords->GetAccuracy(&acc); - - double delta = -1.0; - - static double sLastMLSPosLat = 0; - static double sLastMLSPosLon = 0; - - if (0 != sLastMLSPosLon || 0 != sLastMLSPosLat) { - delta = CalculateDeltaInMeter(lat, lon, sLastMLSPosLat, sLastMLSPosLon); - } - - sLastMLSPosLat = lat; - sLastMLSPosLon = lon; - - // if the MLS coord change is smaller than this arbitrarily small value - // assume the MLS coord is unchanged, and stick with the GPS location - const double kMinMLSCoordChangeInMeters = 10; - - DOMTimeStamp time_ms = 0; - if (provider->mLastGPSPosition) { - provider->mLastGPSPosition->GetTimestamp(&time_ms); - } - const int64_t diff_ms = (PR_Now() / PR_USEC_PER_MSEC) - time_ms; - - // We want to distinguish between the GPS being inactive completely - // and temporarily inactive. In the former case, we would use a low - // accuracy network location; in the latter, we only want a network - // location that appears to updating with movement. - - const bool isGPSFullyInactive = diff_ms > 1000 * 60 * 2; // two mins - const bool isGPSTempInactive = diff_ms > 1000 * 10; // 10 secs - - if (provider->mLocationCallback) { - if (isGPSFullyInactive || - (isGPSTempInactive && delta > kMinMLSCoordChangeInMeters)) - { - if (gDebug_isLoggingEnabled) { - DBG("Using MLS, GPS age:%fs, MLS Delta:%fm\n", diff_ms / 1000.0, delta); - } - provider->mLocationCallback->Update(position); - } else if (provider->mLastGPSPosition) { - if (gDebug_isLoggingEnabled) { - DBG("Using old GPS age:%fs\n", diff_ms / 1000.0); - } - - // This is a fallback case so that the GPS provider responds with its last - // location rather than waiting for a more recent GPS or network location. - // The service decides if the location is too old, not the provider. - provider->mLocationCallback->Update(provider->mLastGPSPosition); - } - } - provider->InjectLocation(lat, lon, acc); - return NS_OK; -} -NS_IMETHODIMP -GonkGPSGeolocationProvider::NetworkLocationUpdate::NotifyError(uint16_t error) -{ - return NS_OK; -} -NS_IMETHODIMP -GonkGPSGeolocationProvider::Startup() -{ - MOZ_ASSERT(NS_IsMainThread()); - - if (mStarted) { - return NS_OK; - } - - RequestSettingValue(kSettingDebugEnabled); - RequestSettingValue(kSettingDebugGpsIgnored); - - // Setup an observer to watch changes to the setting. - nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); - if (observerService) { - MOZ_ASSERT(!mObservingSettingsChange); - nsresult rv = observerService->AddObserver(this, kMozSettingsChangedTopic, false); - if (NS_FAILED(rv)) { - NS_WARNING("geo: Gonk GPS AddObserver failed"); - } else { - mObservingSettingsChange = true; - } - } - - if (!mInitThread) { - nsresult rv = NS_NewThread(getter_AddRefs(mInitThread)); - NS_ENSURE_SUCCESS(rv, rv); - } - - mInitThread->Dispatch(NewRunnableMethod(this, &GonkGPSGeolocationProvider::Init), - NS_DISPATCH_NORMAL); - - mNetworkLocationProvider = do_CreateInstance("@mozilla.org/geolocation/mls-provider;1"); - if (mNetworkLocationProvider) { - nsresult rv = mNetworkLocationProvider->Startup(); - if (NS_SUCCEEDED(rv)) { - RefPtr<NetworkLocationUpdate> update = new NetworkLocationUpdate(); - mNetworkLocationProvider->Watch(update); - } - } - - mStarted = true; - return NS_OK; -} - -NS_IMETHODIMP -GonkGPSGeolocationProvider::Watch(nsIGeolocationUpdate* aCallback) -{ - MOZ_ASSERT(NS_IsMainThread()); - - mLocationCallback = aCallback; - return NS_OK; -} - -NS_IMETHODIMP -GonkGPSGeolocationProvider::Shutdown() -{ - MOZ_ASSERT(NS_IsMainThread()); - - if (!mStarted) { - return NS_OK; - } - - mStarted = false; - if (mNetworkLocationProvider) { - mNetworkLocationProvider->Shutdown(); - mNetworkLocationProvider = nullptr; - } - - nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); - if (obs) { - nsresult rv; - rv = obs->RemoveObserver(this, kMozSettingsChangedTopic); - if (NS_FAILED(rv)) { - NS_WARNING("geo: Gonk GPS mozsettings RemoveObserver failed"); - } else { - mObservingSettingsChange = false; - } - } - - mInitThread->Dispatch(NewRunnableMethod(this, &GonkGPSGeolocationProvider::ShutdownGPS), - NS_DISPATCH_NORMAL); - - return NS_OK; -} - -void -GonkGPSGeolocationProvider::ShutdownGPS() -{ - MOZ_ASSERT(!mStarted, "Should only be called after Shutdown"); - - if (mGpsInterface) { - mGpsInterface->stop(); - mGpsInterface->cleanup(); - } -} - -NS_IMETHODIMP -GonkGPSGeolocationProvider::SetHighAccuracy(bool) -{ - return NS_OK; -} - -namespace { -int -ConvertToGpsNetworkType(int aNetworkInterfaceType) -{ - switch (aNetworkInterfaceType) { - case nsINetworkInfo::NETWORK_TYPE_WIFI: - return AGPS_RIL_NETWORK_TYPE_WIFI; - case nsINetworkInfo::NETWORK_TYPE_MOBILE: - return AGPS_RIL_NETWORK_TYPE_MOBILE; - case nsINetworkInfo::NETWORK_TYPE_MOBILE_MMS: - return AGPS_RIL_NETWORK_TYPE_MOBILE_MMS; - case nsINetworkInfo::NETWORK_TYPE_MOBILE_SUPL: - return AGPS_RIL_NETWORK_TYPE_MOBILE_SUPL; - case nsINetworkInfo::NETWORK_TYPE_MOBILE_DUN: - return AGPS_RIL_NETWORK_TTYPE_MOBILE_DUN; - default: - NS_WARNING(nsPrintfCString("Unknown network type mapping %d", - aNetworkInterfaceType).get()); - return -1; - } -} -} // namespace - -NS_IMETHODIMP -GonkGPSGeolocationProvider::Observe(nsISupports* aSubject, - const char* aTopic, - const char16_t* aData) -{ - MOZ_ASSERT(NS_IsMainThread()); - - if (!strcmp(aTopic, kMozSettingsChangedTopic)) { - // Read changed setting value - RootedDictionary<SettingChangeNotification> setting(RootingCx()); - if (!WrappedJSToDictionary(aSubject, setting)) { - return NS_OK; - } - - if (setting.mKey.EqualsASCII(kSettingDebugGpsIgnored)) { - LOG("received mozsettings-changed: ignoring\n"); - gDebug_isGPSLocationIgnored = - setting.mValue.isBoolean() ? setting.mValue.toBoolean() : false; - if (gDebug_isLoggingEnabled) { - DBG("GPS ignored %d\n", gDebug_isGPSLocationIgnored); - } - return NS_OK; - } else if (setting.mKey.EqualsASCII(kSettingDebugEnabled)) { - LOG("received mozsettings-changed: logging\n"); - gDebug_isLoggingEnabled = - setting.mValue.isBoolean() ? setting.mValue.toBoolean() : false; - return NS_OK; - } - } - - return NS_OK; -} - -/** nsISettingsServiceCallback **/ - -NS_IMETHODIMP -GonkGPSGeolocationProvider::Handle(const nsAString& aName, - JS::Handle<JS::Value> aResult) -{ - return NS_OK; -} - -NS_IMETHODIMP -GonkGPSGeolocationProvider::HandleError(const nsAString& aErrorMessage) -{ - return NS_OK; -} diff --git a/dom/system/gonk/GonkGPSGeolocationProvider.h b/dom/system/gonk/GonkGPSGeolocationProvider.h deleted file mode 100644 index 514398edf..000000000 --- a/dom/system/gonk/GonkGPSGeolocationProvider.h +++ /dev/null @@ -1,103 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef GonkGPSGeolocationProvider_h -#define GonkGPSGeolocationProvider_h - -#include <hardware/gps.h> // for GpsInterface -#include "nsCOMPtr.h" -#include "nsIGeolocationProvider.h" -#include "nsIObserver.h" -#include "nsIDOMGeoPosition.h" -#include "nsISettingsService.h" - -class nsIThread; - -#define GONK_GPS_GEOLOCATION_PROVIDER_CID \ -{ 0x48525ec5, 0x5a7f, 0x490a, { 0x92, 0x77, 0xba, 0x66, 0xe0, 0xd2, 0x2c, 0x8b } } - -#define GONK_GPS_GEOLOCATION_PROVIDER_CONTRACTID \ -"@mozilla.org/gonk-gps-geolocation-provider;1" - -class GonkGPSGeolocationProvider : public nsIGeolocationProvider - , public nsIObserver - , public nsISettingsServiceCallback -{ -public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIGEOLOCATIONPROVIDER - NS_DECL_NSIOBSERVER - NS_DECL_NSISETTINGSSERVICECALLBACK - - static already_AddRefed<GonkGPSGeolocationProvider> GetSingleton(); - -private: - - /* Client should use GetSingleton() to get the provider instance. */ - GonkGPSGeolocationProvider(); - GonkGPSGeolocationProvider(const GonkGPSGeolocationProvider &); - GonkGPSGeolocationProvider & operator = (const GonkGPSGeolocationProvider &); - virtual ~GonkGPSGeolocationProvider(); - - static void LocationCallback(GpsLocation* location); - static void StatusCallback(GpsStatus* status); - static void SvStatusCallback(GpsSvStatus* sv_info); - static void NmeaCallback(GpsUtcTime timestamp, const char* nmea, int length); - static void SetCapabilitiesCallback(uint32_t capabilities); - static void AcquireWakelockCallback(); - static void ReleaseWakelockCallback(); - static pthread_t CreateThreadCallback(const char* name, void (*start)(void*), void* arg); - static void RequestUtcTimeCallback(); - - static GpsCallbacks mCallbacks; - - void Init(); - void StartGPS(); - void ShutdownGPS(); - void InjectLocation(double latitude, double longitude, float accuracy); - void RequestSettingValue(const char* aKey); - - const GpsInterface* GetGPSInterface(); - - static GonkGPSGeolocationProvider* sSingleton; - - bool mStarted; - - bool mSupportsScheduling; - bool mObservingSettingsChange; - bool mSupportsSingleShot; - bool mSupportsTimeInjection; - - const GpsInterface* mGpsInterface; - nsCOMPtr<nsIGeolocationUpdate> mLocationCallback; - nsCOMPtr<nsIThread> mInitThread; - nsCOMPtr<nsIGeolocationProvider> mNetworkLocationProvider; - nsCOMPtr<nsIDOMGeoPosition> mLastGPSPosition; - - class NetworkLocationUpdate : public nsIGeolocationUpdate - { - public: - NS_DECL_ISUPPORTS - NS_DECL_NSIGEOLOCATIONUPDATE - - NetworkLocationUpdate() {} - - private: - virtual ~NetworkLocationUpdate() {} - }; -}; - -#endif /* GonkGPSGeolocationProvider_h */ diff --git a/dom/system/gonk/MozMtpCommon.h b/dom/system/gonk/MozMtpCommon.h deleted file mode 100644 index 81c0a3a74..000000000 --- a/dom/system/gonk/MozMtpCommon.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_mozmtpcommon_h__ -#define mozilla_system_mozmtpcommon_h__ - -#include "mozilla/Types.h" -#include <android/log.h> - -#define USE_DEBUG 0 - -#if USE_DEBUG -#define MTP_DBG(msg, ...) \ - __android_log_print(ANDROID_LOG_DEBUG, "MozMtp", \ - "%s: " msg, __FUNCTION__, ##__VA_ARGS__) -#else -#define MTP_DBG(msg, ...) -#endif - -#define MTP_LOG(msg, ...) \ - __android_log_print(ANDROID_LOG_INFO, "MozMtp", \ - "%s: " msg, __FUNCTION__, ##__VA_ARGS__) - -#define MTP_ERR(msg, ...) \ - __android_log_print(ANDROID_LOG_ERROR, "MozMtp", \ - "%s: " msg, __FUNCTION__, ##__VA_ARGS__) - -#define BEGIN_MTP_NAMESPACE \ - namespace mozilla { namespace system { namespace mtp { -#define END_MTP_NAMESPACE \ - } /* namespace mtp */ } /* namespace system */ } /* namespace mozilla */ -#define USING_MTP_NAMESPACE \ - using namespace mozilla::system::mtp; - -namespace android { - class MOZ_EXPORT MtpServer; - class MOZ_EXPORT MtpStorage; - class MOZ_EXPORT MtpStringBuffer; - class MOZ_EXPORT MtpDatabase; - class MOZ_EXPORT MtpDataPacket; - class MOZ_EXPORT MtpProperty; -} - -#include <mtp.h> -#include <MtpDatabase.h> -#include <MtpObjectInfo.h> -#include <MtpProperty.h> -#include <MtpServer.h> -#include <MtpStorage.h> -#include <MtpStringBuffer.h> -#include <MtpTypes.h> - -#endif // mozilla_system_mtpcommon_h__ diff --git a/dom/system/gonk/MozMtpDatabase.cpp b/dom/system/gonk/MozMtpDatabase.cpp deleted file mode 100644 index 29fe23e8d..000000000 --- a/dom/system/gonk/MozMtpDatabase.cpp +++ /dev/null @@ -1,1542 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "MozMtpDatabase.h" -#include "MozMtpServer.h" - -#include "base/message_loop.h" -#include "DeviceStorage.h" -#include "mozilla/ArrayUtils.h" -#include "mozilla/AutoRestore.h" -#include "mozilla/Scoped.h" -#include "mozilla/Services.h" -#include "nsIFile.h" -#include "nsIObserverService.h" -#include "nsPrintfCString.h" -#include "nsString.h" -#include "prio.h" - -#include <dirent.h> -#include <libgen.h> -#include <utime.h> -#include <sys/stat.h> - -using namespace android; -using namespace mozilla; - -namespace mozilla { -MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedCloseDir, PRDir, PR_CloseDir) -} - -BEGIN_MTP_NAMESPACE - -static const char* kMtpWatcherNotify = "mtp-watcher-notify"; - -#if 0 -// Some debug code for figuring out deadlocks, if you happen to run into -// that scenario - -class DebugMutexAutoLock: public MutexAutoLock -{ -public: - DebugMutexAutoLock(mozilla::Mutex& aMutex) - : MutexAutoLock(aMutex) - { - MTP_LOG("Mutex acquired"); - } - - ~DebugMutexAutoLock() - { - MTP_LOG("Releasing mutex"); - } -}; -#define MutexAutoLock MTP_LOG("About to enter mutex"); DebugMutexAutoLock - -#endif - -static const char * -ObjectPropertyAsStr(MtpObjectProperty aProperty) -{ - switch (aProperty) { - case MTP_PROPERTY_STORAGE_ID: return "MTP_PROPERTY_STORAGE_ID"; - case MTP_PROPERTY_OBJECT_FORMAT: return "MTP_PROPERTY_OBJECT_FORMAT"; - case MTP_PROPERTY_PROTECTION_STATUS: return "MTP_PROPERTY_PROTECTION_STATUS"; - case MTP_PROPERTY_OBJECT_SIZE: return "MTP_PROPERTY_OBJECT_SIZE"; - case MTP_PROPERTY_OBJECT_FILE_NAME: return "MTP_PROPERTY_OBJECT_FILE_NAME"; - case MTP_PROPERTY_DATE_CREATED: return "MTP_PROPERTY_DATE_CREATED"; - case MTP_PROPERTY_DATE_MODIFIED: return "MTP_PROPERTY_DATE_MODIFIED"; - case MTP_PROPERTY_PARENT_OBJECT: return "MTP_PROPERTY_PARENT_OBJECT"; - case MTP_PROPERTY_PERSISTENT_UID: return "MTP_PROPERTY_PERSISTENT_UID"; - case MTP_PROPERTY_NAME: return "MTP_PROPERTY_NAME"; - case MTP_PROPERTY_DATE_ADDED: return "MTP_PROPERTY_DATE_ADDED"; - case MTP_PROPERTY_WIDTH: return "MTP_PROPERTY_WIDTH"; - case MTP_PROPERTY_HEIGHT: return "MTP_PROPERTY_HEIGHT"; - case MTP_PROPERTY_IMAGE_BIT_DEPTH: return "MTP_PROPERTY_IMAGE_BIT_DEPTH"; - case MTP_PROPERTY_DISPLAY_NAME: return "MTP_PROPERTY_DISPLAY_NAME"; - } - return "MTP_PROPERTY_???"; -} - -static char* -FormatDate(time_t aTime, char *aDateStr, size_t aDateStrSize) -{ - struct tm tm; - localtime_r(&aTime, &tm); - MTP_LOG("(%ld) tm_zone = %s off = %ld", aTime, tm.tm_zone, tm.tm_gmtoff); - strftime(aDateStr, aDateStrSize, "%Y%m%dT%H%M%S", &tm); - return aDateStr; -} - -MozMtpDatabase::MozMtpDatabase() - : mMutex("MozMtpDatabase::mMutex"), - mDb(mMutex), - mStorage(mMutex), - mBeginSendObjectCalled(false) -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - // We use the index into the array as the handle. Since zero isn't a valid - // index, we stick a dummy entry there. - - RefPtr<DbEntry> dummy; - - MutexAutoLock lock(mMutex); - mDb.AppendElement(dummy); -} - -//virtual -MozMtpDatabase::~MozMtpDatabase() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); -} - -void -MozMtpDatabase::AddEntry(DbEntry *entry) -{ - MutexAutoLock lock(mMutex); - - entry->mHandle = GetNextHandle(); - MOZ_ASSERT(mDb.Length() == entry->mHandle); - mDb.AppendElement(entry); - - MTP_DBG("Handle: 0x%08x Parent: 0x%08x Path:'%s'", - entry->mHandle, entry->mParent, entry->mPath.get()); -} - -void -MozMtpDatabase::AddEntryAndNotify(DbEntry* entry, RefCountedMtpServer* aMtpServer) -{ - AddEntry(entry); - aMtpServer->sendObjectAdded(entry->mHandle); -} - -void -MozMtpDatabase::DumpEntries(const char* aLabel) -{ - MutexAutoLock lock(mMutex); - - ProtectedDbArray::size_type numEntries = mDb.Length(); - MTP_LOG("%s: numEntries = %d", aLabel, numEntries); - ProtectedDbArray::index_type entryIndex; - for (entryIndex = 1; entryIndex < numEntries; entryIndex++) { - RefPtr<DbEntry> entry = mDb[entryIndex]; - if (entry) { - MTP_LOG("%s: mDb[%d]: mHandle: 0x%08x mParent: 0x%08x StorageID: 0x%08x path: '%s'", - aLabel, entryIndex, entry->mHandle, entry->mParent, entry->mStorageID, entry->mPath.get()); - } else { - MTP_LOG("%s: mDb[%2d]: entry is NULL", aLabel, entryIndex); - } - } -} - -MtpObjectHandle -MozMtpDatabase::FindEntryByPath(const nsACString& aPath) -{ - MutexAutoLock lock(mMutex); - - ProtectedDbArray::size_type numEntries = mDb.Length(); - ProtectedDbArray::index_type entryIndex; - for (entryIndex = 1; entryIndex < numEntries; entryIndex++) { - RefPtr<DbEntry> entry = mDb[entryIndex]; - if (entry && entry->mPath.Equals(aPath)) { - return entryIndex; - } - } - return 0; -} - -already_AddRefed<MozMtpDatabase::DbEntry> -MozMtpDatabase::GetEntry(MtpObjectHandle aHandle) -{ - MutexAutoLock lock(mMutex); - - RefPtr<DbEntry> entry; - - if (aHandle > 0 && aHandle < mDb.Length()) { - entry = mDb[aHandle]; - } - return entry.forget(); -} - -void -MozMtpDatabase::RemoveEntry(MtpObjectHandle aHandle) -{ - MutexAutoLock lock(mMutex); - if (!IsValidHandle(aHandle)) { - return; - } - - RefPtr<DbEntry> removedEntry = mDb[aHandle]; - mDb[aHandle] = nullptr; - MTP_DBG("0x%08x removed", aHandle); - // if the entry is not a folder, just return. - if (removedEntry->mObjectFormat != MTP_FORMAT_ASSOCIATION) { - return; - } - - // Find out and remove the children of aHandle. - // Since the index for a directory will always be less than the index of any of its children, - // we can remove the entire subtree in one pass. - ProtectedDbArray::size_type numEntries = mDb.Length(); - ProtectedDbArray::index_type entryIndex; - for (entryIndex = aHandle+1; entryIndex < numEntries; entryIndex++) { - RefPtr<DbEntry> entry = mDb[entryIndex]; - if (entry && IsValidHandle(entry->mParent) && !mDb[entry->mParent]) { - mDb[entryIndex] = nullptr; - MTP_DBG("0x%08x removed", aHandle); - } - } -} - -void -MozMtpDatabase::RemoveEntryAndNotify(MtpObjectHandle aHandle, RefCountedMtpServer* aMtpServer) -{ - RemoveEntry(aHandle); - aMtpServer->sendObjectRemoved(aHandle); -} - -void -MozMtpDatabase::UpdateEntryAndNotify(MtpObjectHandle aHandle, DeviceStorageFile* aFile, RefCountedMtpServer* aMtpServer) -{ - UpdateEntry(aHandle, aFile); - aMtpServer->sendObjectAdded(aHandle); -} - - -void -MozMtpDatabase::UpdateEntry(MtpObjectHandle aHandle, DeviceStorageFile* aFile) -{ - MutexAutoLock lock(mMutex); - - RefPtr<DbEntry> entry = mDb[aHandle]; - - int64_t fileSize = 0; - aFile->mFile->GetFileSize(&fileSize); - entry->mObjectSize = fileSize; - - PRTime dateModifiedMsecs; - // GetLastModifiedTime returns msecs - aFile->mFile->GetLastModifiedTime(&dateModifiedMsecs); - entry->mDateModified = dateModifiedMsecs / PR_MSEC_PER_SEC; - entry->mDateCreated = entry->mDateModified; - entry->mDateAdded = entry->mDateModified; - - #if USE_DEBUG - char dateStr[20]; - MTP_DBG("UpdateEntry (0x%08x file %s) modified (%ld) %s", - entry->mHandle, entry->mPath.get(), - entry->mDateModified, - FormatDate(entry->mDateModified, dateStr, sizeof(dateStr))); - #endif -} - - -class MtpWatcherNotifyRunnable final : public Runnable -{ -public: - MtpWatcherNotifyRunnable(nsACString& aStorageName, - nsACString& aPath, - const char* aEventType) - : mStorageName(aStorageName), - mPath(aPath), - mEventType(aEventType) - {} - - NS_IMETHOD Run() override - { - MOZ_ASSERT(NS_IsMainThread()); - - NS_ConvertUTF8toUTF16 storageName(mStorageName); - NS_ConvertUTF8toUTF16 path(mPath); - - RefPtr<DeviceStorageFile> dsf( - new DeviceStorageFile(NS_LITERAL_STRING(DEVICESTORAGE_SDCARD), - storageName, path)); - NS_ConvertUTF8toUTF16 eventType(mEventType); - nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); - - MTP_DBG("Sending mtp-watcher-notify %s %s %s", - mEventType.get(), mStorageName.get(), mPath.get()); - - obs->NotifyObservers(dsf, kMtpWatcherNotify, eventType.get()); - return NS_OK; - } - -private: - nsCString mStorageName; - nsCString mPath; - nsCString mEventType; -}; - -// MtpWatcherNotify is used to tell DeviceStorage when a file was changed -// through the MTP server. -void -MozMtpDatabase::MtpWatcherNotify(DbEntry* aEntry, const char* aEventType) -{ - // This function gets called from the MozMtpServer::mServerThread - MOZ_ASSERT(!NS_IsMainThread()); - - MTP_DBG("file: %s %s", aEntry->mPath.get(), aEventType); - - // Tell interested parties that a file was created, deleted, or modified. - - RefPtr<StorageEntry> storageEntry; - { - MutexAutoLock lock(mMutex); - - // FindStorage and the mStorage[] access both need to have the mutex held. - StorageArray::index_type storageIndex = FindStorage(aEntry->mStorageID); - if (storageIndex == StorageArray::NoIndex) { - return; - } - storageEntry = mStorage[storageIndex]; - } - - // DeviceStorage wants the storageName and the path relative to the root - // of the storage area, so we need to strip off the storagePath - - nsAutoCString relPath(Substring(aEntry->mPath, - storageEntry->mStoragePath.Length() + 1)); - - RefPtr<MtpWatcherNotifyRunnable> r = - new MtpWatcherNotifyRunnable(storageEntry->mStorageName, relPath, aEventType); - DebugOnly<nsresult> rv = NS_DispatchToMainThread(r); - MOZ_ASSERT(NS_SUCCEEDED(rv)); -} - -// Called to tell the MTP server about new or deleted files, -void -MozMtpDatabase::MtpWatcherUpdate(RefCountedMtpServer* aMtpServer, - DeviceStorageFile* aFile, - const nsACString& aEventType) -{ - // Runs on the MtpWatcherUpdate->mIOThread (see MozMtpServer.cpp) - MOZ_ASSERT(!NS_IsMainThread()); - - // Figure out which storage the belongs to (if any) - - if (!aFile->mFile) { - // No path - don't bother looking. - return; - } - nsString wideFilePath; - aFile->mFile->GetPath(wideFilePath); - NS_ConvertUTF16toUTF8 filePath(wideFilePath); - - nsCString evtType(aEventType); - MTP_LOG("file %s %s", filePath.get(), evtType.get()); - - MtpObjectHandle entryHandle = FindEntryByPath(filePath); - - if (aEventType.EqualsLiteral("modified")) { - // To update the file information to the newest, we remove the entry for - // the existing file, then re-add the entry for the file. - - if (entryHandle != 0) { - // Update entry for the file and tell MTP. - MTP_LOG("About to update handle 0x%08x file %s", entryHandle, filePath.get()); - UpdateEntryAndNotify(entryHandle, aFile, aMtpServer); - } - else { - // Create entry for the file and tell MTP. - CreateEntryForFileAndNotify(filePath, aFile, aMtpServer); - } - return; - } - - if (aEventType.EqualsLiteral("deleted")) { - if (entryHandle == 0) { - // The entry has already been removed. We can't tell MTP. - return; - } - MTP_LOG("About to call sendObjectRemoved Handle 0x%08x file %s", entryHandle, filePath.get()); - RemoveEntryAndNotify(entryHandle, aMtpServer); - return; - } -} - -nsCString -MozMtpDatabase::BaseName(const nsCString& path) -{ - nsCOMPtr<nsIFile> file; - NS_NewNativeLocalFile(path, false, getter_AddRefs(file)); - if (file) { - nsCString leafName; - file->GetNativeLeafName(leafName); - return leafName; - } - return path; -} - -static nsCString -GetPathWithoutFileName(const nsCString& aFullPath) -{ - nsCString path; - - int32_t offset = aFullPath.RFindChar('/'); - if (offset != kNotFound) { - // The trailing slash will be as part of 'path' - path = StringHead(aFullPath, offset + 1); - } - - MTP_LOG("returning '%s'", path.get()); - - return path; -} - -void -MozMtpDatabase::CreateEntryForFileAndNotify(const nsACString& aPath, - DeviceStorageFile* aFile, - RefCountedMtpServer* aMtpServer) -{ - // Find the StorageID that this path corresponds to. - - nsCString remainder; - MtpStorageID storageID = FindStorageIDFor(aPath, remainder); - if (storageID == 0) { - // The path in question isn't for a storage area we're monitoring. - nsCString path(aPath); - return; - } - - bool exists = false; - aFile->mFile->Exists(&exists); - if (!exists) { - // File doesn't exist, no sense telling MTP about it. - // This could happen if Device Storage created and deleted a file right - // away. Since the notifications wind up being async, the file might - // not exist any more. - return; - } - - // Now walk the remaining directories, finding or creating as required. - - MtpObjectHandle parent = MTP_PARENT_ROOT; - bool doFind = true; - int32_t offset = aPath.Length() - remainder.Length(); - int32_t slash; - - do { - nsDependentCSubstring component; - slash = aPath.FindChar('/', offset); - if (slash == kNotFound) { - component.Rebind(aPath, 0, aPath.Length()); - } else { - component.Rebind(aPath, 0 , slash); - } - if (doFind) { - MtpObjectHandle entryHandle = FindEntryByPath(component); - if (entryHandle != 0) { - // We found an entry. - parent = entryHandle; - offset = slash + 1 ; - continue; - } - } - - // We've got a directory component that doesn't exist. This means that all - // further subdirectories won't exist either, so we can skip searching - // for them. - doFind = false; - - // This directory and the file don't exist, create them - - RefPtr<DbEntry> entry = new DbEntry; - - entry->mStorageID = storageID; - entry->mObjectName = Substring(aPath, offset, slash - offset); - entry->mParent = parent; - entry->mDisplayName = entry->mObjectName; - entry->mPath = component; - - if (slash == kNotFound) { - // No slash - this is the file component - entry->mObjectFormat = MTP_FORMAT_DEFINED; - - int64_t fileSize = 0; - aFile->mFile->GetFileSize(&fileSize); - entry->mObjectSize = fileSize; - - // Note: Even though PRTime records usec, GetLastModifiedTime returns - // msecs. - PRTime dateModifiedMsecs; - aFile->mFile->GetLastModifiedTime(&dateModifiedMsecs); - entry->mDateModified = dateModifiedMsecs / PR_MSEC_PER_SEC; - } else { - // Found a slash, this makes this a directory component - entry->mObjectFormat = MTP_FORMAT_ASSOCIATION; - entry->mObjectSize = 0; - time(&entry->mDateModified); - } - entry->mDateCreated = entry->mDateModified; - entry->mDateAdded = entry->mDateModified; - - AddEntryAndNotify(entry, aMtpServer); - MTP_LOG("About to call sendObjectAdded Handle 0x%08x file %s", entry->mHandle, entry->mPath.get()); - - parent = entry->mHandle; - offset = slash + 1; - } while (slash != kNotFound); - - return; -} - -void -MozMtpDatabase::AddDirectory(MtpStorageID aStorageID, - const char* aPath, - MtpObjectHandle aParent) -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - ScopedCloseDir dir; - - if (!(dir = PR_OpenDir(aPath))) { - MTP_ERR("Unable to open directory '%s'", aPath); - return; - } - - PRDirEntry* dirEntry; - while ((dirEntry = PR_ReadDir(dir, PR_SKIP_BOTH))) { - nsPrintfCString filename("%s/%s", aPath, dirEntry->name); - PRFileInfo64 fileInfo; - if (PR_GetFileInfo64(filename.get(), &fileInfo) != PR_SUCCESS) { - MTP_ERR("Unable to retrieve file information for '%s'", filename.get()); - continue; - } - - RefPtr<DbEntry> entry = new DbEntry; - - entry->mStorageID = aStorageID; - entry->mParent = aParent; - entry->mObjectName = dirEntry->name; - entry->mDisplayName = dirEntry->name; - entry->mPath = filename; - - // PR_GetFileInfo64 returns timestamps in usecs - entry->mDateModified = fileInfo.modifyTime / PR_USEC_PER_SEC; - entry->mDateCreated = fileInfo.creationTime / PR_USEC_PER_SEC; - time(&entry->mDateAdded); - - if (fileInfo.type == PR_FILE_FILE) { - entry->mObjectFormat = MTP_FORMAT_DEFINED; - //TODO: Check how 64-bit filesize are dealt with - entry->mObjectSize = fileInfo.size; - AddEntry(entry); - } else if (fileInfo.type == PR_FILE_DIRECTORY) { - entry->mObjectFormat = MTP_FORMAT_ASSOCIATION; - entry->mObjectSize = 0; - AddEntry(entry); - AddDirectory(aStorageID, filename.get(), entry->mHandle); - } - } -} - -MozMtpDatabase::StorageArray::index_type -MozMtpDatabase::FindStorage(MtpStorageID aStorageID) -{ - // Currently, this routine is called from MozMtpDatabase::RemoveStorage - // and MozMtpDatabase::MtpWatcherNotify, which both hold mMutex. - - StorageArray::size_type numStorages = mStorage.Length(); - StorageArray::index_type storageIndex; - - for (storageIndex = 0; storageIndex < numStorages; storageIndex++) { - RefPtr<StorageEntry> storage = mStorage[storageIndex]; - if (storage->mStorageID == aStorageID) { - return storageIndex; - } - } - return StorageArray::NoIndex; -} - -// Find the storage ID for the storage area that contains aPath. -MtpStorageID -MozMtpDatabase::FindStorageIDFor(const nsACString& aPath, nsCSubstring& aRemainder) -{ - MutexAutoLock lock(mMutex); - - aRemainder.Truncate(); - - StorageArray::size_type numStorages = mStorage.Length(); - StorageArray::index_type storageIndex; - - for (storageIndex = 0; storageIndex < numStorages; storageIndex++) { - RefPtr<StorageEntry> storage = mStorage[storageIndex]; - if (StringHead(aPath, storage->mStoragePath.Length()).Equals(storage->mStoragePath)) { - if (aPath.Length() == storage->mStoragePath.Length()) { - return storage->mStorageID; - } - if (aPath[storage->mStoragePath.Length()] == '/') { - aRemainder = Substring(aPath, storage->mStoragePath.Length() + 1); - return storage->mStorageID; - } - } - } - return 0; -} - -void -MozMtpDatabase::AddStorage(MtpStorageID aStorageID, - const char* aPath, - const char* aName) -{ - // This is called on the IOThread from MozMtpStorage::StorageAvailable - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - MTP_DBG("StorageID: 0x%08x aPath: '%s' aName: '%s'", - aStorageID, aPath, aName); - - PRFileInfo fileInfo; - if (PR_GetFileInfo(aPath, &fileInfo) != PR_SUCCESS) { - MTP_ERR("'%s' doesn't exist", aPath); - return; - } - if (fileInfo.type != PR_FILE_DIRECTORY) { - MTP_ERR("'%s' isn't a directory", aPath); - return; - } - - RefPtr<StorageEntry> storageEntry = new StorageEntry; - - storageEntry->mStorageID = aStorageID; - storageEntry->mStoragePath = aPath; - storageEntry->mStorageName = aName; - { - MutexAutoLock lock(mMutex); - mStorage.AppendElement(storageEntry); - } - - AddDirectory(aStorageID, aPath, MTP_PARENT_ROOT); - { - MutexAutoLock lock(mMutex); - MTP_LOG("added %d items from tree '%s'", mDb.Length(), aPath); - } -} - -void -MozMtpDatabase::RemoveStorage(MtpStorageID aStorageID) -{ - MutexAutoLock lock(mMutex); - - // This is called on the IOThread from MozMtpStorage::StorageAvailable - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - ProtectedDbArray::size_type numEntries = mDb.Length(); - ProtectedDbArray::index_type entryIndex; - for (entryIndex = 1; entryIndex < numEntries; entryIndex++) { - RefPtr<DbEntry> entry = mDb[entryIndex]; - if (entry && entry->mStorageID == aStorageID) { - mDb[entryIndex] = nullptr; - } - } - StorageArray::index_type storageIndex = FindStorage(aStorageID); - if (storageIndex != StorageArray::NoIndex) { - mStorage.RemoveElementAt(storageIndex); - } -} - -// called from SendObjectInfo to reserve a database entry for the incoming file -//virtual -MtpObjectHandle -MozMtpDatabase::beginSendObject(const char* aPath, - MtpObjectFormat aFormat, - MtpObjectHandle aParent, - MtpStorageID aStorageID, - uint64_t aSize, - time_t aModified) -{ - // If MtpServer::doSendObjectInfo receives a request with a parent of - // MTP_PARENT_ROOT, then it fills in aPath with the fully qualified path - // and then passes in a parent of zero. - - if (aParent == 0) { - // Undo what doSendObjectInfo did - aParent = MTP_PARENT_ROOT; - } - - RefPtr<DbEntry> entry = new DbEntry; - - entry->mStorageID = aStorageID; - entry->mParent = aParent; - entry->mPath = aPath; - entry->mObjectName = BaseName(entry->mPath); - entry->mDisplayName = entry->mObjectName; - entry->mObjectFormat = aFormat; - entry->mObjectSize = aSize; - - if (aModified != 0) { - // Currently, due to the way that parseDateTime is coded in - // frameworks/av/media/mtp/MtpUtils.cpp, aModified winds up being the number - // of seconds from the epoch in local time, rather than UTC time. So we - // need to convert it back to being relative to UTC since that's what linux - // expects time_t to contain. - // - // In more concrete testable terms, if the host parses 2015-08-02 02:22:00 - // as a local time in the Pacific timezone, aModified will come to us as - // 1438482120. - // - // What we want is what mktime would pass us with the same date. Using python - // (because its simple) with the current timezone set to be America/Vancouver: - // - // >>> import time - // >>> time.mktime((2015, 8, 2, 2, 22, 0, 0, 0, -1)) - // 1438507320.0 - // >>> time.localtime(1438507320) - // time.struct_time(tm_year=2015, tm_mon=8, tm_mday=2, tm_hour=2, tm_min=22, tm_sec=0, tm_wday=6, tm_yday=214, tm_isdst=1) - // - // Currently, when a file has a modification time of 2015-08-22 02:22:00 PDT - // then aModified will come in as 1438482120 which corresponds to - // 2015-08-22 02:22:00 UTC - - struct tm tm; - if (gmtime_r(&aModified, &tm) != NULL) { - // GMT always comes back with tm_isdst = 0, so we set it to -1 in order - // to have mktime figure out dst based on the date. - tm.tm_isdst = -1; - aModified = mktime(&tm); - if (aModified == (time_t)-1) { - aModified = 0; - } - } else { - aModified = 0; - } - } - if (aModified == 0) { - // The ubuntu host doesn't pass in the modified/created times in the - // SENDOBJECT packet, so aModified winds up being zero. About the best - // we can do with that is to use the current time. - time(&aModified); - } - - // And just an FYI for anybody else looking at timestamps. Under OSX you - // need to use the Android File Transfer program to copy files into the - // phone. That utility passes in both date modified and date created - // timestamps, but they're both equal to the time that the file was copied - // and not the times that are associated with the files. - - // Now we have aModified in a traditional time_t format, which is the number - // of seconds from the UTC epoch. - - entry->mDateModified = aModified; - entry->mDateCreated = entry->mDateModified; - entry->mDateAdded = entry->mDateModified; - - AddEntry(entry); - - #if USE_DEBUG - char dateStr[20]; - MTP_LOG("Handle: 0x%08x Parent: 0x%08x Path: '%s' aModified %ld %s", - entry->mHandle, aParent, aPath, aModified, - FormatDate(entry->mDateModified, dateStr, sizeof(dateStr))); - #endif - - mBeginSendObjectCalled = true; - return entry->mHandle; -} - -// called to report success or failure of the SendObject file transfer -// success should signal a notification of the new object's creation, -// failure should remove the database entry created in beginSendObject - -//virtual -void -MozMtpDatabase::endSendObject(const char* aPath, - MtpObjectHandle aHandle, - MtpObjectFormat aFormat, - bool aSucceeded) -{ - MTP_LOG("Handle: 0x%08x Path: '%s'", aHandle, aPath); - - if (aSucceeded) { - RefPtr<DbEntry> entry = GetEntry(aHandle); - if (entry) { - // The android MTP server only copies the data in, it doesn't set the - // modified timestamp, so we do that here. - - struct utimbuf new_times; - struct stat sb; - - char dateStr[20]; - MTP_LOG("Path: '%s' setting modified time to (%ld) %s", - entry->mPath.get(), entry->mDateModified, - FormatDate(entry->mDateModified, dateStr, sizeof(dateStr))); - - stat(entry->mPath.get(), &sb); - new_times.actime = sb.st_atime; // Preserve atime - new_times.modtime = entry->mDateModified; - utime(entry->mPath.get(), &new_times); - - MtpWatcherNotify(entry, "modified"); - } - } else { - RemoveEntry(aHandle); - } - mBeginSendObjectCalled = false; -} - -//virtual -MtpObjectHandleList* -MozMtpDatabase::getObjectList(MtpStorageID aStorageID, - MtpObjectFormat aFormat, - MtpObjectHandle aParent) -{ - MTP_LOG("StorageID: 0x%08x Format: 0x%04x Parent: 0x%08x", - aStorageID, aFormat, aParent); - - // aStorageID == 0xFFFFFFFF for all storage - // aFormat == 0 for all formats - // aParent == 0xFFFFFFFF for objects with no parents - // aParent == 0 for all objects - - //TODO: Optimize - - UniquePtr<MtpObjectHandleList> list(new MtpObjectHandleList()); - - MutexAutoLock lock(mMutex); - - ProtectedDbArray::size_type numEntries = mDb.Length(); - ProtectedDbArray::index_type entryIndex; - for (entryIndex = 1; entryIndex < numEntries; entryIndex++) { - RefPtr<DbEntry> entry = mDb[entryIndex]; - if (entry && - (aStorageID == 0xFFFFFFFF || entry->mStorageID == aStorageID) && - (aFormat == 0 || entry->mObjectFormat == aFormat) && - (aParent == 0 || entry->mParent == aParent)) { - list->push(entry->mHandle); - } - } - MTP_LOG(" returning %d items", list->size()); - return list.release(); -} - -//virtual -int -MozMtpDatabase::getNumObjects(MtpStorageID aStorageID, - MtpObjectFormat aFormat, - MtpObjectHandle aParent) -{ - MTP_LOG(""); - - // aStorageID == 0xFFFFFFFF for all storage - // aFormat == 0 for all formats - // aParent == 0xFFFFFFFF for objects with no parents - // aParent == 0 for all objects - - int count = 0; - - MutexAutoLock lock(mMutex); - - ProtectedDbArray::size_type numEntries = mDb.Length(); - ProtectedDbArray::index_type entryIndex; - for (entryIndex = 1; entryIndex < numEntries; entryIndex++) { - RefPtr<DbEntry> entry = mDb[entryIndex]; - if (entry && - (aStorageID == 0xFFFFFFFF || entry->mStorageID == aStorageID) && - (aFormat == 0 || entry->mObjectFormat == aFormat) && - (aParent == 0 || entry->mParent == aParent)) { - count++; - } - } - - MTP_LOG(" returning %d items", count); - return count; -} - -//virtual -MtpObjectFormatList* -MozMtpDatabase::getSupportedPlaybackFormats() -{ - static const uint16_t init_data[] = {MTP_FORMAT_UNDEFINED, MTP_FORMAT_ASSOCIATION, - MTP_FORMAT_TEXT, MTP_FORMAT_HTML, MTP_FORMAT_WAV, - MTP_FORMAT_MP3, MTP_FORMAT_MPEG, MTP_FORMAT_EXIF_JPEG, - MTP_FORMAT_TIFF_EP, MTP_FORMAT_BMP, MTP_FORMAT_GIF, - MTP_FORMAT_PNG, MTP_FORMAT_TIFF, MTP_FORMAT_WMA, - MTP_FORMAT_OGG, MTP_FORMAT_AAC, MTP_FORMAT_MP4_CONTAINER, - MTP_FORMAT_MP2, MTP_FORMAT_3GP_CONTAINER, MTP_FORMAT_FLAC}; - - MtpObjectFormatList *list = new MtpObjectFormatList(); - list->appendArray(init_data, MOZ_ARRAY_LENGTH(init_data)); - - MTP_LOG("returning Supported Playback Formats"); - return list; -} - -//virtual -MtpObjectFormatList* -MozMtpDatabase::getSupportedCaptureFormats() -{ - static const uint16_t init_data[] = {MTP_FORMAT_ASSOCIATION, MTP_FORMAT_PNG}; - - MtpObjectFormatList *list = new MtpObjectFormatList(); - list->appendArray(init_data, MOZ_ARRAY_LENGTH(init_data)); - MTP_LOG("returning MTP_FORMAT_ASSOCIATION, MTP_FORMAT_PNG"); - return list; -} - -static const MtpObjectProperty sSupportedObjectProperties[] = -{ - MTP_PROPERTY_STORAGE_ID, - MTP_PROPERTY_OBJECT_FORMAT, - MTP_PROPERTY_PROTECTION_STATUS, // UINT16 - always 0 - MTP_PROPERTY_OBJECT_SIZE, - MTP_PROPERTY_OBJECT_FILE_NAME, // just the filename - no directory - MTP_PROPERTY_NAME, - MTP_PROPERTY_DATE_CREATED, - MTP_PROPERTY_DATE_MODIFIED, - MTP_PROPERTY_PARENT_OBJECT, - MTP_PROPERTY_PERSISTENT_UID, - MTP_PROPERTY_DATE_ADDED, -}; - -//virtual -MtpObjectPropertyList* -MozMtpDatabase::getSupportedObjectProperties(MtpObjectFormat aFormat) -{ - MTP_LOG(""); - MtpObjectPropertyList *list = new MtpObjectPropertyList(); - list->appendArray(sSupportedObjectProperties, - MOZ_ARRAY_LENGTH(sSupportedObjectProperties)); - return list; -} - -//virtual -MtpDevicePropertyList* -MozMtpDatabase::getSupportedDeviceProperties() -{ - MTP_LOG(""); - static const uint16_t init_data[] = { MTP_DEVICE_PROPERTY_UNDEFINED }; - - MtpDevicePropertyList *list = new MtpDevicePropertyList(); - list->appendArray(init_data, MOZ_ARRAY_LENGTH(init_data)); - return list; -} - -//virtual -MtpResponseCode -MozMtpDatabase::getObjectPropertyValue(MtpObjectHandle aHandle, - MtpObjectProperty aProperty, - MtpDataPacket& aPacket) -{ - RefPtr<DbEntry> entry = GetEntry(aHandle); - if (!entry) { - MTP_ERR("Invalid Handle: 0x%08x", aHandle); - return MTP_RESPONSE_INVALID_OBJECT_HANDLE; - } - - MTP_LOG("Handle: 0x%08x '%s' Property: %s 0x%08x", - aHandle, entry->mDisplayName.get(), ObjectPropertyAsStr(aProperty), aProperty); - - switch (aProperty) - { - case MTP_PROPERTY_STORAGE_ID: aPacket.putUInt32(entry->mStorageID); break; - case MTP_PROPERTY_PARENT_OBJECT: aPacket.putUInt32(entry->mParent); break; - case MTP_PROPERTY_OBJECT_FORMAT: aPacket.putUInt16(entry->mObjectFormat); break; - case MTP_PROPERTY_OBJECT_SIZE: aPacket.putUInt64(entry->mObjectSize); break; - case MTP_PROPERTY_DISPLAY_NAME: aPacket.putString(entry->mDisplayName.get()); break; - case MTP_PROPERTY_PERSISTENT_UID: - // the same as aPacket.putUInt128 - aPacket.putUInt64(entry->mHandle); - aPacket.putUInt64(entry->mStorageID); - break; - case MTP_PROPERTY_NAME: aPacket.putString(entry->mDisplayName.get()); break; - - default: - MTP_LOG("Invalid Property: 0x%08x", aProperty); - return MTP_RESPONSE_INVALID_OBJECT_PROP_CODE; - } - - return MTP_RESPONSE_OK; -} - -static int -GetTypeOfObjectProp(MtpObjectProperty aProperty) -{ - struct PropertyTableEntry { - MtpObjectProperty property; - int type; - }; - - static const PropertyTableEntry kObjectPropertyTable[] = { - {MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32 }, - {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16 }, - {MTP_PROPERTY_PROTECTION_STATUS, MTP_TYPE_UINT16 }, - {MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64 }, - {MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR }, - {MTP_PROPERTY_DATE_CREATED, MTP_TYPE_STR }, - {MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR }, - {MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32 }, - {MTP_PROPERTY_DISPLAY_NAME, MTP_TYPE_STR }, - {MTP_PROPERTY_NAME, MTP_TYPE_STR }, - {MTP_PROPERTY_PERSISTENT_UID, MTP_TYPE_UINT128 }, - {MTP_PROPERTY_DATE_ADDED, MTP_TYPE_STR }, - }; - - int count = sizeof(kObjectPropertyTable) / sizeof(kObjectPropertyTable[0]); - const PropertyTableEntry* entryProp = kObjectPropertyTable; - int type = 0; - - for (int i = 0; i < count; ++i, ++entryProp) { - if (entryProp->property == aProperty) { - type = entryProp->type; - break; - } - } - - return type; -} - -//virtual -MtpResponseCode -MozMtpDatabase::setObjectPropertyValue(MtpObjectHandle aHandle, - MtpObjectProperty aProperty, - MtpDataPacket& aPacket) -{ - MTP_LOG("Handle: 0x%08x Property: 0x%08x", aHandle, aProperty); - - // Only support file name change - if (aProperty != MTP_PROPERTY_OBJECT_FILE_NAME) { - MTP_ERR("property 0x%x not supported", aProperty); - return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED; - } - - if (GetTypeOfObjectProp(aProperty) != MTP_TYPE_STR) { - MTP_ERR("property type 0x%x not supported", GetTypeOfObjectProp(aProperty)); - return MTP_RESPONSE_GENERAL_ERROR; - } - - RefPtr<DbEntry> entry = GetEntry(aHandle); - if (!entry) { - MTP_ERR("Invalid Handle: 0x%08x", aHandle); - return MTP_RESPONSE_INVALID_OBJECT_HANDLE; - } - - MtpStringBuffer buf; - aPacket.getString(buf); - - nsDependentCString newFileName(buf); - nsCString newFileFullPath(GetPathWithoutFileName(entry->mPath) + newFileName); - - if (PR_Rename(entry->mPath.get(), newFileFullPath.get()) != PR_SUCCESS) { - MTP_ERR("Failed to rename '%s' to '%s'", - entry->mPath.get(), newFileFullPath.get()); - return MTP_RESPONSE_GENERAL_ERROR; - } - - MTP_LOG("renamed '%s' to '%s'", entry->mPath.get(), newFileFullPath.get()); - - entry->mPath = newFileFullPath; - entry->mObjectName = BaseName(entry->mPath); - entry->mDisplayName = entry->mObjectName; - - return MTP_RESPONSE_OK; -} - -//virtual -MtpResponseCode -MozMtpDatabase::getDevicePropertyValue(MtpDeviceProperty aProperty, - MtpDataPacket& aPacket) -{ - MTP_LOG("(GENERAL ERROR)"); - return MTP_RESPONSE_GENERAL_ERROR; -} - -//virtual -MtpResponseCode -MozMtpDatabase::setDevicePropertyValue(MtpDeviceProperty aProperty, - MtpDataPacket& aPacket) -{ - MTP_LOG("(NOT SUPPORTED)"); - return MTP_RESPONSE_OPERATION_NOT_SUPPORTED; -} - -//virtual -MtpResponseCode -MozMtpDatabase::resetDeviceProperty(MtpDeviceProperty aProperty) -{ - MTP_LOG("(NOT SUPPORTED)"); - return MTP_RESPONSE_OPERATION_NOT_SUPPORTED; -} - -void -MozMtpDatabase::QueryEntries(MozMtpDatabase::MatchType aMatchType, - uint32_t aMatchField1, - uint32_t aMatchField2, - UnprotectedDbArray &result) -{ - MutexAutoLock lock(mMutex); - - ProtectedDbArray::size_type numEntries = mDb.Length(); - ProtectedDbArray::index_type entryIdx; - RefPtr<DbEntry> entry; - - result.Clear(); - - switch (aMatchType) { - - case MatchAll: - for (entryIdx = 0; entryIdx < numEntries; entryIdx++) { - if (mDb[entryIdx]) { - result.AppendElement(mDb[entryIdx]); - } - } - break; - - case MatchHandle: - for (entryIdx = 0; entryIdx < numEntries; entryIdx++) { - entry = mDb[entryIdx]; - if (entry && entry->mHandle == aMatchField1) { - result.AppendElement(entry); - // Handles are unique - return the one that we found. - return; - } - } - break; - - case MatchParent: - for (entryIdx = 0; entryIdx < numEntries; entryIdx++) { - entry = mDb[entryIdx]; - if (entry && entry->mParent == aMatchField1) { - result.AppendElement(entry); - } - } - break; - - case MatchFormat: - for (entryIdx = 0; entryIdx < numEntries; entryIdx++) { - entry = mDb[entryIdx]; - if (entry && entry->mObjectFormat == aMatchField1) { - result.AppendElement(entry); - } - } - break; - - case MatchHandleFormat: - for (entryIdx = 0; entryIdx < numEntries; entryIdx++) { - entry = mDb[entryIdx]; - if (entry && entry->mHandle == aMatchField1) { - if (entry->mObjectFormat == aMatchField2) { - result.AppendElement(entry); - } - // Only 1 entry can match my aHandle. So we can return early. - return; - } - } - break; - - case MatchParentFormat: - for (entryIdx = 0; entryIdx < numEntries; entryIdx++) { - entry = mDb[entryIdx]; - if (entry && entry->mParent == aMatchField1 && entry->mObjectFormat == aMatchField2) { - result.AppendElement(entry); - } - } - break; - - default: - MOZ_ASSERT(!"Invalid MatchType"); - } -} - -//virtual -MtpResponseCode -MozMtpDatabase::getObjectPropertyList(MtpObjectHandle aHandle, - uint32_t aFormat, - uint32_t aProperty, - int aGroupCode, - int aDepth, - MtpDataPacket& aPacket) -{ - MTP_LOG("Handle: 0x%08x Format: 0x%08x aProperty: 0x%08x aGroupCode: %d aDepth %d", - aHandle, aFormat, aProperty, aGroupCode, aDepth); - - if (aDepth > 1) { - return MTP_RESPONSE_SPECIFICATION_BY_DEPTH_UNSUPPORTED; - } - if (aGroupCode != 0) { - return MTP_RESPONSE_SPECIFICATION_BY_GROUP_UNSUPPORTED; - } - - MatchType matchType = MatchAll; - uint32_t matchField1 = 0; - uint32_t matchField2 = 0; - - // aHandle == 0 implies all objects at the root level - // further specificed by aFormat and/or aDepth - - if (aFormat == 0) { - if (aHandle == 0xffffffff) { - // select all objects - matchType = MatchAll; - } else { - if (aDepth == 1) { - // select objects whose Parent matches aHandle - matchType = MatchParent; - matchField1 = aHandle; - } else { - // select object whose handle matches aHandle - matchType = MatchHandle; - matchField1 = aHandle; - } - } - } else { - if (aHandle == 0xffffffff) { - // select all objects whose format matches aFormat - matchType = MatchFormat; - matchField1 = aFormat; - } else { - if (aDepth == 1) { - // select objects whose Parent is aHandle and format matches aFormat - matchType = MatchParentFormat; - matchField1 = aHandle; - matchField2 = aFormat; - } else { - // select objects whose handle is aHandle and format matches aFormat - matchType = MatchHandleFormat; - matchField1 = aHandle; - matchField2 = aFormat; - } - } - } - - UnprotectedDbArray result; - QueryEntries(matchType, matchField1, matchField2, result); - - const MtpObjectProperty *objectPropertyList; - size_t numObjectProperties = 0; - MtpObjectProperty objectProperty; - - if (aProperty == 0xffffffff) { - // return all supported properties - numObjectProperties = MOZ_ARRAY_LENGTH(sSupportedObjectProperties); - objectPropertyList = sSupportedObjectProperties; - } else { - // return property indicated by aProperty - numObjectProperties = 1; - objectProperty = aProperty; - objectPropertyList = &objectProperty; - } - - UnprotectedDbArray::size_type numEntries = result.Length(); - UnprotectedDbArray::index_type entryIdx; - - char dateStr[20]; - - aPacket.putUInt32(numObjectProperties * numEntries); - for (entryIdx = 0; entryIdx < numEntries; entryIdx++) { - RefPtr<DbEntry> entry = result[entryIdx]; - - for (size_t propertyIdx = 0; propertyIdx < numObjectProperties; propertyIdx++) { - aPacket.putUInt32(entry->mHandle); - MtpObjectProperty prop = objectPropertyList[propertyIdx]; - aPacket.putUInt16(prop); - switch (prop) { - - case MTP_PROPERTY_STORAGE_ID: - aPacket.putUInt16(MTP_TYPE_UINT32); - aPacket.putUInt32(entry->mStorageID); - break; - - case MTP_PROPERTY_PARENT_OBJECT: - aPacket.putUInt16(MTP_TYPE_UINT32); - aPacket.putUInt32(entry->mParent); - break; - - case MTP_PROPERTY_PERSISTENT_UID: - aPacket.putUInt16(MTP_TYPE_UINT128); - // the same as aPacket.putUInt128 - aPacket.putUInt64(entry->mHandle); - aPacket.putUInt64(entry->mStorageID); - break; - - case MTP_PROPERTY_OBJECT_FORMAT: - aPacket.putUInt16(MTP_TYPE_UINT16); - aPacket.putUInt16(entry->mObjectFormat); - break; - - case MTP_PROPERTY_OBJECT_SIZE: - aPacket.putUInt16(MTP_TYPE_UINT64); - aPacket.putUInt64(entry->mObjectSize); - break; - - case MTP_PROPERTY_OBJECT_FILE_NAME: - case MTP_PROPERTY_NAME: - aPacket.putUInt16(MTP_TYPE_STR); - aPacket.putString(entry->mObjectName.get()); - break; - - case MTP_PROPERTY_PROTECTION_STATUS: - aPacket.putUInt16(MTP_TYPE_UINT16); - aPacket.putUInt16(0); // 0 = No Protection - break; - - case MTP_PROPERTY_DATE_CREATED: { - aPacket.putUInt16(MTP_TYPE_STR); - aPacket.putString(FormatDate(entry->mDateCreated, dateStr, sizeof(dateStr))); - MTP_LOG("mDateCreated: (%ld) %s", entry->mDateCreated, dateStr); - break; - } - - case MTP_PROPERTY_DATE_MODIFIED: { - aPacket.putUInt16(MTP_TYPE_STR); - aPacket.putString(FormatDate(entry->mDateModified, dateStr, sizeof(dateStr))); - MTP_LOG("mDateModified: (%ld) %s", entry->mDateModified, dateStr); - break; - } - - case MTP_PROPERTY_DATE_ADDED: { - aPacket.putUInt16(MTP_TYPE_STR); - aPacket.putString(FormatDate(entry->mDateAdded, dateStr, sizeof(dateStr))); - MTP_LOG("mDateAdded: (%ld) %s", entry->mDateAdded, dateStr); - break; - } - - default: - MTP_ERR("Unrecognized property code: %u", prop); - return MTP_RESPONSE_GENERAL_ERROR; - } - } - } - return MTP_RESPONSE_OK; -} - -//virtual -MtpResponseCode -MozMtpDatabase::getObjectInfo(MtpObjectHandle aHandle, - MtpObjectInfo& aInfo) -{ - RefPtr<DbEntry> entry = GetEntry(aHandle); - if (!entry) { - MTP_ERR("Handle 0x%08x is invalid", aHandle); - return MTP_RESPONSE_INVALID_OBJECT_HANDLE; - } - - MTP_LOG("Handle: 0x%08x Display:'%s' Object:'%s'", aHandle, entry->mDisplayName.get(), entry->mObjectName.get()); - - aInfo.mHandle = aHandle; - aInfo.mStorageID = entry->mStorageID; - aInfo.mFormat = entry->mObjectFormat; - aInfo.mProtectionStatus = 0x0; - - if (entry->mObjectSize > 0xFFFFFFFFuLL) { - aInfo.mCompressedSize = 0xFFFFFFFFuLL; - } else { - aInfo.mCompressedSize = entry->mObjectSize; - } - - aInfo.mThumbFormat = MTP_FORMAT_UNDEFINED; - aInfo.mThumbCompressedSize = 0; - aInfo.mThumbPixWidth = 0; - aInfo.mThumbPixHeight = 0; - aInfo.mImagePixWidth = 0; - aInfo.mImagePixHeight = 0; - aInfo.mImagePixDepth = 0; - aInfo.mParent = entry->mParent; - aInfo.mAssociationType = 0; - aInfo.mAssociationDesc = 0; - aInfo.mSequenceNumber = 0; - aInfo.mName = ::strdup(entry->mObjectName.get()); - aInfo.mDateCreated = entry->mDateCreated; - aInfo.mDateModified = entry->mDateModified; - - MTP_LOG("aInfo.mDateCreated = %ld entry->mDateCreated = %ld", - aInfo.mDateCreated, entry->mDateCreated); - MTP_LOG("aInfo.mDateModified = %ld entry->mDateModified = %ld", - aInfo.mDateModified, entry->mDateModified); - - aInfo.mKeywords = ::strdup("fxos,touch"); - - return MTP_RESPONSE_OK; -} - -//virtual -void* -MozMtpDatabase::getThumbnail(MtpObjectHandle aHandle, size_t& aOutThumbSize) -{ - MTP_LOG("Handle: 0x%08x (returning nullptr)", aHandle); - - aOutThumbSize = 0; - - return nullptr; -} - -//virtual -MtpResponseCode -MozMtpDatabase::getObjectFilePath(MtpObjectHandle aHandle, - MtpString& aOutFilePath, - int64_t& aOutFileLength, - MtpObjectFormat& aOutFormat) -{ - RefPtr<DbEntry> entry = GetEntry(aHandle); - if (!entry) { - MTP_ERR("Handle 0x%08x is invalid", aHandle); - return MTP_RESPONSE_INVALID_OBJECT_HANDLE; - } - - MTP_LOG("Handle: 0x%08x FilePath: '%s'", aHandle, entry->mPath.get()); - - aOutFilePath = entry->mPath.get(); - aOutFileLength = entry->mObjectSize; - aOutFormat = entry->mObjectFormat; - - return MTP_RESPONSE_OK; -} - -//virtual -MtpResponseCode -MozMtpDatabase::deleteFile(MtpObjectHandle aHandle) -{ - RefPtr<DbEntry> entry = GetEntry(aHandle); - if (!entry) { - MTP_ERR("Invalid Handle: 0x%08x", aHandle); - return MTP_RESPONSE_INVALID_OBJECT_HANDLE; - } - - MTP_LOG("Handle: 0x%08x '%s'", aHandle, entry->mPath.get()); - - // File deletion will happen in lower level implementation. - // The only thing we need to do is removing the entry from the db. - RemoveEntry(aHandle); - - // Tell Device Storage that the file is gone. - MtpWatcherNotify(entry, "deleted"); - - return MTP_RESPONSE_OK; -} - -#if 0 -//virtual -MtpResponseCode -MozMtpDatabase::moveFile(MtpObjectHandle aHandle, MtpObjectHandle aNewParent) -{ - MTP_LOG("Handle: 0x%08x NewParent: 0x%08x", aHandle, aNewParent); - - // change parent - - return MTP_RESPONSE_OK -} - -//virtual -MtpResponseCode -MozMtpDatabase::copyFile(MtpObjectHandle aHandle, MtpObjectHandle aNewParent) -{ - MTP_LOG("Handle: 0x%08x NewParent: 0x%08x", aHandle, aNewParent); - - // duplicate DbEntry - // change parent - - return MTP_RESPONSE_OK -} -#endif - -//virtual -MtpObjectHandleList* -MozMtpDatabase::getObjectReferences(MtpObjectHandle aHandle) -{ - MTP_LOG("Handle: 0x%08x (returning nullptr)", aHandle); - return nullptr; -} - -//virtual -MtpResponseCode -MozMtpDatabase::setObjectReferences(MtpObjectHandle aHandle, - MtpObjectHandleList* aReferences) -{ - MTP_LOG("Handle: 0x%08x (NOT SUPPORTED)", aHandle); - return MTP_RESPONSE_OPERATION_NOT_SUPPORTED; -} - -//virtual -MtpProperty* -MozMtpDatabase::getObjectPropertyDesc(MtpObjectProperty aProperty, - MtpObjectFormat aFormat) -{ - MTP_LOG("Property: %s 0x%08x", ObjectPropertyAsStr(aProperty), aProperty); - - MtpProperty* result = nullptr; - switch (aProperty) - { - case MTP_PROPERTY_PROTECTION_STATUS: - result = new MtpProperty(aProperty, MTP_TYPE_UINT16); - break; - case MTP_PROPERTY_OBJECT_FORMAT: - result = new MtpProperty(aProperty, MTP_TYPE_UINT16, false, aFormat); - break; - case MTP_PROPERTY_STORAGE_ID: - case MTP_PROPERTY_PARENT_OBJECT: - case MTP_PROPERTY_WIDTH: - case MTP_PROPERTY_HEIGHT: - case MTP_PROPERTY_IMAGE_BIT_DEPTH: - result = new MtpProperty(aProperty, MTP_TYPE_UINT32); - break; - case MTP_PROPERTY_OBJECT_SIZE: - result = new MtpProperty(aProperty, MTP_TYPE_UINT64); - break; - case MTP_PROPERTY_DISPLAY_NAME: - case MTP_PROPERTY_NAME: - result = new MtpProperty(aProperty, MTP_TYPE_STR); - break; - case MTP_PROPERTY_OBJECT_FILE_NAME: - result = new MtpProperty(aProperty, MTP_TYPE_STR, true); - break; - case MTP_PROPERTY_DATE_CREATED: - case MTP_PROPERTY_DATE_MODIFIED: - case MTP_PROPERTY_DATE_ADDED: - result = new MtpProperty(aProperty, MTP_TYPE_STR); - result->setFormDateTime(); - break; - case MTP_PROPERTY_PERSISTENT_UID: - result = new MtpProperty(aProperty, MTP_TYPE_UINT128); - break; - default: - break; - } - - return result; -} - -//virtual -MtpProperty* -MozMtpDatabase::getDevicePropertyDesc(MtpDeviceProperty aProperty) -{ - MTP_LOG("(returning MTP_DEVICE_PROPERTY_UNDEFINED)"); - return new MtpProperty(MTP_DEVICE_PROPERTY_UNDEFINED, MTP_TYPE_UNDEFINED); -} - -//virtual -void -MozMtpDatabase::sessionStarted() -{ - MTP_LOG(""); -} - -//virtual -void -MozMtpDatabase::sessionEnded() -{ - MTP_LOG(""); -} - -END_MTP_NAMESPACE diff --git a/dom/system/gonk/MozMtpDatabase.h b/dom/system/gonk/MozMtpDatabase.h deleted file mode 100644 index 8b308762e..000000000 --- a/dom/system/gonk/MozMtpDatabase.h +++ /dev/null @@ -1,288 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_mozmtpdatabase_h__ -#define mozilla_system_mozmtpdatabase_h__ - -#include "MozMtpCommon.h" - -#include "mozilla/Mutex.h" -#include "mozilla/RefPtr.h" -#include "nsCOMPtr.h" -#include "nsString.h" -#include "nsIThread.h" -#include "nsTArray.h" - -class DeviceStorageFile; - -BEGIN_MTP_NAMESPACE // mozilla::system::mtp - -class RefCountedMtpServer; - -using namespace android; - -class MozMtpDatabase final : public MtpDatabase -{ -public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MozMtpDatabase) - - MozMtpDatabase(); - - // called from SendObjectInfo to reserve a database entry for the incoming file - virtual MtpObjectHandle beginSendObject(const char* aPath, - MtpObjectFormat aFormat, - MtpObjectHandle aParent, - MtpStorageID aStorageID, - uint64_t aSize, - time_t aModified); - - // called to report success or failure of the SendObject file transfer - // success should signal a notification of the new object's creation, - // failure should remove the database entry created in beginSendObject - virtual void endSendObject(const char* aPath, - MtpObjectHandle aHandle, - MtpObjectFormat aFormat, - bool aSucceeded); - - virtual MtpObjectHandleList* getObjectList(MtpStorageID aStorageID, - MtpObjectFormat aFormat, - MtpObjectHandle aParent); - - virtual int getNumObjects(MtpStorageID aStorageID, - MtpObjectFormat aFormat, - MtpObjectHandle aParent); - - virtual MtpObjectFormatList* getSupportedPlaybackFormats(); - - virtual MtpObjectFormatList* getSupportedCaptureFormats(); - - virtual MtpObjectPropertyList* getSupportedObjectProperties(MtpObjectFormat aFormat); - - virtual MtpDevicePropertyList* getSupportedDeviceProperties(); - - virtual MtpResponseCode getObjectPropertyValue(MtpObjectHandle aHandle, - MtpObjectProperty aProperty, - MtpDataPacket& aPacket); - - virtual MtpResponseCode setObjectPropertyValue(MtpObjectHandle aHandle, - MtpObjectProperty aProperty, - MtpDataPacket& aPacket); - - virtual MtpResponseCode getDevicePropertyValue(MtpDeviceProperty aProperty, - MtpDataPacket& aPacket); - - virtual MtpResponseCode setDevicePropertyValue(MtpDeviceProperty aProperty, - MtpDataPacket& aPacket); - - virtual MtpResponseCode resetDeviceProperty(MtpDeviceProperty aProperty); - - virtual MtpResponseCode getObjectPropertyList(MtpObjectHandle aHandle, - uint32_t aFormat, - uint32_t aProperty, - int aGroupCode, - int aDepth, - MtpDataPacket& aPacket); - - virtual MtpResponseCode getObjectInfo(MtpObjectHandle aHandle, - MtpObjectInfo& aInfo); - - virtual void* getThumbnail(MtpObjectHandle aHandle, size_t& aOutThumbSize); - - virtual MtpResponseCode getObjectFilePath(MtpObjectHandle aHandle, - MtpString& aOutFilePath, - int64_t& aOutFileLength, - MtpObjectFormat& aOutFormat); - - virtual MtpResponseCode deleteFile(MtpObjectHandle aHandle); - - virtual MtpObjectHandleList* getObjectReferences(MtpObjectHandle aHandle); - - virtual MtpResponseCode setObjectReferences(MtpObjectHandle aHandle, - MtpObjectHandleList* aReferences); - - virtual MtpProperty* getObjectPropertyDesc(MtpObjectProperty aProperty, - MtpObjectFormat aFormat); - - virtual MtpProperty* getDevicePropertyDesc(MtpDeviceProperty aProperty); - - virtual void sessionStarted(); - - virtual void sessionEnded(); - - void AddStorage(MtpStorageID aStorageID, const char* aPath, const char *aName); - void RemoveStorage(MtpStorageID aStorageID); - - void MtpWatcherUpdate(RefCountedMtpServer* aMtpServer, - DeviceStorageFile* aFile, - const nsACString& aEventType); - -protected: - virtual ~MozMtpDatabase(); - -private: - - struct DbEntry final - { - DbEntry() - : mHandle(0), - mStorageID(0), - mObjectFormat(MTP_FORMAT_DEFINED), - mParent(0), - mObjectSize(0), - mDateCreated(0), - mDateModified(0), - mDateAdded(0) {} - - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DbEntry) - - MtpObjectHandle mHandle; // uint32_t - MtpStorageID mStorageID; // uint32_t - nsCString mObjectName; - MtpObjectFormat mObjectFormat; // uint16_t - MtpObjectHandle mParent; // uint32_t - uint64_t mObjectSize; - nsCString mDisplayName; - nsCString mPath; - time_t mDateCreated; - time_t mDateModified; - time_t mDateAdded; - - protected: - ~DbEntry() {} - }; - - template<class T> - class ProtectedTArray : private nsTArray<T> - { - public: - typedef T elem_type; - typedef typename nsTArray<T>::size_type size_type; - typedef typename nsTArray<T>::index_type index_type; - typedef nsTArray<T> base_type; - - static const index_type NoIndex = base_type::NoIndex; - - ProtectedTArray(mozilla::Mutex& aMutex) - : mMutex(aMutex) - {} - - size_type Length() const - { - // GRR - This assert prints to stderr and won't show up in logcat. - mMutex.AssertCurrentThreadOwns(); - return base_type::Length(); - } - - template <class Item> - elem_type* AppendElement(const Item& aItem) - { - mMutex.AssertCurrentThreadOwns(); - return base_type::AppendElement(aItem); - } - - void Clear() - { - mMutex.AssertCurrentThreadOwns(); - base_type::Clear(); - } - - void RemoveElementAt(index_type aIndex) - { - mMutex.AssertCurrentThreadOwns(); - base_type::RemoveElementAt(aIndex); - } - - elem_type& operator[](index_type aIndex) - { - mMutex.AssertCurrentThreadOwns(); - return base_type::ElementAt(aIndex); - } - - const elem_type& operator[](index_type aIndex) const - { - mMutex.AssertCurrentThreadOwns(); - return base_type::ElementAt(aIndex); - } - - private: - mozilla::Mutex& mMutex; - }; - typedef nsTArray<RefPtr<DbEntry> > UnprotectedDbArray; - typedef ProtectedTArray<RefPtr<DbEntry> > ProtectedDbArray; - - struct StorageEntry final - { - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(StorageEntry) - - MtpStorageID mStorageID; - nsCString mStoragePath; - nsCString mStorageName; - - protected: - ~StorageEntry() {} - }; - typedef ProtectedTArray<RefPtr<StorageEntry> > StorageArray; - - enum MatchType - { - MatchAll, - MatchHandle, - MatchParent, - MatchFormat, - MatchHandleFormat, - MatchParentFormat, - }; - - bool IsValidHandle(MtpObjectHandle aHandle) - { - return aHandle > 0 && aHandle < mDb.Length(); - } - - void AddEntry(DbEntry* aEntry); - void AddEntryAndNotify(DbEntry* aEntr, RefCountedMtpServer* aMtpServer); - void DumpEntries(const char* aLabel); - MtpObjectHandle FindEntryByPath(const nsACString& aPath); - already_AddRefed<DbEntry> GetEntry(MtpObjectHandle aHandle); - void RemoveEntry(MtpObjectHandle aHandle); - void RemoveEntryAndNotify(MtpObjectHandle aHandle, RefCountedMtpServer* aMtpServer); - void UpdateEntry(MtpObjectHandle aHandle, DeviceStorageFile* aFile); - void UpdateEntryAndNotify(MtpObjectHandle aHandle, DeviceStorageFile* aFile, - RefCountedMtpServer* aMtpServer); - void QueryEntries(MatchType aMatchType, uint32_t aMatchField1, - uint32_t aMatchField2, UnprotectedDbArray& aResult); - - nsCString BaseName(const nsCString& aPath); - - - MtpObjectHandle GetNextHandle() - { - return mDb.Length(); - } - - void AddDirectory(MtpStorageID aStorageID, const char *aPath, MtpObjectHandle aParent); - - void CreateEntryForFileAndNotify(const nsACString& aPath, - DeviceStorageFile* aFile, - RefCountedMtpServer* aMtpServer); - - StorageArray::index_type FindStorage(MtpStorageID aStorageID); - MtpStorageID FindStorageIDFor(const nsACString& aPath, nsCSubstring& aRemainder); - void MtpWatcherNotify(DbEntry* aEntry, const char* aEventType); - - // We need a mutex to protext mDb and mStorage. The MTP server runs on a - // dedicated thread, and it updates/accesses mDb. When files are updated - // through DeviceStorage, we need to update/access mDb and mStorage as well - // (from a non-MTP server thread). - mozilla::Mutex mMutex; - ProtectedDbArray mDb; - StorageArray mStorage; - - bool mBeginSendObjectCalled; -}; - -END_MTP_NAMESPACE - -#endif // mozilla_system_mozmtpdatabase_h__ diff --git a/dom/system/gonk/MozMtpServer.cpp b/dom/system/gonk/MozMtpServer.cpp deleted file mode 100644 index c26b6368b..000000000 --- a/dom/system/gonk/MozMtpServer.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "MozMtpServer.h" -#include "MozMtpDatabase.h" - -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> - -#include <errno.h> -#include <stdio.h> -#include <unistd.h> - -#include <cutils/properties.h> -#include <private/android_filesystem_config.h> - -#include "base/message_loop.h" -#include "DeviceStorage.h" -#include "mozilla/LazyIdleThread.h" -#include "mozilla/Scoped.h" -#include "mozilla/Services.h" -#include "mozilla/StaticPtr.h" -#include "nsIObserver.h" -#include "nsIObserverService.h" -#include "nsISupportsImpl.h" -#include "nsThreadUtils.h" -#include "nsXULAppAPI.h" - -#include "Volume.h" - -#define DEFAULT_THREAD_TIMEOUT_MS 30000 - -using namespace android; -using namespace mozilla; -BEGIN_MTP_NAMESPACE - -static const char* kMtpWatcherUpdate = "mtp-watcher-update"; - -class MtpWatcherUpdateRunnable final : public Runnable -{ -public: - MtpWatcherUpdateRunnable(MozMtpDatabase* aMozMtpDatabase, - RefCountedMtpServer* aMtpServer, - DeviceStorageFile* aFile, - const nsACString& aEventType) - : mMozMtpDatabase(aMozMtpDatabase), - mMtpServer(aMtpServer), - mFile(aFile), - mEventType(aEventType) - {} - - NS_IMETHOD Run() override - { - // Runs on the MtpWatcherUpdate->mIOThread - MOZ_ASSERT(!NS_IsMainThread()); - - mMozMtpDatabase->MtpWatcherUpdate(mMtpServer, mFile, mEventType); - return NS_OK; - } - -private: - RefPtr<MozMtpDatabase> mMozMtpDatabase; - RefPtr<RefCountedMtpServer> mMtpServer; - RefPtr<DeviceStorageFile> mFile; - nsCString mEventType; -}; - -// The MtpWatcherUpdate class listens for mtp-watcher-update events -// and tells the MtpServer about changes made in device storage. -class MtpWatcherUpdate final : public nsIObserver -{ -public: - NS_DECL_THREADSAFE_ISUPPORTS - - MtpWatcherUpdate(MozMtpServer* aMozMtpServer) - : mMozMtpServer(aMozMtpServer) - { - MOZ_ASSERT(NS_IsMainThread()); - - mIOThread = new LazyIdleThread( - DEFAULT_THREAD_TIMEOUT_MS, - NS_LITERAL_CSTRING("MtpWatcherUpdate")); - - nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); - obs->AddObserver(this, kMtpWatcherUpdate, false); - } - - NS_IMETHOD - Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) - { - MOZ_ASSERT(NS_IsMainThread()); - - if (strcmp(aTopic, kMtpWatcherUpdate)) { - // We're only interested in mtp-watcher-update events - return NS_OK; - } - - NS_ConvertUTF16toUTF8 eventType(aData); - if (!eventType.EqualsLiteral("modified") && !eventType.EqualsLiteral("deleted")) { - // Bug 1074604: Needn't handle "created" event, once file operation - // finished, it would trigger "modified" event. - return NS_OK; - } - - DeviceStorageFile* file = static_cast<DeviceStorageFile*>(aSubject); - file->Dump(kMtpWatcherUpdate); - MTP_LOG("%s: file %s %s", kMtpWatcherUpdate, - NS_LossyConvertUTF16toASCII(file->mPath).get(), - eventType.get()); - - RefPtr<MozMtpDatabase> mozMtpDatabase = mMozMtpServer->GetMozMtpDatabase(); - RefPtr<RefCountedMtpServer> mtpServer = mMozMtpServer->GetMtpServer(); - - // We're not supposed to perform I/O on the main thread, so punt the - // notification (which will write to /dev/mtp_usb) to an I/O Thread. - - RefPtr<MtpWatcherUpdateRunnable> r = - new MtpWatcherUpdateRunnable(mozMtpDatabase, mtpServer, file, eventType); - mIOThread->Dispatch(r, NS_DISPATCH_NORMAL); - - return NS_OK; - } - -protected: - ~MtpWatcherUpdate() - { - MOZ_ASSERT(NS_IsMainThread()); - - nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); - obs->RemoveObserver(this, kMtpWatcherUpdate); - } - -private: - RefPtr<MozMtpServer> mMozMtpServer; - nsCOMPtr<nsIThread> mIOThread; -}; -NS_IMPL_ISUPPORTS(MtpWatcherUpdate, nsIObserver) -static StaticRefPtr<MtpWatcherUpdate> sMtpWatcherUpdate; - -class AllocMtpWatcherUpdateRunnable final : public Runnable -{ -public: - AllocMtpWatcherUpdateRunnable(MozMtpServer* aMozMtpServer) - : mMozMtpServer(aMozMtpServer) - {} - - NS_IMETHOD Run() override - { - MOZ_ASSERT(NS_IsMainThread()); - - sMtpWatcherUpdate = new MtpWatcherUpdate(mMozMtpServer); - return NS_OK; - } -private: - RefPtr<MozMtpServer> mMozMtpServer; -}; - -class FreeMtpWatcherUpdateRunnable final : public Runnable -{ -public: - FreeMtpWatcherUpdateRunnable(MozMtpServer* aMozMtpServer) - : mMozMtpServer(aMozMtpServer) - {} - - NS_IMETHOD Run() override - { - MOZ_ASSERT(NS_IsMainThread()); - - sMtpWatcherUpdate = nullptr; - return NS_OK; - } -private: - RefPtr<MozMtpServer> mMozMtpServer; -}; - -class MtpServerRunnable : public Runnable -{ -public: - MtpServerRunnable(int aMtpUsbFd, MozMtpServer* aMozMtpServer) - : mMozMtpServer(aMozMtpServer), - mMtpUsbFd(aMtpUsbFd) - { - } - - nsresult Run() - { - RefPtr<RefCountedMtpServer> server = mMozMtpServer->GetMtpServer(); - - DebugOnly<nsresult> rv = - NS_DispatchToMainThread(new AllocMtpWatcherUpdateRunnable(mMozMtpServer)); - MOZ_ASSERT(NS_SUCCEEDED(rv)); - - MTP_LOG("MozMtpServer started"); - server->run(); - MTP_LOG("MozMtpServer finished"); - - // server->run will have closed the file descriptor. - mMtpUsbFd.forget(); - - rv = NS_DispatchToMainThread(new FreeMtpWatcherUpdateRunnable(mMozMtpServer)); - MOZ_ASSERT(NS_SUCCEEDED(rv)); - - return NS_OK; - } - -private: - RefPtr<MozMtpServer> mMozMtpServer; - ScopedClose mMtpUsbFd; // We want to hold this open while the server runs -}; - -already_AddRefed<RefCountedMtpServer> -MozMtpServer::GetMtpServer() -{ - RefPtr<RefCountedMtpServer> server = mMtpServer; - return server.forget(); -} - -already_AddRefed<MozMtpDatabase> -MozMtpServer::GetMozMtpDatabase() -{ - RefPtr<MozMtpDatabase> db = mMozMtpDatabase; - return db.forget(); -} - -bool -MozMtpServer::Init() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - const char *mtpUsbFilename = "/dev/mtp_usb"; - mMtpUsbFd = open(mtpUsbFilename, O_RDWR); - if (mMtpUsbFd.get() < 0) { - MTP_ERR("open of '%s' failed((%s))", mtpUsbFilename, strerror(errno)); - return false; - } - MTP_LOG("Opened '%s' fd %d", mtpUsbFilename, mMtpUsbFd.get()); - - mMozMtpDatabase = new MozMtpDatabase(); - mMtpServer = new RefCountedMtpServer(mMtpUsbFd.get(), // fd - mMozMtpDatabase.get(), // MtpDatabase - false, // ptp? - AID_MEDIA_RW, // file group - 0664, // file permissions - 0775); // dir permissions - return true; -} - -void -MozMtpServer::Run() -{ - nsresult rv = NS_NewNamedThread("MtpServer", getter_AddRefs(mServerThread)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - MOZ_ASSERT(mServerThread); - mServerThread->Dispatch(new MtpServerRunnable(mMtpUsbFd.forget(), this), NS_DISPATCH_NORMAL); -} - -END_MTP_NAMESPACE diff --git a/dom/system/gonk/MozMtpServer.h b/dom/system/gonk/MozMtpServer.h deleted file mode 100644 index 4989c25ef..000000000 --- a/dom/system/gonk/MozMtpServer.h +++ /dev/null @@ -1,61 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_mozmtpserver_h__ -#define mozilla_system_mozmtpserver_h__ - -#include "MozMtpCommon.h" -#include "MozMtpDatabase.h" - -#include "mozilla/FileUtils.h" - -#include "nsCOMPtr.h" -#include "nsIThread.h" - -BEGIN_MTP_NAMESPACE -using namespace android; - -class RefCountedMtpServer : public MtpServer -{ -public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedMtpServer) - - RefCountedMtpServer(int aFd, MtpDatabase* aDatabase, bool aPtp, - int aFileGroup, int aFilePerm, int aDirectoryPerm) - : MtpServer(aFd, aDatabase, aPtp, aFileGroup, aFilePerm, aDirectoryPerm) - { - } - -protected: - virtual ~RefCountedMtpServer() {} -}; - -class MozMtpServer -{ -public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MozMtpServer) - - bool Init(); - void Run(); - - already_AddRefed<RefCountedMtpServer> GetMtpServer(); - already_AddRefed<MozMtpDatabase> GetMozMtpDatabase(); - -protected: - virtual ~MozMtpServer() {} - -private: - RefPtr<RefCountedMtpServer> mMtpServer; - RefPtr<MozMtpDatabase> mMozMtpDatabase; - nsCOMPtr<nsIThread> mServerThread; - ScopedClose mMtpUsbFd; -}; - -END_MTP_NAMESPACE - -#endif // mozilla_system_mozmtpserver_h__ - - diff --git a/dom/system/gonk/MozMtpStorage.cpp b/dom/system/gonk/MozMtpStorage.cpp deleted file mode 100644 index 9c358a132..000000000 --- a/dom/system/gonk/MozMtpStorage.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "MozMtpStorage.h" -#include "MozMtpDatabase.h" -#include "MozMtpServer.h" - -#include "base/message_loop.h" -#include "nsXULAppAPI.h" - -BEGIN_MTP_NAMESPACE -using namespace android; - -MozMtpStorage::MozMtpStorage(Volume* aVolume, MozMtpServer* aMozMtpServer) - : mMozMtpServer(aMozMtpServer), - mVolume(aVolume) -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - // The MtpStorageID has the physical volume in the top 16 bits, and the - // logical volumein the lower 16 bits. We treat each volume as a separate - // phsyical storage; - mStorageID = mVolume->Id() << 16 | 1; - - MTP_LOG("Storage constructed for Volume %s mStorageID 0x%08x", - aVolume->NameStr(), mStorageID); - - Volume::RegisterVolumeObserver(this, "MozMtpStorage"); - - // Get things in sync - Notify(mVolume); -} - -MozMtpStorage::~MozMtpStorage() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - MTP_LOG("Storage destructed for Volume %s mStorageID 0x%08x", - mVolume->NameStr(), mStorageID); - - Volume::UnregisterVolumeObserver(this, "MozMtpStorage"); - if (mMtpStorage) { - StorageUnavailable(); - } -} - -// virtual -void -MozMtpStorage::Notify(Volume* const& aVolume) -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - if (aVolume != mVolume) { - // Not our volume - return; - } - Volume::STATE volState = aVolume->State(); - - MTP_LOG("Volume %s mStorageID 0x%08x state changed to %s SharingEnabled: %d", - aVolume->NameStr(), mStorageID, aVolume->StateStr(), - aVolume->IsSharingEnabled()); - - // vol->IsSharingEnabled really only applies to UMS volumes. We assume that - // that as long as MTP is enabled, then all volumes will be shared. The UI - // currently doesn't give us anything more granular than on/off. - - if (mMtpStorage) { - if (volState != nsIVolume::STATE_MOUNTED) { - // The volume is no longer accessible. We need to remove this storage - // from the MTP server - StorageUnavailable(); - } - } else { - if (volState == nsIVolume::STATE_MOUNTED) { - // The volume is accessible. Tell the MTP server. - StorageAvailable(); - } - } -} - -void -MozMtpStorage::StorageAvailable() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - nsCString mountPoint = mVolume->MountPoint(); - - MTP_LOG("Adding Volume %s mStorageID 0x%08x mountPoint %s to MozMtpDatabase", - mVolume->NameStr(), mStorageID, mountPoint.get()); - - RefPtr<MozMtpDatabase> db = mMozMtpServer->GetMozMtpDatabase(); - db->AddStorage(mStorageID, mountPoint.get(), mVolume->NameStr()); - - MOZ_ASSERT(!mMtpStorage); - - //TODO: Figure out what to do about maxFileSize. - - mMtpStorage.reset(new MtpStorage(mStorageID, // id - mountPoint.get(), // filePath - mVolume->NameStr(), // description - 1024uLL * 1024uLL, // reserveSpace - mVolume->IsHotSwappable(), // removable - 2uLL * 1024uLL * 1024uLL * 1024uLL)); // maxFileSize - RefPtr<RefCountedMtpServer> server = mMozMtpServer->GetMtpServer(); - - MTP_LOG("Adding Volume %s mStorageID 0x%08x mountPoint %s to MtpServer", - mVolume->NameStr(), mStorageID, mountPoint.get()); - server->addStorage(mMtpStorage.get()); -} - -void -MozMtpStorage::StorageUnavailable() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - MOZ_ASSERT(mMtpStorage); - - MTP_LOG("Removing mStorageID 0x%08x from MtpServer", mStorageID); - - RefPtr<RefCountedMtpServer> server = mMozMtpServer->GetMtpServer(); - server->removeStorage(mMtpStorage.get()); - - MTP_LOG("Removing mStorageID 0x%08x from MozMtpDatabse", mStorageID); - - RefPtr<MozMtpDatabase> db = mMozMtpServer->GetMozMtpDatabase(); - db->RemoveStorage(mStorageID); - - mMtpStorage = nullptr; -} - -END_MTP_NAMESPACE - - diff --git a/dom/system/gonk/MozMtpStorage.h b/dom/system/gonk/MozMtpStorage.h deleted file mode 100644 index 18d1e04ac..000000000 --- a/dom/system/gonk/MozMtpStorage.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_mozmtpstorage_h__ -#define mozilla_system_mozmtpstorage_h__ - -#include "MozMtpCommon.h" - -#include "mozilla/UniquePtr.h" - -#include "Volume.h" - -BEGIN_MTP_NAMESPACE -using namespace android; - -class MozMtpServer; - -class MozMtpStorage : public Volume::EventObserver -{ -public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MozMtpStorage) - - MozMtpStorage(Volume* aVolume, MozMtpServer* aMozMtpServer); - - typedef nsTArray<RefPtr<MozMtpStorage> > Array; - -private: - virtual ~MozMtpStorage(); - virtual void Notify(Volume* const& aEvent); - - void StorageAvailable(); - void StorageUnavailable(); - - RefPtr<MozMtpServer> mMozMtpServer; - UniquePtr<MtpStorage> mMtpStorage; - RefPtr<Volume> mVolume; - MtpStorageID mStorageID; -}; - -END_MTP_NAMESPACE - -#endif // mozilla_system_mozmtpstorage_h__ - - diff --git a/dom/system/gonk/NetIdManager.cpp b/dom/system/gonk/NetIdManager.cpp deleted file mode 100644 index 510ec8b22..000000000 --- a/dom/system/gonk/NetIdManager.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "NetIdManager.h" - -NetIdManager::NetIdManager() - : mNextNetId(MIN_NET_ID) -{ -} - -int NetIdManager::getNextNetId() -{ - // Modified from - // http://androidxref.com/5.0.0_r2/xref/frameworks/base/services/ - // core/java/com/android/server/ConnectivityService.java#764 - - int netId = mNextNetId; - if (++mNextNetId > MAX_NET_ID) { - mNextNetId = MIN_NET_ID; - } - - return netId; -} - -void NetIdManager::acquire(const nsString& aInterfaceName, - NetIdInfo* aNetIdInfo) -{ - // Lookup or create one. - if (!mInterfaceToNetIdHash.Get(aInterfaceName, aNetIdInfo)) { - aNetIdInfo->mNetId = getNextNetId(); - aNetIdInfo->mRefCnt = 1; - } else { - aNetIdInfo->mRefCnt++; - } - - // Update hash and return. - mInterfaceToNetIdHash.Put(aInterfaceName, *aNetIdInfo); - - return; -} - -bool NetIdManager::lookup(const nsString& aInterfaceName, - NetIdInfo* aNetIdInfo) -{ - return mInterfaceToNetIdHash.Get(aInterfaceName, aNetIdInfo); -} - -bool NetIdManager::release(const nsString& aInterfaceName, - NetIdInfo* aNetIdInfo) -{ - if (!mInterfaceToNetIdHash.Get(aInterfaceName, aNetIdInfo)) { - return false; // No such key. - } - - aNetIdInfo->mRefCnt--; - - // Update the hash if still be referenced. - if (aNetIdInfo->mRefCnt > 0) { - mInterfaceToNetIdHash.Put(aInterfaceName, *aNetIdInfo); - return true; - } - - // No longer be referenced. Remove the entry. - mInterfaceToNetIdHash.Remove(aInterfaceName); - - return true; -}
\ No newline at end of file diff --git a/dom/system/gonk/NetIdManager.h b/dom/system/gonk/NetIdManager.h deleted file mode 100644 index e35d0ecd2..000000000 --- a/dom/system/gonk/NetIdManager.h +++ /dev/null @@ -1,45 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef NetIdManager_h -#define NetIdManager_h - -#include "nsString.h" -#include "nsDataHashtable.h" - -// NetId is a logical network identifier defined by netd. -// A network is typically a physical one (i.e. PhysicalNetwork.cpp) -// for netd but it could be a virtual network as well. -// We currently use physical network only and use one-to-one -// network-interface mapping. - -class NetIdManager { -public: - // keep in sync with system/netd/NetworkController.cpp - enum { - MIN_NET_ID = 100, - MAX_NET_ID = 65535, - }; - - // We need to count the number of references since different - // application like data and mms may use the same interface. - struct NetIdInfo { - int mNetId; - int mRefCnt; - }; - -public: - NetIdManager(); - - bool lookup(const nsString& aInterfaceName, NetIdInfo* aNetIdInfo); - void acquire(const nsString& aInterfaceName, NetIdInfo* aNetIdInfo); - bool release(const nsString& aInterfaceName, NetIdInfo* aNetIdInfo); - -private: - int getNextNetId(); - int mNextNetId; - nsDataHashtable<nsStringHashKey, NetIdInfo> mInterfaceToNetIdHash; -}; - -#endif
\ No newline at end of file diff --git a/dom/system/gonk/NetworkInterfaceListService.js b/dom/system/gonk/NetworkInterfaceListService.js deleted file mode 100644 index 62fe046aa..000000000 --- a/dom/system/gonk/NetworkInterfaceListService.js +++ /dev/null @@ -1,110 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -const NETWORKLISTSERVICE_CONTRACTID = - "@mozilla.org/network/interface-list-service;1"; -const NETWORKLISTSERVICE_CID = - Components.ID("{3780be6e-7012-4e53-ade6-15212fb88a0d}"); - -XPCOMUtils.defineLazyServiceGetter(this, "cpmm", - "@mozilla.org/childprocessmessagemanager;1", - "nsISyncMessageSender"); - -function NetworkInterfaceListService () { -} - -NetworkInterfaceListService.prototype = { - classID: NETWORKLISTSERVICE_CID, - - QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInterfaceListService]), - - getDataInterfaceList: function(aConditions) { - return new NetworkInterfaceList( - cpmm.sendSyncMessage( - 'NetworkInterfaceList:ListInterface', - { - excludeSupl: (aConditions & - Ci.nsINetworkInterfaceListService. - LIST_NOT_INCLUDE_SUPL_INTERFACES) != 0, - excludeMms: (aConditions & - Ci.nsINetworkInterfaceListService. - LIST_NOT_INCLUDE_MMS_INTERFACES) != 0, - excludeIms: (aConditions & - Ci.nsINetworkInterfaceListService. - LIST_NOT_INCLUDE_IMS_INTERFACES) != 0, - excludeDun: (aConditions & - Ci.nsINetworkInterfaceListService. - LIST_NOT_INCLUDE_DUN_INTERFACES) != 0, - excludeFota: (aConditions & - Ci.nsINetworkInterfaceListService. - LIST_NOT_INCLUDE_FOTA_INTERFACES) != 0 - } - )[0]); - } -}; - -function FakeNetworkInfo(aAttributes) { - this.state = aAttributes.state; - this.type = aAttributes.type; - this.name = aAttributes.name; - this.ips = aAttributes.ips; - this.prefixLengths = aAttributes.prefixLengths; - this.gateways = aAttributes.gateways; - this.dnses = aAttributes.dnses; -} -FakeNetworkInfo.prototype = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInfo]), - - getAddresses: function (ips, prefixLengths) { - ips.value = this.ips.slice(); - prefixLengths.value = this.prefixLengths.slice(); - - return this.ips.length; - }, - - getGateways: function (count) { - if (count) { - count.value = this.gateways.length; - } - return this.gateways.slice(); - }, - - getDnses: function (count) { - if (count) { - count.value = this.dnses.length; - } - return this.dnses.slice(); - } -}; - -function NetworkInterfaceList (aInterfaceLiterals) { - this._interfaces = []; - for (let entry of aInterfaceLiterals) { - this._interfaces.push(new FakeNetworkInfo(entry)); - } -} - -NetworkInterfaceList.prototype = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInterfaceList]), - - getNumberOfInterface: function() { - return this._interfaces.length; - }, - - getInterfaceInfo: function(index) { - if (!this._interfaces) { - return null; - } - return this._interfaces[index]; - } -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkInterfaceListService]); - diff --git a/dom/system/gonk/NetworkInterfaceListService.manifest b/dom/system/gonk/NetworkInterfaceListService.manifest deleted file mode 100644 index a827e778f..000000000 --- a/dom/system/gonk/NetworkInterfaceListService.manifest +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright 2012 Mozilla Foundation and Mozilla contributors -# -# 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. - -# NetworkInterfaceListService.js -component {3780be6e-7012-4e53-ade6-15212fb88a0d} NetworkInterfaceListService.js -contract @mozilla.org/network/interface-list-service;1 {3780be6e-7012-4e53-ade6-15212fb88a0d} diff --git a/dom/system/gonk/NetworkManager.js b/dom/system/gonk/NetworkManager.js deleted file mode 100644 index 9d7a5683e..000000000 --- a/dom/system/gonk/NetworkManager.js +++ /dev/null @@ -1,1219 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/FileUtils.jsm"); -Cu.import("resource://gre/modules/systemlibs.js"); -Cu.import("resource://gre/modules/Promise.jsm"); - -const NETWORKMANAGER_CONTRACTID = "@mozilla.org/network/manager;1"; -const NETWORKMANAGER_CID = - Components.ID("{1ba9346b-53b5-4660-9dc6-58f0b258d0a6}"); - -const DEFAULT_PREFERRED_NETWORK_TYPE = Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET; - -XPCOMUtils.defineLazyGetter(this, "ppmm", function() { - return Cc["@mozilla.org/parentprocessmessagemanager;1"] - .getService(Ci.nsIMessageBroadcaster); -}); - -XPCOMUtils.defineLazyServiceGetter(this, "gDNSService", - "@mozilla.org/network/dns-service;1", - "nsIDNSService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gNetworkService", - "@mozilla.org/network/service;1", - "nsINetworkService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gTetheringService", - "@mozilla.org/tethering/service;1", - "nsITetheringService"); - -const TOPIC_INTERFACE_REGISTERED = "network-interface-registered"; -const TOPIC_INTERFACE_UNREGISTERED = "network-interface-unregistered"; -const TOPIC_ACTIVE_CHANGED = "network-active-changed"; -const TOPIC_PREF_CHANGED = "nsPref:changed"; -const TOPIC_XPCOM_SHUTDOWN = "xpcom-shutdown"; -const TOPIC_CONNECTION_STATE_CHANGED = "network-connection-state-changed"; -const PREF_MANAGE_OFFLINE_STATUS = "network.gonk.manage-offline-status"; -const PREF_NETWORK_DEBUG_ENABLED = "network.debugging.enabled"; - -const IPV4_ADDRESS_ANY = "0.0.0.0"; -const IPV6_ADDRESS_ANY = "::0"; - -const IPV4_MAX_PREFIX_LENGTH = 32; -const IPV6_MAX_PREFIX_LENGTH = 128; - -// Connection Type for Network Information API -const CONNECTION_TYPE_CELLULAR = 0; -const CONNECTION_TYPE_BLUETOOTH = 1; -const CONNECTION_TYPE_ETHERNET = 2; -const CONNECTION_TYPE_WIFI = 3; -const CONNECTION_TYPE_OTHER = 4; -const CONNECTION_TYPE_NONE = 5; - -const MANUAL_PROXY_CONFIGURATION = 1; - -var debug; -function updateDebug() { - let debugPref = false; // set default value here. - try { - debugPref = debugPref || Services.prefs.getBoolPref(PREF_NETWORK_DEBUG_ENABLED); - } catch (e) {} - - if (debugPref) { - debug = function(s) { - dump("-*- NetworkManager: " + s + "\n"); - }; - } else { - debug = function(s) {}; - } -} -updateDebug(); - -function defineLazyRegExp(obj, name, pattern) { - obj.__defineGetter__(name, function() { - delete obj[name]; - return obj[name] = new RegExp(pattern); - }); -} - -function ExtraNetworkInfo(aNetwork) { - let ips = {}; - let prefixLengths = {}; - aNetwork.info.getAddresses(ips, prefixLengths); - - this.state = aNetwork.info.state; - this.type = aNetwork.info.type; - this.name = aNetwork.info.name; - this.ips = ips.value; - this.prefixLengths = prefixLengths.value; - this.gateways = aNetwork.info.getGateways(); - this.dnses = aNetwork.info.getDnses(); - this.httpProxyHost = aNetwork.httpProxyHost; - this.httpProxyPort = aNetwork.httpProxyPort; - this.mtu = aNetwork.mtu; -} -ExtraNetworkInfo.prototype = { - getAddresses: function(aIps, aPrefixLengths) { - aIps.value = this.ips.slice(); - aPrefixLengths.value = this.prefixLengths.slice(); - - return this.ips.length; - }, - - getGateways: function(aCount) { - if (aCount) { - aCount.value = this.gateways.length; - } - - return this.gateways.slice(); - }, - - getDnses: function(aCount) { - if (aCount) { - aCount.value = this.dnses.length; - } - - return this.dnses.slice(); - } -}; - -function NetworkInterfaceLinks() -{ - this.resetLinks(); -} -NetworkInterfaceLinks.prototype = { - linkRoutes: null, - gateways: null, - interfaceName: null, - extraRoutes: null, - - setLinks: function(linkRoutes, gateways, interfaceName) { - this.linkRoutes = linkRoutes; - this.gateways = gateways; - this.interfaceName = interfaceName; - }, - - resetLinks: function() { - this.linkRoutes = []; - this.gateways = []; - this.interfaceName = ""; - this.extraRoutes = []; - }, - - compareGateways: function(gateways) { - if (this.gateways.length != gateways.length) { - return false; - } - - for (let i = 0; i < this.gateways.length; i++) { - if (this.gateways[i] != gateways[i]) { - return false; - } - } - - return true; - } -}; - -/** - * This component watches for network interfaces changing state and then - * adjusts routes etc. accordingly. - */ -function NetworkManager() { - this.networkInterfaces = {}; - this.networkInterfaceLinks = {}; - - try { - this._manageOfflineStatus = - Services.prefs.getBoolPref(PREF_MANAGE_OFFLINE_STATUS); - } catch(ex) { - // Ignore. - } - Services.prefs.addObserver(PREF_MANAGE_OFFLINE_STATUS, this, false); - Services.prefs.addObserver(PREF_NETWORK_DEBUG_ENABLED, this, false); - Services.obs.addObserver(this, TOPIC_XPCOM_SHUTDOWN, false); - - this.setAndConfigureActive(); - - ppmm.addMessageListener('NetworkInterfaceList:ListInterface', this); - - // Used in resolveHostname(). - defineLazyRegExp(this, "REGEXP_IPV4", "^\\d{1,3}(?:\\.\\d{1,3}){3}$"); - defineLazyRegExp(this, "REGEXP_IPV6", "^[\\da-fA-F]{4}(?::[\\da-fA-F]{4}){7}$"); -} -NetworkManager.prototype = { - classID: NETWORKMANAGER_CID, - classInfo: XPCOMUtils.generateCI({classID: NETWORKMANAGER_CID, - contractID: NETWORKMANAGER_CONTRACTID, - classDescription: "Network Manager", - interfaces: [Ci.nsINetworkManager]}), - QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkManager, - Ci.nsISupportsWeakReference, - Ci.nsIObserver, - Ci.nsISettingsServiceCallback]), - - // nsIObserver - - observe: function(subject, topic, data) { - switch (topic) { - case TOPIC_PREF_CHANGED: - if (data === PREF_NETWORK_DEBUG_ENABLED) { - updateDebug(); - } else if (data === PREF_MANAGE_OFFLINE_STATUS) { - this._manageOfflineStatus = - Services.prefs.getBoolPref(PREF_MANAGE_OFFLINE_STATUS); - debug(PREF_MANAGE_OFFLINE_STATUS + " has changed to " + this._manageOfflineStatus); - } - break; - case TOPIC_XPCOM_SHUTDOWN: - Services.obs.removeObserver(this, TOPIC_XPCOM_SHUTDOWN); - Services.prefs.removeObserver(PREF_MANAGE_OFFLINE_STATUS, this); - Services.prefs.removeObserver(PREF_NETWORK_DEBUG_ENABLED, this); - break; - } - }, - - receiveMessage: function(aMsg) { - switch (aMsg.name) { - case "NetworkInterfaceList:ListInterface": { - let excludeMms = aMsg.json.excludeMms; - let excludeSupl = aMsg.json.excludeSupl; - let excludeIms = aMsg.json.excludeIms; - let excludeDun = aMsg.json.excludeDun; - let excludeFota = aMsg.json.excludeFota; - let interfaces = []; - - for (let key in this.networkInterfaces) { - let network = this.networkInterfaces[key]; - let i = network.info; - if ((i.type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_MMS && excludeMms) || - (i.type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_SUPL && excludeSupl) || - (i.type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_IMS && excludeIms) || - (i.type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN && excludeDun) || - (i.type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_FOTA && excludeFota)) { - continue; - } - - let ips = {}; - let prefixLengths = {}; - i.getAddresses(ips, prefixLengths); - - interfaces.push({ - state: i.state, - type: i.type, - name: i.name, - ips: ips.value, - prefixLengths: prefixLengths.value, - gateways: i.getGateways(), - dnses: i.getDnses() - }); - } - return interfaces; - } - } - }, - - getNetworkId: function(aNetworkInfo) { - let id = "device"; - try { - if (aNetworkInfo instanceof Ci.nsIRilNetworkInfo) { - let rilInfo = aNetworkInfo.QueryInterface(Ci.nsIRilNetworkInfo); - id = "ril" + rilInfo.serviceId; - } - } catch (e) {} - - return id + "-" + aNetworkInfo.type; - }, - - // nsINetworkManager - - registerNetworkInterface: function(network) { - if (!(network instanceof Ci.nsINetworkInterface)) { - throw Components.Exception("Argument must be nsINetworkInterface.", - Cr.NS_ERROR_INVALID_ARG); - } - let networkId = this.getNetworkId(network.info); - if (networkId in this.networkInterfaces) { - throw Components.Exception("Network with that type already registered!", - Cr.NS_ERROR_INVALID_ARG); - } - this.networkInterfaces[networkId] = network; - this.networkInterfaceLinks[networkId] = new NetworkInterfaceLinks(); - - Services.obs.notifyObservers(network.info, TOPIC_INTERFACE_REGISTERED, null); - debug("Network '" + networkId + "' registered."); - }, - - _addSubnetRoutes: function(network) { - let ips = {}; - let prefixLengths = {}; - let length = network.getAddresses(ips, prefixLengths); - let promises = []; - - for (let i = 0; i < length; i++) { - debug('Adding subnet routes: ' + ips.value[i] + '/' + prefixLengths.value[i]); - promises.push( - gNetworkService.modifyRoute(Ci.nsINetworkService.MODIFY_ROUTE_ADD, - network.name, ips.value[i], prefixLengths.value[i]) - .catch(aError => { - debug("_addSubnetRoutes error: " + aError); - })); - } - - return Promise.all(promises); - }, - - updateNetworkInterface: function(network) { - if (!(network instanceof Ci.nsINetworkInterface)) { - throw Components.Exception("Argument must be nsINetworkInterface.", - Cr.NS_ERROR_INVALID_ARG); - } - let networkId = this.getNetworkId(network.info); - if (!(networkId in this.networkInterfaces)) { - throw Components.Exception("No network with that type registered.", - Cr.NS_ERROR_INVALID_ARG); - } - debug("Network " + network.info.type + "/" + network.info.name + - " changed state to " + network.info.state); - - // Keep a copy of network in case it is modified while we are updating. - let extNetworkInfo = new ExtraNetworkInfo(network); - - // Note that since Lollipop we need to allocate and initialize - // something through netd, so we add createNetwork/destroyNetwork - // to deal with that explicitly. - - switch (extNetworkInfo.state) { - case Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED: - - this._createNetwork(extNetworkInfo.name) - // Remove pre-created default route and let setAndConfigureActive() - // to set default route only on preferred network - .then(() => this._removeDefaultRoute(extNetworkInfo)) - // Set DNS server as early as possible to prevent from - // premature domain name lookup. - .then(() => this._setDNS(extNetworkInfo)) - .then(() => { - // Add host route for data calls - if (!this.isNetworkTypeMobile(extNetworkInfo.type)) { - return; - } - - let currentInterfaceLinks = this.networkInterfaceLinks[networkId]; - let newLinkRoutes = extNetworkInfo.getDnses().concat( - extNetworkInfo.httpProxyHost); - // If gateways have changed, remove all old routes first. - return this._handleGateways(networkId, extNetworkInfo.getGateways()) - .then(() => this._updateRoutes(currentInterfaceLinks.linkRoutes, - newLinkRoutes, - extNetworkInfo.getGateways(), - extNetworkInfo.name)) - .then(() => currentInterfaceLinks.setLinks(newLinkRoutes, - extNetworkInfo.getGateways(), - extNetworkInfo.name)); - }) - .then(() => { - if (extNetworkInfo.type != - Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN) { - return; - } - // Dun type is a special case where we add the default route to a - // secondary table. - return this.setSecondaryDefaultRoute(extNetworkInfo); - }) - .then(() => this._addSubnetRoutes(extNetworkInfo)) - .then(() => { - if (extNetworkInfo.mtu <= 0) { - return; - } - - return this._setMtu(extNetworkInfo); - }) - .then(() => this.setAndConfigureActive()) - .then(() => { - // Update data connection when Wifi connected/disconnected - if (extNetworkInfo.type == - Ci.nsINetworkInfo.NETWORK_TYPE_WIFI && this.mRil) { - for (let i = 0; i < this.mRil.numRadioInterfaces; i++) { - this.mRil.getRadioInterface(i).updateRILNetworkInterface(); - } - } - - // Probing the public network accessibility after routing table is ready - CaptivePortalDetectionHelper - .notify(CaptivePortalDetectionHelper.EVENT_CONNECT, - this.activeNetworkInfo); - }) - .then(() => { - // Notify outer modules like MmsService to start the transaction after - // the configuration of the network interface is done. - Services.obs.notifyObservers(network.info, - TOPIC_CONNECTION_STATE_CHANGED, - this.convertConnectionType(network.info)); - }) - .catch(aError => { - debug("updateNetworkInterface error: " + aError); - }); - break; - case Ci.nsINetworkInfo.NETWORK_STATE_DISCONNECTED: - Promise.resolve() - .then(() => { - if (!this.isNetworkTypeMobile(extNetworkInfo.type)) { - return; - } - // Remove host route for data calls - return this._cleanupAllHostRoutes(networkId); - }) - .then(() => { - if (extNetworkInfo.type != - Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN) { - return; - } - // Remove secondary default route for dun. - return this.removeSecondaryDefaultRoute(extNetworkInfo); - }) - .then(() => { - if (extNetworkInfo.type == Ci.nsINetworkInfo.NETWORK_TYPE_WIFI || - extNetworkInfo.type == Ci.nsINetworkInfo.NETWORK_TYPE_ETHERNET) { - // Remove routing table in /proc/net/route - return this._resetRoutingTable(extNetworkInfo.name); - } - if (extNetworkInfo.type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE) { - return this._removeDefaultRoute(extNetworkInfo) - } - }) - .then(() => { - // Clear http proxy on active network. - if (this.activeNetworkInfo && - extNetworkInfo.type == this.activeNetworkInfo.type) { - this.clearNetworkProxy(); - } - - // Abort ongoing captive portal detection on the wifi interface - CaptivePortalDetectionHelper - .notify(CaptivePortalDetectionHelper.EVENT_DISCONNECT, extNetworkInfo); - }) - .then(() => this.setAndConfigureActive()) - .then(() => { - // Update data connection when Wifi connected/disconnected - if (extNetworkInfo.type == - Ci.nsINetworkInfo.NETWORK_TYPE_WIFI && this.mRil) { - for (let i = 0; i < this.mRil.numRadioInterfaces; i++) { - this.mRil.getRadioInterface(i).updateRILNetworkInterface(); - } - } - }) - .then(() => this._destroyNetwork(extNetworkInfo.name)) - .then(() => { - // Notify outer modules like MmsService to start the transaction after - // the configuration of the network interface is done. - Services.obs.notifyObservers(network.info, - TOPIC_CONNECTION_STATE_CHANGED, - this.convertConnectionType(network.info)); - }) - .catch(aError => { - debug("updateNetworkInterface error: " + aError); - }); - break; - } - }, - - unregisterNetworkInterface: function(network) { - if (!(network instanceof Ci.nsINetworkInterface)) { - throw Components.Exception("Argument must be nsINetworkInterface.", - Cr.NS_ERROR_INVALID_ARG); - } - let networkId = this.getNetworkId(network.info); - if (!(networkId in this.networkInterfaces)) { - throw Components.Exception("No network with that type registered.", - Cr.NS_ERROR_INVALID_ARG); - } - - // This is for in case a network gets unregistered without being - // DISCONNECTED. - if (this.isNetworkTypeMobile(network.info.type)) { - this._cleanupAllHostRoutes(networkId); - } - - delete this.networkInterfaces[networkId]; - - Services.obs.notifyObservers(network.info, TOPIC_INTERFACE_UNREGISTERED, null); - debug("Network '" + networkId + "' unregistered."); - }, - - _manageOfflineStatus: true, - - networkInterfaces: null, - - networkInterfaceLinks: null, - - _networkTypePriorityList: [Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET, - Ci.nsINetworkInterface.NETWORK_TYPE_WIFI, - Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE], - get networkTypePriorityList() { - return this._networkTypePriorityList; - }, - set networkTypePriorityList(val) { - if (val.length != this._networkTypePriorityList.length) { - throw "Priority list length should equal to " + - this._networkTypePriorityList.length; - } - - // Check if types in new priority list are valid and also make sure there - // are no duplicate types. - let list = [Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET, - Ci.nsINetworkInterface.NETWORK_TYPE_WIFI, - Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE]; - while (list.length) { - let type = list.shift(); - if (val.indexOf(type) == -1) { - throw "There is missing network type"; - } - } - - this._networkTypePriorityList = val; - }, - - getPriority: function(type) { - if (this._networkTypePriorityList.indexOf(type) == -1) { - // 0 indicates the lowest priority. - return 0; - } - - return this._networkTypePriorityList.length - - this._networkTypePriorityList.indexOf(type); - }, - - get allNetworkInfo() { - let allNetworkInfo = {}; - - for (let networkId in this.networkInterfaces) { - if (this.networkInterfaces.hasOwnProperty(networkId)) { - allNetworkInfo[networkId] = this.networkInterfaces[networkId].info; - } - } - - return allNetworkInfo; - }, - - _preferredNetworkType: DEFAULT_PREFERRED_NETWORK_TYPE, - get preferredNetworkType() { - return this._preferredNetworkType; - }, - set preferredNetworkType(val) { - if ([Ci.nsINetworkInterface.NETWORK_TYPE_WIFI, - Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE, - Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET].indexOf(val) == -1) { - throw "Invalid network type"; - } - this._preferredNetworkType = val; - }, - - _activeNetwork: null, - - get activeNetworkInfo() { - return this._activeNetwork && this._activeNetwork.info; - }, - - _overriddenActive: null, - - overrideActive: function(network) { - if ([Ci.nsINetworkInterface.NETWORK_TYPE_WIFI, - Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE, - Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET].indexOf(val) == -1) { - throw "Invalid network type"; - } - - this._overriddenActive = network; - this.setAndConfigureActive(); - }, - - _updateRoutes: function(oldLinks, newLinks, gateways, interfaceName) { - // Returns items that are in base but not in target. - function getDifference(base, target) { - return base.filter(function(i) { return target.indexOf(i) < 0; }); - } - - let addedLinks = getDifference(newLinks, oldLinks); - let removedLinks = getDifference(oldLinks, newLinks); - - if (addedLinks.length === 0 && removedLinks.length === 0) { - return Promise.resolve(); - } - - return this._setHostRoutes(false, removedLinks, interfaceName, gateways) - .then(this._setHostRoutes(true, addedLinks, interfaceName, gateways)); - }, - - _setHostRoutes: function(doAdd, ipAddresses, networkName, gateways) { - let getMaxPrefixLength = (aIp) => { - return aIp.match(this.REGEXP_IPV4) ? IPV4_MAX_PREFIX_LENGTH : IPV6_MAX_PREFIX_LENGTH; - } - - let promises = []; - - ipAddresses.forEach((aIpAddress) => { - let gateway = this.selectGateway(gateways, aIpAddress); - if (gateway) { - promises.push((doAdd) - ? gNetworkService.modifyRoute(Ci.nsINetworkService.MODIFY_ROUTE_ADD, - networkName, aIpAddress, - getMaxPrefixLength(aIpAddress), gateway) - : gNetworkService.modifyRoute(Ci.nsINetworkService.MODIFY_ROUTE_REMOVE, - networkName, aIpAddress, - getMaxPrefixLength(aIpAddress), gateway)); - } - }); - - return Promise.all(promises); - }, - - isValidatedNetwork: function(aNetworkInfo) { - let isValid = false; - try { - isValid = (this.getNetworkId(aNetworkInfo) in this.networkInterfaces); - } catch (e) { - debug("Invalid network interface: " + e); - } - - return isValid; - }, - - addHostRoute: function(aNetworkInfo, aHost) { - if (!this.isValidatedNetwork(aNetworkInfo)) { - return Promise.reject("Invalid network info."); - } - - return this.resolveHostname(aNetworkInfo, aHost) - .then((ipAddresses) => { - let promises = []; - let networkId = this.getNetworkId(aNetworkInfo); - - ipAddresses.forEach((aIpAddress) => { - let promise = - this._setHostRoutes(true, [aIpAddress], aNetworkInfo.name, aNetworkInfo.getGateways()) - .then(() => this.networkInterfaceLinks[networkId].extraRoutes.push(aIpAddress)); - - promises.push(promise); - }); - - return Promise.all(promises); - }); - }, - - removeHostRoute: function(aNetworkInfo, aHost) { - if (!this.isValidatedNetwork(aNetworkInfo)) { - return Promise.reject("Invalid network info."); - } - - return this.resolveHostname(aNetworkInfo, aHost) - .then((ipAddresses) => { - let promises = []; - let networkId = this.getNetworkId(aNetworkInfo); - - ipAddresses.forEach((aIpAddress) => { - let found = this.networkInterfaceLinks[networkId].extraRoutes.indexOf(aIpAddress); - if (found < 0) { - return; // continue - } - - let promise = - this._setHostRoutes(false, [aIpAddress], aNetworkInfo.name, aNetworkInfo.getGateways()) - .then(() => { - this.networkInterfaceLinks[networkId].extraRoutes.splice(found, 1); - }, () => { - // We should remove it even if the operation failed. - this.networkInterfaceLinks[networkId].extraRoutes.splice(found, 1); - }); - promises.push(promise); - }); - - return Promise.all(promises); - }); - }, - - isNetworkTypeSecondaryMobile: function(type) { - return (type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_MMS || - type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_SUPL || - type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_IMS || - type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN || - type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_FOTA); - }, - - isNetworkTypeMobile: function(type) { - return (type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE || - this.isNetworkTypeSecondaryMobile(type)); - }, - - _handleGateways: function(networkId, gateways) { - let currentNetworkLinks = this.networkInterfaceLinks[networkId]; - if (currentNetworkLinks.gateways.length == 0 || - currentNetworkLinks.compareGateways(gateways)) { - return Promise.resolve(); - } - - let currentExtraRoutes = currentNetworkLinks.extraRoutes; - return this._cleanupAllHostRoutes(networkId) - .then(() => { - // If gateways have changed, re-add extra host routes with new gateways. - if (currentExtraRoutes.length > 0) { - this._setHostRoutes(true, - currentExtraRoutes, - currentNetworkLinks.interfaceName, - gateways) - .then(() => { - currentNetworkLinks.extraRoutes = currentExtraRoutes; - }); - } - }); - }, - - _cleanupAllHostRoutes: function(networkId) { - let currentNetworkLinks = this.networkInterfaceLinks[networkId]; - let hostRoutes = currentNetworkLinks.linkRoutes.concat( - currentNetworkLinks.extraRoutes); - - if (hostRoutes.length === 0) { - return Promise.resolve(); - } - - return this._setHostRoutes(false, - hostRoutes, - currentNetworkLinks.interfaceName, - currentNetworkLinks.gateways) - .catch((aError) => { - debug("Error (" + aError + ") on _cleanupAllHostRoutes, keep proceeding."); - }) - .then(() => currentNetworkLinks.resetLinks()); - }, - - selectGateway: function(gateways, host) { - for (let i = 0; i < gateways.length; i++) { - let gateway = gateways[i]; - if (gateway.match(this.REGEXP_IPV4) && host.match(this.REGEXP_IPV4) || - gateway.indexOf(":") != -1 && host.indexOf(":") != -1) { - return gateway; - } - } - return null; - }, - - _setSecondaryRoute: function(aDoAdd, aInterfaceName, aRoute) { - return new Promise((aResolve, aReject) => { - if (aDoAdd) { - gNetworkService.addSecondaryRoute(aInterfaceName, aRoute, - (aSuccess) => { - if (!aSuccess) { - aReject("addSecondaryRoute failed"); - return; - } - aResolve(); - }); - } else { - gNetworkService.removeSecondaryRoute(aInterfaceName, aRoute, - (aSuccess) => { - if (!aSuccess) { - debug("removeSecondaryRoute failed") - } - // Always resolve. - aResolve(); - }); - } - }); - }, - - setSecondaryDefaultRoute: function(network) { - let gateways = network.getGateways(); - let promises = []; - - for (let i = 0; i < gateways.length; i++) { - let isIPv6 = (gateways[i].indexOf(":") != -1) ? true : false; - // First, we need to add a host route to the gateway in the secondary - // routing table to make the gateway reachable. Host route takes the max - // prefix and gateway address 'any'. - let hostRoute = { - ip: gateways[i], - prefix: isIPv6 ? IPV6_MAX_PREFIX_LENGTH : IPV4_MAX_PREFIX_LENGTH, - gateway: isIPv6 ? IPV6_ADDRESS_ANY : IPV4_ADDRESS_ANY - }; - // Now we can add the default route through gateway. Default route takes the - // min prefix and destination ip 'any'. - let defaultRoute = { - ip: isIPv6 ? IPV6_ADDRESS_ANY : IPV4_ADDRESS_ANY, - prefix: 0, - gateway: gateways[i] - }; - - let promise = this._setSecondaryRoute(true, network.name, hostRoute) - .then(() => this._setSecondaryRoute(true, network.name, defaultRoute)); - - promises.push(promise); - } - - return Promise.all(promises); - }, - - removeSecondaryDefaultRoute: function(network) { - let gateways = network.getGateways(); - let promises = []; - - for (let i = 0; i < gateways.length; i++) { - let isIPv6 = (gateways[i].indexOf(":") != -1) ? true : false; - // Remove both default route and host route. - let defaultRoute = { - ip: isIPv6 ? IPV6_ADDRESS_ANY : IPV4_ADDRESS_ANY, - prefix: 0, - gateway: gateways[i] - }; - let hostRoute = { - ip: gateways[i], - prefix: isIPv6 ? IPV6_MAX_PREFIX_LENGTH : IPV4_MAX_PREFIX_LENGTH, - gateway: isIPv6 ? IPV6_ADDRESS_ANY : IPV4_ADDRESS_ANY - }; - - let promise = this._setSecondaryRoute(false, network.name, defaultRoute) - .then(() => this._setSecondaryRoute(false, network.name, hostRoute)); - - promises.push(promise); - } - - return Promise.all(promises); - }, - - /** - * Determine the active interface and configure it. - */ - setAndConfigureActive: function() { - debug("Evaluating whether active network needs to be changed."); - let oldActive = this._activeNetwork; - - if (this._overriddenActive) { - debug("We have an override for the active network: " + - this._overriddenActive.info.name); - // The override was just set, so reconfigure the network. - if (this._activeNetwork != this._overriddenActive) { - this._activeNetwork = this._overriddenActive; - this._setDefaultRouteAndProxy(this._activeNetwork, oldActive); - Services.obs.notifyObservers(this.activeNetworkInfo, - TOPIC_ACTIVE_CHANGED, null); - } - return; - } - - // The active network is already our preferred type. - if (this.activeNetworkInfo && - this.activeNetworkInfo.state == Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED && - this.activeNetworkInfo.type == this._preferredNetworkType) { - debug("Active network is already our preferred type."); - return this._setDefaultRouteAndProxy(this._activeNetwork, oldActive); - } - - // Find a suitable network interface to activate. - this._activeNetwork = null; - let anyConnected = false; - - for (let key in this.networkInterfaces) { - let network = this.networkInterfaces[key]; - if (network.info.state != Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) { - continue; - } - anyConnected = true; - - // Set active only for default connections. - if (network.info.type != Ci.nsINetworkInfo.NETWORK_TYPE_WIFI && - network.info.type != Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE && - network.info.type != Ci.nsINetworkInfo.NETWORK_TYPE_ETHERNET) { - continue; - } - - if (network.info.type == this.preferredNetworkType) { - this._activeNetwork = network; - debug("Found our preferred type of network: " + network.info.name); - break; - } - - // Initialize the active network with the first connected network. - if (!this._activeNetwork) { - this._activeNetwork = network; - continue; - } - - // Compare the prioriy between two network types. If found incoming - // network with higher priority, replace the active network. - if (this.getPriority(this._activeNetwork.type) < this.getPriority(network.type)) { - this._activeNetwork = network; - } - } - - return Promise.resolve() - .then(() => { - if (!this._activeNetwork) { - return Promise.resolve(); - } - - return this._setDefaultRouteAndProxy(this._activeNetwork, oldActive); - }) - .then(() => { - if (this._activeNetwork != oldActive) { - Services.obs.notifyObservers(this.activeNetworkInfo, - TOPIC_ACTIVE_CHANGED, null); - } - - if (this._manageOfflineStatus) { - Services.io.offline = !anyConnected && - (gTetheringService.state === - Ci.nsITetheringService.TETHERING_STATE_INACTIVE); - } - }); - }, - - resolveHostname: function(aNetworkInfo, aHostname) { - // Sanity check for null, undefined and empty string... etc. - if (!aHostname) { - return Promise.reject(new Error("hostname is empty: " + aHostname)); - } - - if (aHostname.match(this.REGEXP_IPV4) || - aHostname.match(this.REGEXP_IPV6)) { - return Promise.resolve([aHostname]); - } - - // Wrap gDNSService.asyncResolveExtended to a promise, which - // resolves with an array of ip addresses or rejects with - // the reason otherwise. - let hostResolveWrapper = aNetId => { - return new Promise((aResolve, aReject) => { - // Callback for gDNSService.asyncResolveExtended. - let onLookupComplete = (aRequest, aRecord, aStatus) => { - if (!Components.isSuccessCode(aStatus)) { - aReject(new Error("Failed to resolve '" + aHostname + - "', with status: " + aStatus)); - return; - } - - let retval = []; - while (aRecord.hasMore()) { - retval.push(aRecord.getNextAddrAsString()); - } - - if (!retval.length) { - aReject(new Error("No valid address after DNS lookup!")); - return; - } - - debug("hostname is resolved: " + aHostname); - debug("Addresses: " + JSON.stringify(retval)); - - aResolve(retval); - }; - - debug('Calling gDNSService.asyncResolveExtended: ' + aNetId + ', ' + aHostname); - gDNSService.asyncResolveExtended(aHostname, - 0, - aNetId, - onLookupComplete, - Services.tm.mainThread); - }); - }; - - // TODO: |getNetId| will be implemented as a sync call in nsINetworkManager - // once Bug 1141903 is landed. - return gNetworkService.getNetId(aNetworkInfo.name) - .then(aNetId => hostResolveWrapper(aNetId)); - }, - - convertConnectionType: function(aNetworkInfo) { - // If there is internal interface change (e.g., MOBILE_MMS, MOBILE_SUPL), - // the function will return null so that it won't trigger type change event - // in NetworkInformation API. - if (aNetworkInfo.type != Ci.nsINetworkInterface.NETWORK_TYPE_WIFI && - aNetworkInfo.type != Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE && - aNetworkInfo.type != Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET) { - return null; - } - - if (aNetworkInfo.state == Ci.nsINetworkInfo.NETWORK_STATE_DISCONNECTED) { - return CONNECTION_TYPE_NONE; - } - - switch (aNetworkInfo.type) { - case Ci.nsINetworkInfo.NETWORK_TYPE_WIFI: - return CONNECTION_TYPE_WIFI; - case Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE: - return CONNECTION_TYPE_CELLULAR; - case Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET: - return CONNECTION_TYPE_ETHERNET; - } - }, - - _setDNS: function(aNetworkInfo) { - return new Promise((aResolve, aReject) => { - let dnses = aNetworkInfo.getDnses(); - let gateways = aNetworkInfo.getGateways(); - gNetworkService.setDNS(aNetworkInfo.name, dnses.length, dnses, - gateways.length, gateways, (aError) => { - if (aError) { - aReject("setDNS failed"); - return; - } - aResolve(); - }); - }); - }, - - _setMtu: function(aNetworkInfo) { - return new Promise((aResolve, aReject) => { - gNetworkService.setMtu(aNetworkInfo.name, aNetworkInfo.mtu, (aSuccess) => { - if (!aSuccess) { - debug("setMtu failed"); - } - // Always resolve. - aResolve(); - }); - }); - }, - - _createNetwork: function(aInterfaceName) { - return new Promise((aResolve, aReject) => { - gNetworkService.createNetwork(aInterfaceName, (aSuccess) => { - if (!aSuccess) { - aReject("createNetwork failed"); - return; - } - aResolve(); - }); - }); - }, - - _destroyNetwork: function(aInterfaceName) { - return new Promise((aResolve, aReject) => { - gNetworkService.destroyNetwork(aInterfaceName, (aSuccess) => { - if (!aSuccess) { - debug("destroyNetwork failed") - } - // Always resolve. - aResolve(); - }); - }); - }, - - _resetRoutingTable: function(aInterfaceName) { - return new Promise((aResolve, aReject) => { - gNetworkService.resetRoutingTable(aInterfaceName, (aSuccess) => { - if (!aSuccess) { - debug("resetRoutingTable failed"); - } - // Always resolve. - aResolve(); - }); - }); - }, - - _removeDefaultRoute: function(aNetworkInfo) { - return new Promise((aResolve, aReject) => { - let gateways = aNetworkInfo.getGateways(); - gNetworkService.removeDefaultRoute(aNetworkInfo.name, gateways.length, - gateways, (aSuccess) => { - if (!aSuccess) { - debug("removeDefaultRoute failed"); - } - // Always resolve. - aResolve(); - }); - }); - }, - - _setDefaultRouteAndProxy: function(aNetwork, aOldNetwork) { - if (aOldNetwork) { - return this._removeDefaultRoute(aOldNetwork.info) - .then(() => this._setDefaultRouteAndProxy(aNetwork, null)); - } - - return new Promise((aResolve, aReject) => { - let networkInfo = aNetwork.info; - let gateways = networkInfo.getGateways(); - - gNetworkService.setDefaultRoute(networkInfo.name, gateways.length, gateways, - (aSuccess) => { - if (!aSuccess) { - gNetworkService.destroyNetwork(networkInfo.name, function() { - aReject("setDefaultRoute failed"); - }); - return; - } - this.setNetworkProxy(aNetwork); - aResolve(); - }); - }); - }, - - setNetworkProxy: function(aNetwork) { - try { - if (!aNetwork.httpProxyHost || aNetwork.httpProxyHost === "") { - // Sets direct connection to internet. - this.clearNetworkProxy(); - - debug("No proxy support for " + aNetwork.info.name + " network interface."); - return; - } - - debug("Going to set proxy settings for " + aNetwork.info.name + " network interface."); - // Sets manual proxy configuration. - Services.prefs.setIntPref("network.proxy.type", MANUAL_PROXY_CONFIGURATION); - - // Do not use this proxy server for all protocols. - Services.prefs.setBoolPref("network.proxy.share_proxy_settings", false); - Services.prefs.setCharPref("network.proxy.http", aNetwork.httpProxyHost); - Services.prefs.setCharPref("network.proxy.ssl", aNetwork.httpProxyHost); - let port = aNetwork.httpProxyPort === 0 ? 8080 : aNetwork.httpProxyPort; - Services.prefs.setIntPref("network.proxy.http_port", port); - Services.prefs.setIntPref("network.proxy.ssl_port", port); - } catch(ex) { - debug("Exception " + ex + ". Unable to set proxy setting for " + - aNetwork.info.name + " network interface."); - } - }, - - clearNetworkProxy: function() { - debug("Going to clear all network proxy."); - - Services.prefs.clearUserPref("network.proxy.type"); - Services.prefs.clearUserPref("network.proxy.share_proxy_settings"); - Services.prefs.clearUserPref("network.proxy.http"); - Services.prefs.clearUserPref("network.proxy.http_port"); - Services.prefs.clearUserPref("network.proxy.ssl"); - Services.prefs.clearUserPref("network.proxy.ssl_port"); - }, -}; - -var CaptivePortalDetectionHelper = (function() { - - const EVENT_CONNECT = "Connect"; - const EVENT_DISCONNECT = "Disconnect"; - let _ongoingInterface = null; - let _available = ("nsICaptivePortalDetector" in Ci); - let getService = function() { - return Cc['@mozilla.org/toolkit/captive-detector;1'] - .getService(Ci.nsICaptivePortalDetector); - }; - - let _performDetection = function(interfaceName, callback) { - let capService = getService(); - let capCallback = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsICaptivePortalCallback]), - prepare: function() { - capService.finishPreparation(interfaceName); - }, - complete: function(success) { - _ongoingInterface = null; - callback(success); - } - }; - - // Abort any unfinished captive portal detection. - if (_ongoingInterface != null) { - capService.abort(_ongoingInterface); - _ongoingInterface = null; - } - try { - capService.checkCaptivePortal(interfaceName, capCallback); - _ongoingInterface = interfaceName; - } catch (e) { - debug('Fail to detect captive portal due to: ' + e.message); - } - }; - - let _abort = function(interfaceName) { - if (_ongoingInterface !== interfaceName) { - return; - } - - let capService = getService(); - capService.abort(_ongoingInterface); - _ongoingInterface = null; - }; - - return { - EVENT_CONNECT: EVENT_CONNECT, - EVENT_DISCONNECT: EVENT_DISCONNECT, - notify: function(eventType, network) { - switch (eventType) { - case EVENT_CONNECT: - // perform captive portal detection on wifi interface - if (_available && network && - network.type == Ci.nsINetworkInfo.NETWORK_TYPE_WIFI) { - _performDetection(network.name, function() { - // TODO: bug 837600 - // We can disconnect wifi in here if user abort the login procedure. - }); - } - - break; - case EVENT_DISCONNECT: - if (_available && - network.type == Ci.nsINetworkInfo.NETWORK_TYPE_WIFI) { - _abort(network.name); - } - break; - } - } - }; -}()); - -XPCOMUtils.defineLazyGetter(NetworkManager.prototype, "mRil", function() { - try { - return Cc["@mozilla.org/ril;1"].getService(Ci.nsIRadioInterfaceLayer); - } catch (e) {} - - return null; -}); - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkManager]); diff --git a/dom/system/gonk/NetworkManager.manifest b/dom/system/gonk/NetworkManager.manifest deleted file mode 100644 index 995fa6559..000000000 --- a/dom/system/gonk/NetworkManager.manifest +++ /dev/null @@ -1,3 +0,0 @@ -# NetworkManager.js -component {1ba9346b-53b5-4660-9dc6-58f0b258d0a6} NetworkManager.js -contract @mozilla.org/network/manager;1 {1ba9346b-53b5-4660-9dc6-58f0b258d0a6} diff --git a/dom/system/gonk/NetworkService.js b/dom/system/gonk/NetworkService.js deleted file mode 100644 index 7147f40c7..000000000 --- a/dom/system/gonk/NetworkService.js +++ /dev/null @@ -1,862 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/NetUtil.jsm"); -Cu.import("resource://gre/modules/FileUtils.jsm"); -Cu.import("resource://gre/modules/Promise.jsm"); - -const NETWORKSERVICE_CONTRACTID = "@mozilla.org/network/service;1"; -const NETWORKSERVICE_CID = Components.ID("{48c13741-aec9-4a86-8962-432011708261}"); - -const TOPIC_PREF_CHANGED = "nsPref:changed"; -const TOPIC_XPCOM_SHUTDOWN = "xpcom-shutdown"; -const PREF_NETWORK_DEBUG_ENABLED = "network.debugging.enabled"; - -XPCOMUtils.defineLazyServiceGetter(this, "gNetworkWorker", - "@mozilla.org/network/worker;1", - "nsINetworkWorker"); - -// 1xx - Requested action is proceeding -const NETD_COMMAND_PROCEEDING = 100; -// 2xx - Requested action has been successfully completed -const NETD_COMMAND_OKAY = 200; -// 4xx - The command is accepted but the requested action didn't -// take place. -const NETD_COMMAND_FAIL = 400; -// 5xx - The command syntax or parameters error -const NETD_COMMAND_ERROR = 500; -// 6xx - Unsolicited broadcasts -const NETD_COMMAND_UNSOLICITED = 600; - -const WIFI_CTRL_INTERFACE = "wl0.1"; - -var debug; -function updateDebug() { - let debugPref = false; // set default value here. - try { - debugPref = debugPref || Services.prefs.getBoolPref(PREF_NETWORK_DEBUG_ENABLED); - } catch (e) {} - - if (debugPref) { - debug = function(s) { - dump("-*- NetworkService: " + s + "\n"); - }; - } else { - debug = function(s) {}; - } -} -updateDebug(); - -function netdResponseType(aCode) { - return Math.floor(aCode / 100) * 100; -} - -function isError(aCode) { - let type = netdResponseType(aCode); - return (type !== NETD_COMMAND_PROCEEDING && type !== NETD_COMMAND_OKAY); -} - -function Task(aId, aParams, aSetupFunction) { - this.id = aId; - this.params = aParams; - this.setupFunction = aSetupFunction; -} - -function NetworkWorkerRequestQueue(aNetworkService) { - this.networkService = aNetworkService; - this.tasks = []; -} -NetworkWorkerRequestQueue.prototype = { - runQueue: function() { - if (this.tasks.length === 0) { - return; - } - - let task = this.tasks[0]; - debug("run task id: " + task.id); - - if (typeof task.setupFunction === 'function') { - // If setupFunction returns false, skip sending to Network Worker but call - // handleWorkerMessage() directly with task id, as if the response was - // returned from Network Worker. - if (!task.setupFunction()) { - this.networkService.handleWorkerMessage({id: task.id}); - return; - } - } - - gNetworkWorker.postMessage(task.params); - }, - - enqueue: function(aId, aParams, aSetupFunction) { - debug("enqueue id: " + aId); - this.tasks.push(new Task(aId, aParams, aSetupFunction)); - - if (this.tasks.length === 1) { - this.runQueue(); - } - }, - - dequeue: function(aId) { - debug("dequeue id: " + aId); - - if (!this.tasks.length || this.tasks[0].id != aId) { - debug("Id " + aId + " is not on top of the queue"); - return; - } - - this.tasks.shift(); - if (this.tasks.length > 0) { - // Run queue on the next tick. - Services.tm.currentThread.dispatch(() => { - this.runQueue(); - }, Ci.nsIThread.DISPATCH_NORMAL); - } - } -}; - - -/** - * This component watches for network interfaces changing state and then - * adjusts routes etc. accordingly. - */ -function NetworkService() { - debug("Starting NetworkService."); - - let self = this; - - if (gNetworkWorker) { - let networkListener = { - onEvent: function(aEvent) { - self.handleWorkerMessage(aEvent); - } - }; - gNetworkWorker.start(networkListener); - } - // Callbacks to invoke when a reply arrives from the net_worker. - this.controlCallbacks = Object.create(null); - - this.addedRoutes = new Map(); - this.netWorkerRequestQueue = new NetworkWorkerRequestQueue(this); - this.shutdown = false; - - Services.prefs.addObserver(PREF_NETWORK_DEBUG_ENABLED, this, false); - Services.obs.addObserver(this, TOPIC_XPCOM_SHUTDOWN, false); -} - -NetworkService.prototype = { - classID: NETWORKSERVICE_CID, - classInfo: XPCOMUtils.generateCI({classID: NETWORKSERVICE_CID, - contractID: NETWORKSERVICE_CONTRACTID, - classDescription: "Network Service", - interfaces: [Ci.nsINetworkService]}), - QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkService, - Ci.nsIObserver]), - - addedRoutes: null, - - shutdown: false, - - // nsIObserver - - observe: function(aSubject, aTopic, aData) { - switch (aTopic) { - case TOPIC_PREF_CHANGED: - if (aData === PREF_NETWORK_DEBUG_ENABLED) { - updateDebug(); - } - break; - case TOPIC_XPCOM_SHUTDOWN: - debug("NetworkService shutdown"); - this.shutdown = true; - if (gNetworkWorker) { - gNetworkWorker.shutdown(); - gNetworkWorker = null; - } - - Services.obs.removeObserver(this, TOPIC_XPCOM_SHUTDOWN); - Services.prefs.removeObserver(PREF_NETWORK_DEBUG_ENABLED, this); - break; - } - }, - - // Helpers - - idgen: 0, - controlMessage: function(aParams, aCallback, aSetupFunction) { - if (this.shutdown) { - return; - } - - let id = this.idgen++; - aParams.id = id; - if (aCallback) { - this.controlCallbacks[id] = aCallback; - } - - // For now, we use aSetupFunction to determine if this command needs to be - // queued or not. - if (aSetupFunction) { - this.netWorkerRequestQueue.enqueue(id, aParams, aSetupFunction); - return; - } - - if (gNetworkWorker) { - gNetworkWorker.postMessage(aParams); - } - }, - - handleWorkerMessage: function(aResponse) { - debug("NetworkManager received message from worker: " + JSON.stringify(aResponse)); - let id = aResponse.id; - if (aResponse.broadcast === true) { - Services.obs.notifyObservers(null, aResponse.topic, aResponse.reason); - return; - } - let callback = this.controlCallbacks[id]; - if (callback) { - callback.call(this, aResponse); - delete this.controlCallbacks[id]; - } - - this.netWorkerRequestQueue.dequeue(id); - }, - - // nsINetworkService - - getNetworkInterfaceStats: function(aInterfaceName, aCallback) { - debug("getNetworkInterfaceStats for " + aInterfaceName); - - let file = new FileUtils.File("/proc/net/dev"); - if (!file) { - aCallback.networkStatsAvailable(false, 0, 0, Date.now()); - return; - } - - NetUtil.asyncFetch({ - uri: NetUtil.newURI(file), - loadUsingSystemPrincipal: true - }, function(inputStream, status) { - let rxBytes = 0, - txBytes = 0, - now = Date.now(); - - if (Components.isSuccessCode(status)) { - // Find record for corresponding interface. - let statExpr = /(\S+): +(\d+) +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +(\d+) +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+/; - let data = - NetUtil.readInputStreamToString(inputStream, inputStream.available()) - .split("\n"); - for (let i = 2; i < data.length; i++) { - let parseResult = statExpr.exec(data[i]); - if (parseResult && parseResult[1] === aInterfaceName) { - rxBytes = parseInt(parseResult[2], 10); - txBytes = parseInt(parseResult[3], 10); - break; - } - } - } - - // netd always return success even interface doesn't exist. - aCallback.networkStatsAvailable(true, rxBytes, txBytes, now); - }); - }, - - setNetworkTetheringAlarm(aEnable, aInterface) { - // Method called when enabling disabling tethering, it checks if there is - // some alarm active and move from interfaceAlarm to globalAlarm because - // interfaceAlarm doens't work in tethering scenario due to forwarding. - debug("setNetworkTetheringAlarm for tethering" + aEnable); - - let filename = aEnable ? "/proc/net/xt_quota/" + aInterface + "Alert" : - "/proc/net/xt_quota/globalAlert"; - - let file = new FileUtils.File(filename); - if (!file) { - return; - } - - NetUtil.asyncFetch({ - uri: NetUtil.newURI(file), - loadUsingSystemPrincipal: true - }, (inputStream, status) => { - if (Components.isSuccessCode(status)) { - let data = NetUtil.readInputStreamToString(inputStream, inputStream.available()) - .split("\n"); - if (data) { - let threshold = parseInt(data[0], 10); - - this._setNetworkTetheringAlarm(aEnable, aInterface, threshold); - } - } - }); - }, - - _setNetworkTetheringAlarm(aEnable, aInterface, aThreshold, aCallback) { - debug("_setNetworkTetheringAlarm for tethering" + aEnable); - - let cmd = aEnable ? "setTetheringAlarm" : "removeTetheringAlarm"; - - let params = { - cmd: cmd, - ifname: aInterface, - threshold: aThreshold, - }; - - this.controlMessage(params, function(aData) { - let code = aData.resultCode; - let reason = aData.resultReason; - let enableString = aEnable ? "Enable" : "Disable"; - debug(enableString + " tethering Alarm result: Code " + code + " reason " + reason); - if (aCallback) { - aCallback.networkUsageAlarmResult(null); - } - }); - }, - - setNetworkInterfaceAlarm: function(aInterfaceName, aThreshold, aCallback) { - if (!aInterfaceName) { - aCallback.networkUsageAlarmResult(-1); - return; - } - - let self = this; - this._disableNetworkInterfaceAlarm(aInterfaceName, function(aResult) { - if (aThreshold < 0) { - if (!isError(aResult.resultCode)) { - aCallback.networkUsageAlarmResult(null); - return; - } - aCallback.networkUsageAlarmResult(aResult.reason); - return - } - - // Check if tethering is enabled - let params = { - cmd: "getTetheringStatus" - }; - - self.controlMessage(params, function(aResult) { - if (isError(aResult.resultCode)) { - aCallback.networkUsageAlarmResult(aResult.reason); - return; - } - - if (aResult.resultReason.indexOf('started') == -1) { - // Tethering disabled, set interfaceAlarm - self._setNetworkInterfaceAlarm(aInterfaceName, aThreshold, aCallback); - return; - } - - // Tethering enabled, set globalAlarm - self._setNetworkTetheringAlarm(true, aInterfaceName, aThreshold, aCallback); - }); - }); - }, - - _setNetworkInterfaceAlarm: function(aInterfaceName, aThreshold, aCallback) { - debug("setNetworkInterfaceAlarm for " + aInterfaceName + " at " + aThreshold + "bytes"); - - let params = { - cmd: "setNetworkInterfaceAlarm", - ifname: aInterfaceName, - threshold: aThreshold - }; - - params.report = true; - - this.controlMessage(params, function(aResult) { - if (!isError(aResult.resultCode)) { - aCallback.networkUsageAlarmResult(null); - return; - } - - this._enableNetworkInterfaceAlarm(aInterfaceName, aThreshold, aCallback); - }); - }, - - _enableNetworkInterfaceAlarm: function(aInterfaceName, aThreshold, aCallback) { - debug("enableNetworkInterfaceAlarm for " + aInterfaceName + " at " + aThreshold + "bytes"); - - let params = { - cmd: "enableNetworkInterfaceAlarm", - ifname: aInterfaceName, - threshold: aThreshold - }; - - params.report = true; - - this.controlMessage(params, function(aResult) { - if (!isError(aResult.resultCode)) { - aCallback.networkUsageAlarmResult(null); - return; - } - aCallback.networkUsageAlarmResult(aResult.reason); - }); - }, - - _disableNetworkInterfaceAlarm: function(aInterfaceName, aCallback) { - debug("disableNetworkInterfaceAlarm for " + aInterfaceName); - - let params = { - cmd: "disableNetworkInterfaceAlarm", - ifname: aInterfaceName, - }; - - params.report = true; - - this.controlMessage(params, function(aResult) { - aCallback(aResult); - }); - }, - - setWifiOperationMode: function(aInterfaceName, aMode, aCallback) { - debug("setWifiOperationMode on " + aInterfaceName + " to " + aMode); - - let params = { - cmd: "setWifiOperationMode", - ifname: aInterfaceName, - mode: aMode - }; - - params.report = true; - - this.controlMessage(params, function(aResult) { - if (isError(aResult.resultCode)) { - aCallback.wifiOperationModeResult("netd command error"); - } else { - aCallback.wifiOperationModeResult(null); - } - }); - }, - - resetRoutingTable: function(aInterfaceName, aCallback) { - let options = { - cmd: "removeNetworkRoute", - ifname: aInterfaceName - }; - - this.controlMessage(options, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - }, - - setDNS: function(aInterfaceName, aDnsesCount, aDnses, aGatewaysCount, - aGateways, aCallback) { - debug("Going to set DNS to " + aInterfaceName); - let options = { - cmd: "setDNS", - ifname: aInterfaceName, - domain: "mozilla." + aInterfaceName + ".domain", - dnses: aDnses, - gateways: aGateways - }; - this.controlMessage(options, function(aResult) { - aCallback.setDnsResult(aResult.success ? null : aResult.reason); - }); - }, - - setDefaultRoute: function(aInterfaceName, aCount, aGateways, aCallback) { - debug("Going to change default route to " + aInterfaceName); - let options = { - cmd: "setDefaultRoute", - ifname: aInterfaceName, - gateways: aGateways - }; - this.controlMessage(options, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - }, - - removeDefaultRoute: function(aInterfaceName, aCount, aGateways, aCallback) { - debug("Remove default route for " + aInterfaceName); - let options = { - cmd: "removeDefaultRoute", - ifname: aInterfaceName, - gateways: aGateways - }; - this.controlMessage(options, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - }, - - _routeToString: function(aInterfaceName, aHost, aPrefixLength, aGateway) { - return aHost + "-" + aPrefixLength + "-" + aGateway + "-" + aInterfaceName; - }, - - modifyRoute: function(aAction, aInterfaceName, aHost, aPrefixLength, aGateway) { - let command; - - switch (aAction) { - case Ci.nsINetworkService.MODIFY_ROUTE_ADD: - command = 'addHostRoute'; - break; - case Ci.nsINetworkService.MODIFY_ROUTE_REMOVE: - command = 'removeHostRoute'; - break; - default: - debug('Unknown action: ' + aAction); - return Promise.reject(); - } - - let route = this._routeToString(aInterfaceName, aHost, aPrefixLength, aGateway); - let setupFunc = () => { - let count = this.addedRoutes.get(route); - debug(command + ": " + route + " -> " + count); - - // Return false if there is no need to send the command to network worker. - if ((aAction == Ci.nsINetworkService.MODIFY_ROUTE_ADD && count) || - (aAction == Ci.nsINetworkService.MODIFY_ROUTE_REMOVE && - (!count || count > 1))) { - return false; - } - - return true; - }; - - debug(command + " " + aHost + " on " + aInterfaceName); - let options = { - cmd: command, - ifname: aInterfaceName, - gateway: aGateway, - prefixLength: aPrefixLength, - ip: aHost - }; - - return new Promise((aResolve, aReject) => { - this.controlMessage(options, (aData) => { - let count = this.addedRoutes.get(route); - - // Remove route from addedRoutes on success or failure. - if (aAction == Ci.nsINetworkService.MODIFY_ROUTE_REMOVE) { - if (count > 1) { - this.addedRoutes.set(route, count - 1); - } else { - this.addedRoutes.delete(route); - } - } - - if (aData.error) { - aReject(aData.reason); - return; - } - - if (aAction == Ci.nsINetworkService.MODIFY_ROUTE_ADD) { - this.addedRoutes.set(route, count ? count + 1 : 1); - } - - aResolve(); - }, setupFunc); - }); - }, - - addSecondaryRoute: function(aInterfaceName, aRoute, aCallback) { - debug("Going to add route to secondary table on " + aInterfaceName); - let options = { - cmd: "addSecondaryRoute", - ifname: aInterfaceName, - ip: aRoute.ip, - prefix: aRoute.prefix, - gateway: aRoute.gateway - }; - this.controlMessage(options, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - }, - - removeSecondaryRoute: function(aInterfaceName, aRoute, aCallback) { - debug("Going to remove route from secondary table on " + aInterfaceName); - let options = { - cmd: "removeSecondaryRoute", - ifname: aInterfaceName, - ip: aRoute.ip, - prefix: aRoute.prefix, - gateway: aRoute.gateway - }; - this.controlMessage(options, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - }, - - // Enable/Disable DHCP server. - setDhcpServer: function(aEnabled, aConfig, aCallback) { - if (null === aConfig) { - aConfig = {}; - } - - aConfig.cmd = "setDhcpServer"; - aConfig.enabled = aEnabled; - - this.controlMessage(aConfig, function(aResponse) { - if (!aResponse.success) { - aCallback.dhcpServerResult('Set DHCP server error'); - return; - } - aCallback.dhcpServerResult(null); - }); - }, - - // Enable/disable WiFi tethering by sending commands to netd. - setWifiTethering: function(aEnable, aConfig, aCallback) { - // config should've already contained: - // .ifname - // .internalIfname - // .externalIfname - aConfig.wifictrlinterfacename = WIFI_CTRL_INTERFACE; - aConfig.cmd = "setWifiTethering"; - - // The callback function in controlMessage may not be fired immediately. - this.controlMessage(aConfig, (aData) => { - let code = aData.resultCode; - let reason = aData.resultReason; - let enable = aData.enable; - let enableString = aEnable ? "Enable" : "Disable"; - - debug(enableString + " Wifi tethering result: Code " + code + " reason " + reason); - - this.setNetworkTetheringAlarm(aEnable, aConfig.externalIfname); - - if (isError(code)) { - aCallback.wifiTetheringEnabledChange("netd command error"); - } else { - aCallback.wifiTetheringEnabledChange(null); - } - }); - }, - - // Enable/disable USB tethering by sending commands to netd. - setUSBTethering: function(aEnable, aConfig, aCallback) { - aConfig.cmd = "setUSBTethering"; - // The callback function in controlMessage may not be fired immediately. - this.controlMessage(aConfig, (aData) => { - let code = aData.resultCode; - let reason = aData.resultReason; - let enable = aData.enable; - let enableString = aEnable ? "Enable" : "Disable"; - - debug(enableString + " USB tethering result: Code " + code + " reason " + reason); - - this.setNetworkTetheringAlarm(aEnable, aConfig.externalIfname); - - if (isError(code)) { - aCallback.usbTetheringEnabledChange("netd command error"); - } else { - aCallback.usbTetheringEnabledChange(null); - } - }); - }, - - // Switch usb function by modifying property of persist.sys.usb.config. - enableUsbRndis: function(aEnable, aCallback) { - debug("enableUsbRndis: " + aEnable); - - let params = { - cmd: "enableUsbRndis", - enable: aEnable - }; - // Ask net work to report the result when this value is set to true. - if (aCallback) { - params.report = true; - } else { - params.report = false; - } - - // The callback function in controlMessage may not be fired immediately. - //this._usbTetheringAction = TETHERING_STATE_ONGOING; - this.controlMessage(params, function(aData) { - aCallback.enableUsbRndisResult(aData.result, aData.enable); - }); - }, - - updateUpStream: function(aPrevious, aCurrent, aCallback) { - let params = { - cmd: "updateUpStream", - preInternalIfname: aPrevious.internalIfname, - preExternalIfname: aPrevious.externalIfname, - curInternalIfname: aCurrent.internalIfname, - curExternalIfname: aCurrent.externalIfname - }; - - this.controlMessage(params, function(aData) { - let code = aData.resultCode; - let reason = aData.resultReason; - debug("updateUpStream result: Code " + code + " reason " + reason); - aCallback.updateUpStreamResult(!isError(code), aData.curExternalIfname); - }); - }, - - getInterfaces: function(callback) { - let params = { - cmd: "getInterfaces", - isAsync: true - }; - - this.controlMessage(params, function(data) { - debug("getInterfaces result: " + JSON.stringify(data)); - let success = !isError(data.resultCode); - callback.getInterfacesResult(success, data.interfaceList); - }); - }, - - getInterfaceConfig: function(ifname, callback) { - let params = { - cmd: "getInterfaceConfig", - ifname: ifname, - isAsync: true - }; - - this.controlMessage(params, function(data) { - debug("getInterfaceConfig result: " + JSON.stringify(data)); - let success = !isError(data.resultCode); - let result = { ip: data.ipAddr, - prefix: data.prefixLength, - link: data.flag, - mac: data.macAddr }; - callback.getInterfaceConfigResult(success, result); - }); - }, - - setInterfaceConfig: function(config, callback) { - config.cmd = "setInterfaceConfig"; - config.isAsync = true; - - this.controlMessage(config, function(data) { - debug("setInterfaceConfig result: " + JSON.stringify(data)); - let success = !isError(data.resultCode); - callback.setInterfaceConfigResult(success); - }); - }, - - configureInterface: function(aConfig, aCallback) { - let params = { - cmd: "configureInterface", - ifname: aConfig.ifname, - ipaddr: aConfig.ipaddr, - mask: aConfig.mask, - gateway_long: aConfig.gateway, - dns1_long: aConfig.dns1, - dns2_long: aConfig.dns2, - }; - - this.controlMessage(params, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - }, - - dhcpRequest: function(aInterfaceName, aCallback) { - let params = { - cmd: "dhcpRequest", - ifname: aInterfaceName - }; - - this.controlMessage(params, function(aResult) { - aCallback.dhcpRequestResult(!aResult.error, aResult.error ? null : aResult); - }); - }, - - stopDhcp: function(aInterfaceName, aCallback) { - let params = { - cmd: "stopDhcp", - ifname: aInterfaceName - }; - - this.controlMessage(params, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - }, - - enableInterface: function(aInterfaceName, aCallback) { - let params = { - cmd: "enableInterface", - ifname: aInterfaceName - }; - - this.controlMessage(params, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - }, - - disableInterface: function(aInterfaceName, aCallback) { - let params = { - cmd: "disableInterface", - ifname: aInterfaceName - }; - - this.controlMessage(params, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - }, - - resetConnections: function(aInterfaceName, aCallback) { - let params = { - cmd: "resetConnections", - ifname: aInterfaceName - }; - - this.controlMessage(params, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - }, - - createNetwork: function(aInterfaceName, aCallback) { - let params = { - cmd: "createNetwork", - ifname: aInterfaceName - }; - - this.controlMessage(params, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - }, - - destroyNetwork: function(aInterfaceName, aCallback) { - let params = { - cmd: "destroyNetwork", - ifname: aInterfaceName - }; - - this.controlMessage(params, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - }, - - getNetId: function(aInterfaceName) { - let params = { - cmd: "getNetId", - ifname: aInterfaceName - }; - - return new Promise((aResolve, aReject) => { - this.controlMessage(params, result => { - if (result.error) { - aReject(result.reason); - return; - } - aResolve(result.netId); - }); - }); - }, - - setMtu: function (aInterfaceName, aMtu, aCallback) { - debug("Set MTU on " + aInterfaceName + ": " + aMtu); - - let params = { - cmd: "setMtu", - ifname: aInterfaceName, - mtu: aMtu - }; - - this.controlMessage(params, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - } -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkService]); diff --git a/dom/system/gonk/NetworkService.manifest b/dom/system/gonk/NetworkService.manifest deleted file mode 100644 index caf8f2554..000000000 --- a/dom/system/gonk/NetworkService.manifest +++ /dev/null @@ -1,3 +0,0 @@ -# NetworkService.js -component {48c13741-aec9-4a86-8962-432011708261} NetworkService.js -contract @mozilla.org/network/service;1 {48c13741-aec9-4a86-8962-432011708261} diff --git a/dom/system/gonk/NetworkUtils.cpp b/dom/system/gonk/NetworkUtils.cpp deleted file mode 100644 index d661368b8..000000000 --- a/dom/system/gonk/NetworkUtils.cpp +++ /dev/null @@ -1,2973 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include "NetworkUtils.h" - -#include "mozilla/Sprintf.h" -#include "SystemProperty.h" - -#include <android/log.h> -#include <limits> -#include "mozilla/dom/network/NetUtils.h" -#include "mozilla/fallible.h" -#include "base/task.h" - -#include <errno.h> -#include <string.h> -#include <sys/types.h> // struct addrinfo -#include <sys/socket.h> // getaddrinfo(), freeaddrinfo() -#include <netdb.h> -#include <arpa/inet.h> // inet_ntop() - -#define _DEBUG 0 - -#define WARN(args...) __android_log_print(ANDROID_LOG_WARN, "NetworkUtils", ## args) -#define ERROR(args...) __android_log_print(ANDROID_LOG_ERROR, "NetworkUtils", ## args) - -#if _DEBUG -#define NU_DBG(args...) __android_log_print(ANDROID_LOG_DEBUG, "NetworkUtils" , ## args) -#else -#define NU_DBG(args...) -#endif - -using namespace mozilla::dom; -using namespace mozilla::ipc; -using mozilla::system::Property; - -static const char* PERSIST_SYS_USB_CONFIG_PROPERTY = "persist.sys.usb.config"; -static const char* SYS_USB_CONFIG_PROPERTY = "sys.usb.config"; -static const char* SYS_USB_STATE_PROPERTY = "sys.usb.state"; - -static const char* USB_FUNCTION_RNDIS = "rndis"; -static const char* USB_FUNCTION_ADB = "adb"; - -// Use this command to continue the function chain. -static const char* DUMMY_COMMAND = "tether status"; - -// IPV6 Tethering is not supported in AOSP, use the property to -// identify vendor specific support in IPV6. We can remove this flag -// once upstream Android support IPV6 in tethering. -static const char* IPV6_TETHERING = "ro.tethering.ipv6"; - -// Retry 20 times (2 seconds) for usb state transition. -static const uint32_t USB_FUNCTION_RETRY_TIMES = 20; -// Check "sys.usb.state" every 100ms. -static const uint32_t USB_FUNCTION_RETRY_INTERVAL = 100; - -// 1xx - Requested action is proceeding -static const uint32_t NETD_COMMAND_PROCEEDING = 100; -// 2xx - Requested action has been successfully completed -static const uint32_t NETD_COMMAND_OKAY = 200; -// 4xx - The command is accepted but the requested action didn't -// take place. -static const uint32_t NETD_COMMAND_FAIL = 400; -// 5xx - The command syntax or parameters error -static const uint32_t NETD_COMMAND_ERROR = 500; -// 6xx - Unsolicited broadcasts -static const uint32_t NETD_COMMAND_UNSOLICITED = 600; - -// Broadcast messages -static const uint32_t NETD_COMMAND_INTERFACE_CHANGE = 600; -static const uint32_t NETD_COMMAND_BANDWIDTH_CONTROLLER = 601; - -static const char* INTERFACE_DELIMIT = ","; -static const char* USB_CONFIG_DELIMIT = ","; -static const char* NETD_MESSAGE_DELIMIT = " "; - -static const uint32_t BUF_SIZE = 1024; - -static const int32_t SUCCESS = 0; - -static uint32_t SDK_VERSION; -static uint32_t SUPPORT_IPV6_TETHERING; - -struct IFProperties { - char gateway[Property::VALUE_MAX_LENGTH]; - char dns1[Property::VALUE_MAX_LENGTH]; - char dns2[Property::VALUE_MAX_LENGTH]; -}; - -struct CurrentCommand { - CommandChain* chain; - CommandCallback callback; - char command[MAX_COMMAND_SIZE]; -}; - -typedef Tuple3<NetdCommand*, CommandChain*, CommandCallback> QueueData; - -#define GET_CURRENT_NETD_COMMAND (gCommandQueue.IsEmpty() ? nullptr : gCommandQueue[0].a) -#define GET_CURRENT_CHAIN (gCommandQueue.IsEmpty() ? nullptr : gCommandQueue[0].b) -#define GET_CURRENT_CALLBACK (gCommandQueue.IsEmpty() ? nullptr : gCommandQueue[0].c) -#define GET_CURRENT_COMMAND (gCommandQueue.IsEmpty() ? nullptr : gCommandQueue[0].a->mData) - -// A macro for native function call return value check. -// For native function call, non-zero return value means failure. -#define RETURN_IF_FAILED(rv) do { \ - if (SUCCESS != rv) { \ - return rv; \ - } \ -} while (0); - -#define WARN_IF_FAILED(rv) do { \ - if (SUCCESS != rv) { \ - WARN("Error (%d) occurred in %s (%s:%d)", rv, __PRETTY_FUNCTION__, __FILE__, __LINE__); \ - } \ -} while (0); - -static NetworkUtils* gNetworkUtils; -static nsTArray<QueueData> gCommandQueue; -static CurrentCommand gCurrentCommand; -static bool gPending = false; -static nsTArray<nsCString> gReason; -static NetworkParams *gWifiTetheringParms = 0; - -static nsTArray<CommandChain*> gCommandChainQueue; - -const CommandFunc NetworkUtils::sWifiEnableChain[] = { - NetworkUtils::clearWifiTetherParms, - NetworkUtils::wifiFirmwareReload, - NetworkUtils::startAccessPointDriver, - NetworkUtils::setAccessPoint, - NetworkUtils::startSoftAP, - NetworkUtils::setConfig, - NetworkUtils::tetherInterface, - NetworkUtils::addInterfaceToLocalNetwork, - NetworkUtils::addRouteToLocalNetwork, - NetworkUtils::setIpForwardingEnabled, - NetworkUtils::tetheringStatus, - NetworkUtils::startTethering, - NetworkUtils::setDnsForwarders, - NetworkUtils::enableNat, - NetworkUtils::wifiTetheringSuccess -}; - -const CommandFunc NetworkUtils::sWifiDisableChain[] = { - NetworkUtils::clearWifiTetherParms, - NetworkUtils::stopSoftAP, - NetworkUtils::stopAccessPointDriver, - NetworkUtils::wifiFirmwareReload, - NetworkUtils::untetherInterface, - NetworkUtils::removeInterfaceFromLocalNetwork, - NetworkUtils::preTetherInterfaceList, - NetworkUtils::postTetherInterfaceList, - NetworkUtils::disableNat, - NetworkUtils::setIpForwardingEnabled, - NetworkUtils::stopTethering, - NetworkUtils::wifiTetheringSuccess -}; - -const CommandFunc NetworkUtils::sWifiFailChain[] = { - NetworkUtils::clearWifiTetherParms, - NetworkUtils::stopSoftAP, - NetworkUtils::setIpForwardingEnabled, - NetworkUtils::stopTethering -}; - -const CommandFunc NetworkUtils::sWifiRetryChain[] = { - NetworkUtils::clearWifiTetherParms, - NetworkUtils::stopSoftAP, - NetworkUtils::stopTethering, - - // sWifiEnableChain: - NetworkUtils::wifiFirmwareReload, - NetworkUtils::startAccessPointDriver, - NetworkUtils::setAccessPoint, - NetworkUtils::startSoftAP, - NetworkUtils::setConfig, - NetworkUtils::tetherInterface, - NetworkUtils::addInterfaceToLocalNetwork, - NetworkUtils::addRouteToLocalNetwork, - NetworkUtils::setIpForwardingEnabled, - NetworkUtils::tetheringStatus, - NetworkUtils::startTethering, - NetworkUtils::setDnsForwarders, - NetworkUtils::enableNat, - NetworkUtils::wifiTetheringSuccess -}; - -const CommandFunc NetworkUtils::sWifiOperationModeChain[] = { - NetworkUtils::wifiFirmwareReload, - NetworkUtils::wifiOperationModeSuccess -}; - -const CommandFunc NetworkUtils::sUSBEnableChain[] = { - NetworkUtils::setConfig, - NetworkUtils::enableNat, - NetworkUtils::setIpForwardingEnabled, - NetworkUtils::tetherInterface, - NetworkUtils::addInterfaceToLocalNetwork, - NetworkUtils::addRouteToLocalNetwork, - NetworkUtils::tetheringStatus, - NetworkUtils::startTethering, - NetworkUtils::setDnsForwarders, - NetworkUtils::addUpstreamInterface, - NetworkUtils::usbTetheringSuccess -}; - -const CommandFunc NetworkUtils::sUSBDisableChain[] = { - NetworkUtils::untetherInterface, - NetworkUtils::removeInterfaceFromLocalNetwork, - NetworkUtils::preTetherInterfaceList, - NetworkUtils::postTetherInterfaceList, - NetworkUtils::removeUpstreamInterface, - NetworkUtils::disableNat, - NetworkUtils::setIpForwardingEnabled, - NetworkUtils::stopTethering, - NetworkUtils::usbTetheringSuccess -}; - -const CommandFunc NetworkUtils::sUSBFailChain[] = { - NetworkUtils::stopSoftAP, - NetworkUtils::setIpForwardingEnabled, - NetworkUtils::stopTethering -}; - -const CommandFunc NetworkUtils::sUpdateUpStreamChain[] = { - NetworkUtils::cleanUpStream, - NetworkUtils::removeUpstreamInterface, - NetworkUtils::createUpStream, - NetworkUtils::addUpstreamInterface, - NetworkUtils::updateUpStreamSuccess -}; - -const CommandFunc NetworkUtils::sStartDhcpServerChain[] = { - NetworkUtils::setConfig, - NetworkUtils::startTethering, - NetworkUtils::setDhcpServerSuccess -}; - -const CommandFunc NetworkUtils::sStopDhcpServerChain[] = { - NetworkUtils::stopTethering, - NetworkUtils::setDhcpServerSuccess -}; - -const CommandFunc NetworkUtils::sNetworkInterfaceEnableAlarmChain[] = { - NetworkUtils::enableAlarm, - NetworkUtils::setQuota, - NetworkUtils::setAlarm, - NetworkUtils::networkInterfaceAlarmSuccess -}; - -const CommandFunc NetworkUtils::sNetworkInterfaceDisableAlarmChain[] = { - NetworkUtils::removeQuota, - NetworkUtils::disableAlarm, - NetworkUtils::networkInterfaceAlarmSuccess -}; - -const CommandFunc NetworkUtils::sNetworkInterfaceSetAlarmChain[] = { - NetworkUtils::setAlarm, - NetworkUtils::networkInterfaceAlarmSuccess -}; - -const CommandFunc NetworkUtils::sGetInterfacesChain[] = { - NetworkUtils::getInterfaceList, - NetworkUtils::getInterfacesSuccess -}; - -const CommandFunc NetworkUtils::sGetInterfaceConfigChain[] = { - NetworkUtils::getConfig, - NetworkUtils::getInterfaceConfigSuccess -}; - -const CommandFunc NetworkUtils::sSetInterfaceConfigChain[] = { - NetworkUtils::setConfig, - NetworkUtils::setInterfaceConfigSuccess -}; - -const CommandFunc NetworkUtils::sTetheringInterfaceSetAlarmChain[] = { - NetworkUtils::setGlobalAlarm, - NetworkUtils::removeAlarm, - NetworkUtils::networkInterfaceAlarmSuccess -}; - -const CommandFunc NetworkUtils::sTetheringInterfaceRemoveAlarmChain[] = { - NetworkUtils::removeGlobalAlarm, - NetworkUtils::setAlarm, - NetworkUtils::networkInterfaceAlarmSuccess -}; - -const CommandFunc NetworkUtils::sTetheringGetStatusChain[] = { - NetworkUtils::tetheringStatus, - NetworkUtils::defaultAsyncSuccessHandler -}; - -/** - * Helper function to get the mask from given prefix length. - */ -static uint32_t makeMask(const uint32_t prefixLength) -{ - uint32_t mask = 0; - for (uint32_t i = 0; i < prefixLength; ++i) { - mask |= (0x80000000 >> i); - } - return ntohl(mask); -} - -/** - * Helper function to get the network part of an ip from prefix. - * param ip must be in network byte order. - */ -static char* getNetworkAddr(const uint32_t ip, const uint32_t prefix) -{ - uint32_t mask = 0, subnet = 0; - - mask = ~mask << (32 - prefix); - mask = htonl(mask); - subnet = ip & mask; - - struct in_addr addr; - addr.s_addr = subnet; - - return inet_ntoa(addr); -} - -/** - * Helper function to split string by seperator, store split result as an nsTArray. - */ -static void split(char* str, const char* sep, nsTArray<nsCString>& result) -{ - char *s = strtok(str, sep); - while (s != nullptr) { - result.AppendElement(s); - s = strtok(nullptr, sep); - } -} - -static void split(char* str, const char* sep, nsTArray<nsString>& result) -{ - char *s = strtok(str, sep); - while (s != nullptr) { - result.AppendElement(NS_ConvertUTF8toUTF16(s)); - s = strtok(nullptr, sep); - } -} - -/** - * Helper function that implement join function. - */ -static void join(nsTArray<nsCString>& array, - const char* sep, - const uint32_t maxlen, - char* result) -{ -#define CHECK_LENGTH(len, add, max) len += add; \ - if (len > max - 1) \ - return; \ - - uint32_t len = 0; - uint32_t seplen = strlen(sep); - - if (array.Length() > 0) { - CHECK_LENGTH(len, strlen(array[0].get()), maxlen) - strcpy(result, array[0].get()); - - for (uint32_t i = 1; i < array.Length(); i++) { - CHECK_LENGTH(len, seplen, maxlen) - strcat(result, sep); - - CHECK_LENGTH(len, strlen(array[i].get()), maxlen) - strcat(result, array[i].get()); - } - } - -#undef CHECK_LEN -} - -static void convertUTF8toUTF16(nsTArray<nsCString>& narrow, - nsTArray<nsString>& wide, - uint32_t length) -{ - for (uint32_t i = 0; i < length; i++) { - wide.AppendElement(NS_ConvertUTF8toUTF16(narrow[i].get())); - } -} - -/** - * Helper function to get network interface properties from the system property table. - */ -static void getIFProperties(const char* ifname, IFProperties& prop) -{ - char key[Property::KEY_MAX_LENGTH]; - snprintf(key, Property::KEY_MAX_LENGTH - 1, "net.%s.gw", ifname); - Property::Get(key, prop.gateway, ""); - snprintf(key, Property::KEY_MAX_LENGTH - 1, "net.%s.dns1", ifname); - Property::Get(key, prop.dns1, ""); - snprintf(key, Property::KEY_MAX_LENGTH - 1, "net.%s.dns2", ifname); - Property::Get(key, prop.dns2, ""); -} - -static int getIpType(const char *aIp) { - struct addrinfo hint, *ip_info = NULL; - - memset(&hint, 0, sizeof(hint)); - hint.ai_family = AF_UNSPEC; - hint.ai_flags = AI_NUMERICHOST; - - if (getaddrinfo(aIp, NULL, &hint, &ip_info)) { - return AF_UNSPEC; - } - - int type = ip_info->ai_family; - freeaddrinfo(ip_info); - - return type; -} - -static void postMessage(NetworkResultOptions& aResult) -{ - MOZ_ASSERT(gNetworkUtils); - MOZ_ASSERT(gNetworkUtils->getMessageCallback()); - - if (*(gNetworkUtils->getMessageCallback())) - (*(gNetworkUtils->getMessageCallback()))(aResult); -} - -static void postMessage(NetworkParams& aOptions, NetworkResultOptions& aResult) -{ - MOZ_ASSERT(gNetworkUtils); - MOZ_ASSERT(gNetworkUtils->getMessageCallback()); - - aResult.mId = aOptions.mId; - - if (*(gNetworkUtils->getMessageCallback())) - (*(gNetworkUtils->getMessageCallback()))(aResult); -} - -void NetworkUtils::runNextQueuedCommandChain() -{ - if (gCommandChainQueue.IsEmpty()) { - NU_DBG("No command chain left in the queue. Done!"); - return; - } - NU_DBG("Process the queued command chain."); - CommandChain* nextChain = gCommandChainQueue[0]; - NetworkResultOptions newResult; - next(nextChain, false, newResult); -} - -void NetworkUtils::next(CommandChain* aChain, bool aError, NetworkResultOptions& aResult) -{ - if (aError) { - ErrorCallback onError = aChain->getErrorCallback(); - if(onError) { - aResult.mError = true; - (*onError)(aChain->getParams(), aResult); - } - delete aChain; - gCommandChainQueue.RemoveElementAt(0); - runNextQueuedCommandChain(); - return; - } - CommandFunc f = aChain->getNextCommand(); - if (!f) { - delete aChain; - gCommandChainQueue.RemoveElementAt(0); - runNextQueuedCommandChain(); - return; - } - - (*f)(aChain, next, aResult); -} - -CommandResult::CommandResult(int32_t aResultCode) - : mIsPending(false) -{ - // This is usually not a netd command. We treat the return code - // typical linux convention, which uses 0 to indicate success. - mResult.mError = (aResultCode == SUCCESS ? false : true); - mResult.mResultCode = aResultCode; - if (aResultCode != SUCCESS) { - // The returned value is sometimes negative, make sure we pass a positive - // error number to strerror. - enum { STRERROR_R_BUF_SIZE = 1024, }; - char strerrorBuf[STRERROR_R_BUF_SIZE]; - strerror_r(abs(aResultCode), strerrorBuf, STRERROR_R_BUF_SIZE); - mResult.mReason = NS_ConvertUTF8toUTF16(strerrorBuf); - } -} - -CommandResult::CommandResult(const mozilla::dom::NetworkResultOptions& aResult) - : mResult(aResult) - , mIsPending(false) -{ -} - -CommandResult::CommandResult(const Pending&) - : mIsPending(true) -{ -} - -bool CommandResult::isPending() const -{ - return mIsPending; -} - -/** - * Send command to netd. - */ -void NetworkUtils::nextNetdCommand() -{ - if (gCommandQueue.IsEmpty() || gPending) { - return; - } - - gCurrentCommand.chain = GET_CURRENT_CHAIN; - gCurrentCommand.callback = GET_CURRENT_CALLBACK; - snprintf(gCurrentCommand.command, MAX_COMMAND_SIZE - 1, "%s", GET_CURRENT_COMMAND); - - NU_DBG("Sending \'%s\' command to netd.", gCurrentCommand.command); - SendNetdCommand(GET_CURRENT_NETD_COMMAND); - - gCommandQueue.RemoveElementAt(0); - gPending = true; -} - -/** - * Composite NetdCommand sent to netd - * - * @param aCommand Command sent to netd to execute. - * @param aChain Store command chain data, ex. command parameter. - * @param aCallback Callback function to be executed when the result of - * this command is returned from netd. - */ -void NetworkUtils::doCommand(const char* aCommand, CommandChain* aChain, CommandCallback aCallback) -{ - NU_DBG("Preparing to send \'%s\' command...", aCommand); - - NetdCommand* netdCommand = new NetdCommand(); - - // Android JB version adds sequence number to netd command. - if (SDK_VERSION >= 16) { - snprintf((char*)netdCommand->mData, MAX_COMMAND_SIZE - 1, "0 %s", aCommand); - } else { - snprintf((char*)netdCommand->mData, MAX_COMMAND_SIZE - 1, "%s", aCommand); - } - netdCommand->mSize = strlen((char*)netdCommand->mData) + 1; - - gCommandQueue.AppendElement(QueueData(netdCommand, aChain, aCallback)); - - nextNetdCommand(); -} - -/* - * Netd command function - */ -#define GET_CHAR(prop) NS_ConvertUTF16toUTF8(aChain->getParams().prop).get() -#define GET_FIELD(prop) aChain->getParams().prop - -void NetworkUtils::wifiFirmwareReload(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "softap fwreload %s %s", GET_CHAR(mIfname), GET_CHAR(mMode)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::startAccessPointDriver(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - // Skip the command for sdk version >= 16. - if (SDK_VERSION >= 16) { - aResult.mResultCode = 0; - aResult.mResultReason = NS_ConvertUTF8toUTF16(""); - aCallback(aChain, false, aResult); - return; - } - - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "softap start %s", GET_CHAR(mIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::stopAccessPointDriver(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - // Skip the command for sdk version >= 16. - if (SDK_VERSION >= 16) { - aResult.mResultCode = 0; - aResult.mResultReason = NS_ConvertUTF8toUTF16(""); - aCallback(aChain, false, aResult); - return; - } - - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "softap stop %s", GET_CHAR(mIfname)); - - doCommand(command, aChain, aCallback); -} - -/** - * Command format for sdk version < 16 - * Arguments: - * argv[2] - wlan interface - * argv[3] - SSID - * argv[4] - Security - * argv[5] - Key - * argv[6] - Channel - * argv[7] - Preamble - * argv[8] - Max SCB - * - * Command format for sdk version >= 16 - * Arguments: - * argv[2] - wlan interface - * argv[3] - SSID - * argv[4] - Security - * argv[5] - Key - * - * Command format for sdk version >= 18 - * Arguments: - * argv[2] - wlan interface - * argv[3] - SSID - * argv[4] - Broadcast/Hidden - * argv[5] - Channel - * argv[6] - Security - * argv[7] - Key - */ -void NetworkUtils::setAccessPoint(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - nsCString ssid(GET_CHAR(mSsid)); - nsCString key(GET_CHAR(mKey)); - - escapeQuote(ssid); - escapeQuote(key); - - if (SDK_VERSION >= 19) { - snprintf(command, MAX_COMMAND_SIZE - 1, "softap set %s \"%s\" broadcast 6 %s \"%s\"", - GET_CHAR(mIfname), - ssid.get(), - GET_CHAR(mSecurity), - key.get()); - } else if (SDK_VERSION >= 16) { - snprintf(command, MAX_COMMAND_SIZE - 1, "softap set %s \"%s\" %s \"%s\"", - GET_CHAR(mIfname), - ssid.get(), - GET_CHAR(mSecurity), - key.get()); - } else { - snprintf(command, MAX_COMMAND_SIZE - 1, "softap set %s %s \"%s\" %s \"%s\" 6 0 8", - GET_CHAR(mIfname), - GET_CHAR(mWifictrlinterfacename), - ssid.get(), - GET_CHAR(mSecurity), - key.get()); - } - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::cleanUpStream(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "nat disable %s %s 0", GET_CHAR(mPreInternalIfname), GET_CHAR(mPreExternalIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::createUpStream(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "nat enable %s %s 0", GET_CHAR(mCurInternalIfname), GET_CHAR(mCurExternalIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::startSoftAP(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - const char* command= "softap startap"; - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::stopSoftAP(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - const char* command= "softap stopap"; - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::clearWifiTetherParms(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - delete gWifiTetheringParms; - gWifiTetheringParms = 0; - next(aChain, false, aResult); -} - -void NetworkUtils::enableAlarm(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - const char* command= "bandwidth enable"; - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::disableAlarm(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - const char* command= "bandwidth disable"; - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::setQuota(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "bandwidth setiquota %s % " PRId64, GET_CHAR(mIfname), INT64_MAX); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::removeQuota(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "bandwidth removeiquota %s", GET_CHAR(mIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::setAlarm(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "bandwidth setinterfacealert %s %lld", - GET_CHAR(mIfname), GET_FIELD(mThreshold)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::removeAlarm(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "bandwidth removeinterfacealert %s", GET_CHAR(mIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::setGlobalAlarm(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - - snprintf(command, MAX_COMMAND_SIZE - 1, "bandwidth setglobalalert %lld", GET_FIELD(mThreshold)); - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::removeGlobalAlarm(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - - snprintf(command, MAX_COMMAND_SIZE - 1, "bandwidth removeglobalalert"); - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::tetherInterface(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "tether interface add %s", GET_CHAR(mIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::addInterfaceToLocalNetwork(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - // Skip the command for sdk version < 20. - if (SDK_VERSION < 20) { - aResult.mResultCode = 0; - aResult.mResultReason = NS_ConvertUTF8toUTF16(""); - aCallback(aChain, false, aResult); - return; - } - - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "network interface add local %s", - GET_CHAR(mInternalIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::addRouteToLocalNetwork(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - // Skip the command for sdk version < 20. - if (SDK_VERSION < 20) { - aResult.mResultCode = 0; - aResult.mResultReason = NS_ConvertUTF8toUTF16(""); - aCallback(aChain, false, aResult); - return; - } - - char command[MAX_COMMAND_SIZE]; - uint32_t prefix = atoi(GET_CHAR(mPrefix)); - uint32_t ip = inet_addr(GET_CHAR(mIp)); - char* networkAddr = getNetworkAddr(ip, prefix); - - snprintf(command, MAX_COMMAND_SIZE - 1, "network route add local %s %s/%s", - GET_CHAR(mInternalIfname), networkAddr, GET_CHAR(mPrefix)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::preTetherInterfaceList(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - if (SDK_VERSION >= 16) { - snprintf(command, MAX_COMMAND_SIZE - 1, "tether interface list"); - } else { - snprintf(command, MAX_COMMAND_SIZE - 1, "tether interface list 0"); - } - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::postTetherInterfaceList(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - // Send the dummy command to continue the function chain. - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "%s", DUMMY_COMMAND); - - char buf[BUF_SIZE]; - NS_ConvertUTF16toUTF8 reason(aResult.mResultReason); - - size_t length = reason.Length() + 1 < BUF_SIZE ? reason.Length() + 1 : BUF_SIZE; - memcpy(buf, reason.get(), length); - split(buf, INTERFACE_DELIMIT, GET_FIELD(mInterfaceList)); - - doCommand(command, aChain, aCallback); -} - -bool isCommandChainIPv6(CommandChain* aChain, const char *externalInterface) { - // Check by gateway address - if (getIpType(GET_CHAR(mGateway)) == AF_INET6) { - return true; - } - - uint32_t length = GET_FIELD(mGateways).Length(); - for (uint32_t i = 0; i < length; i++) { - NS_ConvertUTF16toUTF8 autoGateway(GET_FIELD(mGateways)[i]); - if(getIpType(autoGateway.get()) == AF_INET6) { - return true; - } - } - - // Check by external inteface address - FILE *file = fopen("/proc/net/if_inet6", "r"); - if (!file) { - return false; - } - - bool isIPv6 = false; - char interface[32]; - while(fscanf(file, "%*s %*s %*s %*s %*s %32s", interface)) { - if (strcmp(interface, externalInterface) == 0) { - isIPv6 = true; - break; - } - } - - fclose(file); - return isIPv6; -} - -void NetworkUtils::addUpstreamInterface(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - nsCString interface(GET_CHAR(mExternalIfname)); - if (!interface.get()[0]) { - interface = GET_CHAR(mCurExternalIfname); - } - - if (SUPPORT_IPV6_TETHERING == 0 || !isCommandChainIPv6(aChain, interface.get())) { - aCallback(aChain, false, aResult); - return; - } - - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "tether interface add_upstream %s", - interface.get()); - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::removeUpstreamInterface(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - nsCString interface(GET_CHAR(mExternalIfname)); - if (!interface.get()[0]) { - interface = GET_CHAR(mPreExternalIfname); - } - - if (SUPPORT_IPV6_TETHERING == 0 || !isCommandChainIPv6(aChain, interface.get())) { - aCallback(aChain, false, aResult); - return; - } - - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "tether interface remove_upstream %s", - interface.get()); - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::setIpForwardingEnabled(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - - if (GET_FIELD(mEnable)) { - snprintf(command, MAX_COMMAND_SIZE - 1, "ipfwd enable"); - } else { - // Don't disable ip forwarding because others interface still need it. - // Send the dummy command to continue the function chain. - if (GET_FIELD(mInterfaceList).Length() > 1) { - snprintf(command, MAX_COMMAND_SIZE - 1, "%s", DUMMY_COMMAND); - } else { - snprintf(command, MAX_COMMAND_SIZE - 1, "ipfwd disable"); - } - } - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::tetheringStatus(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - const char* command= "tether status"; - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::stopTethering(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - - // Don't stop tethering because others interface still need it. - // Send the dummy to continue the function chain. - if (GET_FIELD(mInterfaceList).Length() > 1) { - snprintf(command, MAX_COMMAND_SIZE - 1, "%s", DUMMY_COMMAND); - } else { - snprintf(command, MAX_COMMAND_SIZE - 1, "tether stop"); - } - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::startTethering(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - - // We don't need to start tethering again. - // Send the dummy command to continue the function chain. - if (aResult.mResultReason.Find("started") != kNotFound) { - snprintf(command, MAX_COMMAND_SIZE - 1, "%s", DUMMY_COMMAND); - } else { - // If usbStartIp/usbEndIp is not valid, don't append them since - // the trailing white spaces will be parsed to extra empty args - // See: http://androidxref.com/4.3_r2.1/xref/system/core/libsysutils/src/FrameworkListener.cpp#78 - if (!GET_FIELD(mUsbStartIp).IsEmpty() && !GET_FIELD(mUsbEndIp).IsEmpty()) { - snprintf(command, MAX_COMMAND_SIZE - 1, "tether start %s %s %s %s", - GET_CHAR(mWifiStartIp), GET_CHAR(mWifiEndIp), - GET_CHAR(mUsbStartIp), GET_CHAR(mUsbEndIp)); - } else { - snprintf(command, MAX_COMMAND_SIZE - 1, "tether start %s %s", - GET_CHAR(mWifiStartIp), GET_CHAR(mWifiEndIp)); - } - } - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::untetherInterface(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "tether interface remove %s", GET_CHAR(mIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::removeInterfaceFromLocalNetwork(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - // Skip the command for sdk version < 20. - if (SDK_VERSION < 20) { - aResult.mResultCode = 0; - aResult.mResultReason = NS_ConvertUTF8toUTF16(""); - aCallback(aChain, false, aResult); - return; - } - - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "network interface remove local %s", - GET_CHAR(mIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::setDnsForwarders(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - - if (SDK_VERSION >= 20) { - snprintf(command, MAX_COMMAND_SIZE - 1, "tether dns set %d %s %s", - GET_FIELD(mNetId), GET_CHAR(mDns1), GET_CHAR(mDns2)); - } else { - snprintf(command, MAX_COMMAND_SIZE - 1, "tether dns set %s %s", - GET_CHAR(mDns1), GET_CHAR(mDns2)); - } - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::enableNat(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - - if (!GET_FIELD(mIp).IsEmpty() && !GET_FIELD(mPrefix).IsEmpty()) { - uint32_t prefix = atoi(GET_CHAR(mPrefix)); - uint32_t ip = inet_addr(GET_CHAR(mIp)); - char* networkAddr = getNetworkAddr(ip, prefix); - - // address/prefix will only take effect when secondary routing table exists. - snprintf(command, MAX_COMMAND_SIZE - 1, "nat enable %s %s 1 %s/%s", - GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname), networkAddr, - GET_CHAR(mPrefix)); - } else { - snprintf(command, MAX_COMMAND_SIZE - 1, "nat enable %s %s 0", - GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname)); - } - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::disableNat(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - - if (!GET_FIELD(mIp).IsEmpty() && !GET_FIELD(mPrefix).IsEmpty()) { - uint32_t prefix = atoi(GET_CHAR(mPrefix)); - uint32_t ip = inet_addr(GET_CHAR(mIp)); - char* networkAddr = getNetworkAddr(ip, prefix); - - snprintf(command, MAX_COMMAND_SIZE - 1, "nat disable %s %s 1 %s/%s", - GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname), networkAddr, - GET_CHAR(mPrefix)); - } else { - snprintf(command, MAX_COMMAND_SIZE - 1, "nat disable %s %s 0", - GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname)); - } - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::setDefaultInterface(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "resolver setdefaultif %s", GET_CHAR(mIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::removeDefaultRoute(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - if (GET_FIELD(mLoopIndex) >= GET_FIELD(mGateways).Length()) { - aCallback(aChain, false, aResult); - return; - } - - char command[MAX_COMMAND_SIZE]; - nsTArray<nsString>& gateways = GET_FIELD(mGateways); - NS_ConvertUTF16toUTF8 autoGateway(gateways[GET_FIELD(mLoopIndex)]); - - int type = getIpType(autoGateway.get()); - snprintf(command, MAX_COMMAND_SIZE - 1, "network route remove %d %s %s/0 %s", - GET_FIELD(mNetId), GET_CHAR(mIfname), - type == AF_INET6 ? "::" : "0.0.0.0", autoGateway.get()); - - struct MyCallback { - static void callback(CommandCallback::CallbackType aOriginalCallback, - CommandChain* aChain, - bool aError, - mozilla::dom::NetworkResultOptions& aResult) - { - NS_ConvertUTF16toUTF8 reason(aResult.mResultReason); - NU_DBG("removeDefaultRoute's reason: %s", reason.get()); - if (aError && !reason.EqualsASCII("removeRoute() failed (No such process)")) { - return aOriginalCallback(aChain, aError, aResult); - } - - GET_FIELD(mLoopIndex)++; - return removeDefaultRoute(aChain, aOriginalCallback, aResult); - } - }; - - CommandCallback wrappedCallback(MyCallback::callback, aCallback); - doCommand(command, aChain, wrappedCallback); -} - -void NetworkUtils::setInterfaceDns(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - int written; - - if (SDK_VERSION >= 20) { - written = SprintfLiteral(command, "resolver setnetdns %d %s", - GET_FIELD(mNetId), GET_CHAR(mDomain)); - } else { - written = SprintfLiteral(command, "resolver setifdns %s %s", - GET_CHAR(mIfname), GET_CHAR(mDomain)); - } - - nsTArray<nsString>& dnses = GET_FIELD(mDnses); - uint32_t length = dnses.Length(); - - for (uint32_t i = 0; i < length; i++) { - NS_ConvertUTF16toUTF8 autoDns(dnses[i]); - - int ret = snprintf(command + written, sizeof(command) - written, " %s", autoDns.get()); - if (ret <= 1) { - command[written] = '\0'; - continue; - } - - if (((size_t)ret + written) >= sizeof(command)) { - command[written] = '\0'; - break; - } - - written += ret; - } - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::getInterfaceList(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "interface list"); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::getConfig(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "interface getcfg %s", GET_CHAR(mIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::setConfig(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - if (SDK_VERSION >= 16) { - snprintf(command, MAX_COMMAND_SIZE - 1, "interface setcfg %s %s %s %s", - GET_CHAR(mIfname), - GET_CHAR(mIp), - GET_CHAR(mPrefix), - GET_CHAR(mLink)); - } else { - snprintf(command, MAX_COMMAND_SIZE - 1, "interface setcfg %s %s %s [%s]", - GET_CHAR(mIfname), - GET_CHAR(mIp), - GET_CHAR(mPrefix), - GET_CHAR(mLink)); - } - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::clearAddrForInterface(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "interface clearaddrs %s", GET_CHAR(mIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::createNetwork(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "network create %d", GET_FIELD(mNetId)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::destroyNetwork(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "network destroy %d", GET_FIELD(mNetId)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::addInterfaceToNetwork(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "network interface add %d %s", - GET_FIELD(mNetId), GET_CHAR(mIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::addRouteToInterface(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - struct MyCallback { - static void callback(CommandCallback::CallbackType aOriginalCallback, - CommandChain* aChain, - bool aError, - mozilla::dom::NetworkResultOptions& aResult) - { - NS_ConvertUTF16toUTF8 reason(aResult.mResultReason); - NU_DBG("addRouteToInterface's reason: %s", reason.get()); - if (aError && reason.EqualsASCII("addRoute() failed (File exists)")) { - NU_DBG("Ignore \"File exists\" error when adding host route."); - return aOriginalCallback(aChain, false, aResult); - } - aOriginalCallback(aChain, aError, aResult); - } - }; - - CommandCallback wrappedCallback(MyCallback::callback, aCallback); - modifyRouteOnInterface(aChain, wrappedCallback, aResult, true); -} - -void NetworkUtils::removeRouteFromInterface(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - modifyRouteOnInterface(aChain, aCallback, aResult, false); -} - -void NetworkUtils::modifyRouteOnInterface(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult, - bool aDoAdd) -{ - char command[MAX_COMMAND_SIZE]; - - // AOSP adds host route to its interface table but it doesn't work for - // B2G because we cannot set fwmark per application. So, we add - // all host routes to legacy_system table except scope link route. - - nsCString ipOrSubnetIp = NS_ConvertUTF16toUTF8(GET_FIELD(mIp)); - nsCString gatewayOrEmpty; - const char* legacyOrEmpty = "legacy 0 "; // Add to legacy by default. - if (GET_FIELD(mGateway).IsEmpty()) { - ipOrSubnetIp = getSubnetIp(ipOrSubnetIp, GET_FIELD(mPrefixLength)); - legacyOrEmpty = ""; // Add to interface table for scope link route. - } else { - gatewayOrEmpty = nsCString(" ") + NS_ConvertUTF16toUTF8(GET_FIELD(mGateway)); - } - - const char* action = aDoAdd ? "add" : "remove"; - - snprintf(command, MAX_COMMAND_SIZE - 1, "network route %s%s %d %s %s/%d%s", - legacyOrEmpty, action, - GET_FIELD(mNetId), GET_CHAR(mIfname), ipOrSubnetIp.get(), - GET_FIELD(mPrefixLength), gatewayOrEmpty.get()); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::addDefaultRouteToNetwork(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - if (GET_FIELD(mLoopIndex) >= GET_FIELD(mGateways).Length()) { - aCallback(aChain, false, aResult); - return; - } - - char command[MAX_COMMAND_SIZE]; - nsTArray<nsString>& gateways = GET_FIELD(mGateways); - NS_ConvertUTF16toUTF8 autoGateway(gateways[GET_FIELD(mLoopIndex)]); - - int type = getIpType(autoGateway.get()); - snprintf(command, MAX_COMMAND_SIZE - 1, "network route add %d %s %s/0 %s", - GET_FIELD(mNetId), GET_CHAR(mIfname), - type == AF_INET6 ? "::" : "0.0.0.0", autoGateway.get()); - - struct MyCallback { - static void callback(CommandCallback::CallbackType aOriginalCallback, - CommandChain* aChain, - bool aError, - mozilla::dom::NetworkResultOptions& aResult) - { - NS_ConvertUTF16toUTF8 reason(aResult.mResultReason); - NU_DBG("addDefaultRouteToNetwork's reason: %s", reason.get()); - if (aError && !reason.EqualsASCII("addRoute() failed (File exists)")) { - return aOriginalCallback(aChain, aError, aResult); - } - - GET_FIELD(mLoopIndex)++; - return addDefaultRouteToNetwork(aChain, aOriginalCallback, aResult); - } - }; - - CommandCallback wrappedCallback(MyCallback::callback, aCallback); - doCommand(command, aChain, wrappedCallback); -} - -void NetworkUtils::setDefaultNetwork(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "network default set %d", GET_FIELD(mNetId)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::addRouteToSecondaryTable(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) { - - char command[MAX_COMMAND_SIZE]; - - if (SDK_VERSION >= 20) { - snprintf(command, MAX_COMMAND_SIZE - 1, - "network route add %d %s %s/%s %s", - GET_FIELD(mNetId), - GET_CHAR(mIfname), - GET_CHAR(mIp), - GET_CHAR(mPrefix), - GET_CHAR(mGateway)); - } else { - snprintf(command, MAX_COMMAND_SIZE - 1, - "interface route add %s secondary %s %s %s", - GET_CHAR(mIfname), - GET_CHAR(mIp), - GET_CHAR(mPrefix), - GET_CHAR(mGateway)); - } - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::removeRouteFromSecondaryTable(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) { - char command[MAX_COMMAND_SIZE]; - - if (SDK_VERSION >= 20) { - snprintf(command, MAX_COMMAND_SIZE - 1, - "network route remove %d %s %s/%s %s", - GET_FIELD(mNetId), - GET_CHAR(mIfname), - GET_CHAR(mIp), - GET_CHAR(mPrefix), - GET_CHAR(mGateway)); - } else { - snprintf(command, MAX_COMMAND_SIZE - 1, - "interface route remove %s secondary %s %s %s", - GET_CHAR(mIfname), - GET_CHAR(mIp), - GET_CHAR(mPrefix), - GET_CHAR(mGateway)); - } - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::setIpv6Enabled(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult, - bool aEnabled) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "interface ipv6 %s %s", - GET_CHAR(mIfname), aEnabled ? "enable" : "disable"); - - struct MyCallback { - static void callback(CommandCallback::CallbackType aOriginalCallback, - CommandChain* aChain, - bool aError, - mozilla::dom::NetworkResultOptions& aResult) - { - aOriginalCallback(aChain, false, aResult); - } - }; - - CommandCallback wrappedCallback(MyCallback::callback, aCallback); - doCommand(command, aChain, wrappedCallback); -} - -void NetworkUtils::enableIpv6(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - setIpv6Enabled(aChain, aCallback, aResult, true); -} - -void NetworkUtils::disableIpv6(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - setIpv6Enabled(aChain, aCallback, aResult, false); -} - -void NetworkUtils::setMtu(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "interface setmtu %s %ld", - GET_CHAR(mIfname), GET_FIELD(mMtu)); - - doCommand(command, aChain, aCallback); -} - -#undef GET_CHAR -#undef GET_FIELD - -/* - * Netd command success/fail function - */ -#define ASSIGN_FIELD(prop) aResult.prop = aChain->getParams().prop; -#define ASSIGN_FIELD_VALUE(prop, value) aResult.prop = value; - -template<size_t N> -void NetworkUtils::runChain(const NetworkParams& aParams, - const CommandFunc (&aCmds)[N], - ErrorCallback aError) -{ - CommandChain* chain = new CommandChain(aParams, aCmds, N, aError); - gCommandChainQueue.AppendElement(chain); - - if (gCommandChainQueue.Length() > 1) { - NU_DBG("%d command chains are queued. Wait!", gCommandChainQueue.Length()); - return; - } - - NetworkResultOptions result; - NetworkUtils::next(gCommandChainQueue[0], false, result); -} - -// Called to clean up the command chain and process the queued command chain if any. -void NetworkUtils::finalizeSuccess(CommandChain* aChain, - NetworkResultOptions& aResult) -{ - next(aChain, false, aResult); -} - -void NetworkUtils::wifiTetheringFail(NetworkParams& aOptions, NetworkResultOptions& aResult) -{ - // Notify the main thread. - postMessage(aOptions, aResult); - - // If one of the stages fails, we try roll back to ensure - // we don't leave the network systems in limbo. - ASSIGN_FIELD_VALUE(mEnable, false) - runChain(aOptions, sWifiFailChain, nullptr); -} - -void NetworkUtils::wifiTetheringSuccess(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - ASSIGN_FIELD(mEnable) - - if (aChain->getParams().mEnable) { - MOZ_ASSERT(!gWifiTetheringParms); - gWifiTetheringParms = new NetworkParams(aChain->getParams()); - } - postMessage(aChain->getParams(), aResult); - finalizeSuccess(aChain, aResult); -} - -void NetworkUtils::usbTetheringFail(NetworkParams& aOptions, - NetworkResultOptions& aResult) -{ - // Notify the main thread. - postMessage(aOptions, aResult); - // Try to roll back to ensure - // we don't leave the network systems in limbo. - // This parameter is used to disable ipforwarding. - { - aOptions.mEnable = false; - runChain(aOptions, sUSBFailChain, nullptr); - } - - // Disable usb rndis function. - { - NetworkParams options; - options.mEnable = false; - options.mReport = false; - gNetworkUtils->enableUsbRndis(options); - } -} - -void NetworkUtils::usbTetheringSuccess(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - ASSIGN_FIELD(mEnable) - postMessage(aChain->getParams(), aResult); - finalizeSuccess(aChain, aResult); -} - -void NetworkUtils::networkInterfaceAlarmFail(NetworkParams& aOptions, NetworkResultOptions& aResult) -{ - postMessage(aOptions, aResult); -} - -void NetworkUtils::networkInterfaceAlarmSuccess(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - // TODO : error is not used , and it is conflict with boolean type error. - // params.error = parseFloat(params.resultReason); - postMessage(aChain->getParams(), aResult); - finalizeSuccess(aChain, aResult); -} - -void NetworkUtils::updateUpStreamFail(NetworkParams& aOptions, NetworkResultOptions& aResult) -{ - postMessage(aOptions, aResult); -} - -void NetworkUtils::updateUpStreamSuccess(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - ASSIGN_FIELD(mCurExternalIfname) - ASSIGN_FIELD(mCurInternalIfname) - postMessage(aChain->getParams(), aResult); - finalizeSuccess(aChain, aResult); -} - -void NetworkUtils::setDhcpServerFail(NetworkParams& aOptions, NetworkResultOptions& aResult) -{ - aResult.mSuccess = false; - postMessage(aOptions, aResult); -} - -void NetworkUtils::setDhcpServerSuccess(CommandChain* aChain, CommandCallback aCallback, NetworkResultOptions& aResult) -{ - aResult.mSuccess = true; - postMessage(aChain->getParams(), aResult); - finalizeSuccess(aChain, aResult); -} - -void NetworkUtils::wifiOperationModeFail(NetworkParams& aOptions, NetworkResultOptions& aResult) -{ - postMessage(aOptions, aResult); -} - -void NetworkUtils::wifiOperationModeSuccess(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - postMessage(aChain->getParams(), aResult); - finalizeSuccess(aChain, aResult); -} - -void NetworkUtils::setDnsFail(NetworkParams& aOptions, NetworkResultOptions& aResult) -{ - postMessage(aOptions, aResult); -} - -void NetworkUtils::defaultAsyncSuccessHandler(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - NU_DBG("defaultAsyncSuccessHandler"); - aResult.mRet = true; - postMessage(aChain->getParams(), aResult); - finalizeSuccess(aChain, aResult); -} - -void NetworkUtils::defaultAsyncFailureHandler(NetworkParams& aOptions, NetworkResultOptions& aResult) -{ - aResult.mRet = false; - postMessage(aOptions, aResult); -} - -void NetworkUtils::getInterfacesFail(NetworkParams& aOptions, NetworkResultOptions& aResult) -{ - postMessage(aOptions, aResult); -} - -void NetworkUtils::getInterfacesSuccess(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char buf[BUF_SIZE]; - NS_ConvertUTF16toUTF8 reason(aResult.mResultReason); - memcpy(buf, reason.get(), strlen(reason.get())); - - nsTArray<nsCString> result; - split(buf, INTERFACE_DELIMIT, result); - - nsTArray<nsString> interfaceList; - uint32_t length = result.Length(); - convertUTF8toUTF16(result, interfaceList, length); - - aResult.mInterfaceList.Construct(); - for (uint32_t i = 0; i < length; i++) { - aResult.mInterfaceList.Value().AppendElement(interfaceList[i], fallible_t()); - } - - postMessage(aChain->getParams(), aResult); - finalizeSuccess(aChain, aResult); -} - -void NetworkUtils::getInterfaceConfigFail(NetworkParams& aOptions, - NetworkResultOptions& aResult) -{ - postMessage(aOptions, aResult); -} - -void NetworkUtils::getInterfaceConfigSuccess(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char buf[BUF_SIZE]; - NS_ConvertUTF16toUTF8 reason(aResult.mResultReason); - memcpy(buf, reason.get(), strlen(reason.get())); - - nsTArray<nsCString> result; - split(buf, NETD_MESSAGE_DELIMIT, result); - - ASSIGN_FIELD_VALUE(mMacAddr, NS_ConvertUTF8toUTF16(result[0])) - ASSIGN_FIELD_VALUE(mIpAddr, NS_ConvertUTF8toUTF16(result[1])) - ASSIGN_FIELD_VALUE(mPrefixLength, atol(result[2].get())) - - if (result[3].Find("up")) { - ASSIGN_FIELD_VALUE(mFlag, NS_ConvertUTF8toUTF16("up")) - } else { - ASSIGN_FIELD_VALUE(mFlag, NS_ConvertUTF8toUTF16("down")) - } - - postMessage(aChain->getParams(), aResult); - finalizeSuccess(aChain, aResult); -} - -void NetworkUtils::setInterfaceConfigFail(NetworkParams& aOptions, - NetworkResultOptions& aResult) -{ - postMessage(aOptions, aResult); -} - -void NetworkUtils::setInterfaceConfigSuccess(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - postMessage(aChain->getParams(), aResult); - finalizeSuccess(aChain, aResult); -} - -#undef ASSIGN_FIELD -#undef ASSIGN_FIELD_VALUE - -NetworkUtils::NetworkUtils(MessageCallback aCallback) - : mMessageCallback(aCallback) -{ - mNetUtils = new NetUtils(); - - char value[Property::VALUE_MAX_LENGTH]; - Property::Get("ro.build.version.sdk", value, nullptr); - SDK_VERSION = atoi(value); - - Property::Get(IPV6_TETHERING, value, "0"); - SUPPORT_IPV6_TETHERING = atoi(value); - - gNetworkUtils = this; -} - -NetworkUtils::~NetworkUtils() -{ -} - -#define GET_CHAR(prop) NS_ConvertUTF16toUTF8(aOptions.prop).get() -#define GET_FIELD(prop) aOptions.prop - -// Hoist this type definition to global to avoid template -// instantiation error on gcc 4.4 used by ICS emulator. -typedef CommandResult (NetworkUtils::*CommandHandler)(NetworkParams&); -struct CommandHandlerEntry -{ - const char* mCommandName; - CommandHandler mCommandHandler; -}; - -void NetworkUtils::ExecuteCommand(NetworkParams aOptions) -{ - const static CommandHandlerEntry - COMMAND_HANDLER_TABLE[] = { - - // For command 'testCommand', BUILD_ENTRY(testCommand) will generate - // {"testCommand", NetworkUtils::testCommand} - #define BUILD_ENTRY(c) {#c, &NetworkUtils::c} - - BUILD_ENTRY(removeNetworkRoute), - BUILD_ENTRY(setDNS), - BUILD_ENTRY(setDefaultRoute), - BUILD_ENTRY(removeDefaultRoute), - BUILD_ENTRY(addHostRoute), - BUILD_ENTRY(removeHostRoute), - BUILD_ENTRY(addSecondaryRoute), - BUILD_ENTRY(removeSecondaryRoute), - BUILD_ENTRY(setNetworkInterfaceAlarm), - BUILD_ENTRY(enableNetworkInterfaceAlarm), - BUILD_ENTRY(disableNetworkInterfaceAlarm), - BUILD_ENTRY(setTetheringAlarm), - BUILD_ENTRY(removeTetheringAlarm), - BUILD_ENTRY(getTetheringStatus), - BUILD_ENTRY(setWifiOperationMode), - BUILD_ENTRY(setDhcpServer), - BUILD_ENTRY(setWifiTethering), - BUILD_ENTRY(setUSBTethering), - BUILD_ENTRY(enableUsbRndis), - BUILD_ENTRY(updateUpStream), - BUILD_ENTRY(configureInterface), - BUILD_ENTRY(dhcpRequest), - BUILD_ENTRY(stopDhcp), - BUILD_ENTRY(enableInterface), - BUILD_ENTRY(disableInterface), - BUILD_ENTRY(resetConnections), - BUILD_ENTRY(createNetwork), - BUILD_ENTRY(destroyNetwork), - BUILD_ENTRY(getNetId), - BUILD_ENTRY(getInterfaces), - BUILD_ENTRY(getInterfaceConfig), - BUILD_ENTRY(setInterfaceConfig), - BUILD_ENTRY(setMtu), - - #undef BUILD_ENTRY - }; - - // Loop until we find the command name which matches aOptions.mCmd. - CommandHandler handler = nullptr; - for (size_t i = 0; i < mozilla::ArrayLength(COMMAND_HANDLER_TABLE); i++) { - if (aOptions.mCmd.EqualsASCII(COMMAND_HANDLER_TABLE[i].mCommandName)) { - handler = COMMAND_HANDLER_TABLE[i].mCommandHandler; - break; - } - } - - if (!handler) { - // Command not found in COMMAND_HANDLER_TABLE. - WARN("unknown message: %s", NS_ConvertUTF16toUTF8(aOptions.mCmd).get()); - return; - } - - // The handler would return one of the following 3 values - // to be wrapped to CommandResult: - // - // 1) |int32_t| for mostly synchronous native function calls. - // 2) |NetworkResultOptions| to populate additional results. (e.g. dhcpRequest) - // 3) |CommandResult::Pending| to indicate the result is not - // obtained yet. - // - // If the handler returns "Pending", the handler should take the - // responsibility for posting result to main thread. - CommandResult commandResult = (this->*handler)(aOptions); - if (!commandResult.isPending()) { - postMessage(aOptions, commandResult.mResult); - } -} - -/** - * Handle received data from netd. - */ -void NetworkUtils::onNetdMessage(NetdCommand* aCommand) -{ - char* data = (char*)aCommand->mData; - - // get code & reason. - char* result = strtok(data, NETD_MESSAGE_DELIMIT); - - if (!result) { - nextNetdCommand(); - return; - } - uint32_t code = atoi(result); - - if (!isBroadcastMessage(code) && SDK_VERSION >= 16) { - strtok(nullptr, NETD_MESSAGE_DELIMIT); - } - - char* reason = strtok(nullptr, "\0"); - - if (isBroadcastMessage(code)) { - NU_DBG("Receiving broadcast message from netd."); - NU_DBG(" ==> Code: %d Reason: %s", code, reason); - sendBroadcastMessage(code, reason); - - if (code == NETD_COMMAND_INTERFACE_CHANGE) { - if (gWifiTetheringParms) { - char linkdownReason[MAX_COMMAND_SIZE]; - snprintf(linkdownReason, MAX_COMMAND_SIZE - 1, - "Iface linkstate %s down", - NS_ConvertUTF16toUTF8(gWifiTetheringParms->mIfname).get()); - - if (!strcmp(reason, linkdownReason)) { - NU_DBG("Wifi link down, restarting tethering."); - runChain(*gWifiTetheringParms, sWifiRetryChain, wifiTetheringFail); - } - } - } - - nextNetdCommand(); - return; - } - - // Set pending to false before we handle next command. - NU_DBG("Receiving \"%s\" command response from netd.", gCurrentCommand.command); - NU_DBG(" ==> Code: %d Reason: %s", code, reason); - - gReason.AppendElement(nsCString(reason)); - - // 1xx response code regards as command is proceeding, we need to wait for - // final response code such as 2xx, 4xx and 5xx before sending next command. - if (isProceeding(code)) { - return; - } - - if (isComplete(code)) { - gPending = false; - } - - { - char buf[BUF_SIZE]; - join(gReason, INTERFACE_DELIMIT, BUF_SIZE, buf); - - NetworkResultOptions result; - result.mResultCode = code; - result.mResultReason = NS_ConvertUTF8toUTF16(buf); - (gCurrentCommand.callback)(gCurrentCommand.chain, isError(code), result); - gReason.Clear(); - } - - // Handling pending commands if any. - if (isComplete(code)) { - nextNetdCommand(); - } -} - -/** - * Start/Stop DHCP server. - */ -CommandResult NetworkUtils::setDhcpServer(NetworkParams& aOptions) -{ - if (aOptions.mEnabled) { - aOptions.mWifiStartIp = aOptions.mStartIp; - aOptions.mWifiEndIp = aOptions.mEndIp; - aOptions.mIp = aOptions.mServerIp; - aOptions.mPrefix = aOptions.mMaskLength; - aOptions.mLink = NS_ConvertUTF8toUTF16("up"); - - runChain(aOptions, sStartDhcpServerChain, setDhcpServerFail); - } else { - runChain(aOptions, sStopDhcpServerChain, setDhcpServerFail); - } - return CommandResult::Pending(); -} - -/** - * Set DNS servers for given network interface. - */ -CommandResult NetworkUtils::setDNS(NetworkParams& aOptions) -{ - uint32_t length = aOptions.mDnses.Length(); - - if (length > 0) { - for (uint32_t i = 0; i < length; i++) { - NS_ConvertUTF16toUTF8 autoDns(aOptions.mDnses[i]); - - char dns_prop_key[Property::VALUE_MAX_LENGTH]; - SprintfLiteral(dns_prop_key, "net.dns%d", i+1); - Property::Set(dns_prop_key, autoDns.get()); - } - } else { - // Set dnses from system properties. - IFProperties interfaceProperties; - getIFProperties(GET_CHAR(mIfname), interfaceProperties); - - Property::Set("net.dns1", interfaceProperties.dns1); - Property::Set("net.dns2", interfaceProperties.dns2); - } - - // Bump the DNS change property. - char dnschange[Property::VALUE_MAX_LENGTH]; - Property::Get("net.dnschange", dnschange, "0"); - - char num[Property::VALUE_MAX_LENGTH]; - snprintf(num, Property::VALUE_MAX_LENGTH - 1, "%d", atoi(dnschange) + 1); - Property::Set("net.dnschange", num); - - // DNS needs to be set through netd since JellyBean (4.3). - if (SDK_VERSION >= 20) { - // Lollipop. - static CommandFunc COMMAND_CHAIN[] = { - setInterfaceDns, - addDefaultRouteToNetwork, - defaultAsyncSuccessHandler - }; - NetIdManager::NetIdInfo netIdInfo; - if (!mNetIdManager.lookup(aOptions.mIfname, &netIdInfo)) { - return -1; - } - aOptions.mNetId = netIdInfo.mNetId; - runChain(aOptions, COMMAND_CHAIN, setDnsFail); - return CommandResult::Pending(); - } - if (SDK_VERSION >= 18) { - // JB, KK. - static CommandFunc COMMAND_CHAIN[] = { - #if ANDROID_VERSION == 18 - // Since we don't use per-interface DNS lookup feature on JB, - // we need to set the default DNS interface whenever setting the - // DNS name server. - setDefaultInterface, - #endif - setInterfaceDns, - defaultAsyncSuccessHandler - }; - runChain(aOptions, COMMAND_CHAIN, setDnsFail); - return CommandResult::Pending(); - } - - return SUCCESS; -} - -CommandResult NetworkUtils::configureInterface(NetworkParams& aOptions) -{ - NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname); - return mNetUtils->do_ifc_configure( - autoIfname.get(), - aOptions.mIpaddr, - aOptions.mMask, - aOptions.mGateway_long, - aOptions.mDns1_long, - aOptions.mDns2_long - ); -} - -CommandResult NetworkUtils::stopDhcp(NetworkParams& aOptions) -{ - return mNetUtils->do_dhcp_stop(GET_CHAR(mIfname)); -} - -CommandResult NetworkUtils::dhcpRequest(NetworkParams& aOptions) { - mozilla::dom::NetworkResultOptions result; - - NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname); - char ipaddr[Property::VALUE_MAX_LENGTH]; - char gateway[Property::VALUE_MAX_LENGTH]; - uint32_t prefixLength; - char dns1[Property::VALUE_MAX_LENGTH]; - char dns2[Property::VALUE_MAX_LENGTH]; - char server[Property::VALUE_MAX_LENGTH]; - uint32_t lease; - char vendorinfo[Property::VALUE_MAX_LENGTH]; - int32_t ret = mNetUtils->do_dhcp_do_request(autoIfname.get(), - ipaddr, - gateway, - &prefixLength, - dns1, - dns2, - server, - &lease, - vendorinfo); - - RETURN_IF_FAILED(ret); - - result.mIpaddr_str = NS_ConvertUTF8toUTF16(ipaddr); - result.mGateway_str = NS_ConvertUTF8toUTF16(gateway); - result.mDns1_str = NS_ConvertUTF8toUTF16(dns1); - result.mDns2_str = NS_ConvertUTF8toUTF16(dns2); - result.mServer_str = NS_ConvertUTF8toUTF16(server); - result.mVendor_str = NS_ConvertUTF8toUTF16(vendorinfo); - result.mLease = lease; - result.mPrefixLength = prefixLength; - result.mMask = makeMask(prefixLength); - - uint32_t inet4; // only support IPv4 for now. - -#define INET_PTON(var, field) \ - PR_BEGIN_MACRO \ - inet_pton(AF_INET, var, &inet4); \ - result.field = inet4; \ - PR_END_MACRO - - INET_PTON(ipaddr, mIpaddr); - INET_PTON(gateway, mGateway); - - if (dns1[0] != '\0') { - INET_PTON(dns1, mDns1); - } - - if (dns2[0] != '\0') { - INET_PTON(dns2, mDns2); - } - - INET_PTON(server, mServer); - - char inet_str[64]; - if (inet_ntop(AF_INET, &result.mMask, inet_str, sizeof(inet_str))) { - result.mMask_str = NS_ConvertUTF8toUTF16(inet_str); - } - - return result; -} - -CommandResult NetworkUtils::enableInterface(NetworkParams& aOptions) { - return mNetUtils->do_ifc_enable( - NS_ConvertUTF16toUTF8(aOptions.mIfname).get()); -} - -CommandResult NetworkUtils::disableInterface(NetworkParams& aOptions) { - return mNetUtils->do_ifc_disable( - NS_ConvertUTF16toUTF8(aOptions.mIfname).get()); -} - -CommandResult NetworkUtils::resetConnections(NetworkParams& aOptions) { - NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname); - return mNetUtils->do_ifc_reset_connections( - NS_ConvertUTF16toUTF8(aOptions.mIfname).get(), - RESET_ALL_ADDRESSES); -} - -/** - * Set default route and DNS servers for given network interface. - */ -CommandResult NetworkUtils::setDefaultRoute(NetworkParams& aOptions) -{ - if (SDK_VERSION < 20) { - return setDefaultRouteLegacy(aOptions); - } - - static CommandFunc COMMAND_CHAIN[] = { - addDefaultRouteToNetwork, - setDefaultNetwork, - defaultAsyncSuccessHandler, - }; - - NetIdManager::NetIdInfo netIdInfo; - if (!mNetIdManager.lookup(GET_FIELD(mIfname), &netIdInfo)) { - ERROR("No such interface"); - return -1; - } - - aOptions.mNetId = netIdInfo.mNetId; - aOptions.mLoopIndex = 0; - runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler); - - return CommandResult::Pending(); -} - -/** - * Set default route and DNS servers for given network interface by obsoleted libnetutils. - */ -CommandResult NetworkUtils::setDefaultRouteLegacy(NetworkParams& aOptions) -{ - NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname); - - uint32_t length = aOptions.mGateways.Length(); - if (length > 0) { - for (uint32_t i = 0; i < length; i++) { - NS_ConvertUTF16toUTF8 autoGateway(aOptions.mGateways[i]); - - int type = getIpType(autoGateway.get()); - if (type != AF_INET && type != AF_INET6) { - continue; - } - - if (type == AF_INET6) { - RETURN_IF_FAILED(mNetUtils->do_ifc_add_route(autoIfname.get(), "::", 0, autoGateway.get())); - } else { /* type == AF_INET */ - RETURN_IF_FAILED(mNetUtils->do_ifc_set_default_route(autoIfname.get(), inet_addr(autoGateway.get()))); - } - } - } else { - // Set default froute from system properties. - char key[Property::KEY_MAX_LENGTH]; - char gateway[Property::KEY_MAX_LENGTH]; - - snprintf(key, sizeof key - 1, "net.%s.gw", autoIfname.get()); - Property::Get(key, gateway, ""); - - int type = getIpType(gateway); - if (type != AF_INET && type != AF_INET6) { - return EAFNOSUPPORT; - } - - if (type == AF_INET6) { - RETURN_IF_FAILED(mNetUtils->do_ifc_add_route(autoIfname.get(), "::", 0, gateway)); - } else { /* type == AF_INET */ - RETURN_IF_FAILED(mNetUtils->do_ifc_set_default_route(autoIfname.get(), inet_addr(gateway))); - } - } - - // Set the default DNS interface. - if (SDK_VERSION >= 18) { - // For JB, KK only. - static CommandFunc COMMAND_CHAIN[] = { - setDefaultInterface, - defaultAsyncSuccessHandler - }; - runChain(aOptions, COMMAND_CHAIN, setDnsFail); - return CommandResult::Pending(); - } - - return SUCCESS; -} - -/** - * Remove default route for given network interface. - */ -CommandResult NetworkUtils::removeDefaultRoute(NetworkParams& aOptions) -{ - NU_DBG("Calling NetworkUtils::removeDefaultRoute"); - - if (SDK_VERSION < 20) { - return removeDefaultRouteLegacy(aOptions); - } - - static CommandFunc COMMAND_CHAIN[] = { - removeDefaultRoute, - defaultAsyncSuccessHandler, - }; - - NetIdManager::NetIdInfo netIdInfo; - if (!mNetIdManager.lookup(GET_FIELD(mIfname), &netIdInfo)) { - ERROR("No such interface: %s", GET_CHAR(mIfname)); - return -1; - } - - NU_DBG("Obtained netid %d for interface %s", netIdInfo.mNetId, GET_CHAR(mIfname)); - - aOptions.mNetId = netIdInfo.mNetId; - aOptions.mLoopIndex = 0; - runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler); - - return CommandResult::Pending(); -} - -/** - * Remove default route for given network interface by obsoleted libnetutils. - */ -CommandResult NetworkUtils::removeDefaultRouteLegacy(NetworkParams& aOptions) -{ - // Legacy libnetutils calls before Lollipop. - uint32_t length = aOptions.mGateways.Length(); - for (uint32_t i = 0; i < length; i++) { - NS_ConvertUTF16toUTF8 autoGateway(aOptions.mGateways[i]); - - int type = getIpType(autoGateway.get()); - if (type != AF_INET && type != AF_INET6) { - return EAFNOSUPPORT; - } - - WARN_IF_FAILED(mNetUtils->do_ifc_remove_route(GET_CHAR(mIfname), - type == AF_INET ? "0.0.0.0" : "::", - 0, autoGateway.get())); - } - - return SUCCESS; -} - -/** - * Add host route for given network interface. - */ -CommandResult NetworkUtils::addHostRoute(NetworkParams& aOptions) -{ - if (SDK_VERSION < 20) { - return addHostRouteLegacy(aOptions); - } - - static CommandFunc COMMAND_CHAIN[] = { - addRouteToInterface, - defaultAsyncSuccessHandler, - }; - - NetIdManager::NetIdInfo netIdInfo; - if (!mNetIdManager.lookup(GET_FIELD(mIfname), &netIdInfo)) { - ERROR("No such interface: %s", GET_CHAR(mIfname)); - return -1; - } - - NU_DBG("Obtained netid %d for interface %s", netIdInfo.mNetId, GET_CHAR(mIfname)); - - aOptions.mNetId = netIdInfo.mNetId; - runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler); - - return CommandResult::Pending(); -} - -/** - * Add host route for given network interface. - */ -CommandResult NetworkUtils::addHostRouteLegacy(NetworkParams& aOptions) -{ - if (aOptions.mGateway.IsEmpty()) { - ERROR("addHostRouteLegacy does not support empty gateway."); - return EINVAL; - } - - NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname); - NS_ConvertUTF16toUTF8 autoHostname(aOptions.mIp); - NS_ConvertUTF16toUTF8 autoGateway(aOptions.mGateway); - int type, prefix; - - type = getIpType(autoHostname.get()); - if (type != AF_INET && type != AF_INET6) { - return EAFNOSUPPORT; - } - - if (type != getIpType(autoGateway.get())) { - return EINVAL; - } - - prefix = type == AF_INET ? 32 : 128; - return mNetUtils->do_ifc_add_route(autoIfname.get(), autoHostname.get(), - prefix, autoGateway.get()); -} - -/** - * Remove host route for given network interface. - */ -CommandResult NetworkUtils::removeHostRoute(NetworkParams& aOptions) -{ - if (SDK_VERSION < 20) { - return removeHostRouteLegacy(aOptions); - } - - static CommandFunc COMMAND_CHAIN[] = { - removeRouteFromInterface, - defaultAsyncSuccessHandler, - }; - - NetIdManager::NetIdInfo netIdInfo; - if (!mNetIdManager.lookup(GET_FIELD(mIfname), &netIdInfo)) { - ERROR("No such interface: %s", GET_CHAR(mIfname)); - return -1; - } - - NU_DBG("Obtained netid %d for interface %s", netIdInfo.mNetId, GET_CHAR(mIfname)); - - aOptions.mNetId = netIdInfo.mNetId; - runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler); - - return CommandResult::Pending(); -} - -/** - * Remove host route for given network interface. - */ -CommandResult NetworkUtils::removeHostRouteLegacy(NetworkParams& aOptions) -{ - NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname); - NS_ConvertUTF16toUTF8 autoHostname(aOptions.mIp); - NS_ConvertUTF16toUTF8 autoGateway(aOptions.mGateway); - int type, prefix; - - type = getIpType(autoHostname.get()); - if (type != AF_INET && type != AF_INET6) { - return EAFNOSUPPORT; - } - - if (type != getIpType(autoGateway.get())) { - return EINVAL; - } - - prefix = type == AF_INET ? 32 : 128; - return mNetUtils->do_ifc_remove_route(autoIfname.get(), autoHostname.get(), - prefix, autoGateway.get()); -} - -CommandResult NetworkUtils::removeNetworkRoute(NetworkParams& aOptions) -{ - if (SDK_VERSION < 20) { - return removeNetworkRouteLegacy(aOptions); - } - - static CommandFunc COMMAND_CHAIN[] = { - clearAddrForInterface, - defaultAsyncSuccessHandler, - }; - - NetIdManager::NetIdInfo netIdInfo; - if (!mNetIdManager.lookup(GET_FIELD(mIfname), &netIdInfo)) { - ERROR("interface %s is not present in any network", GET_CHAR(mIfname)); - return -1; - } - - NU_DBG("Obtained netid %d for interface %s", netIdInfo.mNetId, GET_CHAR(mIfname)); - - aOptions.mNetId = netIdInfo.mNetId; - runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler); - - return CommandResult::Pending(); -} - -nsCString NetworkUtils::getSubnetIp(const nsCString& aIp, int aPrefixLength) -{ - int type = getIpType(aIp.get()); - - if (AF_INET6 == type) { - struct in6_addr in6; - if (inet_pton(AF_INET6, aIp.get(), &in6) != 1) { - return nsCString(); - } - - uint32_t p, i, p1, mask; - p = aPrefixLength; - i = 0; - while (i < 4) { - p1 = p > 32 ? 32 : p; - p -= p1; - mask = p1 ? ~0x0 << (32 - p1) : 0; - in6.s6_addr32[i++] &= htonl(mask); - } - - char subnetStr[INET6_ADDRSTRLEN]; - if (!inet_ntop(AF_INET6, &in6, subnetStr, sizeof subnetStr)) { - return nsCString(); - } - - return nsCString(subnetStr); - } - - if (AF_INET == type) { - uint32_t ip = inet_addr(aIp.get()); - uint32_t netmask = makeMask(aPrefixLength); - uint32_t subnet = ip & netmask; - struct in_addr addr; - addr.s_addr = subnet; - return nsCString(inet_ntoa(addr)); - } - - return nsCString(); -} - -CommandResult NetworkUtils::removeNetworkRouteLegacy(NetworkParams& aOptions) -{ - NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname); - NS_ConvertUTF16toUTF8 autoIp(aOptions.mIp); - - int type = getIpType(autoIp.get()); - if (type != AF_INET && type != AF_INET6) { - return EAFNOSUPPORT; - } - - uint32_t prefixLength = GET_FIELD(mPrefixLength); - - if (type == AF_INET6) { - // Calculate subnet. - struct in6_addr in6; - if (inet_pton(AF_INET6, autoIp.get(), &in6) != 1) { - return EINVAL; - } - - uint32_t p, i, p1, mask; - p = prefixLength; - i = 0; - while (i < 4) { - p1 = p > 32 ? 32 : p; - p -= p1; - mask = p1 ? ~0x0 << (32 - p1) : 0; - in6.s6_addr32[i++] &= htonl(mask); - } - - char subnetStr[INET6_ADDRSTRLEN]; - if (!inet_ntop(AF_INET6, &in6, subnetStr, sizeof subnetStr)) { - return EINVAL; - } - - // Remove default route. - WARN_IF_FAILED(mNetUtils->do_ifc_remove_route(autoIfname.get(), "::", 0, NULL)); - - // Remove subnet route. - RETURN_IF_FAILED(mNetUtils->do_ifc_remove_route(autoIfname.get(), subnetStr, prefixLength, NULL)); - return SUCCESS; - } - - /* type == AF_INET */ - uint32_t ip = inet_addr(autoIp.get()); - uint32_t netmask = makeMask(prefixLength); - uint32_t subnet = ip & netmask; - const char* gateway = "0.0.0.0"; - struct in_addr addr; - addr.s_addr = subnet; - const char* dst = inet_ntoa(addr); - - RETURN_IF_FAILED(mNetUtils->do_ifc_remove_default_route(autoIfname.get())); - RETURN_IF_FAILED(mNetUtils->do_ifc_remove_route(autoIfname.get(), dst, prefixLength, gateway)); - return SUCCESS; -} - -CommandResult NetworkUtils::addSecondaryRoute(NetworkParams& aOptions) -{ - static CommandFunc COMMAND_CHAIN[] = { - addRouteToSecondaryTable, - defaultAsyncSuccessHandler - }; - - if (SDK_VERSION >= 20) { - NetIdManager::NetIdInfo netIdInfo; - if (!mNetIdManager.lookup(aOptions.mIfname, &netIdInfo)) { - return -1; - } - aOptions.mNetId = netIdInfo.mNetId; - } - - runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler); - return CommandResult::Pending(); -} - -CommandResult NetworkUtils::removeSecondaryRoute(NetworkParams& aOptions) -{ - static CommandFunc COMMAND_CHAIN[] = { - removeRouteFromSecondaryTable, - defaultAsyncSuccessHandler - }; - - if (SDK_VERSION >= 20) { - NetIdManager::NetIdInfo netIdInfo; - if (!mNetIdManager.lookup(aOptions.mIfname, &netIdInfo)) { - return -1; - } - aOptions.mNetId = netIdInfo.mNetId; - } - - runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler); - return CommandResult::Pending(); -} - -CommandResult NetworkUtils::setNetworkInterfaceAlarm(NetworkParams& aOptions) -{ - NU_DBG("setNetworkInterfaceAlarms: %s", GET_CHAR(mIfname)); - runChain(aOptions, sNetworkInterfaceSetAlarmChain, networkInterfaceAlarmFail); - return CommandResult::Pending(); -} - -CommandResult NetworkUtils::enableNetworkInterfaceAlarm(NetworkParams& aOptions) -{ - NU_DBG("enableNetworkInterfaceAlarm: %s", GET_CHAR(mIfname)); - runChain(aOptions, sNetworkInterfaceEnableAlarmChain, networkInterfaceAlarmFail); - return CommandResult::Pending(); -} - -CommandResult NetworkUtils::disableNetworkInterfaceAlarm(NetworkParams& aOptions) -{ - NU_DBG("disableNetworkInterfaceAlarms: %s", GET_CHAR(mIfname)); - runChain(aOptions, sNetworkInterfaceDisableAlarmChain, networkInterfaceAlarmFail); - return CommandResult::Pending(); -} - -CommandResult NetworkUtils::setTetheringAlarm(NetworkParams& aOptions) -{ - NU_DBG("setTetheringAlarm"); - runChain(aOptions, sTetheringInterfaceSetAlarmChain, networkInterfaceAlarmFail); - return CommandResult::Pending(); -} - -CommandResult NetworkUtils::removeTetheringAlarm(NetworkParams& aOptions) -{ - NU_DBG("removeTetheringAlarm"); - runChain(aOptions, sTetheringInterfaceRemoveAlarmChain, networkInterfaceAlarmFail); - return CommandResult::Pending(); -} - -CommandResult NetworkUtils::getTetheringStatus(NetworkParams& aOptions) -{ - NU_DBG("getTetheringStatus"); - runChain(aOptions, sTetheringGetStatusChain, networkInterfaceAlarmFail); - return CommandResult::Pending(); -} - -/** - * handling main thread's reload Wifi firmware request - */ -CommandResult NetworkUtils::setWifiOperationMode(NetworkParams& aOptions) -{ - NU_DBG("setWifiOperationMode: %s %s", GET_CHAR(mIfname), GET_CHAR(mMode)); - runChain(aOptions, sWifiOperationModeChain, wifiOperationModeFail); - return CommandResult::Pending(); -} - -/** - * handling main thread's enable/disable WiFi Tethering request - */ -CommandResult NetworkUtils::setWifiTethering(NetworkParams& aOptions) -{ - bool enable = aOptions.mEnable; - IFProperties interfaceProperties; - getIFProperties(GET_CHAR(mExternalIfname), interfaceProperties); - - if (strcmp(interfaceProperties.dns1, "")) { - int type = getIpType(interfaceProperties.dns1); - if (type != AF_INET6) { - aOptions.mDns1 = NS_ConvertUTF8toUTF16(interfaceProperties.dns1); - } - } - if (strcmp(interfaceProperties.dns2, "")) { - int type = getIpType(interfaceProperties.dns2); - if (type != AF_INET6) { - aOptions.mDns2 = NS_ConvertUTF8toUTF16(interfaceProperties.dns2); - } - } - dumpParams(aOptions, "WIFI"); - - if (SDK_VERSION >= 20) { - NetIdManager::NetIdInfo netIdInfo; - if (!mNetIdManager.lookup(aOptions.mExternalIfname, &netIdInfo)) { - ERROR("No such interface: %s", GET_CHAR(mExternalIfname)); - return -1; - } - aOptions.mNetId = netIdInfo.mNetId; - } - - if (enable) { - NU_DBG("Starting Wifi Tethering on %s <-> %s", - GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname)); - runChain(aOptions, sWifiEnableChain, wifiTetheringFail); - } else { - NU_DBG("Stopping Wifi Tethering on %s <-> %s", - GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname)); - runChain(aOptions, sWifiDisableChain, wifiTetheringFail); - } - return CommandResult::Pending(); -} - -CommandResult NetworkUtils::setUSBTethering(NetworkParams& aOptions) -{ - bool enable = aOptions.mEnable; - IFProperties interfaceProperties; - getIFProperties(GET_CHAR(mExternalIfname), interfaceProperties); - - if (strcmp(interfaceProperties.dns1, "")) { - int type = getIpType(interfaceProperties.dns1); - if (type != AF_INET6) { - aOptions.mDns1 = NS_ConvertUTF8toUTF16(interfaceProperties.dns1); - } - } - if (strcmp(interfaceProperties.dns2, "")) { - int type = getIpType(interfaceProperties.dns2); - if (type != AF_INET6) { - aOptions.mDns2 = NS_ConvertUTF8toUTF16(interfaceProperties.dns2); - } - } - dumpParams(aOptions, "USB"); - - if (SDK_VERSION >= 20) { - NetIdManager::NetIdInfo netIdInfo; - if (!mNetIdManager.lookup(aOptions.mExternalIfname, &netIdInfo)) { - ERROR("No such interface: %s", GET_CHAR(mExternalIfname)); - return -1; - } - aOptions.mNetId = netIdInfo.mNetId; - } - - if (enable) { - NU_DBG("Starting USB Tethering on %s <-> %s", - GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname)); - runChain(aOptions, sUSBEnableChain, usbTetheringFail); - } else { - NU_DBG("Stopping USB Tethering on %s <-> %s", - GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname)); - runChain(aOptions, sUSBDisableChain, usbTetheringFail); - } - return CommandResult::Pending(); -} - -void NetworkUtils::escapeQuote(nsCString& aString) -{ - aString.ReplaceSubstring("\\", "\\\\"); - aString.ReplaceSubstring("\"", "\\\""); -} - -CommandResult NetworkUtils::checkUsbRndisState(NetworkParams& aOptions) -{ - static uint32_t retry = 0; - - char currentState[Property::VALUE_MAX_LENGTH]; - Property::Get(SYS_USB_STATE_PROPERTY, currentState, nullptr); - - nsTArray<nsCString> stateFuncs; - split(currentState, USB_CONFIG_DELIMIT, stateFuncs); - bool rndisPresent = stateFuncs.Contains(nsCString(USB_FUNCTION_RNDIS)); - - if (aOptions.mEnable == rndisPresent) { - NetworkResultOptions result; - result.mEnable = aOptions.mEnable; - result.mResult = true; - retry = 0; - return result; - } - if (retry < USB_FUNCTION_RETRY_TIMES) { - retry++; - usleep(USB_FUNCTION_RETRY_INTERVAL * 1000); - return checkUsbRndisState(aOptions); - } - - NetworkResultOptions result; - result.mResult = false; - retry = 0; - return result; -} - -/** - * Modify usb function's property to turn on USB RNDIS function - */ -CommandResult NetworkUtils::enableUsbRndis(NetworkParams& aOptions) -{ - bool report = aOptions.mReport; - - // For some reason, rndis doesn't play well with diag,modem,nmea. - // So when turning rndis on, we set sys.usb.config to either "rndis" - // or "rndis,adb". When turning rndis off, we go back to - // persist.sys.usb.config. - // - // On the otoro/unagi, persist.sys.usb.config should be one of: - // - // diag,modem,nmea,mass_storage - // diag,modem,nmea,mass_storage,adb - // - // When rndis is enabled, sys.usb.config should be one of: - // - // rdnis - // rndis,adb - // - // and when rndis is disabled, it should revert to persist.sys.usb.config - - char currentConfig[Property::VALUE_MAX_LENGTH]; - Property::Get(SYS_USB_CONFIG_PROPERTY, currentConfig, nullptr); - - nsTArray<nsCString> configFuncs; - split(currentConfig, USB_CONFIG_DELIMIT, configFuncs); - - char persistConfig[Property::VALUE_MAX_LENGTH]; - Property::Get(PERSIST_SYS_USB_CONFIG_PROPERTY, persistConfig, nullptr); - - nsTArray<nsCString> persistFuncs; - split(persistConfig, USB_CONFIG_DELIMIT, persistFuncs); - - if (aOptions.mEnable) { - configFuncs.Clear(); - configFuncs.AppendElement(nsCString(USB_FUNCTION_RNDIS)); - if (persistFuncs.Contains(nsCString(USB_FUNCTION_ADB))) { - configFuncs.AppendElement(nsCString(USB_FUNCTION_ADB)); - } - } else { - // We're turning rndis off, revert back to the persist setting. - // adb will already be correct there, so we don't need to do any - // further adjustments. - configFuncs = persistFuncs; - } - - char newConfig[Property::VALUE_MAX_LENGTH] = ""; - Property::Get(SYS_USB_CONFIG_PROPERTY, currentConfig, nullptr); - join(configFuncs, USB_CONFIG_DELIMIT, Property::VALUE_MAX_LENGTH, newConfig); - if (strcmp(currentConfig, newConfig)) { - Property::Set(SYS_USB_CONFIG_PROPERTY, newConfig); - } - - // Trigger the timer to check usb state and report the result to NetworkManager. - if (report) { - usleep(USB_FUNCTION_RETRY_INTERVAL * 1000); - return checkUsbRndisState(aOptions); - } - return SUCCESS; -} - -/** - * handling upstream interface change event. - */ -CommandResult NetworkUtils::updateUpStream(NetworkParams& aOptions) -{ - runChain(aOptions, sUpdateUpStreamChain, updateUpStreamFail); - return CommandResult::Pending(); -} - -/** - * handling upstream interface change event. - */ -CommandResult NetworkUtils::createNetwork(NetworkParams& aOptions) -{ - if (SDK_VERSION < 20) { - return SUCCESS; - } - - static CommandFunc COMMAND_CHAIN[] = { - createNetwork, - enableIpv6, - addInterfaceToNetwork, - defaultAsyncSuccessHandler, - }; - - NetIdManager::NetIdInfo netIdInfo; - mNetIdManager.acquire(GET_FIELD(mIfname), &netIdInfo); - if (netIdInfo.mRefCnt > 1) { - // Already created. Just return. - NU_DBG("Interface %s (%d) has been created.", GET_CHAR(mIfname), - netIdInfo.mNetId); - return SUCCESS; - } - - NU_DBG("Request netd to create a network with netid %d", netIdInfo.mNetId); - // Newly created netid. Ask netd to create network. - aOptions.mNetId = netIdInfo.mNetId; - runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler); - - return CommandResult::Pending(); -} - -/** - * handling upstream interface change event. - */ -CommandResult NetworkUtils::destroyNetwork(NetworkParams& aOptions) -{ - if (SDK_VERSION < 20) { - return SUCCESS; - } - - static CommandFunc COMMAND_CHAIN[] = { - disableIpv6, - destroyNetwork, - defaultAsyncSuccessHandler, - }; - - NetIdManager::NetIdInfo netIdInfo; - if (!mNetIdManager.release(GET_FIELD(mIfname), &netIdInfo)) { - ERROR("No existing netid for %s", GET_CHAR(mIfname)); - return -1; - } - - if (netIdInfo.mRefCnt > 0) { - // Still be referenced. Just return. - NU_DBG("Someone is still using this interface."); - return SUCCESS; - } - - NU_DBG("Interface %s (%d) is no longer used. Tell netd to destroy.", - GET_CHAR(mIfname), netIdInfo.mNetId); - - aOptions.mNetId = netIdInfo.mNetId; - runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler); - return CommandResult::Pending(); -} - -/** - * Query the netId associated with the given network interface name. - */ -CommandResult NetworkUtils::getNetId(NetworkParams& aOptions) -{ - NetworkResultOptions result; - - if (SDK_VERSION < 20) { - // For pre-Lollipop, use the interface name as the fallback. - result.mNetId = GET_FIELD(mIfname); - return result; - } - - NetIdManager::NetIdInfo netIdInfo; - if (-1 == mNetIdManager.lookup(GET_FIELD(mIfname), &netIdInfo)) { - return ESRCH; - } - result.mNetId.AppendInt(netIdInfo.mNetId, 10); - return result; -} - -/** - * Get existing network interfaces. - */ -CommandResult NetworkUtils::getInterfaces(NetworkParams& aOptions) -{ - runChain(aOptions, sGetInterfacesChain, getInterfacesFail); - return CommandResult::Pending(); -} - -/** - * Get network config of a specified interface. - */ -CommandResult NetworkUtils::getInterfaceConfig(NetworkParams& aOptions) -{ - runChain(aOptions, sGetInterfaceConfigChain, getInterfaceConfigFail); - return CommandResult::Pending(); -} - -/** - * Set network config for a specified interface. - */ -CommandResult NetworkUtils::setInterfaceConfig(NetworkParams& aOptions) -{ - runChain(aOptions, sSetInterfaceConfigChain, setInterfaceConfigFail); - return CommandResult::Pending(); -} - -CommandResult NetworkUtils::setMtu(NetworkParams& aOptions) -{ - // Setting/getting mtu is supported since Kitkat. - if (SDK_VERSION < 19) { - ERROR("setMtu is not supported in current SDK_VERSION."); - return -1; - } - - static CommandFunc COMMAND_CHAIN[] = { - setMtu, - defaultAsyncSuccessHandler, - }; - - runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler); - return CommandResult::Pending(); -} - -void NetworkUtils::sendBroadcastMessage(uint32_t code, char* reason) -{ - NetworkResultOptions result; - switch(code) { - case NETD_COMMAND_INTERFACE_CHANGE: - result.mTopic = NS_ConvertUTF8toUTF16("netd-interface-change"); - break; - case NETD_COMMAND_BANDWIDTH_CONTROLLER: - result.mTopic = NS_ConvertUTF8toUTF16("netd-bandwidth-control"); - break; - default: - return; - } - - result.mBroadcast = true; - result.mReason = NS_ConvertUTF8toUTF16(reason); - postMessage(result); -} - -inline uint32_t NetworkUtils::netdResponseType(uint32_t code) -{ - return (code / 100) * 100; -} - -inline bool NetworkUtils::isBroadcastMessage(uint32_t code) -{ - uint32_t type = netdResponseType(code); - return type == NETD_COMMAND_UNSOLICITED; -} - -inline bool NetworkUtils::isError(uint32_t code) -{ - uint32_t type = netdResponseType(code); - return type != NETD_COMMAND_PROCEEDING && type != NETD_COMMAND_OKAY; -} - -inline bool NetworkUtils::isComplete(uint32_t code) -{ - uint32_t type = netdResponseType(code); - return type != NETD_COMMAND_PROCEEDING; -} - -inline bool NetworkUtils::isProceeding(uint32_t code) -{ - uint32_t type = netdResponseType(code); - return type == NETD_COMMAND_PROCEEDING; -} - -void NetworkUtils::dumpParams(NetworkParams& aOptions, const char* aType) -{ -#ifdef _DEBUG - NU_DBG("Dump params:"); - NU_DBG(" ifname: %s", GET_CHAR(mIfname)); - NU_DBG(" ip: %s", GET_CHAR(mIp)); - NU_DBG(" link: %s", GET_CHAR(mLink)); - NU_DBG(" prefix: %s", GET_CHAR(mPrefix)); - NU_DBG(" wifiStartIp: %s", GET_CHAR(mWifiStartIp)); - NU_DBG(" wifiEndIp: %s", GET_CHAR(mWifiEndIp)); - NU_DBG(" usbStartIp: %s", GET_CHAR(mUsbStartIp)); - NU_DBG(" usbEndIp: %s", GET_CHAR(mUsbEndIp)); - NU_DBG(" dnsserver1: %s", GET_CHAR(mDns1)); - NU_DBG(" dnsserver2: %s", GET_CHAR(mDns2)); - NU_DBG(" internalIfname: %s", GET_CHAR(mInternalIfname)); - NU_DBG(" externalIfname: %s", GET_CHAR(mExternalIfname)); - if (!strcmp(aType, "WIFI")) { - NU_DBG(" wifictrlinterfacename: %s", GET_CHAR(mWifictrlinterfacename)); - NU_DBG(" ssid: %s", GET_CHAR(mSsid)); - NU_DBG(" security: %s", GET_CHAR(mSecurity)); - NU_DBG(" key: %s", GET_CHAR(mKey)); - } -#endif -} - -#undef GET_CHAR -#undef GET_FIELD diff --git a/dom/system/gonk/NetworkUtils.h b/dom/system/gonk/NetworkUtils.h deleted file mode 100644 index d1af35f09..000000000 --- a/dom/system/gonk/NetworkUtils.h +++ /dev/null @@ -1,498 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef NetworkUtils_h -#define NetworkUtils_h - -#include "nsAutoPtr.h" -#include "nsString.h" -#include "mozilla/dom/NetworkOptionsBinding.h" -#include "mozilla/dom/network/NetUtils.h" -#include "mozilla/ipc/Netd.h" -#include "nsTArray.h" -#include "NetIdManager.h" - -class NetworkParams; -class CommandChain; - -class CommandCallback { -public: - typedef void (*CallbackType)(CommandChain*, bool, - mozilla::dom::NetworkResultOptions& aResult); - - typedef void (*CallbackWrapperType)(CallbackType aOriginalCallback, - CommandChain*, bool, - mozilla::dom::NetworkResultOptions& aResult); - - CommandCallback() - : mCallback(nullptr) - , mCallbackWrapper(nullptr) - { - } - - CommandCallback(CallbackType aCallback) - : mCallback(aCallback) - , mCallbackWrapper(nullptr) - { - } - - CommandCallback(CallbackWrapperType aCallbackWrapper, - CommandCallback aOriginalCallback) - : mCallback(aOriginalCallback.mCallback) - , mCallbackWrapper(aCallbackWrapper) - { - } - - void operator()(CommandChain* aChain, bool aError, - mozilla::dom::NetworkResultOptions& aResult) - { - if (mCallbackWrapper) { - return mCallbackWrapper(mCallback, aChain, aError, aResult); - } - if (mCallback) { - return mCallback(aChain, aError, aResult); - } - } - -private: - CallbackType mCallback; - CallbackWrapperType mCallbackWrapper; -}; - -typedef void (*CommandFunc)(CommandChain*, CommandCallback, - mozilla::dom::NetworkResultOptions& aResult); -typedef void (*MessageCallback)(mozilla::dom::NetworkResultOptions& aResult); -typedef void (*ErrorCallback)(NetworkParams& aOptions, - mozilla::dom::NetworkResultOptions& aResult); - -class NetworkParams -{ -public: - NetworkParams() { - } - - NetworkParams(const mozilla::dom::NetworkCommandOptions& aOther) { - -#define COPY_SEQUENCE_FIELD(prop, type) \ - if (aOther.prop.WasPassed()) { \ - mozilla::dom::Sequence<type > const & currentValue = aOther.prop.InternalValue(); \ - uint32_t length = currentValue.Length(); \ - for (uint32_t idx = 0; idx < length; idx++) { \ - prop.AppendElement(currentValue[idx]); \ - } \ - } - -#define COPY_OPT_STRING_FIELD(prop, defaultValue) \ - if (aOther.prop.WasPassed()) { \ - if (aOther.prop.Value().EqualsLiteral("null")) { \ - prop = defaultValue; \ - } else { \ - prop = aOther.prop.Value(); \ - } \ - } else { \ - prop = defaultValue; \ - } - -#define COPY_OPT_FIELD(prop, defaultValue) \ - if (aOther.prop.WasPassed()) { \ - prop = aOther.prop.Value(); \ - } else { \ - prop = defaultValue; \ - } - -#define COPY_FIELD(prop) prop = aOther.prop; - - COPY_FIELD(mId) - COPY_FIELD(mCmd) - COPY_OPT_STRING_FIELD(mDomain, EmptyString()) - COPY_OPT_STRING_FIELD(mGateway, EmptyString()) - COPY_SEQUENCE_FIELD(mGateways, nsString) - COPY_OPT_STRING_FIELD(mIfname, EmptyString()) - COPY_OPT_STRING_FIELD(mIp, EmptyString()) - COPY_OPT_FIELD(mPrefixLength, 0) - COPY_OPT_STRING_FIELD(mMode, EmptyString()) - COPY_OPT_FIELD(mReport, false) - COPY_OPT_FIELD(mEnabled, false) - COPY_OPT_STRING_FIELD(mWifictrlinterfacename, EmptyString()) - COPY_OPT_STRING_FIELD(mInternalIfname, EmptyString()) - COPY_OPT_STRING_FIELD(mExternalIfname, EmptyString()) - COPY_OPT_FIELD(mEnable, false) - COPY_OPT_STRING_FIELD(mSsid, EmptyString()) - COPY_OPT_STRING_FIELD(mSecurity, EmptyString()) - COPY_OPT_STRING_FIELD(mKey, EmptyString()) - COPY_OPT_STRING_FIELD(mPrefix, EmptyString()) - COPY_OPT_STRING_FIELD(mLink, EmptyString()) - COPY_SEQUENCE_FIELD(mInterfaceList, nsString) - COPY_OPT_STRING_FIELD(mWifiStartIp, EmptyString()) - COPY_OPT_STRING_FIELD(mWifiEndIp, EmptyString()) - COPY_OPT_STRING_FIELD(mUsbStartIp, EmptyString()) - COPY_OPT_STRING_FIELD(mUsbEndIp, EmptyString()) - COPY_OPT_STRING_FIELD(mDns1, EmptyString()) - COPY_OPT_STRING_FIELD(mDns2, EmptyString()) - COPY_SEQUENCE_FIELD(mDnses, nsString) - COPY_OPT_STRING_FIELD(mStartIp, EmptyString()) - COPY_OPT_STRING_FIELD(mEndIp, EmptyString()) - COPY_OPT_STRING_FIELD(mServerIp, EmptyString()) - COPY_OPT_STRING_FIELD(mMaskLength, EmptyString()) - COPY_OPT_STRING_FIELD(mPreInternalIfname, EmptyString()) - COPY_OPT_STRING_FIELD(mPreExternalIfname, EmptyString()) - COPY_OPT_STRING_FIELD(mCurInternalIfname, EmptyString()) - COPY_OPT_STRING_FIELD(mCurExternalIfname, EmptyString()) - COPY_OPT_FIELD(mThreshold, -1) - COPY_OPT_FIELD(mIpaddr, 0) - COPY_OPT_FIELD(mMask, 0) - COPY_OPT_FIELD(mGateway_long, 0) - COPY_OPT_FIELD(mDns1_long, 0) - COPY_OPT_FIELD(mDns2_long, 0) - COPY_OPT_FIELD(mMtu, 0) - - mLoopIndex = 0; - -#undef COPY_SEQUENCE_FIELD -#undef COPY_OPT_STRING_FIELD -#undef COPY_OPT_FIELD -#undef COPY_FIELD - } - - // Followings attributes are 1-to-1 mapping to NetworkCommandOptions. - int32_t mId; - nsString mCmd; - nsString mDomain; - nsString mGateway; - nsTArray<nsString> mGateways; - nsString mIfname; - nsString mIp; - uint32_t mPrefixLength; - nsString mMode; - bool mReport; - bool mEnabled; - nsString mWifictrlinterfacename; - nsString mInternalIfname; - nsString mExternalIfname; - bool mEnable; - nsString mSsid; - nsString mSecurity; - nsString mKey; - nsString mPrefix; - nsString mLink; - nsTArray<nsString> mInterfaceList; - nsString mWifiStartIp; - nsString mWifiEndIp; - nsString mUsbStartIp; - nsString mUsbEndIp; - nsString mDns1; - nsString mDns2; - nsTArray<nsString> mDnses; - nsString mStartIp; - nsString mEndIp; - nsString mServerIp; - nsString mMaskLength; - nsString mPreInternalIfname; - nsString mPreExternalIfname; - nsString mCurInternalIfname; - nsString mCurExternalIfname; - long long mThreshold; - long mIpaddr; - long mMask; - long mGateway_long; - long mDns1_long; - long mDns2_long; - long mMtu; - - // Auxiliary information required to carry accros command chain. - int mNetId; // A locally defined id per interface. - uint32_t mLoopIndex; // Loop index for adding/removing multiple gateways. -}; - -// CommandChain store the necessary information to execute command one by one. -// Including : -// 1. Command parameters. -// 2. Command list. -// 3. Error callback function. -// 4. Index of current execution command. -class CommandChain final -{ -public: - CommandChain(const NetworkParams& aParams, - const CommandFunc aCmds[], - uint32_t aLength, - ErrorCallback aError) - : mIndex(-1) - , mParams(aParams) - , mCommands(aCmds) - , mLength(aLength) - , mError(aError) { - } - - NetworkParams& - getParams() - { - return mParams; - }; - - CommandFunc - getNextCommand() - { - mIndex++; - return mIndex < mLength ? mCommands[mIndex] : nullptr; - }; - - ErrorCallback - getErrorCallback() const - { - return mError; - }; - -private: - uint32_t mIndex; - NetworkParams mParams; - const CommandFunc* mCommands; - uint32_t mLength; - ErrorCallback mError; -}; - -// A helper class to easily construct a resolved -// or a pending result for command execution. -class CommandResult -{ -public: - struct Pending {}; - -public: - CommandResult(int32_t aResultCode); - CommandResult(const mozilla::dom::NetworkResultOptions& aResult); - CommandResult(const Pending&); - bool isPending() const; - - mozilla::dom::NetworkResultOptions mResult; - -private: - bool mIsPending; -}; - -class NetworkUtils final -{ -public: - NetworkUtils(MessageCallback aCallback); - ~NetworkUtils(); - - void ExecuteCommand(NetworkParams aOptions); - void onNetdMessage(mozilla::ipc::NetdCommand* aCommand); - - MessageCallback getMessageCallback() { return mMessageCallback; } - -private: - /** - * Commands supported by NetworkUtils. - */ - CommandResult configureInterface(NetworkParams& aOptions); - CommandResult dhcpRequest(NetworkParams& aOptions); - CommandResult stopDhcp(NetworkParams& aOptions); - CommandResult enableInterface(NetworkParams& aOptions); - CommandResult disableInterface(NetworkParams& aOptions); - CommandResult resetConnections(NetworkParams& aOptions); - CommandResult setDefaultRoute(NetworkParams& aOptions); - CommandResult addHostRoute(NetworkParams& aOptions); - CommandResult removeDefaultRoute(NetworkParams& aOptions); - CommandResult removeHostRoute(NetworkParams& aOptions); - CommandResult removeNetworkRoute(NetworkParams& aOptions); - CommandResult setDNS(NetworkParams& aOptions); - CommandResult addSecondaryRoute(NetworkParams& aOptions); - CommandResult removeSecondaryRoute(NetworkParams& aOptions); - CommandResult setNetworkInterfaceAlarm(NetworkParams& aOptions); - CommandResult enableNetworkInterfaceAlarm(NetworkParams& aOptions); - CommandResult disableNetworkInterfaceAlarm(NetworkParams& aOptions); - CommandResult setTetheringAlarm(NetworkParams& aOptions); - CommandResult removeTetheringAlarm(NetworkParams& aOptions); - CommandResult getTetheringStatus(NetworkParams& aOptions); - CommandResult setWifiOperationMode(NetworkParams& aOptions); - CommandResult setDhcpServer(NetworkParams& aOptions); - CommandResult setWifiTethering(NetworkParams& aOptions); - CommandResult setUSBTethering(NetworkParams& aOptions); - CommandResult enableUsbRndis(NetworkParams& aOptions); - CommandResult updateUpStream(NetworkParams& aOptions); - CommandResult createNetwork(NetworkParams& aOptions); - CommandResult destroyNetwork(NetworkParams& aOptions); - CommandResult getNetId(NetworkParams& aOptions); - CommandResult setMtu(NetworkParams& aOptions); - CommandResult getInterfaces(NetworkParams& aOptions); - CommandResult getInterfaceConfig(NetworkParams& aOptions); - CommandResult setInterfaceConfig(NetworkParams& aOptions); - - CommandResult addHostRouteLegacy(NetworkParams& aOptions); - CommandResult removeHostRouteLegacy(NetworkParams& aOptions); - CommandResult setDefaultRouteLegacy(NetworkParams& aOptions); - CommandResult removeDefaultRouteLegacy(NetworkParams& aOptions); - CommandResult removeNetworkRouteLegacy(NetworkParams& aOptions); - - - /** - * function pointer array holds all netd commands should be executed - * in sequence to accomplish a given command by other module. - */ - static const CommandFunc sWifiEnableChain[]; - static const CommandFunc sWifiDisableChain[]; - static const CommandFunc sWifiFailChain[]; - static const CommandFunc sWifiRetryChain[]; - static const CommandFunc sWifiOperationModeChain[]; - static const CommandFunc sUSBEnableChain[]; - static const CommandFunc sUSBDisableChain[]; - static const CommandFunc sUSBFailChain[]; - static const CommandFunc sUpdateUpStreamChain[]; - static const CommandFunc sStartDhcpServerChain[]; - static const CommandFunc sStopDhcpServerChain[]; - static const CommandFunc sNetworkInterfaceEnableAlarmChain[]; - static const CommandFunc sNetworkInterfaceDisableAlarmChain[]; - static const CommandFunc sNetworkInterfaceSetAlarmChain[]; - static const CommandFunc sTetheringInterfaceSetAlarmChain[]; - static const CommandFunc sTetheringInterfaceRemoveAlarmChain[]; - static const CommandFunc sTetheringGetStatusChain[]; - static const CommandFunc sGetInterfacesChain[]; - static const CommandFunc sGetInterfaceConfigChain[]; - static const CommandFunc sSetInterfaceConfigChain[]; - - /** - * Individual netd command stored in command chain. - */ -#define PARAMS CommandChain* aChain, CommandCallback aCallback, \ - mozilla::dom::NetworkResultOptions& aResult - static void wifiFirmwareReload(PARAMS); - static void startAccessPointDriver(PARAMS); - static void stopAccessPointDriver(PARAMS); - static void setAccessPoint(PARAMS); - static void cleanUpStream(PARAMS); - static void createUpStream(PARAMS); - static void startSoftAP(PARAMS); - static void stopSoftAP(PARAMS); - static void clearWifiTetherParms(PARAMS); - static void enableAlarm(PARAMS); - static void disableAlarm(PARAMS); - static void setQuota(PARAMS); - static void removeQuota(PARAMS); - static void setAlarm(PARAMS); - static void removeAlarm(PARAMS); - static void setGlobalAlarm(PARAMS); - static void removeGlobalAlarm(PARAMS); - static void tetherInterface(PARAMS); - static void addInterfaceToLocalNetwork(PARAMS); - static void addRouteToLocalNetwork(PARAMS); - static void preTetherInterfaceList(PARAMS); - static void postTetherInterfaceList(PARAMS); - static void addUpstreamInterface(PARAMS); - static void removeUpstreamInterface(PARAMS); - static void setIpForwardingEnabled(PARAMS); - static void tetheringStatus(PARAMS); - static void stopTethering(PARAMS); - static void startTethering(PARAMS); - static void untetherInterface(PARAMS); - static void removeInterfaceFromLocalNetwork(PARAMS); - static void setDnsForwarders(PARAMS); - static void enableNat(PARAMS); - static void disableNat(PARAMS); - static void setDefaultInterface(PARAMS); - static void setInterfaceDns(PARAMS); - static void getInterfaceList(PARAMS); - static void getConfig(PARAMS); - static void setConfig(PARAMS); - static void wifiTetheringSuccess(PARAMS); - static void usbTetheringSuccess(PARAMS); - static void networkInterfaceAlarmSuccess(PARAMS); - static void updateUpStreamSuccess(PARAMS); - static void setDhcpServerSuccess(PARAMS); - static void wifiOperationModeSuccess(PARAMS); - static void clearAddrForInterface(PARAMS); - static void createNetwork(PARAMS); - static void destroyNetwork(PARAMS); - static void addInterfaceToNetwork(PARAMS); - static void addDefaultRouteToNetwork(PARAMS); - static void setDefaultNetwork(PARAMS); - static void removeDefaultRoute(PARAMS); - static void removeNetworkRouteSuccess(PARAMS); - static void removeNetworkRoute(PARAMS); - static void addRouteToInterface(PARAMS); - static void removeRouteFromInterface(PARAMS); - static void modifyRouteOnInterface(PARAMS, bool aDoAdd); - static void enableIpv6(PARAMS); - static void disableIpv6(PARAMS); - static void setMtu(PARAMS); - static void setIpv6Enabled(PARAMS, bool aEnabled); - static void addRouteToSecondaryTable(PARAMS); - static void removeRouteFromSecondaryTable(PARAMS); - static void defaultAsyncSuccessHandler(PARAMS); - static void getInterfacesSuccess(PARAMS); - static void getInterfaceConfigSuccess(PARAMS); - static void setInterfaceConfigSuccess(PARAMS); - -#undef PARAMS - - /** - * Error callback function executed when a command is fail. - */ -#define PARAMS NetworkParams& aOptions, \ - mozilla::dom::NetworkResultOptions& aResult - static void wifiTetheringFail(PARAMS); - static void wifiOperationModeFail(PARAMS); - static void usbTetheringFail(PARAMS); - static void updateUpStreamFail(PARAMS); - static void setDhcpServerFail(PARAMS); - static void networkInterfaceAlarmFail(PARAMS); - static void setDnsFail(PARAMS); - static void defaultAsyncFailureHandler(PARAMS); - static void getInterfacesFail(PARAMS); - static void getInterfaceConfigFail(PARAMS); - static void setInterfaceConfigFail(PARAMS); - -#undef PARAMS - - /** - * Command chain processing functions. - */ - static void next(CommandChain* aChain, bool aError, - mozilla::dom::NetworkResultOptions& aResult); - static void nextNetdCommand(); - static void doCommand(const char* aCommand, CommandChain* aChain, CommandCallback aCallback); - - /** - * Notify broadcast message to main thread. - */ - void sendBroadcastMessage(uint32_t code, char* reason); - - /** - * Utility functions. - */ - CommandResult checkUsbRndisState(NetworkParams& aOptions); - void dumpParams(NetworkParams& aOptions, const char* aType); - - static void escapeQuote(nsCString& aString); - inline uint32_t netdResponseType(uint32_t code); - inline bool isBroadcastMessage(uint32_t code); - inline bool isError(uint32_t code); - inline bool isComplete(uint32_t code); - inline bool isProceeding(uint32_t code); - void Shutdown(); - static void runNextQueuedCommandChain(); - static void finalizeSuccess(CommandChain* aChain, - mozilla::dom::NetworkResultOptions& aResult); - - template<size_t N> - static void runChain(const NetworkParams& aParams, - const CommandFunc (&aCmds)[N], - ErrorCallback aError); - - static nsCString getSubnetIp(const nsCString& aIp, int aPrefixLength); - - /** - * Callback function to send netd result to main thread. - */ - MessageCallback mMessageCallback; - - /* - * Utility class to access libnetutils. - */ - nsAutoPtr<NetUtils> mNetUtils; - - NetIdManager mNetIdManager; -}; - -#endif diff --git a/dom/system/gonk/NetworkWorker.cpp b/dom/system/gonk/NetworkWorker.cpp deleted file mode 100644 index caf07f375..000000000 --- a/dom/system/gonk/NetworkWorker.cpp +++ /dev/null @@ -1,271 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "NetworkWorker.h" -#include "NetworkUtils.h" -#include <nsThreadUtils.h> -#include "mozilla/ModuleUtils.h" -#include "mozilla/ClearOnShutdown.h" -#include "mozilla/dom/ScriptSettings.h" -#include "mozilla/dom/ToJSValue.h" -#include "nsAutoPtr.h" -#include "nsXULAppAPI.h" - -#define NS_NETWORKWORKER_CID \ - { 0x6df093e1, 0x8127, 0x4fa7, {0x90, 0x13, 0xa3, 0xaa, 0xa7, 0x79, 0xbb, 0xdd} } - -using namespace mozilla; -using namespace mozilla::dom; -using namespace mozilla::ipc; - -namespace mozilla { - -nsCOMPtr<nsIThread> gWorkerThread; - -// The singleton network worker, to be used on the main thread. -StaticRefPtr<NetworkWorker> gNetworkWorker; - -// The singleton networkutils class, that can be used on any thread. -static nsAutoPtr<NetworkUtils> gNetworkUtils; - -// Runnable used dispatch command result on the main thread. -class NetworkResultDispatcher : public Runnable -{ -public: - NetworkResultDispatcher(const NetworkResultOptions& aResult) - : mResult(aResult) - { - MOZ_ASSERT(!NS_IsMainThread()); - } - - NS_IMETHOD Run() override - { - MOZ_ASSERT(NS_IsMainThread()); - - if (gNetworkWorker) { - gNetworkWorker->DispatchNetworkResult(mResult); - } - return NS_OK; - } -private: - NetworkResultOptions mResult; -}; - -// Runnable used dispatch netd command on the worker thread. -class NetworkCommandDispatcher : public Runnable -{ -public: - NetworkCommandDispatcher(const NetworkParams& aParams) - : mParams(aParams) - { - MOZ_ASSERT(NS_IsMainThread()); - } - - NS_IMETHOD Run() override - { - MOZ_ASSERT(!NS_IsMainThread()); - - if (gNetworkUtils) { - gNetworkUtils->ExecuteCommand(mParams); - } - return NS_OK; - } -private: - NetworkParams mParams; -}; - -// Runnable used dispatch netd result on the worker thread. -class NetdEventRunnable : public Runnable -{ -public: - NetdEventRunnable(NetdCommand* aCommand) - : mCommand(aCommand) - { - MOZ_ASSERT(!NS_IsMainThread()); - } - - NS_IMETHOD Run() override - { - MOZ_ASSERT(!NS_IsMainThread()); - - if (gNetworkUtils) { - gNetworkUtils->onNetdMessage(mCommand); - } - return NS_OK; - } - -private: - nsAutoPtr<NetdCommand> mCommand; -}; - -class NetdMessageConsumer : public NetdConsumer -{ -public: - NetdMessageConsumer() - { - MOZ_ASSERT(NS_IsMainThread()); - } - - void MessageReceived(NetdCommand* aCommand) - { - MOZ_ASSERT(!NS_IsMainThread()); - - nsCOMPtr<nsIRunnable> runnable = new NetdEventRunnable(aCommand); - if (gWorkerThread) { - gWorkerThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL); - } - } -}; - -NS_IMPL_ISUPPORTS(NetworkWorker, nsINetworkWorker) - -NetworkWorker::NetworkWorker() -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(!gNetworkWorker); -} - -NetworkWorker::~NetworkWorker() -{ - MOZ_ASSERT(!gNetworkWorker); - MOZ_ASSERT(!mListener); -} - -already_AddRefed<NetworkWorker> -NetworkWorker::FactoryCreate() -{ - if (!XRE_IsParentProcess()) { - return nullptr; - } - - MOZ_ASSERT(NS_IsMainThread()); - - if (!gNetworkWorker) { - gNetworkWorker = new NetworkWorker(); - ClearOnShutdown(&gNetworkWorker); - - gNetworkUtils = new NetworkUtils(NetworkWorker::NotifyResult); - ClearOnShutdown(&gNetworkUtils); - } - - RefPtr<NetworkWorker> worker = gNetworkWorker.get(); - return worker.forget(); -} - -NS_IMETHODIMP -NetworkWorker::Start(nsINetworkEventListener* aListener) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(aListener); - - if (mListener) { - return NS_OK; - } - - nsresult rv; - - rv = NS_NewNamedThread("NetworkWorker", getter_AddRefs(gWorkerThread)); - if (NS_FAILED(rv)) { - NS_WARNING("Can't create network control thread"); - return NS_ERROR_FAILURE; - } - - StartNetd(new NetdMessageConsumer()); - mListener = aListener; - - return NS_OK; -} - -NS_IMETHODIMP -NetworkWorker::Shutdown() -{ - MOZ_ASSERT(NS_IsMainThread()); - - if (!mListener) { - return NS_OK; - } - - StopNetd(); - - gWorkerThread->Shutdown(); - gWorkerThread = nullptr; - - mListener = nullptr; - return NS_OK; -} - -// Receive command from main thread (NetworkService.js). -NS_IMETHODIMP -NetworkWorker::PostMessage(JS::Handle<JS::Value> aOptions, JSContext* aCx) -{ - MOZ_ASSERT(NS_IsMainThread()); - - NetworkCommandOptions options; - if (!options.Init(aCx, aOptions)) { - NS_WARNING("Bad dictionary passed to NetworkWorker::SendCommand"); - return NS_ERROR_FAILURE; - } - - // Dispatch the command to the control thread. - NetworkParams NetworkParams(options); - nsCOMPtr<nsIRunnable> runnable = new NetworkCommandDispatcher(NetworkParams); - if (gWorkerThread) { - gWorkerThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL); - } - return NS_OK; -} - -void -NetworkWorker::DispatchNetworkResult(const NetworkResultOptions& aOptions) -{ - MOZ_ASSERT(NS_IsMainThread()); - - mozilla::AutoSafeJSContext cx; - JS::RootedValue val(cx); - - if (!ToJSValue(cx, aOptions, &val)) { - return; - } - - // Call the listener with a JS value. - if (mListener) { - mListener->OnEvent(val); - } -} - -// Callback function from network worker thread to update result on main thread. -void -NetworkWorker::NotifyResult(NetworkResultOptions& aResult) -{ - MOZ_ASSERT(!NS_IsMainThread()); - - nsCOMPtr<nsIRunnable> runnable = new NetworkResultDispatcher(aResult); - NS_DispatchToMainThread(runnable); -} - -NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(NetworkWorker, - NetworkWorker::FactoryCreate) - -NS_DEFINE_NAMED_CID(NS_NETWORKWORKER_CID); - -static const mozilla::Module::CIDEntry kNetworkWorkerCIDs[] = { - { &kNS_NETWORKWORKER_CID, false, nullptr, NetworkWorkerConstructor }, - { nullptr } -}; - -static const mozilla::Module::ContractIDEntry kNetworkWorkerContracts[] = { - { "@mozilla.org/network/worker;1", &kNS_NETWORKWORKER_CID }, - { nullptr } -}; - -static const mozilla::Module kNetworkWorkerModule = { - mozilla::Module::kVersion, - kNetworkWorkerCIDs, - kNetworkWorkerContracts, - nullptr -}; - -} // namespace mozilla - -NSMODULE_DEFN(NetworkWorkerModule) = &kNetworkWorkerModule; diff --git a/dom/system/gonk/NetworkWorker.h b/dom/system/gonk/NetworkWorker.h deleted file mode 100644 index f5c0a8fdd..000000000 --- a/dom/system/gonk/NetworkWorker.h +++ /dev/null @@ -1,37 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef NetworkWorker_h -#define NetworkWorker_h - -#include "mozilla/dom/NetworkOptionsBinding.h" -#include "mozilla/ipc/Netd.h" -#include "nsINetworkWorker.h" -#include "nsCOMPtr.h" -#include "nsThread.h" - -namespace mozilla { - -class NetworkWorker final : public nsINetworkWorker -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSINETWORKWORKER - - static already_AddRefed<NetworkWorker> FactoryCreate(); - - void DispatchNetworkResult(const mozilla::dom::NetworkResultOptions& aOptions); - -private: - NetworkWorker(); - ~NetworkWorker(); - - static void NotifyResult(mozilla::dom::NetworkResultOptions& aResult); - - nsCOMPtr<nsINetworkEventListener> mListener; -}; - -} // namespace mozilla - -#endif // NetworkWorker_h diff --git a/dom/system/gonk/OpenFileFinder.cpp b/dom/system/gonk/OpenFileFinder.cpp deleted file mode 100644 index 388e813e1..000000000 --- a/dom/system/gonk/OpenFileFinder.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "OpenFileFinder.h" - -#include "mozilla/FileUtils.h" -#include "nsPrintfCString.h" - -#include <sys/stat.h> -#include <errno.h> - -#undef USE_DEBUG -#define USE_DEBUG 0 - -#undef LOG -#undef LOGW -#undef ERR -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "OpenFileFinder", ## args) -#define LOGW(args...) __android_log_print(ANDROID_LOG_WARN, "OpenFileFinder", ## args) -#define ERR(args...) __android_log_print(ANDROID_LOG_ERROR, "OpenFileFinder", ## args) - -#undef DBG -#if USE_DEBUG -#define DBG(args...) __android_log_print(ANDROID_LOG_DEBUG, "OpenFileFinder" , ## args) -#else -#define DBG(args...) -#endif - -namespace mozilla { -namespace system { - -OpenFileFinder::OpenFileFinder(const nsACString& aPath, - bool aCheckIsB2gOrDescendant /* = true */) - : mPath(aPath), - mProcDir(nullptr), - mFdDir(nullptr), - mPid(0), - mCheckIsB2gOrDescendant(aCheckIsB2gOrDescendant) -{ - // We assume that we're running in the parent process - mMyPid = getpid(); -} - -OpenFileFinder::~OpenFileFinder() -{ - Close(); -} - -bool -OpenFileFinder::First(OpenFileFinder::Info* aInfo) -{ - Close(); - - mProcDir = opendir("/proc"); - if (!mProcDir) { - return false; - } - mState = NEXT_PID; - return Next(aInfo); -} - -bool -OpenFileFinder::Next(OpenFileFinder::Info* aInfo) -{ - // NOTE: This function calls readdir and readlink, neither of which should - // block since we're using the proc filesystem, which is a purely - // kernel in-memory filesystem and doesn't depend on external driver - // behaviour. - while (mState != DONE) { - switch (mState) { - case NEXT_PID: { - struct dirent *pidEntry; - pidEntry = readdir(mProcDir); - if (!pidEntry) { - mState = DONE; - break; - } - char *endPtr; - mPid = strtol(pidEntry->d_name, &endPtr, 10); - if (mPid == 0 || *endPtr != '\0') { - // Not a +ve number - ignore - continue; - } - // We've found a /proc/PID directory. Scan open file descriptors. - if (mFdDir) { - closedir(mFdDir); - } - nsPrintfCString fdDirPath("/proc/%d/fd", mPid); - mFdDir = opendir(fdDirPath.get()); - if (!mFdDir) { - continue; - } - mState = CHECK_FDS; - } - // Fall through - case CHECK_FDS: { - struct dirent *fdEntry; - while((fdEntry = readdir(mFdDir))) { - if (!strcmp(fdEntry->d_name, ".") || - !strcmp(fdEntry->d_name, "..")) { - continue; - } - nsPrintfCString fdSymLink("/proc/%d/fd/%s", mPid, fdEntry->d_name); - nsCString resolvedPath; - if (ReadSymLink(fdSymLink, resolvedPath) && PathMatches(resolvedPath)) { - // We found an open file contained within the directory tree passed - // into the constructor. - FillInfo(aInfo, resolvedPath); - // If sCheckIsB2gOrDescendant is set false, the caller cares about - // all processes which have open files. If sCheckIsB2gOrDescendant - // is set false, we only care about the b2g proccess or its descendants. - if (!mCheckIsB2gOrDescendant || aInfo->mIsB2gOrDescendant) { - return true; - } - LOG("Ignore process(%d), not a b2g process or its descendant.", - aInfo->mPid); - } - } - // We've checked all of the files for this pid, move onto the next one. - mState = NEXT_PID; - continue; - } - case DONE: - default: - mState = DONE; // covers the default case - break; - } - } - return false; -} - -void -OpenFileFinder::Close() -{ - if (mFdDir) { - closedir(mFdDir); - } - if (mProcDir) { - closedir(mProcDir); - } -} - -void -OpenFileFinder::FillInfo(OpenFileFinder::Info* aInfo, const nsACString& aPath) -{ - aInfo->mFileName = aPath; - aInfo->mPid = mPid; - nsPrintfCString exePath("/proc/%d/exe", mPid); - ReadSymLink(exePath, aInfo->mExe); - aInfo->mComm.Truncate(); - aInfo->mAppName.Truncate(); - nsPrintfCString statPath("/proc/%d/stat", mPid); - nsCString statString; - statString.SetLength(200); - char *stat = statString.BeginWriting(); - if (!stat) { - return; - } - ReadSysFile(statPath.get(), stat, statString.Length()); - // The stat line includes the comm field, surrounded by parenthesis. - // However, the contents of the comm field itself is arbitrary and - // and can include ')', so we search for the rightmost ) as being - // the end of the comm field. - char *closeParen = strrchr(stat, ')'); - if (!closeParen) { - return; - } - char *openParen = strchr(stat, '('); - if (!openParen) { - return; - } - if (openParen >= closeParen) { - return; - } - nsDependentCSubstring comm(&openParen[1], closeParen - openParen - 1); - aInfo->mComm = comm; - // There is a single character field after the comm and then - // the parent pid (the field we're interested in). - // ) X ppid - // 01234 - int ppid = atoi(&closeParen[4]); - - if (mPid == mMyPid) { - // This is chrome process - aInfo->mIsB2gOrDescendant = true; - DBG("Chrome process has open file(s)"); - return; - } - // For the rest (non-chrome process), we recursively check the ppid to know - // it is a descendant of b2g or not. See bug 931456. - while (ppid != mMyPid && ppid != 1) { - DBG("Process(%d) is not forked from b2g(%d) or Init(1), keep looking", - ppid, mMyPid); - nsPrintfCString ppStatPath("/proc/%d/stat", ppid); - ReadSysFile(ppStatPath.get(), stat, statString.Length()); - closeParen = strrchr(stat, ')'); - if (!closeParen) { - return; - } - ppid = atoi(&closeParen[4]); - } - if (ppid == 1) { - // This is a not a b2g process. - DBG("Non-b2g process has open file(s)"); - aInfo->mIsB2gOrDescendant = false; - return; - } - if (ppid == mMyPid) { - // This is a descendant of b2g. - DBG("Child process of chrome process has open file(s)"); - aInfo->mIsB2gOrDescendant = true; - } - - // This looks like a content process. The comm field will be the - // app name. - aInfo->mAppName = aInfo->mComm; -} - -bool -OpenFileFinder::ReadSymLink(const nsACString& aSymLink, nsACString& aOutPath) -{ - aOutPath.Truncate(); - const char *symLink = aSymLink.BeginReading(); - - // Verify that we actually have a symlink. - struct stat st; - if (lstat(symLink, &st)) { - return false; - } - if ((st.st_mode & S_IFMT) != S_IFLNK) { - return false; - } - - // Contrary to the documentation st.st_size doesn't seem to be a reliable - // indication of the length when reading from /proc, so we use a fixed - // size buffer instead. - - char resolvedSymLink[PATH_MAX]; - ssize_t pathLength = readlink(symLink, resolvedSymLink, - sizeof(resolvedSymLink) - 1); - if (pathLength <= 0) { - return false; - } - resolvedSymLink[pathLength] = '\0'; - aOutPath.Assign(resolvedSymLink); - return true; -} - -} // system -} // mozilla diff --git a/dom/system/gonk/OpenFileFinder.h b/dom/system/gonk/OpenFileFinder.h deleted file mode 100644 index 24517965a..000000000 --- a/dom/system/gonk/OpenFileFinder.h +++ /dev/null @@ -1,63 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_openfilefinder_h__ -#define mozilla_system_openfilefinder_h__ - -#include "nsString.h" - -#include <dirent.h> - -namespace mozilla { -namespace system { - -class OpenFileFinder -{ -public: - enum State - { - NEXT_PID, - CHECK_FDS, - DONE - }; - class Info - { - public: - nsCString mFileName; // name of the the open file - nsCString mAppName; // App which has the file open (if it's a b2g app) - pid_t mPid; // pid of the process which has the file open - nsCString mComm; // comm associated with pid - nsCString mExe; // executable name associated with pid - bool mIsB2gOrDescendant; // this is b2g/its descendant or not - }; - - OpenFileFinder(const nsACString& aPath, bool aCheckIsB2gOrDescendant = true); - ~OpenFileFinder(); - - bool First(Info* aInfo); // Return the first open file - bool Next(Info* aInfo); // Return the next open file - void Close(); - -private: - - void FillInfo(Info *aInfo, const nsACString& aPath); - bool ReadSymLink(const nsACString& aSymLink, nsACString& aOutPath); - bool PathMatches(const nsACString& aPath) - { - return Substring(aPath, 0, mPath.Length()).Equals(mPath); - } - - State mState; // Keeps track of what we're doing. - nsCString mPath; // Only report files contained within this directory tree - DIR* mProcDir; // Used for scanning /proc - DIR* mFdDir; // Used for scanning /proc/PID/fd - int mPid; // PID currently being processed - pid_t mMyPid; // PID of parent process, we assume we're running on it. - bool mCheckIsB2gOrDescendant; // Do we care about non-b2g process? -}; - -} // system -} // mozilla - -#endif // mozilla_system_nsvolume_h__ diff --git a/dom/system/gonk/RILSystemMessenger.jsm b/dom/system/gonk/RILSystemMessenger.jsm deleted file mode 100644 index 81373458c..000000000 --- a/dom/system/gonk/RILSystemMessenger.jsm +++ /dev/null @@ -1,338 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -XPCOMUtils.defineLazyGetter(this, "RIL", function () { - let obj = {}; - Cu.import("resource://gre/modules/ril_consts.js", obj); - return obj; -}); - -/** - * RILSystemMessenger - */ -this.RILSystemMessenger = function() {}; -RILSystemMessenger.prototype = { - - /** - * Hook of Broadcast function - * - * @param aType - * The type of the message to be sent. - * @param aMessage - * The message object to be broadcasted. - */ - broadcastMessage: function(aType, aMessage) { - // Function stub to be replaced by the owner of this messenger. - }, - - /** - * Hook of the function to create MozStkCommand message. - * @param aStkProactiveCmd - * nsIStkProactiveCmd instance. - * - * @return a JS object which complies the dictionary of MozStkCommand defined - * in MozStkCommandEvent.webidl - */ - createCommandMessage: function(aStkProactiveCmd) { - // Function stub to be replaced by the owner of this messenger. - }, - - /** - * Wrapper to send "telephony-new-call" system message. - */ - notifyNewCall: function() { - this.broadcastMessage("telephony-new-call", {}); - }, - - /** - * Wrapper to send "telephony-call-ended" system message. - */ - notifyCallEnded: function(aServiceId, aNumber, aCdmaWaitingNumber, aEmergency, - aDuration, aOutgoing, aHangUpLocal) { - let data = { - serviceId: aServiceId, - number: aNumber, - emergency: aEmergency, - duration: aDuration, - direction: aOutgoing ? "outgoing" : "incoming", - hangUpLocal: aHangUpLocal - }; - - if (aCdmaWaitingNumber != null) { - data.secondNumber = aCdmaWaitingNumber; - } - - this.broadcastMessage("telephony-call-ended", data); - }, - - _convertSmsMessageClass: function(aMessageClass) { - return RIL.GECKO_SMS_MESSAGE_CLASSES[aMessageClass] || null; - }, - - _convertSmsDelivery: function(aDelivery) { - return ["received", "sending", "sent", "error"][aDelivery] || null; - }, - - _convertSmsDeliveryStatus: function(aDeliveryStatus) { - return [ - RIL.GECKO_SMS_DELIVERY_STATUS_NOT_APPLICABLE, - RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS, - RIL.GECKO_SMS_DELIVERY_STATUS_PENDING, - RIL.GECKO_SMS_DELIVERY_STATUS_ERROR - ][aDeliveryStatus] || null; - }, - - /** - * Wrapper to send 'sms-received', 'sms-delivery-success', 'sms-sent', - * 'sms-failed', 'sms-delivery-error' system message. - */ - notifySms: function(aNotificationType, aId, aThreadId, aIccId, aDelivery, - aDeliveryStatus, aSender, aReceiver, aBody, aMessageClass, - aTimestamp, aSentTimestamp, aDeliveryTimestamp, aRead) { - let msgType = [ - "sms-received", - "sms-sent", - "sms-delivery-success", - "sms-failed", - "sms-delivery-error" - ][aNotificationType]; - - if (!msgType) { - throw new Error("Invalid Notification Type: " + aNotificationType); - } - - this.broadcastMessage(msgType, { - iccId: aIccId, - type: "sms", - id: aId, - threadId: aThreadId, - delivery: this._convertSmsDelivery(aDelivery), - deliveryStatus: this._convertSmsDeliveryStatus(aDeliveryStatus), - sender: aSender, - receiver: aReceiver, - body: aBody, - messageClass: this._convertSmsMessageClass(aMessageClass), - timestamp: aTimestamp, - sentTimestamp: aSentTimestamp, - deliveryTimestamp: aDeliveryTimestamp, - read: aRead - }); - }, - - _convertCbGsmGeographicalScope: function(aGeographicalScope) { - return RIL.CB_GSM_GEOGRAPHICAL_SCOPE_NAMES[aGeographicalScope] || null; - }, - - _convertCbMessageClass: function(aMessageClass) { - return RIL.GECKO_SMS_MESSAGE_CLASSES[aMessageClass] || null; - }, - - _convertCbEtwsWarningType: function(aWarningType) { - return RIL.CB_ETWS_WARNING_TYPE_NAMES[aWarningType] || null; - }, - - /** - * Wrapper to send 'cellbroadcast-received' system message. - */ - notifyCbMessageReceived: function(aServiceId, aGsmGeographicalScope, aMessageCode, - aMessageId, aLanguage, aBody, aMessageClass, - aTimestamp, aCdmaServiceCategory, aHasEtwsInfo, - aEtwsWarningType, aEtwsEmergencyUserAlert, aEtwsPopup) { - // Align the same layout to MozCellBroadcastMessage - let data = { - serviceId: aServiceId, - gsmGeographicalScope: this._convertCbGsmGeographicalScope(aGsmGeographicalScope), - messageCode: aMessageCode, - messageId: aMessageId, - language: aLanguage, - body: aBody, - messageClass: this._convertCbMessageClass(aMessageClass), - timestamp: aTimestamp, - cdmaServiceCategory: null, - etws: null - }; - - if (aHasEtwsInfo) { - data.etws = { - warningType: this._convertCbEtwsWarningType(aEtwsWarningType), - emergencyUserAlert: aEtwsEmergencyUserAlert, - popup: aEtwsPopup - }; - } - - if (aCdmaServiceCategory != - Ci.nsICellBroadcastService.CDMA_SERVICE_CATEGORY_INVALID) { - data.cdmaServiceCategory = aCdmaServiceCategory; - } - - this.broadcastMessage("cellbroadcast-received", data); - }, - - /** - * Wrapper to send 'ussd-received' system message. - */ - notifyUssdReceived: function(aServiceId, aMessage, aSessionEnded) { - this.broadcastMessage("ussd-received", { - serviceId: aServiceId, - message: aMessage, - sessionEnded: aSessionEnded - }); - }, - - /** - * Wrapper to send 'cdma-info-rec-received' system message with Display Info. - */ - notifyCdmaInfoRecDisplay: function(aServiceId, aDisplay) { - this.broadcastMessage("cdma-info-rec-received", { - clientId: aServiceId, - display: aDisplay - }); - }, - - /** - * Wrapper to send 'cdma-info-rec-received' system message with Called Party - * Number Info. - */ - notifyCdmaInfoRecCalledPartyNumber: function(aServiceId, aType, aPlan, - aNumber, aPi, aSi) { - this.broadcastMessage("cdma-info-rec-received", { - clientId: aServiceId, - calledNumber: { - type: aType, - plan: aPlan, - number: aNumber, - pi: aPi, - si: aSi - } - }); - }, - - /** - * Wrapper to send 'cdma-info-rec-received' system message with Calling Party - * Number Info. - */ - notifyCdmaInfoRecCallingPartyNumber: function(aServiceId, aType, aPlan, - aNumber, aPi, aSi) { - this.broadcastMessage("cdma-info-rec-received", { - clientId: aServiceId, - callingNumber: { - type: aType, - plan: aPlan, - number: aNumber, - pi: aPi, - si: aSi - } - }); - }, - - /** - * Wrapper to send 'cdma-info-rec-received' system message with Connected Party - * Number Info. - */ - notifyCdmaInfoRecConnectedPartyNumber: function(aServiceId, aType, aPlan, - aNumber, aPi, aSi) { - this.broadcastMessage("cdma-info-rec-received", { - clientId: aServiceId, - connectedNumber: { - type: aType, - plan: aPlan, - number: aNumber, - pi: aPi, - si: aSi - } - }); - }, - - /** - * Wrapper to send 'cdma-info-rec-received' system message with Signal Info. - */ - notifyCdmaInfoRecSignal: function(aServiceId, aType, aAlertPitch, aSignal) { - this.broadcastMessage("cdma-info-rec-received", { - clientId: aServiceId, - signal: { - type: aType, - alertPitch: aAlertPitch, - signal: aSignal - } - }); - }, - - /** - * Wrapper to send 'cdma-info-rec-received' system message with Redirecting - * Number Info. - */ - notifyCdmaInfoRecRedirectingNumber: function(aServiceId, aType, aPlan, - aNumber, aPi, aSi, aReason) { - this.broadcastMessage("cdma-info-rec-received", { - clientId: aServiceId, - redirect: { - type: aType, - plan: aPlan, - number: aNumber, - pi: aPi, - si: aSi, - reason: aReason - } - }); - }, - - /** - * Wrapper to send 'cdma-info-rec-received' system message with Line Control Info. - */ - notifyCdmaInfoRecLineControl: function(aServiceId, aPolarityIncluded, - aToggle, aReverse, aPowerDenial) { - this.broadcastMessage("cdma-info-rec-received", { - clientId: aServiceId, - lineControl: { - polarityIncluded: aPolarityIncluded, - toggle: aToggle, - reverse: aReverse, - powerDenial: aPowerDenial - } - }); - }, - - /** - * Wrapper to send 'cdma-info-rec-received' system message with CLIR Info. - */ - notifyCdmaInfoRecClir: function(aServiceId, aCause) { - this.broadcastMessage("cdma-info-rec-received", { - clientId: aServiceId, - clirCause: aCause - }); - }, - - /** - * Wrapper to send 'cdma-info-rec-received' system message with Audio Control Info. - */ - notifyCdmaInfoRecAudioControl: function(aServiceId, aUpLink, aDownLink) { - this.broadcastMessage("cdma-info-rec-received", { - clientId: aServiceId, - audioControl: { - upLink: aUpLink, - downLink: aDownLink - } - }); - }, - - /** - * Wrapper to send 'icc-stkcommand' system message with Audio Control Info. - */ - notifyStkProactiveCommand: function(aIccId, aCommand) { - this.broadcastMessage("icc-stkcommand", { - iccId: aIccId, - command: this.createCommandMessage(aCommand) - }); - } -}; - -this.EXPORTED_SYMBOLS = [ - 'RILSystemMessenger' -]; diff --git a/dom/system/gonk/RILSystemMessengerHelper.js b/dom/system/gonk/RILSystemMessengerHelper.js deleted file mode 100644 index 6ef263b66..000000000 --- a/dom/system/gonk/RILSystemMessengerHelper.js +++ /dev/null @@ -1,169 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -var RSM = {}; -Cu.import("resource://gre/modules/RILSystemMessenger.jsm", RSM); - -const RILSYSTEMMESSENGERHELPER_CONTRACTID = - "@mozilla.org/ril/system-messenger-helper;1"; -const RILSYSTEMMESSENGERHELPER_CID = - Components.ID("{19d9a4ea-580d-11e4-8f6c-37ababfaaea9}"); - -XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger", - "@mozilla.org/system-message-internal;1", - "nsISystemMessagesInternal"); - -XPCOMUtils.defineLazyServiceGetter(this, "gStkCmdFactory", - "@mozilla.org/icc/stkcmdfactory;1", - "nsIStkCmdFactory"); - -var DEBUG = false; -function debug(s) { - dump("-@- RILSystemMessenger: " + s + "\n"); -}; - -// Read debug setting from pref. -try { - let debugPref = Services.prefs.getBoolPref("ril.debugging.enabled"); - DEBUG = DEBUG || debugPref; -} catch (e) {} - -/** - * RILSystemMessengerHelper - */ -function RILSystemMessengerHelper() { - this.messenger = new RSM.RILSystemMessenger(); - this.messenger.broadcastMessage = (aType, aMessage) => { - if (DEBUG) { - debug("broadcastMessage: aType: " + aType + - ", aMessage: "+ JSON.stringify(aMessage)); - } - - gSystemMessenger.broadcastMessage(aType, aMessage); - }; - - this.messenger.createCommandMessage = (aStkProactiveCmd) => { - return gStkCmdFactory.createCommandMessage(aStkProactiveCmd); - }; -} -RILSystemMessengerHelper.prototype = { - - classID: RILSYSTEMMESSENGERHELPER_CID, - QueryInterface: XPCOMUtils.generateQI([Ci.nsITelephonyMessenger, - Ci.nsISmsMessenger, - Ci.nsICellbroadcastMessenger, - Ci.nsIMobileConnectionMessenger, - Ci.nsIIccMessenger]), - - /** - * RILSystemMessenger instance. - */ - messenger: null, - - /** - * nsITelephonyMessenger API - */ - notifyNewCall: function() { - this.messenger.notifyNewCall(); - }, - - notifyCallEnded: function(aServiceId, aNumber, aCdmaWaitingNumber, aEmergency, - aDuration, aOutgoing, aHangUpLocal) { - this.messenger.notifyCallEnded(aServiceId, aNumber, aCdmaWaitingNumber, aEmergency, - aDuration, aOutgoing, aHangUpLocal); - }, - - notifyUssdReceived: function(aServiceId, aMessage, aSessionEnded) { - this.messenger.notifyUssdReceived(aServiceId, aMessage, aSessionEnded); - }, - - /** - * nsISmsMessenger API - */ - notifySms: function(aNotificationType, aId, aThreadId, aIccId, aDelivery, - aDeliveryStatus, aSender, aReceiver, aBody, aMessageClass, - aTimestamp, aSentTimestamp, aDeliveryTimestamp, aRead) { - this.messenger.notifySms(aNotificationType, aId, aThreadId, aIccId, aDelivery, - aDeliveryStatus, aSender, aReceiver, aBody, aMessageClass, - aTimestamp, aSentTimestamp, aDeliveryTimestamp, aRead); - }, - - /** - * nsICellbroadcastMessenger API - */ - notifyCbMessageReceived: function(aServiceId, aGsmGeographicalScope, aMessageCode, - aMessageId, aLanguage, aBody, aMessageClass, - aTimestamp, aCdmaServiceCategory, aHasEtwsInfo, - aEtwsWarningType, aEtwsEmergencyUserAlert, aEtwsPopup) { - this.messenger.notifyCbMessageReceived(aServiceId, aGsmGeographicalScope, aMessageCode, - aMessageId, aLanguage, aBody, aMessageClass, - aTimestamp, aCdmaServiceCategory, aHasEtwsInfo, - aEtwsWarningType, aEtwsEmergencyUserAlert, aEtwsPopup); - }, - - /** - * nsIMobileConnectionMessenger API - */ - notifyCdmaInfoRecDisplay: function(aServiceId, aDisplay) { - this.messenger.notifyCdmaInfoRecDisplay(aServiceId, aDisplay); - }, - - notifyCdmaInfoRecCalledPartyNumber: function(aServiceId, aType, aPlan, - aNumber, aPi, aSi) { - this.messenger.notifyCdmaInfoRecCalledPartyNumber(aServiceId, aType, aPlan, - aNumber, aPi, aSi); - }, - - notifyCdmaInfoRecCallingPartyNumber: function(aServiceId, aType, aPlan, - aNumber, aPi, aSi) { - this.messenger.notifyCdmaInfoRecCallingPartyNumber(aServiceId, aType, aPlan, - aNumber, aPi, aSi); - }, - - notifyCdmaInfoRecConnectedPartyNumber: function(aServiceId, aType, aPlan, - aNumber, aPi, aSi) { - this.messenger.notifyCdmaInfoRecConnectedPartyNumber(aServiceId, aType, aPlan, - aNumber, aPi, aSi); - }, - - notifyCdmaInfoRecSignal: function(aServiceId, aType, aAlertPitch, aSignal) { - this.messenger.notifyCdmaInfoRecSignal(aServiceId, aType, aAlertPitch, aSignal); - }, - - notifyCdmaInfoRecRedirectingNumber: function(aServiceId, aType, aPlan, - aNumber, aPi, aSi, aReason) { - this.messenger.notifyCdmaInfoRecRedirectingNumber(aServiceId, aType, aPlan, - aNumber, aPi, aSi, aReason); - }, - - notifyCdmaInfoRecLineControl: function(aServiceId, aPolarityIncluded, - aToggle, aReverse, aPowerDenial) { - this.messenger.notifyCdmaInfoRecLineControl(aServiceId, aPolarityIncluded, - aToggle, aReverse, aPowerDenial); - }, - - notifyCdmaInfoRecClir: function(aServiceId, aCause) { - this.messenger.notifyCdmaInfoRecClir(aServiceId, aCause); - }, - - notifyCdmaInfoRecAudioControl: function(aServiceId, aUpLink, aDownLink) { - this.messenger.notifyCdmaInfoRecAudioControl(aServiceId, aUpLink, aDownLink); - }, - - /** - * nsIIccMessenger API - */ - notifyStkProactiveCommand: function(aIccId, aCommand) { - this.messenger.notifyStkProactiveCommand(aIccId, aCommand); - } -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RILSystemMessengerHelper]); diff --git a/dom/system/gonk/RILSystemMessengerHelper.manifest b/dom/system/gonk/RILSystemMessengerHelper.manifest deleted file mode 100644 index 7d1943702..000000000 --- a/dom/system/gonk/RILSystemMessengerHelper.manifest +++ /dev/null @@ -1,6 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -component {19d9a4ea-580d-11e4-8f6c-37ababfaaea9} RILSystemMessengerHelper.js -contract @mozilla.org/ril/system-messenger-helper;1 {19d9a4ea-580d-11e4-8f6c-37ababfaaea9}
\ No newline at end of file diff --git a/dom/system/gonk/RadioInterfaceLayer.js b/dom/system/gonk/RadioInterfaceLayer.js deleted file mode 100644 index f5885db5d..000000000 --- a/dom/system/gonk/RadioInterfaceLayer.js +++ /dev/null @@ -1,1324 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/Sntp.jsm"); -Cu.import("resource://gre/modules/systemlibs.js"); -Cu.import("resource://gre/modules/Promise.jsm"); -Cu.import("resource://gre/modules/FileUtils.jsm"); - -XPCOMUtils.defineLazyGetter(this, "RIL", function () { - let obj = {}; - Cu.import("resource://gre/modules/ril_consts.js", obj); - return obj; -}); - -// Ril quirk to always turn the radio off for the client without SIM card -// except hw default client. -var RILQUIRKS_RADIO_OFF_WO_CARD = - libcutils.property_get("ro.moz.ril.radio_off_wo_card", "false") == "true"; - -const RADIOINTERFACELAYER_CID = - Components.ID("{2d831c8d-6017-435b-a80c-e5d422810cea}"); -const RADIOINTERFACE_CID = - Components.ID("{6a7c91f0-a2b3-4193-8562-8969296c0b54}"); - -const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown"; -const kNetworkConnStateChangedTopic = "network-connection-state-changed"; -const kMozSettingsChangedObserverTopic = "mozsettings-changed"; -const kSysMsgListenerReadyObserverTopic = "system-message-listener-ready"; -const kSysClockChangeObserverTopic = "system-clock-change"; -const kScreenStateChangedTopic = "screen-state-changed"; - -const kSettingsClockAutoUpdateEnabled = "time.clock.automatic-update.enabled"; -const kSettingsClockAutoUpdateAvailable = "time.clock.automatic-update.available"; -const kSettingsTimezoneAutoUpdateEnabled = "time.timezone.automatic-update.enabled"; -const kSettingsTimezoneAutoUpdateAvailable = "time.timezone.automatic-update.available"; - -const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed"; - -const kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces"; -const kPrefRilDebuggingEnabled = "ril.debugging.enabled"; - -const RADIO_POWER_OFF_TIMEOUT = 30000; -const HW_DEFAULT_CLIENT_ID = 0; - -const NETWORK_TYPE_WIFI = Ci.nsINetworkInfo.NETWORK_TYPE_WIFI; -const NETWORK_TYPE_MOBILE = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE; - -// set to true in ril_consts.js to see debug messages -var DEBUG = RIL.DEBUG_RIL; - -function updateDebugFlag() { - // Read debug setting from pref - let debugPref; - try { - debugPref = Services.prefs.getBoolPref(kPrefRilDebuggingEnabled); - } catch (e) { - debugPref = false; - } - DEBUG = RIL.DEBUG_RIL || debugPref; -} -updateDebugFlag(); - -function debug(s) { - dump("-*- RadioInterfaceLayer: " + s + "\n"); -} - -XPCOMUtils.defineLazyServiceGetter(this, "gIccService", - "@mozilla.org/icc/gonkiccservice;1", - "nsIGonkIccService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gMobileMessageService", - "@mozilla.org/mobilemessage/mobilemessageservice;1", - "nsIMobileMessageService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gSmsService", - "@mozilla.org/sms/gonksmsservice;1", - "nsIGonkSmsService"); - -XPCOMUtils.defineLazyServiceGetter(this, "ppmm", - "@mozilla.org/parentprocessmessagemanager;1", - "nsIMessageBroadcaster"); - -XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService", - "@mozilla.org/settingsService;1", - "nsISettingsService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager", - "@mozilla.org/network/manager;1", - "nsINetworkManager"); - -XPCOMUtils.defineLazyServiceGetter(this, "gTimeService", - "@mozilla.org/time/timeservice;1", - "nsITimeService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gSystemWorkerManager", - "@mozilla.org/telephony/system-worker-manager;1", - "nsISystemWorkerManager"); - -XPCOMUtils.defineLazyServiceGetter(this, "gTelephonyService", - "@mozilla.org/telephony/telephonyservice;1", - "nsIGonkTelephonyService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService", - "@mozilla.org/mobileconnection/mobileconnectionservice;1", - "nsIGonkMobileConnectionService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gCellBroadcastService", - "@mozilla.org/cellbroadcast/cellbroadcastservice;1", - "nsIGonkCellBroadcastService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gDataCallManager", - "@mozilla.org/datacall/manager;1", - "nsIDataCallManager"); - -XPCOMUtils.defineLazyServiceGetter(this, "gDataCallInterfaceService", - "@mozilla.org/datacall/interfaceservice;1", - "nsIGonkDataCallInterfaceService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gStkCmdFactory", - "@mozilla.org/icc/stkcmdfactory;1", - "nsIStkCmdFactory"); - -XPCOMUtils.defineLazyGetter(this, "gRadioEnabledController", function() { - let _ril = null; - let _pendingMessages = []; // For queueing "setRadioEnabled" message. - let _isProcessingPending = false; - let _timer = null; - let _request = null; - let _deactivatingDeferred = {}; - let _initializedCardState = {}; - let _allCardStateInitialized = !RILQUIRKS_RADIO_OFF_WO_CARD; - - return { - init: function(ril) { - _ril = ril; - }, - - receiveCardState: function(clientId) { - if (_allCardStateInitialized) { - return; - } - - if (DEBUG) debug("RadioControl: receive cardState from " + clientId); - _initializedCardState[clientId] = true; - if (Object.keys(_initializedCardState).length == _ril.numRadioInterfaces) { - _allCardStateInitialized = true; - this._startProcessingPending(); - } - }, - - setRadioEnabled: function(clientId, data, callback) { - if (DEBUG) debug("setRadioEnabled: " + clientId + ": " + JSON.stringify(data)); - let message = { - clientId: clientId, - data: data, - callback: callback - }; - _pendingMessages.push(message); - this._startProcessingPending(); - }, - - notifyRadioStateChanged: function(clientId, radioState) { - gMobileConnectionService.notifyRadioStateChanged(clientId, radioState); - }, - - _startProcessingPending: function() { - if (!_isProcessingPending) { - if (DEBUG) debug("RadioControl: start dequeue"); - _isProcessingPending = true; - this._processNextMessage(); - } - }, - - _processNextMessage: function() { - if (_pendingMessages.length === 0 || !_allCardStateInitialized) { - if (DEBUG) debug("RadioControl: stop dequeue"); - _isProcessingPending = false; - return; - } - - let msg = _pendingMessages.shift(); - this._handleMessage(msg); - }, - - _getNumCards: function() { - let numCards = 0; - for (let i = 0, N = _ril.numRadioInterfaces; i < N; ++i) { - if (_ril.getRadioInterface(i).isCardPresent()) { - numCards++; - } - } - return numCards; - }, - - _isRadioAbleToEnableAtClient: function(clientId, numCards) { - if (!RILQUIRKS_RADIO_OFF_WO_CARD) { - return true; - } - - // We could only turn on the radio for clientId if - // 1. a SIM card is presented or - // 2. it is the default clientId and there is no any SIM card at any client. - - if (_ril.getRadioInterface(clientId).isCardPresent()) { - return true; - } - - numCards = numCards == null ? this._getNumCards() : numCards; - if (clientId === HW_DEFAULT_CLIENT_ID && numCards === 0) { - return true; - } - - return false; - }, - - _handleMessage: function(message) { - if (DEBUG) debug("RadioControl: handleMessage: " + JSON.stringify(message)); - let clientId = message.clientId || 0; - let connection = - gMobileConnectionService.getItemByServiceId(clientId); - let radioState = connection && connection.radioState; - - if (message.data.enabled) { - if (this._isRadioAbleToEnableAtClient(clientId)) { - this._setRadioEnabledInternal(message); - } else { - // Not really do it but respond success. - message.callback(message.data); - } - - this._processNextMessage(); - } else { - _request = this._setRadioEnabledInternal.bind(this, message); - - // In 2G network, modem takes 35+ seconds to process deactivate data - // call request if device has active voice call (please see bug 964974 - // for more details). Therefore we should hangup all active voice calls - // first. And considering some DSDS architecture, toggling one radio may - // toggle both, so we send hangUpAll to all clients. - let hangUpCallback = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsITelephonyCallback]), - notifySuccess: function() {}, - notifyError: function() {} - }; - - gTelephonyService.enumerateCalls({ - QueryInterface: XPCOMUtils.generateQI([Ci.nsITelephonyListener]), - enumerateCallState: function(aInfo) { - gTelephonyService.hangUpCall(aInfo.clientId, aInfo.callIndex, - hangUpCallback); - }, - enumerateCallStateComplete: function() {} - }); - - // In some DSDS architecture with only one modem, toggling one radio may - // toggle both. Therefore, for safely turning off, we should first - // explicitly deactivate all data calls from all clients. - this._deactivateDataCalls().then(() => { - if (DEBUG) debug("RadioControl: deactivation done"); - this._executeRequest(); - }); - - this._createTimer(); - } - }, - - _setRadioEnabledInternal: function(message) { - let clientId = message.clientId || 0; - let enabled = message.data.enabled || false; - let radioInterface = _ril.getRadioInterface(clientId); - - radioInterface.workerMessenger.send("setRadioEnabled", message.data, - (function(response) { - if (response.errorMsg) { - // If request fails, set current radio state to unknown, since we will - // handle it in |mobileConnectionService|. - this.notifyRadioStateChanged(clientId, - Ci.nsIMobileConnection.MOBILE_RADIO_STATE_UNKNOWN); - } - return message.callback(response); - }).bind(this)); - }, - - _deactivateDataCalls: function() { - if (DEBUG) debug("RadioControl: deactivating data calls..."); - _deactivatingDeferred = {}; - - let promise = Promise.resolve(); - for (let i = 0, N = _ril.numRadioInterfaces; i < N; ++i) { - promise = promise.then(this._deactivateDataCallsForClient(i)); - } - - return promise; - }, - - _deactivateDataCallsForClient: function(clientId) { - return function() { - let deferred = _deactivatingDeferred[clientId] = Promise.defer(); - let dataCallHandler = gDataCallManager.getDataCallHandler(clientId); - - dataCallHandler.deactivateDataCalls(function() { - deferred.resolve(); - }); - - return deferred.promise; - }; - }, - - _createTimer: function() { - if (!_timer) { - _timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - } - _timer.initWithCallback(this._executeRequest.bind(this), - RADIO_POWER_OFF_TIMEOUT, - Ci.nsITimer.TYPE_ONE_SHOT); - }, - - _cancelTimer: function() { - if (_timer) { - _timer.cancel(); - } - }, - - _executeRequest: function() { - if (typeof _request === "function") { - if (DEBUG) debug("RadioControl: executeRequest"); - this._cancelTimer(); - _request(); - _request = null; - } - this._processNextMessage(); - }, - }; -}); - -// Initialize shared preference "ril.numRadioInterfaces" according to system -// property. -try { - Services.prefs.setIntPref(kPrefRilNumRadioInterfaces, (function() { - // When Gonk property "ro.moz.ril.numclients" is not set, return 1; if - // explicitly set to any number larger-equal than 0, return num; else, return - // 1 for compatibility. - try { - let numString = libcutils.property_get("ro.moz.ril.numclients", "1"); - let num = parseInt(numString, 10); - if (num >= 0) { - return num; - } - } catch (e) {} - - return 1; - })()); -} catch (e) {} - -function DataCall(aAttributes) { - for (let key in aAttributes) { - if (key === "pdpType") { - // Convert pdp type into constant int value. - this[key] = RIL.RIL_DATACALL_PDP_TYPES.indexOf(aAttributes[key]); - continue; - } - - this[key] = aAttributes[key]; - } -} -DataCall.prototype = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCall]), - - failCause: Ci.nsIDataCallInterface.DATACALL_FAIL_NONE, - suggestedRetryTime: -1, - cid: -1, - active: -1, - pdpType: -1, - ifname: null, - addreses: null, - dnses: null, - gateways: null, - pcscf: null, - mtu: -1 -}; - -function RadioInterfaceLayer() { - let workerMessenger = new WorkerMessenger(); - workerMessenger.init(); - this.setWorkerDebugFlag = workerMessenger.setDebugFlag.bind(workerMessenger); - - let numIfaces = this.numRadioInterfaces; - if (DEBUG) debug(numIfaces + " interfaces"); - this.radioInterfaces = []; - for (let clientId = 0; clientId < numIfaces; clientId++) { - this.radioInterfaces.push(new RadioInterface(clientId, workerMessenger)); - } - - Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); - Services.prefs.addObserver(kPrefRilDebuggingEnabled, this, false); - - gRadioEnabledController.init(this); -} -RadioInterfaceLayer.prototype = { - - classID: RADIOINTERFACELAYER_CID, - classInfo: XPCOMUtils.generateCI({classID: RADIOINTERFACELAYER_CID, - classDescription: "RadioInterfaceLayer", - interfaces: [Ci.nsIRadioInterfaceLayer]}), - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIRadioInterfaceLayer, - Ci.nsIObserver]), - - /** - * nsIObserver interface methods. - */ - - observe: function(subject, topic, data) { - switch (topic) { - case NS_XPCOM_SHUTDOWN_OBSERVER_ID: - for (let radioInterface of this.radioInterfaces) { - radioInterface.shutdown(); - } - this.radioInterfaces = null; - Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); - break; - - case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID: - if (data === kPrefRilDebuggingEnabled) { - updateDebugFlag(); - this.setWorkerDebugFlag(DEBUG); - } - break; - } - }, - - /** - * nsIRadioInterfaceLayer interface methods. - */ - - getRadioInterface: function(clientId) { - return this.radioInterfaces[clientId]; - }, - - setMicrophoneMuted: function(muted) { - for (let clientId = 0; clientId < this.numRadioInterfaces; clientId++) { - let radioInterface = this.radioInterfaces[clientId]; - radioInterface.workerMessenger.send("setMute", { muted: muted }); - } - } -}; - -XPCOMUtils.defineLazyGetter(RadioInterfaceLayer.prototype, - "numRadioInterfaces", function() { - try { - return Services.prefs.getIntPref(kPrefRilNumRadioInterfaces); - } catch(e) {} - - return 1; -}); - -function WorkerMessenger() { - // Initial owning attributes. - this.radioInterfaces = []; - this.tokenCallbackMap = {}; - - this.worker = new ChromeWorker("resource://gre/modules/ril_worker.js"); - this.worker.onerror = this.onerror.bind(this); - this.worker.onmessage = this.onmessage.bind(this); -} -WorkerMessenger.prototype = { - radioInterfaces: null, - worker: null, - - // This gets incremented each time we send out a message. - token: 1, - - // Maps tokens we send out with messages to the message callback. - tokenCallbackMap: null, - - init: function() { - let options = { - debug: DEBUG, - quirks: { - callstateExtraUint32: - libcutils.property_get("ro.moz.ril.callstate_extra_int", "false") === "true", - requestUseDialEmergencyCall: - libcutils.property_get("ro.moz.ril.dial_emergency_call", "false") === "true", - simAppStateExtraFields: - libcutils.property_get("ro.moz.ril.simstate_extra_field", "false") === "true", - extraUint2ndCall: - libcutils.property_get("ro.moz.ril.extra_int_2nd_call", "false") === "true", - haveQueryIccLockRetryCount: - libcutils.property_get("ro.moz.ril.query_icc_count", "false") === "true", - sendStkProfileDownload: - libcutils.property_get("ro.moz.ril.send_stk_profile_dl", "false") === "true", - smscAddressFormat: - libcutils.property_get("ro.moz.ril.smsc_address_format", "text"), - dataRegistrationOnDemand: - libcutils.property_get("ro.moz.ril.data_reg_on_demand", "false") === "true", - subscriptionControl: - libcutils.property_get("ro.moz.ril.subscription_control", "false") === "true", - signalExtraInt: - libcutils.property_get("ro.moz.ril.signal_extra_int", "false") === "true", - availableNetworkExtraStr: - libcutils.property_get("ro.moz.ril.avlbl_nw_extra_str", "false") === "true", - } - }; - - this.send(null, "setInitialOptions", options); - }, - - setDebugFlag: function(aDebug) { - let options = { debug: aDebug }; - this.send(null, "setDebugFlag", options); - }, - - debug: function(aClientId, aMessage) { - // We use the same debug subject with RadioInterface's here. - dump("-*- RadioInterface[" + aClientId + "]: " + aMessage + "\n"); - }, - - onerror: function(event) { - if (DEBUG) { - this.debug("X", "Got an error: " + event.filename + ":" + - event.lineno + ": " + event.message + "\n"); - } - event.preventDefault(); - }, - - /** - * Process the incoming message from the RIL worker. - */ - onmessage: function(event) { - let message = event.data; - let clientId = message.rilMessageClientId; - if (clientId === null) { - return; - } - - if (DEBUG) { - this.debug(clientId, "Received message from worker: " + JSON.stringify(message)); - } - - let token = message.rilMessageToken; - if (token == null) { - // That's an unsolicited message. Pass to RadioInterface directly. - let radioInterface = this.radioInterfaces[clientId]; - radioInterface.handleUnsolicitedWorkerMessage(message); - return; - } - - let callback = this.tokenCallbackMap[message.rilMessageToken]; - if (!callback) { - if (DEBUG) this.debug(clientId, "Ignore orphan token: " + message.rilMessageToken); - return; - } - - let keep = false; - try { - keep = callback(message); - } catch(e) { - if (DEBUG) this.debug(clientId, "callback throws an exception: " + e); - } - - if (!keep) { - delete this.tokenCallbackMap[message.rilMessageToken]; - } - }, - - registerClient: function(aClientId, aRadioInterface) { - if (DEBUG) this.debug(aClientId, "Starting RIL Worker"); - - // Keep a reference so that we can dispatch unsolicited messages to it. - this.radioInterfaces[aClientId] = aRadioInterface; - - this.send(null, "registerClient", { clientId: aClientId }); - gSystemWorkerManager.registerRilWorker(aClientId, this.worker); - }, - - /** - * Send arbitrary message to worker. - * - * @param rilMessageType - * A text message type. - * @param message [optional] - * An optional message object to send. - * @param callback [optional] - * An optional callback function which is called when worker replies - * with an message containing a "rilMessageToken" attribute of the - * same value we passed. This callback function accepts only one - * parameter -- the reply from worker. It also returns a boolean - * value true to keep current token-callback mapping and wait for - * another worker reply, or false to remove the mapping. - */ - send: function(clientId, rilMessageType, message, callback) { - message = message || {}; - - message.rilMessageClientId = clientId; - message.rilMessageToken = this.token; - this.token++; - - if (callback) { - // Only create the map if callback is provided. For sending a request - // and intentionally leaving the callback undefined, that reply will - // be dropped in |this.onmessage| because of that orphan token. - // - // For sending a request that never replied at all, we're fine with this - // because no callback shall be passed and we leave nothing to be cleaned - // up later. - this.tokenCallbackMap[message.rilMessageToken] = callback; - } - - message.rilMessageType = rilMessageType; - this.worker.postMessage(message); - } -}; - -function RadioInterface(aClientId, aWorkerMessenger) { - this.clientId = aClientId; - this.workerMessenger = { - send: aWorkerMessenger.send.bind(aWorkerMessenger, aClientId) - }; - aWorkerMessenger.registerClient(aClientId, this); - - this.operatorInfo = {}; - - let lock = gSettingsService.createLock(); - - // Read the "time.clock.automatic-update.enabled" setting to see if - // we need to adjust the system clock time by NITZ or SNTP. - lock.get(kSettingsClockAutoUpdateEnabled, this); - - // Read the "time.timezone.automatic-update.enabled" setting to see if - // we need to adjust the system timezone by NITZ. - lock.get(kSettingsTimezoneAutoUpdateEnabled, this); - - // Set "time.clock.automatic-update.available" to false when starting up. - this.setClockAutoUpdateAvailable(false); - - // Set "time.timezone.automatic-update.available" to false when starting up. - this.setTimezoneAutoUpdateAvailable(false); - - Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false); - Services.obs.addObserver(this, kSysClockChangeObserverTopic, false); - Services.obs.addObserver(this, kScreenStateChangedTopic, false); - - Services.obs.addObserver(this, kNetworkConnStateChangedTopic, false); - - this._sntp = new Sntp(this.setClockBySntp.bind(this), - Services.prefs.getIntPref("network.sntp.maxRetryCount"), - Services.prefs.getIntPref("network.sntp.refreshPeriod"), - Services.prefs.getIntPref("network.sntp.timeout"), - Services.prefs.getCharPref("network.sntp.pools").split(";"), - Services.prefs.getIntPref("network.sntp.port")); -} - -RadioInterface.prototype = { - - classID: RADIOINTERFACE_CID, - classInfo: XPCOMUtils.generateCI({classID: RADIOINTERFACE_CID, - classDescription: "RadioInterface", - interfaces: [Ci.nsIRadioInterface]}), - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIRadioInterface, - Ci.nsIObserver, - Ci.nsISettingsServiceCallback]), - - // A private wrapped WorkerMessenger instance. - workerMessenger: null, - - debug: function(s) { - dump("-*- RadioInterface[" + this.clientId + "]: " + s + "\n"); - }, - - shutdown: function() { - Services.obs.removeObserver(this, kMozSettingsChangedObserverTopic); - Services.obs.removeObserver(this, kSysClockChangeObserverTopic); - Services.obs.removeObserver(this, kScreenStateChangedTopic); - Services.obs.removeObserver(this, kNetworkConnStateChangedTopic); - }, - - isCardPresent: function() { - let icc = gIccService.getIccByServiceId(this.clientId); - let cardState = icc ? icc.cardState : Ci.nsIIcc.CARD_STATE_UNKNOWN; - return cardState !== Ci.nsIIcc.CARD_STATE_UNDETECTED && - cardState !== Ci.nsIIcc.CARD_STATE_UNKNOWN; - }, - - handleUnsolicitedWorkerMessage: function(message) { - switch (message.rilMessageType) { - case "callRing": - gTelephonyService.notifyCallRing(); - break; - case "currentCalls": - gTelephonyService.notifyCurrentCalls(this.clientId, message.calls); - break; - case "cdmaCallWaiting": - gTelephonyService.notifyCdmaCallWaiting(this.clientId, - message.waitingCall); - break; - case "suppSvcNotification": - gTelephonyService.notifySupplementaryService(this.clientId, - message.number, - message.notification); - break; - case "ussdreceived": - gTelephonyService.notifyUssdReceived(this.clientId, message.message, - message.sessionEnded); - break; - case "datacalllistchanged": - let dataCalls = message.datacalls.map(dataCall => new DataCall(dataCall)); - gDataCallInterfaceService.notifyDataCallListChanged(this.clientId, - dataCalls.length, - dataCalls); - break; - case "emergencyCbModeChange": - gMobileConnectionService.notifyEmergencyCallbackModeChanged(this.clientId, - message.active, - message.timeoutMs); - break; - case "networkinfochanged": - gMobileConnectionService.notifyNetworkInfoChanged(this.clientId, - message); - break; - case "networkselectionmodechange": - gMobileConnectionService.notifyNetworkSelectModeChanged(this.clientId, - message.mode); - break; - case "voiceregistrationstatechange": - gMobileConnectionService.notifyVoiceInfoChanged(this.clientId, message); - break; - case "dataregistrationstatechange": - gMobileConnectionService.notifyDataInfoChanged(this.clientId, message); - break; - case "signalstrengthchange": - gMobileConnectionService.notifySignalStrengthChanged(this.clientId, - message); - break; - case "operatorchange": - gMobileConnectionService.notifyOperatorChanged(this.clientId, message); - break; - case "otastatuschange": - gMobileConnectionService.notifyOtaStatusChanged(this.clientId, message.status); - break; - case "deviceidentitieschange": - gMobileConnectionService.notifyDeviceIdentitiesChanged(this.clientId, - message.deviceIdentities.imei, - message.deviceIdentities.imeisv, - message.deviceIdentities.esn, - message.deviceIdentities.meid); - break; - case "radiostatechange": - // gRadioEnabledController should know the radio state for each client, - // so notify gRadioEnabledController here. - gRadioEnabledController.notifyRadioStateChanged(this.clientId, - message.radioState); - break; - case "cardstatechange": - gIccService.notifyCardStateChanged(this.clientId, - message.cardState); - gRadioEnabledController.receiveCardState(this.clientId); - break; - case "sms-received": - this.handleSmsReceived(message); - break; - case "cellbroadcast-received": - this.handleCellbroadcastMessageReceived(message); - break; - case "nitzTime": - this.handleNitzTime(message); - break; - case "iccinfochange": - gIccService.notifyIccInfoChanged(this.clientId, - message.iccid ? message : null); - break; - case "iccimsi": - gIccService.notifyImsiChanged(this.clientId, message.imsi); - break; - case "iccmbdn": - this.handleIccMbdn(message); - break; - case "iccmwis": - this.handleIccMwis(message.mwi); - break; - case "stkcommand": - gIccService.notifyStkCommand(this.clientId, - gStkCmdFactory.createCommand(message)); - break; - case "stksessionend": - gIccService.notifyStkSessionEnd(this.clientId); - break; - case "cdma-info-rec-received": - this.handleCdmaInformationRecords(message.records); - break; - default: - throw new Error("Don't know about this message type: " + - message.rilMessageType); - } - }, - - setDataRegistration: function(attach) { - let deferred = Promise.defer(); - this.workerMessenger.send("setDataRegistration", - {attach: attach}, - (function(response) { - // Always resolve to proceed with the following steps. - deferred.resolve(response.errorMsg ? response.errorMsg : null); - }).bind(this)); - - return deferred.promise; - }, - - /** - * TODO: Bug 911713 - B2G NetworkManager: Move policy control logic to - * NetworkManager - */ - updateRILNetworkInterface: function() { - let connHandler = gDataCallManager.getDataCallHandler(this.clientId); - connHandler.updateRILNetworkInterface(); - }, - - /** - * handle received SMS. - */ - handleSmsReceived: function(aMessage) { - let header = aMessage.header; - // Concatenation Info: - // - segmentRef: a modulo 256 counter indicating the reference number for a - // particular concatenated short message. '0' is a valid number. - // - The concatenation info will not be available in |header| if - // segmentSeq or segmentMaxSeq is 0. - // See 3GPP TS 23.040, 9.2.3.24.1 Concatenated Short Messages. - let segmentRef = (header && header.segmentRef !== undefined) - ? header.segmentRef : 1; - let segmentSeq = header && header.segmentSeq || 1; - let segmentMaxSeq = header && header.segmentMaxSeq || 1; - // Application Ports: - // The port number ranges from 0 to 49151. - // see 3GPP TS 23.040, 9.2.3.24.3/4 Application Port Addressing. - let originatorPort = (header && header.originatorPort !== undefined) - ? header.originatorPort - : Ci.nsIGonkSmsService.SMS_APPLICATION_PORT_INVALID; - let destinationPort = (header && header.destinationPort !== undefined) - ? header.destinationPort - : Ci.nsIGonkSmsService.SMS_APPLICATION_PORT_INVALID; - // MWI info: - let mwiPresent = (aMessage.mwi)? true : false; - let mwiDiscard = (mwiPresent)? aMessage.mwi.discard: false; - let mwiMsgCount = (mwiPresent)? aMessage.mwi.msgCount: 0; - let mwiActive = (mwiPresent)? aMessage.mwi.active: false; - // CDMA related attributes: - let cdmaMessageType = aMessage.messageType || 0; - let cdmaTeleservice = aMessage.teleservice || 0; - let cdmaServiceCategory = aMessage.serviceCategory || 0; - - gSmsService - .notifyMessageReceived(this.clientId, - aMessage.SMSC || null, - aMessage.sentTimestamp, - aMessage.sender, - aMessage.pid, - aMessage.encoding, - RIL.GECKO_SMS_MESSAGE_CLASSES - .indexOf(aMessage.messageClass), - aMessage.language || null, - segmentRef, - segmentSeq, - segmentMaxSeq, - originatorPort, - destinationPort, - mwiPresent, - mwiDiscard, - mwiMsgCount, - mwiActive, - cdmaMessageType, - cdmaTeleservice, - cdmaServiceCategory, - aMessage.body || null, - aMessage.data || [], - (aMessage.data) ? aMessage.data.length : 0); - }, - - /** - * Set the setting value of "time.clock.automatic-update.available". - */ - setClockAutoUpdateAvailable: function(value) { - gSettingsService.createLock().set(kSettingsClockAutoUpdateAvailable, value, null); - }, - - /** - * Set the setting value of "time.timezone.automatic-update.available". - */ - setTimezoneAutoUpdateAvailable: function(value) { - gSettingsService.createLock().set(kSettingsTimezoneAutoUpdateAvailable, value, null); - }, - - /** - * Set the system clock by NITZ. - */ - setClockByNitz: function(message) { - // To set the system clock time. Note that there could be a time diff - // between when the NITZ was received and when the time is actually set. - gTimeService.set( - message.networkTimeInMS + (Date.now() - message.receiveTimeInMS)); - }, - - /** - * Set the system time zone by NITZ. - */ - setTimezoneByNitz: function(message) { - // To set the sytem timezone. Note that we need to convert the time zone - // value to a UTC repesentation string in the format of "UTC(+/-)hh:mm". - // Ex, time zone -480 is "UTC+08:00"; time zone 630 is "UTC-10:30". - // - // We can unapply the DST correction if we want the raw time zone offset: - // message.networkTimeZoneInMinutes -= message.networkDSTInMinutes; - if (message.networkTimeZoneInMinutes != (new Date()).getTimezoneOffset()) { - let absTimeZoneInMinutes = Math.abs(message.networkTimeZoneInMinutes); - let timeZoneStr = "UTC"; - timeZoneStr += (message.networkTimeZoneInMinutes > 0 ? "-" : "+"); - timeZoneStr += ("0" + Math.floor(absTimeZoneInMinutes / 60)).slice(-2); - timeZoneStr += ":"; - timeZoneStr += ("0" + absTimeZoneInMinutes % 60).slice(-2); - gSettingsService.createLock().set("time.timezone", timeZoneStr, null); - } - }, - - /** - * Handle the NITZ message. - */ - handleNitzTime: function(message) { - // Got the NITZ info received from the ril_worker. - this.setClockAutoUpdateAvailable(true); - this.setTimezoneAutoUpdateAvailable(true); - - // Cache the latest NITZ message whenever receiving it. - this._lastNitzMessage = message; - - // Set the received NITZ clock if the setting is enabled. - if (this._clockAutoUpdateEnabled) { - this.setClockByNitz(message); - } - // Set the received NITZ timezone if the setting is enabled. - if (this._timezoneAutoUpdateEnabled) { - this.setTimezoneByNitz(message); - } - }, - - /** - * Set the system clock by SNTP. - */ - setClockBySntp: function(offset) { - // Got the SNTP info. - this.setClockAutoUpdateAvailable(true); - if (!this._clockAutoUpdateEnabled) { - return; - } - if (this._lastNitzMessage) { - if (DEBUG) debug("SNTP: NITZ available, discard SNTP"); - return; - } - gTimeService.set(Date.now() + offset); - }, - - handleIccMbdn: function(message) { - let service = Cc["@mozilla.org/voicemail/voicemailservice;1"] - .getService(Ci.nsIGonkVoicemailService); - service.notifyInfoChanged(this.clientId, message.number, message.alphaId); - }, - - handleIccMwis: function(mwi) { - let service = Cc["@mozilla.org/voicemail/voicemailservice;1"] - .getService(Ci.nsIGonkVoicemailService); - // Note: returnNumber and returnMessage is not available from UICC. - service.notifyStatusChanged(this.clientId, mwi.active, mwi.msgCount, - null, null); - }, - - _convertCbGsmGeographicalScope: function(aGeographicalScope) { - return (aGeographicalScope != null) - ? aGeographicalScope - : Ci.nsICellBroadcastService.GSM_GEOGRAPHICAL_SCOPE_INVALID; - }, - - _convertCbMessageClass: function(aMessageClass) { - let index = RIL.GECKO_SMS_MESSAGE_CLASSES.indexOf(aMessageClass); - return (index != -1) - ? index - : Ci.nsICellBroadcastService.GSM_MESSAGE_CLASS_NORMAL; - }, - - _convertCbEtwsWarningType: function(aWarningType) { - return (aWarningType != null) - ? aWarningType - : Ci.nsICellBroadcastService.GSM_ETWS_WARNING_INVALID; - }, - - handleCellbroadcastMessageReceived: function(aMessage) { - let etwsInfo = aMessage.etws; - let hasEtwsInfo = etwsInfo != null; - let serviceCategory = (aMessage.serviceCategory) - ? aMessage.serviceCategory - : Ci.nsICellBroadcastService.CDMA_SERVICE_CATEGORY_INVALID; - - gCellBroadcastService - .notifyMessageReceived(this.clientId, - this._convertCbGsmGeographicalScope(aMessage.geographicalScope), - aMessage.messageCode, - aMessage.messageId, - aMessage.language, - aMessage.fullBody, - this._convertCbMessageClass(aMessage.messageClass), - Date.now(), - serviceCategory, - hasEtwsInfo, - (hasEtwsInfo) - ? this._convertCbEtwsWarningType(etwsInfo.warningType) - : Ci.nsICellBroadcastService.GSM_ETWS_WARNING_INVALID, - hasEtwsInfo ? etwsInfo.emergencyUserAlert : false, - hasEtwsInfo ? etwsInfo.popup : false); - }, - - handleCdmaInformationRecords: function(aRecords) { - if (DEBUG) this.debug("cdma-info-rec-received: " + JSON.stringify(aRecords)); - - let clientId = this.clientId; - - aRecords.forEach(function(aRecord) { - if (aRecord.display) { - gMobileConnectionService - .notifyCdmaInfoRecDisplay(clientId, aRecord.display); - return; - } - - if (aRecord.calledNumber) { - gMobileConnectionService - .notifyCdmaInfoRecCalledPartyNumber(clientId, - aRecord.calledNumber.type, - aRecord.calledNumber.plan, - aRecord.calledNumber.number, - aRecord.calledNumber.pi, - aRecord.calledNumber.si); - return; - } - - if (aRecord.callingNumber) { - gMobileConnectionService - .notifyCdmaInfoRecCallingPartyNumber(clientId, - aRecord.callingNumber.type, - aRecord.callingNumber.plan, - aRecord.callingNumber.number, - aRecord.callingNumber.pi, - aRecord.callingNumber.si); - return; - } - - if (aRecord.connectedNumber) { - gMobileConnectionService - .notifyCdmaInfoRecConnectedPartyNumber(clientId, - aRecord.connectedNumber.type, - aRecord.connectedNumber.plan, - aRecord.connectedNumber.number, - aRecord.connectedNumber.pi, - aRecord.connectedNumber.si); - return; - } - - if (aRecord.signal) { - gMobileConnectionService - .notifyCdmaInfoRecSignal(clientId, - aRecord.signal.type, - aRecord.signal.alertPitch, - aRecord.signal.signal); - return; - } - - if (aRecord.redirect) { - gMobileConnectionService - .notifyCdmaInfoRecRedirectingNumber(clientId, - aRecord.redirect.type, - aRecord.redirect.plan, - aRecord.redirect.number, - aRecord.redirect.pi, - aRecord.redirect.si, - aRecord.redirect.reason); - return; - } - - if (aRecord.lineControl) { - gMobileConnectionService - .notifyCdmaInfoRecLineControl(clientId, - aRecord.lineControl.polarityIncluded, - aRecord.lineControl.toggle, - aRecord.lineControl.reverse, - aRecord.lineControl.powerDenial); - return; - } - - if (aRecord.clirCause) { - gMobileConnectionService - .notifyCdmaInfoRecClir(clientId, - aRecord.clirCause); - return; - } - - if (aRecord.audioControl) { - gMobileConnectionService - .notifyCdmaInfoRecAudioControl(clientId, - aRecord.audioControl.upLink, - aRecord.audioControl.downLink); - return; - } - }); - }, - - // nsIObserver - - observe: function(subject, topic, data) { - switch (topic) { - case kMozSettingsChangedObserverTopic: - if ("wrappedJSObject" in subject) { - subject = subject.wrappedJSObject; - } - this.handleSettingsChange(subject.key, subject.value, subject.isInternalChange); - break; - case kSysClockChangeObserverTopic: - let offset = parseInt(data, 10); - if (this._lastNitzMessage) { - this._lastNitzMessage.receiveTimeInMS += offset; - } - this._sntp.updateOffset(offset); - break; - case kNetworkConnStateChangedTopic: - let networkInfo = subject.QueryInterface(Ci.nsINetworkInfo); - if (networkInfo.state != Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) { - return; - } - - // SNTP can only update when we have mobile or Wifi connections. - if (networkInfo.type != NETWORK_TYPE_WIFI && - networkInfo.type != NETWORK_TYPE_MOBILE) { - return; - } - - // If the network comes from RIL, make sure the RIL service is matched. - if (subject instanceof Ci.nsIRilNetworkInfo) { - networkInfo = subject.QueryInterface(Ci.nsIRilNetworkInfo); - if (networkInfo.serviceId != this.clientId) { - return; - } - } - - // SNTP won't update unless the SNTP is already expired. - if (this._sntp.isExpired()) { - this._sntp.request(); - } - break; - case kScreenStateChangedTopic: - this.workerMessenger.send("setScreenState", { on: (data === "on") }); - break; - } - }, - - // Flag to determine whether to update system clock automatically. It - // corresponds to the "time.clock.automatic-update.enabled" setting. - _clockAutoUpdateEnabled: null, - - // Flag to determine whether to update system timezone automatically. It - // corresponds to the "time.clock.automatic-update.enabled" setting. - _timezoneAutoUpdateEnabled: null, - - // Remember the last NITZ message so that we can set the time based on - // the network immediately when users enable network-based time. - _lastNitzMessage: null, - - // Object that handles SNTP. - _sntp: null, - - // Cell Broadcast settings values. - _cellBroadcastSearchList: null, - - handleSettingsChange: function(aName, aResult, aIsInternalSetting) { - // Don't allow any content processes to modify the setting - // "time.clock.automatic-update.available" except for the chrome process. - if (aName === kSettingsClockAutoUpdateAvailable && - !aIsInternalSetting) { - let isClockAutoUpdateAvailable = this._lastNitzMessage !== null || - this._sntp.isAvailable(); - if (aResult !== isClockAutoUpdateAvailable) { - if (DEBUG) { - debug("Content processes cannot modify 'time.clock.automatic-update.available'. Restore!"); - } - // Restore the setting to the current value. - this.setClockAutoUpdateAvailable(isClockAutoUpdateAvailable); - } - } - - // Don't allow any content processes to modify the setting - // "time.timezone.automatic-update.available" except for the chrome - // process. - if (aName === kSettingsTimezoneAutoUpdateAvailable && - !aIsInternalSetting) { - let isTimezoneAutoUpdateAvailable = this._lastNitzMessage !== null; - if (aResult !== isTimezoneAutoUpdateAvailable) { - if (DEBUG) { - this.debug("Content processes cannot modify 'time.timezone.automatic-update.available'. Restore!"); - } - // Restore the setting to the current value. - this.setTimezoneAutoUpdateAvailable(isTimezoneAutoUpdateAvailable); - } - } - - this.handle(aName, aResult); - }, - - // nsISettingsServiceCallback - handle: function(aName, aResult) { - switch(aName) { - case kSettingsClockAutoUpdateEnabled: - this._clockAutoUpdateEnabled = aResult; - if (!this._clockAutoUpdateEnabled) { - break; - } - - // Set the latest cached NITZ time if it's available. - if (this._lastNitzMessage) { - this.setClockByNitz(this._lastNitzMessage); - } else if (gNetworkManager.activeNetworkInfo && - gNetworkManager.activeNetworkInfo.state == - Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) { - // Set the latest cached SNTP time if it's available. - if (!this._sntp.isExpired()) { - this.setClockBySntp(this._sntp.getOffset()); - } else { - // Or refresh the SNTP. - this._sntp.request(); - } - } else { - // Set a sane minimum time. - let buildTime = libcutils.property_get("ro.build.date.utc", "0") * 1000; - let file = FileUtils.File("/system/b2g/b2g"); - if (file.lastModifiedTime > buildTime) { - buildTime = file.lastModifiedTime; - } - if (buildTime > Date.now()) { - gTimeService.set(buildTime); - } - } - break; - case kSettingsTimezoneAutoUpdateEnabled: - this._timezoneAutoUpdateEnabled = aResult; - - if (this._timezoneAutoUpdateEnabled) { - // Apply the latest cached NITZ for timezone if it's available. - if (this._timezoneAutoUpdateEnabled && this._lastNitzMessage) { - this.setTimezoneByNitz(this._lastNitzMessage); - } - } - break; - } - }, - - handleError: function(aErrorMessage) { - if (DEBUG) { - this.debug("There was an error while reading RIL settings."); - } - }, - - // nsIRadioInterface - - // TODO: Bug 928861 - B2G NetworkManager: Provide a more generic function - // for connecting - setupDataCallByType: function(networkType) { - let connHandler = gDataCallManager.getDataCallHandler(this.clientId); - connHandler.setupDataCallByType(networkType); - }, - - // TODO: Bug 928861 - B2G NetworkManager: Provide a more generic function - // for connecting - deactivateDataCallByType: function(networkType) { - let connHandler = gDataCallManager.getDataCallHandler(this.clientId); - connHandler.deactivateDataCallByType(networkType); - }, - - // TODO: Bug 904514 - [meta] NetworkManager enhancement - getDataCallStateByType: function(networkType) { - let connHandler = gDataCallManager.getDataCallHandler(this.clientId); - return connHandler.getDataCallStateByType(networkType); - }, - - sendWorkerMessage: function(rilMessageType, message, callback) { - // Special handler for setRadioEnabled. - if (rilMessageType === "setRadioEnabled") { - // Forward it to gRadioEnabledController. - gRadioEnabledController.setRadioEnabled(this.clientId, message, - callback.handleResponse); - return; - } - - if (callback) { - this.workerMessenger.send(rilMessageType, message, function(response) { - return callback.handleResponse(response); - }); - } else { - this.workerMessenger.send(rilMessageType, message); - } - }, -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RadioInterfaceLayer]); diff --git a/dom/system/gonk/RadioInterfaceLayer.manifest b/dom/system/gonk/RadioInterfaceLayer.manifest deleted file mode 100644 index 3c7c3b808..000000000 --- a/dom/system/gonk/RadioInterfaceLayer.manifest +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2012 Mozilla Foundation and Mozilla contributors -# -# 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. - -# RadioInterfaceLayer.js -component {2d831c8d-6017-435b-a80c-e5d422810cea} RadioInterfaceLayer.js -contract @mozilla.org/ril;1 {2d831c8d-6017-435b-a80c-e5d422810cea} -category profile-after-change RadioInterfaceLayer @mozilla.org/ril;1 diff --git a/dom/system/gonk/SystemProperty.cpp b/dom/system/gonk/SystemProperty.cpp deleted file mode 100644 index 1f874ce90..000000000 --- a/dom/system/gonk/SystemProperty.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "SystemProperty.h" - -#include <dlfcn.h> -#include <string.h> - -#include "nsDebug.h" -#include "prinit.h" - -namespace mozilla { -namespace system { - -namespace { - -typedef int (*PropertyGet)(const char*, char*, const char*); -typedef int (*PropertySet)(const char*, const char*); - -static void *sLibcUtils; -static PRCallOnceType sInitLibcUtils; - -static int -FakePropertyGet(const char* key, char* value, const char* default_value) -{ - if(!default_value) { - value[0] = '\0'; - return 0; - } - - int len = strlen(default_value); - if (len >= Property::VALUE_MAX_LENGTH) { - len = Property::VALUE_MAX_LENGTH - 1; - } - memcpy(value, default_value, len); - value[len] = '\0'; - - return len; -} - -static int -FakePropertySet(const char* key, const char* value) -{ - return 0; -} - -static PRStatus -InitLibcUtils() -{ - sLibcUtils = dlopen("/system/lib/libcutils.so", RTLD_LAZY); - // We will fallback to the fake getter/setter when sLibcUtils is not valid. - return PR_SUCCESS; -} - -static void* -GetLibcUtils() -{ - PR_CallOnce(&sInitLibcUtils, InitLibcUtils); - return sLibcUtils; -} - -} // anonymous namespace - -/*static*/ int -Property::Get(const char* key, char* value, const char* default_value) -{ - void *libcutils = GetLibcUtils(); - if (libcutils) { - PropertyGet getter = (PropertyGet) dlsym(libcutils, "property_get"); - if (getter) { - return getter(key, value, default_value); - } - NS_WARNING("Failed to get property_get() from libcutils!"); - } - NS_WARNING("Fallback to the FakePropertyGet()"); - return FakePropertyGet(key, value, default_value); -} - -/*static*/ int -Property::Set(const char* key, const char* value) -{ - void *libcutils = GetLibcUtils(); - if (libcutils) { - PropertySet setter = (PropertySet) dlsym(libcutils, "property_set"); - if (setter) { - return setter(key, value); - } - NS_WARNING("Failed to get property_set() from libcutils!"); - } - NS_WARNING("Fallback to the FakePropertySet()"); - return FakePropertySet(key, value); -} - -} // namespace system -} // namespace mozilla diff --git a/dom/system/gonk/SystemProperty.h b/dom/system/gonk/SystemProperty.h deleted file mode 100644 index 2b5ceae8b..000000000 --- a/dom/system/gonk/SystemProperty.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_Property_h -#define mozilla_system_Property_h - -namespace mozilla { -namespace system { - -/** -* Abstraction of property_get/property_get in libcutils from AOSP. -*/ -class Property -{ -public: - // Constants defined in system_properties.h from AOSP. - enum { - KEY_MAX_LENGTH = 32, - VALUE_MAX_LENGTH = 92 - }; - - static int - Get(const char* key, char* value, const char* default_value); - - static int - Set(const char* key, const char* value); - -private: - Property() {} - virtual ~Property() {} -}; - -} // namespace system -} // namespace mozilla - - #endif // mozilla_system_Property_h diff --git a/dom/system/gonk/SystemWorkerManager.cpp b/dom/system/gonk/SystemWorkerManager.cpp deleted file mode 100644 index ee3fc8de3..000000000 --- a/dom/system/gonk/SystemWorkerManager.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include "SystemWorkerManager.h" - -#include "nsINetworkService.h" -#include "nsIWifi.h" -#include "nsIWorkerHolder.h" -#include "nsIXPConnect.h" - -#include "jsfriendapi.h" -#include "mozilla/dom/workers/Workers.h" -#include "AutoMounter.h" -#include "TimeZoneSettingObserver.h" -#include "AudioManager.h" -#include "mozilla/dom/ScriptSettings.h" -#include "mozilla/ipc/KeyStore.h" -#include "nsIObserverService.h" -#include "nsServiceManagerUtils.h" -#include "nsThreadUtils.h" -#include "WifiWorker.h" -#include "mozilla/Services.h" - -USING_WORKERS_NAMESPACE - -using namespace mozilla::dom::gonk; -using namespace mozilla::ipc; -using namespace mozilla::system; - -namespace { - -NS_DEFINE_CID(kWifiWorkerCID, NS_WIFIWORKER_CID); - -// Doesn't carry a reference, we're owned by services. -SystemWorkerManager *gInstance = nullptr; - -} // namespace - -SystemWorkerManager::SystemWorkerManager() - : mShutdown(false) -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - NS_ASSERTION(!gInstance, "There should only be one instance!"); -} - -SystemWorkerManager::~SystemWorkerManager() -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - NS_ASSERTION(!gInstance || gInstance == this, - "There should only be one instance!"); - gInstance = nullptr; -} - -nsresult -SystemWorkerManager::Init() -{ - if (!XRE_IsParentProcess()) { - return NS_ERROR_NOT_AVAILABLE; - } - - NS_ASSERTION(NS_IsMainThread(), "We can only initialize on the main thread"); - NS_ASSERTION(!mShutdown, "Already shutdown!"); - - nsresult rv = InitWifi(); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to initialize WiFi Networking!"); - return rv; - } - - InitKeyStore(); - - InitAutoMounter(); - InitializeTimeZoneSettingObserver(); - nsCOMPtr<nsIAudioManager> audioManager = - do_GetService(NS_AUDIOMANAGER_CONTRACTID); - - nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); - if (!obs) { - NS_WARNING("Failed to get observer service!"); - return NS_ERROR_FAILURE; - } - - rv = obs->AddObserver(this, WORKERS_SHUTDOWN_TOPIC, false); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to initialize worker shutdown event!"); - return rv; - } - - return NS_OK; -} - -void -SystemWorkerManager::Shutdown() -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - - mShutdown = true; - - ShutdownAutoMounter(); - - nsCOMPtr<nsIWifi> wifi(do_QueryInterface(mWifiWorker)); - if (wifi) { - wifi->Shutdown(); - wifi = nullptr; - } - mWifiWorker = nullptr; - - if (mKeyStore) { - mKeyStore->Shutdown(); - mKeyStore = nullptr; - } - - nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); - if (obs) { - obs->RemoveObserver(this, WORKERS_SHUTDOWN_TOPIC); - } -} - -// static -already_AddRefed<SystemWorkerManager> -SystemWorkerManager::FactoryCreate() -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - - RefPtr<SystemWorkerManager> instance(gInstance); - - if (!instance) { - instance = new SystemWorkerManager(); - if (NS_FAILED(instance->Init())) { - instance->Shutdown(); - return nullptr; - } - - gInstance = instance; - } - - return instance.forget(); -} - -// static -nsIInterfaceRequestor* -SystemWorkerManager::GetInterfaceRequestor() -{ - return gInstance; -} - -NS_IMETHODIMP -SystemWorkerManager::GetInterface(const nsIID &aIID, void **aResult) -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - - if (aIID.Equals(NS_GET_IID(nsIWifi))) { - return CallQueryInterface(mWifiWorker, - reinterpret_cast<nsIWifi**>(aResult)); - } - - NS_WARNING("Got nothing for the requested IID!"); - return NS_ERROR_NO_INTERFACE; -} - -nsresult -SystemWorkerManager::RegisterRilWorker(unsigned int aClientId, - JS::Handle<JS::Value> aWorker, - JSContext *aCx) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -nsresult -SystemWorkerManager::InitWifi() -{ - nsCOMPtr<nsIWorkerHolder> worker = do_CreateInstance(kWifiWorkerCID); - NS_ENSURE_TRUE(worker, NS_ERROR_FAILURE); - - mWifiWorker = worker; - return NS_OK; -} - -nsresult -SystemWorkerManager::InitKeyStore() -{ - mKeyStore = new KeyStore(); - return NS_OK; -} - -NS_IMPL_ISUPPORTS(SystemWorkerManager, - nsIObserver, - nsIInterfaceRequestor, - nsISystemWorkerManager) - -NS_IMETHODIMP -SystemWorkerManager::Observe(nsISupports *aSubject, const char *aTopic, - const char16_t *aData) -{ - if (!strcmp(aTopic, WORKERS_SHUTDOWN_TOPIC)) { - Shutdown(); - } - - return NS_OK; -} diff --git a/dom/system/gonk/SystemWorkerManager.h b/dom/system/gonk/SystemWorkerManager.h deleted file mode 100644 index 625cda261..000000000 --- a/dom/system/gonk/SystemWorkerManager.h +++ /dev/null @@ -1,75 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=40: */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef mozilla_dom_system_b2g_systemworkermanager_h__ -#define mozilla_dom_system_b2g_systemworkermanager_h__ - -#include "nsIInterfaceRequestor.h" -#include "nsISystemWorkerManager.h" -#include "nsIObserver.h" -#include "nsCOMPtr.h" -#include "nsXULAppAPI.h" // For XRE_GetProcessType - -class nsIWorkerHolder; - -namespace mozilla { - -namespace ipc { - class KeyStore; -} - -namespace dom { -namespace gonk { - -class SystemWorkerManager final : public nsIObserver, - public nsIInterfaceRequestor, - public nsISystemWorkerManager -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER - NS_DECL_NSIINTERFACEREQUESTOR - NS_DECL_NSISYSTEMWORKERMANAGER - - nsresult Init(); - void Shutdown(); - - static already_AddRefed<SystemWorkerManager> - FactoryCreate(); - - static nsIInterfaceRequestor* - GetInterfaceRequestor(); - -private: - SystemWorkerManager(); - ~SystemWorkerManager(); - - nsresult InitWifi(); - nsresult InitKeyStore(); - - nsCOMPtr<nsIWorkerHolder> mWifiWorker; - - RefPtr<mozilla::ipc::KeyStore> mKeyStore; - - bool mShutdown; -}; - -} -} -} - -#endif // mozilla_dom_system_b2g_systemworkermanager_h__ diff --git a/dom/system/gonk/TetheringService.js b/dom/system/gonk/TetheringService.js deleted file mode 100644 index c5c478180..000000000 --- a/dom/system/gonk/TetheringService.js +++ /dev/null @@ -1,891 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/FileUtils.jsm"); -Cu.import("resource://gre/modules/systemlibs.js"); - -const TETHERINGSERVICE_CONTRACTID = "@mozilla.org/tethering/service;1"; -const TETHERINGSERVICE_CID = - Components.ID("{527a4121-ee5a-4651-be9c-f46f59cf7c01}"); - -XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager", - "@mozilla.org/network/manager;1", - "nsINetworkManager"); - -XPCOMUtils.defineLazyServiceGetter(this, "gNetworkService", - "@mozilla.org/network/service;1", - "nsINetworkService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService", - "@mozilla.org/settingsService;1", - "nsISettingsService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService", - "@mozilla.org/mobileconnection/mobileconnectionservice;1", - "nsIMobileConnectionService"); - -XPCOMUtils.defineLazyGetter(this, "gRil", function() { - try { - return Cc["@mozilla.org/ril;1"].getService(Ci.nsIRadioInterfaceLayer); - } catch (e) {} - - return null; -}); - -const TOPIC_MOZSETTINGS_CHANGED = "mozsettings-changed"; -const TOPIC_CONNECTION_STATE_CHANGED = "network-connection-state-changed"; -const TOPIC_PREF_CHANGED = "nsPref:changed"; -const TOPIC_XPCOM_SHUTDOWN = "xpcom-shutdown"; -const PREF_MANAGE_OFFLINE_STATUS = "network.gonk.manage-offline-status"; -const PREF_NETWORK_DEBUG_ENABLED = "network.debugging.enabled"; - -const POSSIBLE_USB_INTERFACE_NAME = "rndis0,usb0"; -const DEFAULT_USB_INTERFACE_NAME = "rndis0"; -const DEFAULT_3G_INTERFACE_NAME = "rmnet0"; -const DEFAULT_WIFI_INTERFACE_NAME = "wlan0"; - -// The kernel's proc entry for network lists. -const KERNEL_NETWORK_ENTRY = "/sys/class/net"; - -const TETHERING_TYPE_WIFI = "WiFi"; -const TETHERING_TYPE_USB = "USB"; - -const WIFI_FIRMWARE_AP = "AP"; -const WIFI_FIRMWARE_STATION = "STA"; -const WIFI_SECURITY_TYPE_NONE = "open"; -const WIFI_SECURITY_TYPE_WPA_PSK = "wpa-psk"; -const WIFI_SECURITY_TYPE_WPA2_PSK = "wpa2-psk"; -const WIFI_CTRL_INTERFACE = "wl0.1"; - -const NETWORK_INTERFACE_UP = "up"; -const NETWORK_INTERFACE_DOWN = "down"; - -const TETHERING_STATE_ONGOING = "ongoing"; -const TETHERING_STATE_IDLE = "idle"; -const TETHERING_STATE_ACTIVE = "active"; - -// Settings DB path for USB tethering. -const SETTINGS_USB_ENABLED = "tethering.usb.enabled"; -const SETTINGS_USB_IP = "tethering.usb.ip"; -const SETTINGS_USB_PREFIX = "tethering.usb.prefix"; -const SETTINGS_USB_DHCPSERVER_STARTIP = "tethering.usb.dhcpserver.startip"; -const SETTINGS_USB_DHCPSERVER_ENDIP = "tethering.usb.dhcpserver.endip"; -const SETTINGS_USB_DNS1 = "tethering.usb.dns1"; -const SETTINGS_USB_DNS2 = "tethering.usb.dns2"; - -// Settings DB path for WIFI tethering. -const SETTINGS_WIFI_DHCPSERVER_STARTIP = "tethering.wifi.dhcpserver.startip"; -const SETTINGS_WIFI_DHCPSERVER_ENDIP = "tethering.wifi.dhcpserver.endip"; - -// Settings DB patch for dun required setting. -const SETTINGS_DUN_REQUIRED = "tethering.dun.required"; - -// Default value for USB tethering. -const DEFAULT_USB_IP = "192.168.0.1"; -const DEFAULT_USB_PREFIX = "24"; -const DEFAULT_USB_DHCPSERVER_STARTIP = "192.168.0.10"; -const DEFAULT_USB_DHCPSERVER_ENDIP = "192.168.0.30"; - -const DEFAULT_DNS1 = "8.8.8.8"; -const DEFAULT_DNS2 = "8.8.4.4"; - -const DEFAULT_WIFI_DHCPSERVER_STARTIP = "192.168.1.10"; -const DEFAULT_WIFI_DHCPSERVER_ENDIP = "192.168.1.30"; - -const SETTINGS_DATA_DEFAULT_SERVICE_ID = "ril.data.defaultServiceId"; -const MOBILE_DUN_CONNECT_TIMEOUT = 30000; -const MOBILE_DUN_RETRY_INTERVAL = 5000; -const MOBILE_DUN_MAX_RETRIES = 5; - -var debug; -function updateDebug() { - let debugPref = false; // set default value here. - try { - debugPref = debugPref || Services.prefs.getBoolPref(PREF_NETWORK_DEBUG_ENABLED); - } catch (e) {} - - if (debugPref) { - debug = function(s) { - dump("-*- TetheringService: " + s + "\n"); - }; - } else { - debug = function(s) {}; - } -} -updateDebug(); - -function TetheringService() { - Services.obs.addObserver(this, TOPIC_XPCOM_SHUTDOWN, false); - Services.obs.addObserver(this, TOPIC_MOZSETTINGS_CHANGED, false); - Services.obs.addObserver(this, TOPIC_CONNECTION_STATE_CHANGED, false); - Services.prefs.addObserver(PREF_NETWORK_DEBUG_ENABLED, this, false); - Services.prefs.addObserver(PREF_MANAGE_OFFLINE_STATUS, this, false); - - try { - this._manageOfflineStatus = - Services.prefs.getBoolPref(PREF_MANAGE_OFFLINE_STATUS); - } catch(ex) { - // Ignore. - } - - this._dataDefaultServiceId = 0; - - // Possible usb tethering interfaces for different gonk platform. - this.possibleInterface = POSSIBLE_USB_INTERFACE_NAME.split(","); - - // Default values for internal and external interfaces. - this._tetheringInterface = {}; - this._tetheringInterface[TETHERING_TYPE_USB] = { - externalInterface: DEFAULT_3G_INTERFACE_NAME, - internalInterface: DEFAULT_USB_INTERFACE_NAME - }; - this._tetheringInterface[TETHERING_TYPE_WIFI] = { - externalInterface: DEFAULT_3G_INTERFACE_NAME, - internalInterface: DEFAULT_WIFI_INTERFACE_NAME - }; - - this.tetheringSettings = {}; - this.initTetheringSettings(); - - let settingsLock = gSettingsService.createLock(); - // Read the default service id for data call. - settingsLock.get(SETTINGS_DATA_DEFAULT_SERVICE_ID, this); - - // Read usb tethering data from settings DB. - settingsLock.get(SETTINGS_USB_IP, this); - settingsLock.get(SETTINGS_USB_PREFIX, this); - settingsLock.get(SETTINGS_USB_DHCPSERVER_STARTIP, this); - settingsLock.get(SETTINGS_USB_DHCPSERVER_ENDIP, this); - settingsLock.get(SETTINGS_USB_DNS1, this); - settingsLock.get(SETTINGS_USB_DNS2, this); - settingsLock.get(SETTINGS_USB_ENABLED, this); - - // Read wifi tethering data from settings DB. - settingsLock.get(SETTINGS_WIFI_DHCPSERVER_STARTIP, this); - settingsLock.get(SETTINGS_WIFI_DHCPSERVER_ENDIP, this); - - this._usbTetheringSettingsToRead = [SETTINGS_USB_IP, - SETTINGS_USB_PREFIX, - SETTINGS_USB_DHCPSERVER_STARTIP, - SETTINGS_USB_DHCPSERVER_ENDIP, - SETTINGS_USB_DNS1, - SETTINGS_USB_DNS2, - SETTINGS_USB_ENABLED, - SETTINGS_WIFI_DHCPSERVER_STARTIP, - SETTINGS_WIFI_DHCPSERVER_ENDIP]; - - this.wantConnectionEvent = null; - - this.dunConnectTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - - this.dunRetryTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - - this._pendingTetheringRequests = []; -} -TetheringService.prototype = { - classID: TETHERINGSERVICE_CID, - classInfo: XPCOMUtils.generateCI({classID: TETHERINGSERVICE_CID, - contractID: TETHERINGSERVICE_CONTRACTID, - classDescription: "Tethering Service", - interfaces: [Ci.nsITetheringService]}), - QueryInterface: XPCOMUtils.generateQI([Ci.nsITetheringService, - Ci.nsISupportsWeakReference, - Ci.nsIObserver, - Ci.nsISettingsServiceCallback]), - - // Flag to record the default client id for data call. - _dataDefaultServiceId: null, - - // Number of usb tehering requests to be processed. - _usbTetheringRequestCount: 0, - - // Usb tethering state. - _usbTetheringAction: TETHERING_STATE_IDLE, - - // Tethering settings. - tetheringSettings: null, - - // Tethering settings need to be read from settings DB. - _usbTetheringSettingsToRead: null, - - // Previous usb tethering enabled state. - _oldUsbTetheringEnabledState: null, - - // External and internal interface name. - _tetheringInterface: null, - - // Dun connection timer. - dunConnectTimer: null, - - // Dun connection retry times. - dunRetryTimes: 0, - - // Dun retry timer. - dunRetryTimer: null, - - // Pending tethering request to handle after dun is connected. - _pendingTetheringRequests: null, - - // Flag to indicate wether wifi tethering is being processed. - _wifiTetheringRequestOngoing: false, - - // Arguments for pending wifi tethering request. - _pendingWifiTetheringRequestArgs: null, - - // The state of tethering. - state: Ci.nsITetheringService.TETHERING_STATE_INACTIVE, - - // Flag to check if we can modify the Services.io.offline. - _manageOfflineStatus: true, - - // nsIObserver - - observe: function(aSubject, aTopic, aData) { - let network; - - switch(aTopic) { - case TOPIC_PREF_CHANGED: - if (aData === PREF_NETWORK_DEBUG_ENABLED) { - updateDebug(); - } - break; - case TOPIC_MOZSETTINGS_CHANGED: - if ("wrappedJSObject" in aSubject) { - aSubject = aSubject.wrappedJSObject; - } - this.handle(aSubject.key, aSubject.value); - break; - case TOPIC_CONNECTION_STATE_CHANGED: - network = aSubject.QueryInterface(Ci.nsINetworkInfo); - debug("Network " + network.type + "/" + network.name + - " changed state to " + network.state); - this.onConnectionChanged(network); - break; - case TOPIC_XPCOM_SHUTDOWN: - Services.obs.removeObserver(this, TOPIC_XPCOM_SHUTDOWN); - Services.obs.removeObserver(this, TOPIC_MOZSETTINGS_CHANGED); - Services.obs.removeObserver(this, TOPIC_CONNECTION_STATE_CHANGED); - Services.prefs.removeObserver(PREF_NETWORK_DEBUG_ENABLED, this); - Services.prefs.removeObserver(PREF_MANAGE_OFFLINE_STATUS, this); - - this.dunConnectTimer.cancel(); - this.dunRetryTimer.cancel(); - break; - case PREF_MANAGE_OFFLINE_STATUS: - try { - this._manageOfflineStatus = - Services.prefs.getBoolPref(PREF_MANAGE_OFFLINE_STATUS); - } catch(ex) { - // Ignore. - } - break; - } - }, - - // nsISettingsServiceCallback - - handle: function(aName, aResult) { - switch(aName) { - case SETTINGS_DATA_DEFAULT_SERVICE_ID: - this._dataDefaultServiceId = aResult || 0; - debug("'_dataDefaultServiceId' is now " + this._dataDefaultServiceId); - break; - case SETTINGS_USB_ENABLED: - this._oldUsbTetheringEnabledState = this.tetheringSettings[SETTINGS_USB_ENABLED]; - case SETTINGS_USB_IP: - case SETTINGS_USB_PREFIX: - case SETTINGS_USB_DHCPSERVER_STARTIP: - case SETTINGS_USB_DHCPSERVER_ENDIP: - case SETTINGS_USB_DNS1: - case SETTINGS_USB_DNS2: - case SETTINGS_WIFI_DHCPSERVER_STARTIP: - case SETTINGS_WIFI_DHCPSERVER_ENDIP: - if (aResult !== null) { - this.tetheringSettings[aName] = aResult; - } - debug("'" + aName + "'" + " is now " + this.tetheringSettings[aName]); - let index = this._usbTetheringSettingsToRead.indexOf(aName); - - if (index != -1) { - this._usbTetheringSettingsToRead.splice(index, 1); - } - - if (this._usbTetheringSettingsToRead.length) { - debug("We haven't read completely the usb Tethering data from settings db."); - break; - } - - if (this._oldUsbTetheringEnabledState === this.tetheringSettings[SETTINGS_USB_ENABLED]) { - debug("No changes for SETTINGS_USB_ENABLED flag. Nothing to do."); - this.handlePendingWifiTetheringRequest(); - break; - } - - this._usbTetheringRequestCount++; - if (this._usbTetheringRequestCount === 1) { - if (this._wifiTetheringRequestOngoing) { - debug('USB tethering request is blocked by ongoing wifi tethering request.'); - } else { - this.handleLastUsbTetheringRequest(); - } - } - break; - }; - }, - - handleError: function(aErrorMessage) { - debug("There was an error while reading Tethering settings."); - this.tetheringSettings = {}; - this.tetheringSettings[SETTINGS_USB_ENABLED] = false; - }, - - initTetheringSettings: function() { - this.tetheringSettings[SETTINGS_USB_ENABLED] = false; - this.tetheringSettings[SETTINGS_USB_IP] = DEFAULT_USB_IP; - this.tetheringSettings[SETTINGS_USB_PREFIX] = DEFAULT_USB_PREFIX; - this.tetheringSettings[SETTINGS_USB_DHCPSERVER_STARTIP] = DEFAULT_USB_DHCPSERVER_STARTIP; - this.tetheringSettings[SETTINGS_USB_DHCPSERVER_ENDIP] = DEFAULT_USB_DHCPSERVER_ENDIP; - this.tetheringSettings[SETTINGS_USB_DNS1] = DEFAULT_DNS1; - this.tetheringSettings[SETTINGS_USB_DNS2] = DEFAULT_DNS2; - - this.tetheringSettings[SETTINGS_WIFI_DHCPSERVER_STARTIP] = DEFAULT_WIFI_DHCPSERVER_STARTIP; - this.tetheringSettings[SETTINGS_WIFI_DHCPSERVER_ENDIP] = DEFAULT_WIFI_DHCPSERVER_ENDIP; - - this.tetheringSettings[SETTINGS_DUN_REQUIRED] = - libcutils.property_get("ro.tethering.dun_required") === "1"; - }, - - getNetworkInfo: function(aType, aServiceId) { - for (let networkId in gNetworkManager.allNetworkInfo) { - let networkInfo = gNetworkManager.allNetworkInfo[networkId]; - if (networkInfo.type == aType) { - try { - if (networkInfo instanceof Ci.nsIRilNetworkInfo) { - let rilNetwork = networkInfo.QueryInterface(Ci.nsIRilNetworkInfo); - if (rilNetwork.serviceId != aServiceId) { - continue; - } - } - } catch (e) {} - return networkInfo; - } - } - return null; - }, - - handleLastUsbTetheringRequest: function() { - debug('handleLastUsbTetheringRequest... ' + this._usbTetheringRequestCount); - - if (this._usbTetheringRequestCount === 0) { - if (this.wantConnectionEvent) { - if (this.tetheringSettings[SETTINGS_USB_ENABLED]) { - this.wantConnectionEvent.call(this); - } - this.wantConnectionEvent = null; - } - this.handlePendingWifiTetheringRequest(); - return; - } - - // Cancel the accumlated count to 1 since we only care about the - // last state. - this._usbTetheringRequestCount = 1; - this.handleUSBTetheringToggle(this.tetheringSettings[SETTINGS_USB_ENABLED]); - this.wantConnectionEvent = null; - }, - - handlePendingWifiTetheringRequest: function() { - if (this._pendingWifiTetheringRequestArgs) { - this.setWifiTethering.apply(this, this._pendingWifiTetheringRequestArgs); - this._pendingWifiTetheringRequestArgs = null; - } - }, - - /** - * Callback when dun connection fails to connect within timeout. - */ - onDunConnectTimerTimeout: function() { - while (this._pendingTetheringRequests.length > 0) { - debug("onDunConnectTimerTimeout: callback without network info."); - let callback = this._pendingTetheringRequests.shift(); - if (typeof callback === 'function') { - callback(); - } - } - }, - - setupDunConnection: function() { - this.dunRetryTimer.cancel(); - let connection = - gMobileConnectionService.getItemByServiceId(this._dataDefaultServiceId); - let data = connection && connection.data; - if (data && data.state === "registered") { - let ril = gRil.getRadioInterface(this._dataDefaultServiceId); - - this.dunRetryTimes = 0; - ril.setupDataCallByType(Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN); - this.dunConnectTimer.cancel(); - this.dunConnectTimer. - initWithCallback(this.onDunConnectTimerTimeout.bind(this), - MOBILE_DUN_CONNECT_TIMEOUT, Ci.nsITimer.TYPE_ONE_SHOT); - return; - } - - if (this.dunRetryTimes++ >= this.MOBILE_DUN_MAX_RETRIES) { - debug("setupDunConnection: max retries reached."); - this.dunRetryTimes = 0; - // same as dun connect timeout. - this.onDunConnectTimerTimeout(); - return; - } - - debug("Data not ready, retry dun after " + MOBILE_DUN_RETRY_INTERVAL + " ms."); - this.dunRetryTimer. - initWithCallback(this.setupDunConnection.bind(this), - MOBILE_DUN_RETRY_INTERVAL, Ci.nsITimer.TYPE_ONE_SHOT); - }, - - _dunActiveUsers: 0, - handleDunConnection: function(aEnable, aCallback) { - debug("handleDunConnection: " + aEnable); - let dun = this.getNetworkInfo( - Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN, this._dataDefaultServiceId); - - if (!aEnable) { - this._dunActiveUsers--; - if (this._dunActiveUsers > 0) { - debug("Dun still needed by others, do not disconnect.") - return; - } - - this.dunRetryTimes = 0; - this.dunRetryTimer.cancel(); - this.dunConnectTimer.cancel(); - this._pendingTetheringRequests = []; - - if (dun && (dun.state == Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED)) { - gRil.getRadioInterface(this._dataDefaultServiceId) - .deactivateDataCallByType(Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN); - } - return; - } - - this._dunActiveUsers++; - if (!dun || (dun.state != Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED)) { - debug("DUN data call inactive, setup dun data call!") - this._pendingTetheringRequests.push(aCallback); - this.dunRetryTimes = 0; - this.setupDunConnection(); - - return; - } - - this._tetheringInterface[TETHERING_TYPE_USB].externalInterface = dun.name; - aCallback(dun); - }, - - handleUSBTetheringToggle: function(aEnable) { - debug("handleUSBTetheringToggle: " + aEnable); - if (aEnable && - (this._usbTetheringAction === TETHERING_STATE_ONGOING || - this._usbTetheringAction === TETHERING_STATE_ACTIVE)) { - debug("Usb tethering already connecting/connected."); - this._usbTetheringRequestCount = 0; - this.handlePendingWifiTetheringRequest(); - return; - } - - if (!aEnable && - this._usbTetheringAction === TETHERING_STATE_IDLE) { - debug("Usb tethering already disconnected."); - this._usbTetheringRequestCount = 0; - this.handlePendingWifiTetheringRequest(); - return; - } - - if (!aEnable) { - this.tetheringSettings[SETTINGS_USB_ENABLED] = false; - gNetworkService.enableUsbRndis(false, this.enableUsbRndisResult.bind(this)); - return; - } - - this.tetheringSettings[SETTINGS_USB_ENABLED] = true; - this._usbTetheringAction = TETHERING_STATE_ONGOING; - - if (this.tetheringSettings[SETTINGS_DUN_REQUIRED]) { - this.handleDunConnection(true, (aNetworkInfo) => { - if (!aNetworkInfo){ - this.usbTetheringResultReport(aEnable, "Dun connection failed"); - return; - } - this._tetheringInterface[TETHERING_TYPE_USB].externalInterface = - aNetworkInfo.name; - gNetworkService.enableUsbRndis(true, this.enableUsbRndisResult.bind(this)); - }); - return; - } - - if (gNetworkManager.activeNetworkInfo) { - this._tetheringInterface[TETHERING_TYPE_USB].externalInterface = - gNetworkManager.activeNetworkInfo.name; - } else { - let mobile = this.getNetworkInfo( - Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE, this._dataDefaultServiceId); - if (mobile && mobile.name) { - this._tetheringInterface[TETHERING_TYPE_USB].externalInterface = mobile.name; - } - } - gNetworkService.enableUsbRndis(true, this.enableUsbRndisResult.bind(this)); - }, - - getUSBTetheringParameters: function(aEnable, aTetheringInterface) { - let interfaceIp = this.tetheringSettings[SETTINGS_USB_IP]; - let prefix = this.tetheringSettings[SETTINGS_USB_PREFIX]; - let wifiDhcpStartIp = this.tetheringSettings[SETTINGS_WIFI_DHCPSERVER_STARTIP]; - let wifiDhcpEndIp = this.tetheringSettings[SETTINGS_WIFI_DHCPSERVER_ENDIP]; - let usbDhcpStartIp = this.tetheringSettings[SETTINGS_USB_DHCPSERVER_STARTIP]; - let usbDhcpEndIp = this.tetheringSettings[SETTINGS_USB_DHCPSERVER_ENDIP]; - let dns1 = this.tetheringSettings[SETTINGS_USB_DNS1]; - let dns2 = this.tetheringSettings[SETTINGS_USB_DNS2]; - let internalInterface = aTetheringInterface.internalInterface; - let externalInterface = aTetheringInterface.externalInterface; - - // Using the default values here until application support these settings. - if (interfaceIp == "" || prefix == "" || - wifiDhcpStartIp == "" || wifiDhcpEndIp == "" || - usbDhcpStartIp == "" || usbDhcpEndIp == "") { - debug("Invalid subnet information."); - return null; - } - - return { - ifname: internalInterface, - ip: interfaceIp, - prefix: prefix, - wifiStartIp: wifiDhcpStartIp, - wifiEndIp: wifiDhcpEndIp, - usbStartIp: usbDhcpStartIp, - usbEndIp: usbDhcpEndIp, - dns1: dns1, - dns2: dns2, - internalIfname: internalInterface, - externalIfname: externalInterface, - enable: aEnable, - link: aEnable ? NETWORK_INTERFACE_UP : NETWORK_INTERFACE_DOWN - }; - }, - - notifyError: function(aResetSettings, aCallback, aMsg) { - if (aResetSettings) { - let settingsLock = gSettingsService.createLock(); - // Disable wifi tethering with a useful error message for the user. - settingsLock.set("tethering.wifi.enabled", false, null, aMsg); - } - - debug("setWifiTethering: " + (aMsg ? aMsg : "success")); - - if (aCallback) { - // Callback asynchronously to avoid netsted toggling. - Services.tm.currentThread.dispatch(() => { - aCallback.wifiTetheringEnabledChange(aMsg); - }, Ci.nsIThread.DISPATCH_NORMAL); - } - }, - - enableWifiTethering: function(aEnable, aConfig, aCallback) { - // Fill in config's required fields. - aConfig.ifname = this._tetheringInterface[TETHERING_TYPE_WIFI].internalInterface; - aConfig.internalIfname = this._tetheringInterface[TETHERING_TYPE_WIFI].internalInterface; - aConfig.externalIfname = this._tetheringInterface[TETHERING_TYPE_WIFI].externalInterface; - - this._wifiTetheringRequestOngoing = true; - gNetworkService.setWifiTethering(aEnable, aConfig, (aError) => { - // Change the tethering state to WIFI if there is no error. - if (aEnable && !aError) { - this.state = Ci.nsITetheringService.TETHERING_STATE_WIFI; - } else { - // If wifi thethering is disable, or any error happens, - // then consider the following statements. - - // Check whether the state is USB now or not. If no then just change - // it to INACTIVE, if yes then just keep it. - // It means that don't let the disable or error of WIFI affect - // the original active state. - if (this.state != Ci.nsITetheringService.TETHERING_STATE_USB) { - this.state = Ci.nsITetheringService.TETHERING_STATE_INACTIVE; - } - - // Disconnect dun on error or when wifi tethering is disabled. - if (this.tetheringSettings[SETTINGS_DUN_REQUIRED]) { - this.handleDunConnection(false); - } - } - - if (this._manageOfflineStatus) { - Services.io.offline = !this.isAnyConnected() && - (this.state === - Ci.nsITetheringService.TETHERING_STATE_INACTIVE); - } - - let resetSettings = aError; - debug('gNetworkService.setWifiTethering finished'); - this.notifyError(resetSettings, aCallback, aError); - this._wifiTetheringRequestOngoing = false; - if (this._usbTetheringRequestCount > 0) { - debug('Perform pending USB tethering requests.'); - this.handleLastUsbTetheringRequest(); - } - }); - }, - - // Enable/disable WiFi tethering by sending commands to netd. - setWifiTethering: function(aEnable, aInterfaceName, aConfig, aCallback) { - debug("setWifiTethering: " + aEnable); - if (!aInterfaceName) { - this.notifyError(true, aCallback, "invalid network interface name"); - return; - } - - if (!aConfig) { - this.notifyError(true, aCallback, "invalid configuration"); - return; - } - - if (this._usbTetheringRequestCount > 0) { - // If there's still pending usb tethering request, save - // the request params and redo |setWifiTethering| on - // usb tethering task complete. - debug('USB tethering request is being processed. Queue this wifi tethering request.'); - this._pendingWifiTetheringRequestArgs = Array.prototype.slice.call(arguments); - debug('Pending args: ' + JSON.stringify(this._pendingWifiTetheringRequestArgs)); - return; - } - - // Re-check again, test cases set this property later. - this.tetheringSettings[SETTINGS_DUN_REQUIRED] = - libcutils.property_get("ro.tethering.dun_required") === "1"; - - if (!aEnable) { - this.enableWifiTethering(false, aConfig, aCallback); - return; - } - - this._tetheringInterface[TETHERING_TYPE_WIFI].internalInterface = - aInterfaceName; - - if (this.tetheringSettings[SETTINGS_DUN_REQUIRED]) { - this.handleDunConnection(true, (aNetworkInfo) => { - if (!aNetworkInfo) { - this.notifyError(true, aCallback, "Dun connection failed"); - return; - } - this._tetheringInterface[TETHERING_TYPE_WIFI].externalInterface = - aNetworkInfo.name; - this.enableWifiTethering(true, aConfig, aCallback); - }); - return; - } - - let mobile = this.getNetworkInfo( - Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE, this._dataDefaultServiceId); - // Update the real interface name - if (mobile && mobile.name) { - this._tetheringInterface[TETHERING_TYPE_WIFI].externalInterface = mobile.name; - } - - this.enableWifiTethering(true, aConfig, aCallback); - }, - - // Enable/disable USB tethering by sending commands to netd. - setUSBTethering: function(aEnable, aTetheringInterface, aCallback) { - let params = this.getUSBTetheringParameters(aEnable, aTetheringInterface); - - if (params === null) { - gNetworkService.enableUsbRndis(false, function() { - this.usbTetheringResultReport(aEnable, "Invalid parameters"); - }); - return; - } - - gNetworkService.setUSBTethering(aEnable, params, aCallback); - }, - - getUsbInterface: function() { - // Find the rndis interface. - for (let i = 0; i < this.possibleInterface.length; i++) { - try { - let file = new FileUtils.File(KERNEL_NETWORK_ENTRY + "/" + - this.possibleInterface[i]); - if (file.exists()) { - return this.possibleInterface[i]; - } - } catch (e) { - debug("Not " + this.possibleInterface[i] + " interface."); - } - } - debug("Can't find rndis interface in possible lists."); - return DEFAULT_USB_INTERFACE_NAME; - }, - - enableUsbRndisResult: function(aSuccess, aEnable) { - if (aSuccess) { - // If enable is false, don't find usb interface cause it is already down, - // just use the internal interface in settings. - if (aEnable) { - this._tetheringInterface[TETHERING_TYPE_USB].internalInterface = - this.getUsbInterface(); - } - this.setUSBTethering(aEnable, - this._tetheringInterface[TETHERING_TYPE_USB], - this.usbTetheringResultReport.bind(this, aEnable)); - } else { - this.usbTetheringResultReport(aEnable, "enableUsbRndisResult failure"); - throw new Error("failed to set USB Function to adb"); - } - }, - - usbTetheringResultReport: function(aEnable, aError) { - this._usbTetheringRequestCount--; - - let settingsLock = gSettingsService.createLock(); - - debug('usbTetheringResultReport callback. enable: ' + aEnable + - ', error: ' + aError); - - // Disable tethering settings when fail to enable it. - if (aError) { - this.tetheringSettings[SETTINGS_USB_ENABLED] = false; - settingsLock.set("tethering.usb.enabled", false, null); - // Skip others request when we found an error. - this._usbTetheringRequestCount = 0; - this._usbTetheringAction = TETHERING_STATE_IDLE; - // If the thethering state is WIFI now, then just keep it, - // if not, just change the state to INACTIVE. - // It means that don't let the error of USB affect the original active state. - if (this.state != Ci.nsITetheringService.TETHERING_STATE_WIFI) { - this.state = Ci.nsITetheringService.TETHERING_STATE_INACTIVE; - } - if (this.tetheringSettings[SETTINGS_DUN_REQUIRED]) { - this.handleDunConnection(false); - } - } else { - if (aEnable) { - this._usbTetheringAction = TETHERING_STATE_ACTIVE; - this.state = Ci.nsITetheringService.TETHERING_STATE_USB; - } else { - this._usbTetheringAction = TETHERING_STATE_IDLE; - // If the state is now WIFI, don't let the disable of USB affect it. - if (this.state != Ci.nsITetheringService.TETHERING_STATE_WIFI) { - this.state = Ci.nsITetheringService.TETHERING_STATE_INACTIVE; - } - if (this.tetheringSettings[SETTINGS_DUN_REQUIRED]) { - this.handleDunConnection(false); - } - } - - if (this._manageOfflineStatus) { - Services.io.offline = !this.isAnyConnected() && - (this.state === - Ci.nsITetheringService.TETHERING_STATE_INACTIVE); - } - - this.handleLastUsbTetheringRequest(); - } - }, - - onConnectionChangedReport: function(aSuccess, aExternalIfname) { - debug("onConnectionChangedReport result: success " + aSuccess); - - if (aSuccess) { - // Update the external interface. - this._tetheringInterface[TETHERING_TYPE_USB].externalInterface = - aExternalIfname; - debug("Change the interface name to " + aExternalIfname); - } - }, - - onConnectionChanged: function(aNetworkInfo) { - if (aNetworkInfo.state != Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) { - debug("We are only interested in CONNECTED event"); - return; - } - - if (this.tetheringSettings[SETTINGS_DUN_REQUIRED] && - aNetworkInfo.type === Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN) { - this.dunConnectTimer.cancel(); - debug("DUN data call connected, process callbacks."); - while (this._pendingTetheringRequests.length > 0) { - let callback = this._pendingTetheringRequests.shift(); - if (typeof callback === 'function') { - callback(aNetworkInfo); - } - } - return; - } - - if (!this.tetheringSettings[SETTINGS_USB_ENABLED]) { - debug("Usb tethering settings is not enabled"); - return; - } - - if (this.tetheringSettings[SETTINGS_DUN_REQUIRED] && - aNetworkInfo.type === Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN && - this._tetheringInterface[TETHERING_TYPE_USB].externalInterface === - aNetworkInfo.name) { - debug("Dun required and dun interface is the same"); - return; - } - - if (this._tetheringInterface[TETHERING_TYPE_USB].externalInterface === - gNetworkManager.activeNetworkInfo.name) { - debug("The active interface is the same"); - return; - } - - let previous = { - internalIfname: this._tetheringInterface[TETHERING_TYPE_USB].internalInterface, - externalIfname: this._tetheringInterface[TETHERING_TYPE_USB].externalInterface - }; - - let current = { - internalIfname: this._tetheringInterface[TETHERING_TYPE_USB].internalInterface, - externalIfname: aNetworkInfo.name - }; - - let callback = (() => { - // Update external network interface. - debug("Update upstream interface to " + aNetworkInfo.name); - gNetworkService.updateUpStream(previous, current, - this.onConnectionChangedReport.bind(this)); - }); - - if (this._usbTetheringAction === TETHERING_STATE_ONGOING) { - debug("Postpone the event and handle it when state is idle."); - this.wantConnectionEvent = callback; - return; - } - this.wantConnectionEvent = null; - - callback.call(this); - }, - - isAnyConnected: function() { - let allNetworkInfo = gNetworkManager.allNetworkInfo; - for (let networkId in allNetworkInfo) { - if (allNetworkInfo.hasOwnProperty(networkId) && - allNetworkInfo[networkId].state === Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) { - return true; - } - } - return false; - }, -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TetheringService]); diff --git a/dom/system/gonk/TetheringService.manifest b/dom/system/gonk/TetheringService.manifest deleted file mode 100644 index b8f18dec1..000000000 --- a/dom/system/gonk/TetheringService.manifest +++ /dev/null @@ -1,4 +0,0 @@ -# TetheringService.js -component {527a4121-ee5a-4651-be9c-f46f59cf7c01} TetheringService.js -contract @mozilla.org/tethering/service;1 {527a4121-ee5a-4651-be9c-f46f59cf7c01} -category profile-after-change TetheringService @mozilla.org/tethering/service;1 diff --git a/dom/system/gonk/TimeZoneSettingObserver.cpp b/dom/system/gonk/TimeZoneSettingObserver.cpp deleted file mode 100644 index 512f79908..000000000 --- a/dom/system/gonk/TimeZoneSettingObserver.cpp +++ /dev/null @@ -1,239 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "base/message_loop.h" -#include "jsapi.h" -#include "mozilla/dom/ScriptSettings.h" -#include "mozilla/Attributes.h" -#include "mozilla/ClearOnShutdown.h" -#include "mozilla/Hal.h" -#include "mozilla/Services.h" -#include "mozilla/StaticPtr.h" -#include "nsCOMPtr.h" -#include "nsDebug.h" -#include "nsIObserver.h" -#include "nsIObserverService.h" -#include "nsISettingsService.h" -#include "nsJSUtils.h" -#include "nsServiceManagerUtils.h" -#include "nsString.h" -#include "TimeZoneSettingObserver.h" -#include "xpcpublic.h" -#include "nsContentUtils.h" -#include "nsPrintfCString.h" -#include "mozilla/dom/BindingUtils.h" -#include "mozilla/dom/SettingChangeNotificationBinding.h" - -#undef LOG -#undef ERR -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Time Zone Setting" , ## args) -#define ERR(args...) __android_log_print(ANDROID_LOG_ERROR, "Time Zone Setting" , ## args) - -#define TIME_TIMEZONE "time.timezone" -#define MOZSETTINGS_CHANGED "mozsettings-changed" - -using namespace mozilla; -using namespace mozilla::dom; - -namespace { - -class TimeZoneSettingObserver : public nsIObserver -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER - - TimeZoneSettingObserver(); - static nsresult SetTimeZone(const JS::Value &aValue, JSContext *aContext); - -protected: - virtual ~TimeZoneSettingObserver(); -}; - -class TimeZoneSettingCb final : public nsISettingsServiceCallback -{ -public: - NS_DECL_ISUPPORTS - - TimeZoneSettingCb() {} - - NS_IMETHOD Handle(const nsAString &aName, JS::Handle<JS::Value> aResult) { - - JSContext *cx = nsContentUtils::GetCurrentJSContext(); - NS_ENSURE_TRUE(cx, NS_OK); - - // If we don't have time.timezone value in the settings, we need - // to initialize the settings based on the current system timezone - // to make settings consistent with system. This usually happens - // at the very first boot. After that, settings must have a value. - if (aResult.isNull()) { - // Get the current system time zone offset. Note that we need to - // convert the value to a UTC representation in the format of - // "UTC{+,-}hh:mm", so that the Gaia end can know how to interpret. - // E.g., -480 is "UTC+08:00"; 630 is "UTC-10:30". - int32_t timeZoneOffset = hal::GetTimezoneOffset(); - nsPrintfCString curTimeZone("UTC%+03d:%02d", - -timeZoneOffset / 60, - abs(timeZoneOffset) % 60); - - // Convert it to a JS string. - NS_ConvertUTF8toUTF16 utf16Str(curTimeZone); - - JS::Rooted<JSString*> jsStr(cx, JS_NewUCStringCopyN(cx, - utf16Str.get(), - utf16Str.Length())); - if (!jsStr) { - return NS_ERROR_OUT_OF_MEMORY; - } - - // Set the settings based on the current system timezone. - nsCOMPtr<nsISettingsServiceLock> lock; - nsCOMPtr<nsISettingsService> settingsService = - do_GetService("@mozilla.org/settingsService;1"); - if (!settingsService) { - ERR("Failed to get settingsLock service!"); - return NS_OK; - } - settingsService->CreateLock(nullptr, getter_AddRefs(lock)); - JS::Rooted<JS::Value> value(cx, JS::StringValue(jsStr)); - lock->Set(TIME_TIMEZONE, value, nullptr, nullptr); - return NS_OK; - } - - // Set the system timezone based on the current settings. - if (aResult.isString()) { - return TimeZoneSettingObserver::SetTimeZone(aResult, cx); - } - - return NS_OK; - } - - NS_IMETHOD HandleError(const nsAString &aName) { - ERR("TimeZoneSettingCb::HandleError: %s\n", NS_LossyConvertUTF16toASCII(aName).get()); - return NS_OK; - } - -protected: - ~TimeZoneSettingCb() {} -}; - -NS_IMPL_ISUPPORTS(TimeZoneSettingCb, nsISettingsServiceCallback) - -TimeZoneSettingObserver::TimeZoneSettingObserver() -{ - // Setup an observer to watch changes to the setting. - nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); - if (!observerService) { - ERR("GetObserverService failed"); - return; - } - nsresult rv; - rv = observerService->AddObserver(this, MOZSETTINGS_CHANGED, false); - if (NS_FAILED(rv)) { - ERR("AddObserver failed"); - return; - } - - // Read the 'time.timezone' setting in order to start with a known - // value at boot time. The handle() will be called after reading. - nsCOMPtr<nsISettingsServiceLock> lock; - nsCOMPtr<nsISettingsService> settingsService = - do_GetService("@mozilla.org/settingsService;1"); - if (!settingsService) { - ERR("Failed to get settingsLock service!"); - return; - } - settingsService->CreateLock(nullptr, getter_AddRefs(lock)); - nsCOMPtr<nsISettingsServiceCallback> callback = new TimeZoneSettingCb(); - lock->Get(TIME_TIMEZONE, callback); -} - -nsresult TimeZoneSettingObserver::SetTimeZone(const JS::Value &aValue, JSContext *aContext) -{ - // Convert the JS value to a nsCString type. - // The value should be a JS string like "America/Chicago" or "UTC-05:00". - nsAutoJSString valueStr; - if (!valueStr.init(aContext, aValue.toString())) { - ERR("Failed to convert JS value to nsCString"); - return NS_ERROR_FAILURE; - } - NS_ConvertUTF16toUTF8 newTimezone(valueStr); - - // Hal expects opposite sign from general notations, - // so we need to flip it. - if (newTimezone.Find(NS_LITERAL_CSTRING("UTC+")) == 0) { - if (!newTimezone.SetCharAt('-', 3)) { - return NS_ERROR_FAILURE; - } - } else if (newTimezone.Find(NS_LITERAL_CSTRING("UTC-")) == 0) { - if (!newTimezone.SetCharAt('+', 3)) { - return NS_ERROR_FAILURE; - } - } - - // Set the timezone only when the system timezone is not identical. - nsCString curTimezone = hal::GetTimezone(); - if (!curTimezone.Equals(newTimezone)) { - hal::SetTimezone(newTimezone); - } - - return NS_OK; -} - -TimeZoneSettingObserver::~TimeZoneSettingObserver() -{ - nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); - if (observerService) { - observerService->RemoveObserver(this, MOZSETTINGS_CHANGED); - } -} - -NS_IMPL_ISUPPORTS(TimeZoneSettingObserver, nsIObserver) - -NS_IMETHODIMP -TimeZoneSettingObserver::Observe(nsISupports *aSubject, - const char *aTopic, - const char16_t *aData) -{ - if (strcmp(aTopic, MOZSETTINGS_CHANGED) != 0) { - return NS_OK; - } - - // Note that this function gets called for any and all settings changes, - // so we need to carefully check if we have the one we're interested in. - // - // The string that we're interested in will be a JSON string that looks like: - // {"key":"time.timezone","value":"America/Chicago"} or - // {"key":"time.timezone","value":"UTC-05:00"} - - AutoSafeJSContext cx; - RootedDictionary<SettingChangeNotification> setting(cx); - if (!WrappedJSToDictionary(cx, aSubject, setting)) { - return NS_OK; - } - if (!setting.mKey.EqualsASCII(TIME_TIMEZONE)) { - return NS_OK; - } - if (!setting.mValue.isString()) { - return NS_OK; - } - - // Set the system timezone. - return SetTimeZone(setting.mValue, cx); -} - -} // namespace - -static mozilla::StaticRefPtr<TimeZoneSettingObserver> sTimeZoneSettingObserver; -namespace mozilla { -namespace system { -void -InitializeTimeZoneSettingObserver() -{ - sTimeZoneSettingObserver = new TimeZoneSettingObserver(); - ClearOnShutdown(&sTimeZoneSettingObserver); -} - -} // namespace system -} // namespace mozilla diff --git a/dom/system/gonk/TimeZoneSettingObserver.h b/dom/system/gonk/TimeZoneSettingObserver.h deleted file mode 100644 index 08b7cebb3..000000000 --- a/dom/system/gonk/TimeZoneSettingObserver.h +++ /dev/null @@ -1,20 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_timesetting_h__ -#define mozilla_system_timesetting_h__ - -namespace mozilla { -namespace system { - -// Initialize TimeZoneSettingObserver which observes the time zone change -// event from settings service. When receiving the event, it modifies the -// system time zone. -void InitializeTimeZoneSettingObserver(); - -} // namespace system -} // namespace mozilla - -#endif // mozilla_system_timesetting_h__ - diff --git a/dom/system/gonk/Volume.cpp b/dom/system/gonk/Volume.cpp deleted file mode 100644 index f90c7b693..000000000 --- a/dom/system/gonk/Volume.cpp +++ /dev/null @@ -1,596 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "Volume.h" -#include "VolumeCommand.h" -#include "VolumeManager.h" -#include "VolumeManagerLog.h" -#include "nsIVolume.h" -#include "nsXULAppAPI.h" - -#include <vold/ResponseCode.h> - -namespace mozilla { -namespace system { - -#if DEBUG_VOLUME_OBSERVER -void -VolumeObserverList::Broadcast(Volume* const& aVolume) -{ - uint32_t size = mObservers.Length(); - for (uint32_t i = 0; i < size; ++i) { - LOG("VolumeObserverList::Broadcast to [%u] %p volume '%s'", - i, mObservers[i], aVolume->NameStr()); - mObservers[i]->Notify(aVolume); - } -} -#endif - -VolumeObserverList Volume::sEventObserverList; - -// We have a feature where volumes can be locked when mounted. This -// is used to prevent a volume from being shared with the PC while -// it is actively being used (say for storing an update image) -// -// We use WakeLocks (a poor choice of name, but it does what we want) -// from the PowerManagerService to determine when we're locked. -// In particular we'll create a wakelock called volume-NAME-GENERATION -// (where NAME is the volume name, and GENERATION is its generation -// number), and if this wakelock is locked, then we'll prevent a volume -// from being shared. -// -// Implementation Details: -// -// Since the AutoMounter can only control when something gets mounted -// and not when it gets unmounted (for example: a user pulls the SDCard) -// and because Volume and nsVolume data structures are maintained on -// separate threads, we have the potential for some race conditions. -// We eliminate the race conditions by introducing the concept of a -// generation number. Every time a volume transitions to the Mounted -// state, it gets assigned a new generation number. Whenever the state -// of a Volume changes, we send the updated state and current generation -// number to the main thread where it gets updated in the nsVolume. -// -// Since WakeLocks can only be queried from the main-thread, the -// nsVolumeService looks for WakeLock status changes, and forwards -// the results to the IOThread. -// -// If the Volume (IOThread) receives a volume update where the generation -// number mismatches, then the update is simply ignored. -// -// When a Volume (IOThread) initially becomes mounted, we assume it to -// be locked until we get our first update from nsVolume (MainThread). -static int32_t sMountGeneration = 0; - -static uint32_t sNextId = 1; - -// We don't get media inserted/removed events at startup. So we -// assume it's present, and we'll be told that it's missing. -Volume::Volume(const nsCSubstring& aName) - : mMediaPresent(true), - mState(nsIVolume::STATE_INIT), - mName(aName), - mMountGeneration(-1), - mMountLocked(true), // Needs to agree with nsVolume::nsVolume - mSharingEnabled(false), - mFormatRequested(false), - mMountRequested(false), - mUnmountRequested(false), - mCanBeShared(true), - mIsSharing(false), - mIsFormatting(false), - mIsUnmounting(false), - mIsRemovable(false), - mIsHotSwappable(false), - mId(sNextId++) -{ - DBG("Volume %s: created", NameStr()); -} - -void -Volume::Dump(const char* aLabel) const -{ - LOG("%s: Volume: %s (%d) is %s and %s @ %s gen %d locked %d", - aLabel, - NameStr(), - Id(), - StateStr(), - MediaPresent() ? "inserted" : "missing", - MountPoint().get(), - MountGeneration(), - (int)IsMountLocked()); - LOG("%s: Sharing %s Mounting %s Formating %s Unmounting %s", - aLabel, - CanBeShared() ? (IsSharingEnabled() ? (IsSharing() ? "en-y" : "en-n") - : "dis") - : "x", - IsMountRequested() ? "req" : "n", - IsFormatRequested() ? (IsFormatting() ? "req-y" : "req-n") - : (IsFormatting() ? "y" : "n"), - IsUnmountRequested() ? (IsUnmounting() ? "req-y" : "req-n") - : (IsUnmounting() ? "y" : "n")); -} - -void -Volume::ResolveAndSetMountPoint(const nsCSubstring& aMountPoint) -{ - nsCString mountPoint(aMountPoint); - char realPathBuf[PATH_MAX]; - - // Call realpath so that we wind up with a path which is compatible with - // functions like nsVolumeService::GetVolumeByPath. - - if (realpath(mountPoint.get(), realPathBuf) < 0) { - // The path we were handed doesn't exist. Warn about it, but use it - // anyways assuming that the user knows what they're doing. - - ERR("ResolveAndSetMountPoint: realpath on '%s' failed: %d", - mountPoint.get(), errno); - mMountPoint = mountPoint; - } else { - mMountPoint = realPathBuf; - } - DBG("Volume %s: Setting mountpoint to '%s'", NameStr(), mMountPoint.get()); -} - -void Volume::SetFakeVolume(const nsACString& aMountPoint) -{ - this->mMountLocked = false; - this->mCanBeShared = false; - ResolveAndSetMountPoint(aMountPoint); - SetState(nsIVolume::STATE_MOUNTED); -} - -void -Volume::SetIsSharing(bool aIsSharing) -{ - if (aIsSharing == mIsSharing) { - return; - } - mIsSharing = aIsSharing; - LOG("Volume %s: IsSharing set to %d state %s", - NameStr(), (int)mIsSharing, StateStr(mState)); - sEventObserverList.Broadcast(this); -} - -void -Volume::SetIsFormatting(bool aIsFormatting) -{ - if (aIsFormatting == mIsFormatting) { - return; - } - mIsFormatting = aIsFormatting; - LOG("Volume %s: IsFormatting set to %d state %s", - NameStr(), (int)mIsFormatting, StateStr(mState)); - if (mIsFormatting) { - sEventObserverList.Broadcast(this); - } -} - -void -Volume::SetIsUnmounting(bool aIsUnmounting) -{ - if (aIsUnmounting == mIsUnmounting) { - return; - } - mIsUnmounting = aIsUnmounting; - LOG("Volume %s: IsUnmounting set to %d state %s", - NameStr(), (int)mIsUnmounting, StateStr(mState)); - sEventObserverList.Broadcast(this); -} - -void -Volume::SetIsRemovable(bool aIsRemovable) -{ - if (aIsRemovable == mIsRemovable) { - return; - } - mIsRemovable = aIsRemovable; - if (!mIsRemovable) { - mIsHotSwappable = false; - } - LOG("Volume %s: IsRemovable set to %d state %s", - NameStr(), (int)mIsRemovable, StateStr(mState)); - sEventObserverList.Broadcast(this); -} - -void -Volume::SetIsHotSwappable(bool aIsHotSwappable) -{ - if (aIsHotSwappable == mIsHotSwappable) { - return; - } - mIsHotSwappable = aIsHotSwappable; - if (mIsHotSwappable) { - mIsRemovable = true; - } - LOG("Volume %s: IsHotSwappable set to %d state %s", - NameStr(), (int)mIsHotSwappable, StateStr(mState)); - sEventObserverList.Broadcast(this); -} - -bool -Volume::BoolConfigValue(const nsCString& aConfigValue, bool& aBoolValue) -{ - if (aConfigValue.EqualsLiteral("1") || - aConfigValue.LowerCaseEqualsLiteral("true")) { - aBoolValue = true; - return true; - } - if (aConfigValue.EqualsLiteral("0") || - aConfigValue.LowerCaseEqualsLiteral("false")) { - aBoolValue = false; - return true; - } - return false; -} - -void -Volume::SetConfig(const nsCString& aConfigName, const nsCString& aConfigValue) -{ - if (aConfigName.LowerCaseEqualsLiteral("removable")) { - bool value = false; - if (BoolConfigValue(aConfigValue, value)) { - SetIsRemovable(value); - } else { - ERR("Volume %s: invalid value '%s' for configuration '%s'", - NameStr(), aConfigValue.get(), aConfigName.get()); - } - return; - } - if (aConfigName.LowerCaseEqualsLiteral("hotswappable")) { - bool value = false; - if (BoolConfigValue(aConfigValue, value)) { - SetIsHotSwappable(value); - } else { - ERR("Volume %s: invalid value '%s' for configuration '%s'", - NameStr(), aConfigValue.get(), aConfigName.get()); - } - return; - } - ERR("Volume %s: invalid config '%s'", NameStr(), aConfigName.get()); -} - -void -Volume::SetMediaPresent(bool aMediaPresent) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - // mMediaPresent is slightly redunant to the state, however - // when media is removed (while Idle), we get the following: - // 631 Volume sdcard /mnt/sdcard disk removed (179:0) - // 605 Volume sdcard /mnt/sdcard state changed from 1 (Idle-Unmounted) to 0 (No-Media) - // - // And on media insertion, we get: - // 630 Volume sdcard /mnt/sdcard disk inserted (179:0) - // 605 Volume sdcard /mnt/sdcard state changed from 0 (No-Media) to 2 (Pending) - // 605 Volume sdcard /mnt/sdcard state changed from 2 (Pending) to 1 (Idle-Unmounted) - // - // On media removal while the media is mounted: - // 632 Volume sdcard /mnt/sdcard bad removal (179:1) - // 605 Volume sdcard /mnt/sdcard state changed from 4 (Mounted) to 5 (Unmounting) - // 605 Volume sdcard /mnt/sdcard state changed from 5 (Unmounting) to 1 (Idle-Unmounted) - // 631 Volume sdcard /mnt/sdcard disk removed (179:0) - // 605 Volume sdcard /mnt/sdcard state changed from 1 (Idle-Unmounted) to 0 (No-Media) - // - // When sharing with a PC, it goes Mounted -> Idle -> Shared - // When unsharing with a PC, it goes Shared -> Idle -> Mounted - // - // The AutoMounter needs to know whether the media is present or not when - // processing the Idle state. - - if (mMediaPresent == aMediaPresent) { - return; - } - - LOG("Volume: %s media %s", NameStr(), aMediaPresent ? "inserted" : "removed"); - mMediaPresent = aMediaPresent; - sEventObserverList.Broadcast(this); -} - -void -Volume::SetSharingEnabled(bool aSharingEnabled) -{ - mSharingEnabled = aSharingEnabled; - - LOG("SetSharingMode for volume %s to %d canBeShared = %d", - NameStr(), (int)mSharingEnabled, (int)mCanBeShared); - sEventObserverList.Broadcast(this); -} - -void -Volume::SetFormatRequested(bool aFormatRequested) -{ - mFormatRequested = aFormatRequested; - - LOG("SetFormatRequested for volume %s to %d CanBeFormatted = %d", - NameStr(), (int)mFormatRequested, (int)CanBeFormatted()); -} - -void -Volume::SetMountRequested(bool aMountRequested) -{ - mMountRequested = aMountRequested; - - LOG("SetMountRequested for volume %s to %d CanBeMounted = %d", - NameStr(), (int)mMountRequested, (int)CanBeMounted()); -} - -void -Volume::SetUnmountRequested(bool aUnmountRequested) -{ - mUnmountRequested = aUnmountRequested; - - LOG("SetUnmountRequested for volume %s to %d CanBeMounted = %d", - NameStr(), (int)mUnmountRequested, (int)CanBeMounted()); -} - -void -Volume::SetState(Volume::STATE aNewState) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - if (aNewState == mState) { - return; - } - if (aNewState == nsIVolume::STATE_MOUNTED) { - mMountGeneration = ++sMountGeneration; - LOG("Volume %s (%u): changing state from %s to %s @ '%s' (%d observers) " - "mountGeneration = %d, locked = %d", - NameStr(), mId, StateStr(mState), - StateStr(aNewState), mMountPoint.get(), sEventObserverList.Length(), - mMountGeneration, (int)mMountLocked); - } else { - LOG("Volume %s (%u): changing state from %s to %s (%d observers)", - NameStr(), mId, StateStr(mState), - StateStr(aNewState), sEventObserverList.Length()); - } - - switch (aNewState) { - case nsIVolume::STATE_NOMEDIA: - // Cover the startup case where we don't get insertion/removal events - mMediaPresent = false; - mIsSharing = false; - mUnmountRequested = false; - mMountRequested = false; - mIsUnmounting = false; - break; - - case nsIVolume::STATE_MOUNTED: - case nsIVolume::STATE_MOUNT_FAIL: - mMountRequested = false; - mIsFormatting = false; - mIsSharing = false; - mIsUnmounting = false; - break; - - case nsIVolume::STATE_FORMATTING: - mFormatRequested = false; - mIsFormatting = true; - mIsSharing = false; - mIsUnmounting = false; - break; - - case nsIVolume::STATE_SHARED: - case nsIVolume::STATE_SHAREDMNT: - // Covers startup cases. Normally, mIsSharing would be set to true - // when we issue the command to initiate the sharing process, but - // it's conceivable that a volume could already be in a shared state - // when b2g starts. - mIsSharing = true; - mIsUnmounting = false; - mIsFormatting = false; - break; - - case nsIVolume::STATE_UNMOUNTING: - mIsUnmounting = true; - mIsFormatting = false; - mIsSharing = false; - break; - - case nsIVolume::STATE_IDLE: // Fall through - case nsIVolume::STATE_CHECKMNT: // Fall through - default: - break; - } - mState = aNewState; - sEventObserverList.Broadcast(this); -} - -void -Volume::SetMountPoint(const nsCSubstring& aMountPoint) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - if (mMountPoint.Equals(aMountPoint)) { - return; - } - ResolveAndSetMountPoint(aMountPoint); -} - -void -Volume::StartMount(VolumeResponseCallback* aCallback) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - StartCommand(new VolumeActionCommand(this, "mount", "", aCallback)); -} - -void -Volume::StartUnmount(VolumeResponseCallback* aCallback) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - StartCommand(new VolumeActionCommand(this, "unmount", "force", aCallback)); -} - -void -Volume::StartFormat(VolumeResponseCallback* aCallback) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - StartCommand(new VolumeActionCommand(this, "format", "", aCallback)); -} - -void -Volume::StartShare(VolumeResponseCallback* aCallback) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - StartCommand(new VolumeActionCommand(this, "share", "ums", aCallback)); -} - -void -Volume::StartUnshare(VolumeResponseCallback* aCallback) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - StartCommand(new VolumeActionCommand(this, "unshare", "ums", aCallback)); -} - -void -Volume::StartCommand(VolumeCommand* aCommand) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - VolumeManager::PostCommand(aCommand); -} - -//static -void -Volume::RegisterVolumeObserver(Volume::EventObserver* aObserver, const char* aName) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - sEventObserverList.AddObserver(aObserver); - - DBG("Added Volume Observer '%s' @%p, length = %u", - aName, aObserver, sEventObserverList.Length()); - - // Send an initial event to the observer (for each volume) - size_t numVolumes = VolumeManager::NumVolumes(); - for (size_t volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr<Volume> vol = VolumeManager::GetVolume(volIndex); - aObserver->Notify(vol); - } -} - -//static -void -Volume::UnregisterVolumeObserver(Volume::EventObserver* aObserver, const char* aName) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - sEventObserverList.RemoveObserver(aObserver); - - DBG("Removed Volume Observer '%s' @%p, length = %u", - aName, aObserver, sEventObserverList.Length()); -} - -//static -void -Volume::UpdateMountLock(const nsACString& aVolumeName, - const int32_t& aMountGeneration, - const bool& aMountLocked) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - RefPtr<Volume> vol = VolumeManager::FindVolumeByName(aVolumeName); - if (!vol || (vol->mMountGeneration != aMountGeneration)) { - return; - } - if (vol->mMountLocked != aMountLocked) { - vol->mMountLocked = aMountLocked; - DBG("Volume::UpdateMountLock for '%s' to %d\n", vol->NameStr(), (int)aMountLocked); - sEventObserverList.Broadcast(vol); - } -} - -void -Volume::HandleVoldResponse(int aResponseCode, nsCWhitespaceTokenizer& aTokenizer) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - // The volume name will have already been parsed, and the tokenizer will point - // to the token after the volume name - switch (aResponseCode) { - case ::ResponseCode::VolumeListResult: { - // Each line will look something like: - // - // sdcard /mnt/sdcard 1 - // - nsDependentCSubstring mntPoint(aTokenizer.nextToken()); - SetMountPoint(mntPoint); - nsresult errCode; - nsCString state(aTokenizer.nextToken()); - if (state.EqualsLiteral("X")) { - // Special state for creating fake volumes which can't be shared. - mCanBeShared = false; - SetState(nsIVolume::STATE_MOUNTED); - } else { - SetState((STATE)state.ToInteger(&errCode)); - } - break; - } - - case ::ResponseCode::VolumeStateChange: { - // Format of the line looks something like: - // - // Volume sdcard /mnt/sdcard state changed from 7 (Shared-Unmounted) to 1 (Idle-Unmounted) - // - // So we parse out the state after the string " to " - while (aTokenizer.hasMoreTokens()) { - nsAutoCString token(aTokenizer.nextToken()); - if (token.EqualsLiteral("to")) { - nsresult errCode; - token = aTokenizer.nextToken(); - STATE newState = (STATE)(token.ToInteger(&errCode)); - if (newState == nsIVolume::STATE_MOUNTED) { - // We set the state to STATE_CHECKMNT here, and the once the - // AutoMounter detects that the volume is actually accessible - // then the AutoMounter will set the volume as STATE_MOUNTED. - SetState(nsIVolume::STATE_CHECKMNT); - } else { - if (State() == nsIVolume::STATE_CHECKING && newState == nsIVolume::STATE_IDLE) { - LOG("Mount of volume '%s' failed", NameStr()); - SetState(nsIVolume::STATE_MOUNT_FAIL); - } else { - SetState(newState); - } - } - break; - } - } - break; - } - - case ::ResponseCode::VolumeDiskInserted: - SetMediaPresent(true); - break; - - case ::ResponseCode::VolumeDiskRemoved: // fall-thru - case ::ResponseCode::VolumeBadRemoval: - SetMediaPresent(false); - break; - - default: - LOG("Volume: %s unrecognized reponse code (ignored)", NameStr()); - break; - } -} - -} // namespace system -} // namespace mozilla diff --git a/dom/system/gonk/Volume.h b/dom/system/gonk/Volume.h deleted file mode 100644 index 821292a9a..000000000 --- a/dom/system/gonk/Volume.h +++ /dev/null @@ -1,157 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_volume_h__ -#define mozilla_system_volume_h__ - -#include "VolumeCommand.h" -#include "nsIVolume.h" -#include "nsString.h" -#include "mozilla/Observer.h" -#include "nsISupportsImpl.h" -#include "nsWhitespaceTokenizer.h" - -namespace mozilla { -namespace system { - -/*************************************************************************** -* -* There is an instance of the Volume class for each volume reported -* from vold. -* -* Each volume originates from the /system/etv/vold.fstab file. -* -***************************************************************************/ - -class Volume; - -#define DEBUG_VOLUME_OBSERVER 0 - -#if DEBUG_VOLUME_OBSERVER -class VolumeObserverList : public mozilla::ObserverList<Volume*> -{ -public: - void Broadcast(Volume* const& aVolume); -}; -#else -typedef mozilla::ObserverList<Volume*> VolumeObserverList; -#endif - -class Volume final -{ -public: - NS_INLINE_DECL_REFCOUNTING(Volume) - - Volume(const nsCSubstring& aVolumeName); - - typedef long STATE; // States are now defined in nsIVolume.idl - - static const char* StateStr(STATE aState) { return NS_VolumeStateStr(aState); } - const char* StateStr() const { return StateStr(mState); } - STATE State() const { return mState; } - - const nsCString& Name() const { return mName; } - const char* NameStr() const { return mName.get(); } - - void Dump(const char* aLabel) const; - - // The mount point is the name of the directory where the volume is mounted. - // (i.e. path that leads to the files stored on the volume). - const nsCString& MountPoint() const { return mMountPoint; } - - uint32_t Id() const { return mId; } - - int32_t MountGeneration() const { return mMountGeneration; } - bool IsMountLocked() const { return mMountLocked; } - bool MediaPresent() const { return mMediaPresent; } - bool CanBeShared() const { return mCanBeShared; } - bool CanBeFormatted() const { return CanBeShared(); } - bool CanBeMounted() const { return CanBeShared(); } - bool IsSharingEnabled() const { return mCanBeShared && mSharingEnabled; } - bool IsFormatRequested() const { return CanBeFormatted() && mFormatRequested; } - bool IsMountRequested() const { return CanBeMounted() && mMountRequested; } - bool IsUnmountRequested() const { return CanBeMounted() && mUnmountRequested; } - bool IsSharing() const { return mIsSharing; } - bool IsFormatting() const { return mIsFormatting; } - bool IsUnmounting() const { return mIsUnmounting; } - bool IsRemovable() const { return mIsRemovable; } - bool IsHotSwappable() const { return mIsHotSwappable; } - - void SetFakeVolume(const nsACString& aMountPoint); - - void SetSharingEnabled(bool aSharingEnabled); - void SetFormatRequested(bool aFormatRequested); - void SetMountRequested(bool aMountRequested); - void SetUnmountRequested(bool aUnmountRequested); - - typedef mozilla::Observer<Volume *> EventObserver; - - // NOTE: that observers must live in the IOThread. - static void RegisterVolumeObserver(EventObserver* aObserver, const char* aName); - static void UnregisterVolumeObserver(EventObserver* aObserver, const char* aName); - -protected: - ~Volume() {} - -private: - friend class AutoMounter; // Calls StartXxx - friend class nsVolume; // Calls UpdateMountLock - friend class VolumeManager; // Calls HandleVoldResponse - friend class VolumeListCallback; // Calls SetMountPoint, SetState - - // The StartXxx functions will queue up a command to the VolumeManager. - // You can queue up as many commands as you like, and aCallback will - // be called as each one completes. - void StartMount(VolumeResponseCallback* aCallback); - void StartUnmount(VolumeResponseCallback* aCallback); - void StartFormat(VolumeResponseCallback* aCallback); - void StartShare(VolumeResponseCallback* aCallback); - void StartUnshare(VolumeResponseCallback* aCallback); - - void SetIsSharing(bool aIsSharing); - void SetIsFormatting(bool aIsFormatting); - void SetIsUnmounting(bool aIsUnmounting); - void SetIsRemovable(bool aIsRemovable); - void SetIsHotSwappable(bool aIsHotSwappable); - void SetState(STATE aNewState); - void SetMediaPresent(bool aMediaPresent); - void SetMountPoint(const nsCSubstring& aMountPoint); - void StartCommand(VolumeCommand* aCommand); - - void ResolveAndSetMountPoint(const nsCSubstring& aMountPoint); - - bool BoolConfigValue(const nsCString& aConfigValue, bool& aBoolValue); - void SetConfig(const nsCString& aConfigName, const nsCString& aConfigValue); - - void HandleVoldResponse(int aResponseCode, nsCWhitespaceTokenizer& aTokenizer); - - static void UpdateMountLock(const nsACString& aVolumeName, - const int32_t& aMountGeneration, - const bool& aMountLocked); - - bool mMediaPresent; - STATE mState; - const nsCString mName; - nsCString mMountPoint; - int32_t mMountGeneration; - bool mMountLocked; - bool mSharingEnabled; - bool mFormatRequested; - bool mMountRequested; - bool mUnmountRequested; - bool mCanBeShared; - bool mIsSharing; - bool mIsFormatting; - bool mIsUnmounting; - bool mIsRemovable; - bool mIsHotSwappable; - uint32_t mId; // Unique ID (used by MTP) - - static VolumeObserverList sEventObserverList; -}; - -} // system -} // mozilla - -#endif // mozilla_system_volumemanager_h__ diff --git a/dom/system/gonk/VolumeCommand.cpp b/dom/system/gonk/VolumeCommand.cpp deleted file mode 100644 index 8095956a7..000000000 --- a/dom/system/gonk/VolumeCommand.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsString.h" -#include "nsWhitespaceTokenizer.h" - -#include "Volume.h" -#include "VolumeCommand.h" -#include "VolumeManager.h" -#include "VolumeManagerLog.h" - -namespace mozilla { -namespace system { - -/*************************************************************************** -* -* The VolumeActionCommand class is used to send commands which apply -* to a particular volume. -* -* The following commands would fit into this category: -* -* volume mount <volname> -* volume unmount <volname> [force] -* volume format <volname> -* volume share <volname> <method> -* volume unshare <volname> <method> -* volume shared <volname> <method> -* -* A typical response looks like: -* -* # vdc volume unshare sdcard ums -* 605 Volume sdcard /mnt/sdcard state changed from 7 (Shared-Unmounted) to 1 (Idle-Unmounted) -* 200 volume operation succeeded -* -* Note that the 600 series of responses are considered unsolicited and -* are dealt with directly by the VolumeManager. This command will only -* see the terminating response code (200 in the example above). -* -***************************************************************************/ - -VolumeActionCommand::VolumeActionCommand(Volume* aVolume, - const char* aAction, - const char* aExtraArgs, - VolumeResponseCallback* aCallback) - : VolumeCommand(aCallback), - mVolume(aVolume) -{ - nsAutoCString cmd; - - cmd = "volume "; - cmd += aAction; - cmd += " "; - cmd += aVolume->Name().get(); - - // vold doesn't like trailing white space, so only add it if we really need to. - if (aExtraArgs && (*aExtraArgs != '\0')) { - cmd += " "; - cmd += aExtraArgs; - } - SetCmd(cmd); -} - -/*************************************************************************** -* -* The VolumeListCommand class is used to send the "volume list" command to -* vold. -* -* A typical response looks like: -* -* # vdc volume list -* 110 sdcard /mnt/sdcard 4 -* 110 sdcard1 /mnt/sdcard/external_sd 4 -* 200 Volumes listed. -* -***************************************************************************/ - -VolumeListCommand::VolumeListCommand(VolumeResponseCallback* aCallback) - : VolumeCommand(NS_LITERAL_CSTRING("volume list"), aCallback) -{ -} - -} // system -} // mozilla - diff --git a/dom/system/gonk/VolumeCommand.h b/dom/system/gonk/VolumeCommand.h deleted file mode 100644 index 022965b5e..000000000 --- a/dom/system/gonk/VolumeCommand.h +++ /dev/null @@ -1,204 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_volumecommand_h__ -#define mozilla_system_volumecommand_h__ - -#include "nsString.h" -#include "nsISupportsImpl.h" -#include "mozilla/RefPtr.h" -#include <algorithm> -#include <vold/ResponseCode.h> - -namespace mozilla { -namespace system { - -class Volume; -class VolumeCommand; - -/*************************************************************************** -* -* The VolumeResponseCallback class is an abstract base class. The ResponseReceived -* method will be called for each response received. -* -* Depending on the command, there may be multiple responses for the -* command. Done() will return true if this is the last response. -* -* The responses from vold are all of the form: -* -* <ResponseCode> <String> -* -* Valid Response codes can be found in the vold/ResponseCode.h header. -* -***************************************************************************/ - -class VolumeResponseCallback -{ -protected: - virtual ~VolumeResponseCallback() {} - -public: - NS_INLINE_DECL_REFCOUNTING(VolumeResponseCallback) - VolumeResponseCallback() - : mResponseCode(0), mPending(false) {} - - bool Done() const - { - // Response codes from the 200, 400, and 500 series all indicated that - // the command has completed. - - return (mResponseCode >= ::ResponseCode::CommandOkay) - && (mResponseCode < ::ResponseCode::UnsolicitedInformational); - } - - bool WasSuccessful() const - { - return mResponseCode == ::ResponseCode::CommandOkay; - } - - bool IsPending() const { return mPending; } - int ResponseCode() const { return mResponseCode; } - const nsCString &ResponseStr() const { return mResponseStr; } - -protected: - virtual void ResponseReceived(const VolumeCommand* aCommand) = 0; - -private: - friend class VolumeCommand; // Calls HandleResponse and SetPending - - void HandleResponse(const VolumeCommand* aCommand, - int aResponseCode, - nsACString& aResponseStr) - { - mResponseCode = aResponseCode; -#if ANDROID_VERSION >= 17 - // There's a sequence number here that we don't care about - // We expect it to be 0. See VolumeCommand::SetCmd - mResponseStr = Substring(aResponseStr, 2); -#else - mResponseStr = aResponseStr; -#endif - if (mResponseCode >= ::ResponseCode::CommandOkay) { - // This is a final response. - mPending = false; - } - ResponseReceived(aCommand); - } - - void SetPending(bool aPending) { mPending = aPending; } - - int mResponseCode; // The response code parsed from vold - nsCString mResponseStr; // The rest of the line. - bool mPending; // Waiting for response? -}; - -/*************************************************************************** -* -* The VolumeCommand class is an abstract base class used to encapsulate -* volume commands send to vold. -* -* See VolumeManager.h for a list of the volume commands. -* -* Commands sent to vold need an explicit null character so we add one -* to the command to ensure that it's included in the length. -* -* All of these commands are asynchronous in nature, and the -* ResponseReceived callback will be called when a response is available. -* -***************************************************************************/ - -class VolumeCommand -{ -protected: - virtual ~VolumeCommand() {} - -public: - NS_INLINE_DECL_REFCOUNTING(VolumeCommand) - - VolumeCommand(VolumeResponseCallback* aCallback) - : mBytesConsumed(0), - mCallback(aCallback) - { - SetCmd(NS_LITERAL_CSTRING("")); - } - - VolumeCommand(const nsACString& aCommand, VolumeResponseCallback* aCallback) - : mBytesConsumed(0), - mCallback(aCallback) - { - SetCmd(aCommand); - } - - void SetCmd(const nsACString& aCommand) - { - mCmd.Truncate(); -#if ANDROID_VERSION >= 17 - // JB requires a sequence number at the beginning of messages. - // It doesn't matter what we use, so we use 0. - mCmd = "0 "; -#endif - mCmd.Append(aCommand); - // Add a null character. We want this to be included in the length since - // vold uses it to determine the end of the command. - mCmd.Append('\0'); - } - - const char* CmdStr() const { return mCmd.get(); } - const char* Data() const { return mCmd.Data() + mBytesConsumed; } - size_t BytesConsumed() const { return mBytesConsumed; } - - size_t BytesRemaining() const - { - return mCmd.Length() - std::min(mCmd.Length(), mBytesConsumed); - } - - void ConsumeBytes(size_t aNumBytes) - { - mBytesConsumed += std::min(BytesRemaining(), aNumBytes); - } - -private: - friend class VolumeManager; // Calls SetPending & HandleResponse - - void SetPending(bool aPending) - { - if (mCallback) { - mCallback->SetPending(aPending); - } - } - - void HandleResponse(int aResponseCode, nsACString& aResponseStr) - { - if (mCallback) { - mCallback->HandleResponse(this, aResponseCode, aResponseStr); - } - } - - nsCString mCmd; // Command being sent - size_t mBytesConsumed; // How many bytes have been sent - - // Called when a response to the command is received. - RefPtr<VolumeResponseCallback> mCallback; -}; - -class VolumeActionCommand : public VolumeCommand -{ -public: - VolumeActionCommand(Volume* aVolume, const char* aAction, - const char* aExtraArgs, VolumeResponseCallback* aCallback); - -private: - RefPtr<Volume> mVolume; -}; - -class VolumeListCommand : public VolumeCommand -{ -public: - VolumeListCommand(VolumeResponseCallback* aCallback); -}; - -} // system -} // mozilla - -#endif // mozilla_system_volumecommand_h__ diff --git a/dom/system/gonk/VolumeManager.cpp b/dom/system/gonk/VolumeManager.cpp deleted file mode 100644 index ddfa7af09..000000000 --- a/dom/system/gonk/VolumeManager.cpp +++ /dev/null @@ -1,591 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "VolumeManager.h" - -#include "Volume.h" -#include "VolumeCommand.h" -#include "VolumeManagerLog.h" -#include "VolumeServiceTest.h" - -#include "nsWhitespaceTokenizer.h" -#include "nsXULAppAPI.h" - -#include "base/message_loop.h" -#include "base/task.h" -#include "mozilla/Scoped.h" -#include "mozilla/StaticPtr.h" - -#include <android/log.h> -#include <cutils/sockets.h> -#include <fcntl.h> -#include <sys/socket.h> - -namespace mozilla { -namespace system { - -static StaticRefPtr<VolumeManager> sVolumeManager; - -VolumeManager::STATE VolumeManager::mState = VolumeManager::UNINITIALIZED; -VolumeManager::StateObserverList VolumeManager::mStateObserverList; - -/***************************************************************************/ - -VolumeManager::VolumeManager() - : LineWatcher('\0', kRcvBufSize), - mSocket(-1), - mCommandPending(false) -{ - DBG("VolumeManager constructor called"); -} - -VolumeManager::~VolumeManager() -{ -} - -//static -void -VolumeManager::Dump(const char* aLabel) -{ - if (!sVolumeManager) { - LOG("%s: sVolumeManager == null", aLabel); - return; - } - - VolumeArray::size_type numVolumes = NumVolumes(); - VolumeArray::index_type volIndex; - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr<Volume> vol = GetVolume(volIndex); - vol->Dump(aLabel); - } -} - -//static -size_t -VolumeManager::NumVolumes() -{ - if (!sVolumeManager) { - return 0; - } - return sVolumeManager->mVolumeArray.Length(); -} - -//static -already_AddRefed<Volume> -VolumeManager::GetVolume(size_t aIndex) -{ - MOZ_ASSERT(aIndex < NumVolumes()); - RefPtr<Volume> vol = sVolumeManager->mVolumeArray[aIndex]; - return vol.forget(); -} - -//static -VolumeManager::STATE -VolumeManager::State() -{ - return mState; -} - -//static -const char * -VolumeManager::StateStr(VolumeManager::STATE aState) -{ - switch (aState) { - case UNINITIALIZED: return "Uninitialized"; - case STARTING: return "Starting"; - case VOLUMES_READY: return "Volumes Ready"; - } - return "???"; -} - - -//static -void -VolumeManager::SetState(STATE aNewState) -{ - if (mState != aNewState) { - LOG("changing state from '%s' to '%s'", - StateStr(mState), StateStr(aNewState)); - mState = aNewState; - mStateObserverList.Broadcast(StateChangedEvent()); - } -} - -//static -void -VolumeManager::RegisterStateObserver(StateObserver* aObserver) -{ - mStateObserverList.AddObserver(aObserver); -} - -//static -void VolumeManager::UnregisterStateObserver(StateObserver* aObserver) -{ - mStateObserverList.RemoveObserver(aObserver); -} - -//static -already_AddRefed<Volume> -VolumeManager::FindVolumeByName(const nsCSubstring& aName) -{ - if (!sVolumeManager) { - return nullptr; - } - VolumeArray::size_type numVolumes = NumVolumes(); - VolumeArray::index_type volIndex; - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr<Volume> vol = GetVolume(volIndex); - if (vol->Name().Equals(aName)) { - return vol.forget(); - } - } - return nullptr; -} - -//static -already_AddRefed<Volume> -VolumeManager::FindAddVolumeByName(const nsCSubstring& aName) -{ - RefPtr<Volume> vol = FindVolumeByName(aName); - if (vol) { - return vol.forget(); - } - // No volume found, create and add a new one. - vol = new Volume(aName); - sVolumeManager->mVolumeArray.AppendElement(vol); - return vol.forget(); -} - -//static -bool -VolumeManager::RemoveVolumeByName(const nsCSubstring& aName) -{ - if (!sVolumeManager) { - return false; - } - VolumeArray::size_type numVolumes = NumVolumes(); - VolumeArray::index_type volIndex; - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr<Volume> vol = GetVolume(volIndex); - if (vol->Name().Equals(aName)) { - sVolumeManager->mVolumeArray.RemoveElementAt(volIndex); - return true; - } - } - // No volume found. Return false to indicate this. - return false; -} - - -//static -void VolumeManager::InitConfig() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - // This function uses /system/etc/volume.cfg to add additional volumes - // to the Volume Manager. - // - // This is useful on devices like the Nexus 4, which have no physical sd card - // or dedicated partition. - // - // The format of the volume.cfg file is as follows: - // create volume-name mount-point - // configure volume-name preference preference-value - // Blank lines and lines starting with the hash character "#" will be ignored. - - ScopedCloseFile fp; - int n = 0; - char line[255]; - const char *filename = "/system/etc/volume.cfg"; - if (!(fp = fopen(filename, "r"))) { - LOG("Unable to open volume configuration file '%s' - ignoring", filename); - return; - } - while(fgets(line, sizeof(line), fp)) { - n++; - - if (line[0] == '#') - continue; - - nsCString commandline(line); - nsCWhitespaceTokenizer tokenizer(commandline); - if (!tokenizer.hasMoreTokens()) { - // Blank line - ignore - continue; - } - - nsCString command(tokenizer.nextToken()); - if (command.EqualsLiteral("create")) { - if (!tokenizer.hasMoreTokens()) { - ERR("No vol_name in %s line %d", filename, n); - continue; - } - nsCString volName(tokenizer.nextToken()); - if (!tokenizer.hasMoreTokens()) { - ERR("No mount point for volume '%s'. %s line %d", - volName.get(), filename, n); - continue; - } - nsCString mountPoint(tokenizer.nextToken()); - RefPtr<Volume> vol = FindAddVolumeByName(volName); - vol->SetFakeVolume(mountPoint); - continue; - } - if (command.EqualsLiteral("configure")) { - if (!tokenizer.hasMoreTokens()) { - ERR("No vol_name in %s line %d", filename, n); - continue; - } - nsCString volName(tokenizer.nextToken()); - if (!tokenizer.hasMoreTokens()) { - ERR("No configuration name specified for volume '%s'. %s line %d", - volName.get(), filename, n); - continue; - } - nsCString configName(tokenizer.nextToken()); - if (!tokenizer.hasMoreTokens()) { - ERR("No value for configuration name '%s'. %s line %d", - configName.get(), filename, n); - continue; - } - nsCString configValue(tokenizer.nextToken()); - RefPtr<Volume> vol = FindVolumeByName(volName); - if (vol) { - vol->SetConfig(configName, configValue); - } else { - ERR("Invalid volume name '%s'.", volName.get()); - } - continue; - } - if (command.EqualsLiteral("ignore")) { - // This command is useful to remove volumes which are being tracked by - // vold, but for which we have no interest. - if (!tokenizer.hasMoreTokens()) { - ERR("No vol_name in %s line %d", filename, n); - continue; - } - nsCString volName(tokenizer.nextToken()); - RemoveVolumeByName(volName); - continue; - } - ERR("Unrecognized command: '%s'", command.get()); - } -} - -void -VolumeManager::DefaultConfig() -{ - - VolumeManager::VolumeArray::size_type numVolumes = VolumeManager::NumVolumes(); - if (numVolumes == 0) { - return; - } - if (numVolumes == 1) { - // This is to cover early shipping phones like the Buri, - // which had no internal storage, and only external sdcard. - // - // Phones line the nexus-4 which only have an internal - // storage area will need to have a volume.cfg file with - // removable set to false. - RefPtr<Volume> vol = VolumeManager::GetVolume(0); - vol->SetIsRemovable(true); - vol->SetIsHotSwappable(true); - return; - } - VolumeManager::VolumeArray::index_type volIndex; - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr<Volume> vol = VolumeManager::GetVolume(volIndex); - if (!vol->Name().EqualsLiteral("sdcard")) { - vol->SetIsRemovable(true); - vol->SetIsHotSwappable(true); - } - } -} - -class VolumeListCallback : public VolumeResponseCallback -{ - virtual void ResponseReceived(const VolumeCommand* aCommand) - { - switch (ResponseCode()) { - case ::ResponseCode::VolumeListResult: { - // Each line will look something like: - // - // sdcard /mnt/sdcard 1 - // - // So for each volume that we get back, we update any volumes that - // we have of the same name, or add new ones if they don't exist. - nsCWhitespaceTokenizer tokenizer(ResponseStr()); - nsDependentCSubstring volName(tokenizer.nextToken()); - RefPtr<Volume> vol = VolumeManager::FindAddVolumeByName(volName); - vol->HandleVoldResponse(ResponseCode(), tokenizer); - break; - } - - case ::ResponseCode::CommandOkay: { - // We've received the list of volumes. Now read the Volume.cfg - // file to perform customizations, and then tell everybody - // that we're ready for business. - VolumeManager::DefaultConfig(); - VolumeManager::InitConfig(); - VolumeManager::Dump("READY"); - VolumeManager::SetState(VolumeManager::VOLUMES_READY); - break; - } - } - } -}; - -bool -VolumeManager::OpenSocket() -{ - SetState(STARTING); - if ((mSocket.rwget() = socket_local_client("vold", - ANDROID_SOCKET_NAMESPACE_RESERVED, - SOCK_STREAM)) < 0) { - ERR("Error connecting to vold: (%s) - will retry", strerror(errno)); - return false; - } - // add FD_CLOEXEC flag - int flags = fcntl(mSocket.get(), F_GETFD); - if (flags == -1) { - return false; - } - flags |= FD_CLOEXEC; - if (fcntl(mSocket.get(), F_SETFD, flags) == -1) { - return false; - } - // set non-blocking - if (fcntl(mSocket.get(), F_SETFL, O_NONBLOCK) == -1) { - return false; - } - if (!MessageLoopForIO::current()-> - WatchFileDescriptor(mSocket.get(), - true, - MessageLoopForIO::WATCH_READ, - &mReadWatcher, - this)) { - return false; - } - - LOG("Connected to vold"); - PostCommand(new VolumeListCommand(new VolumeListCallback)); - return true; -} - -//static -void -VolumeManager::PostCommand(VolumeCommand* aCommand) -{ - if (!sVolumeManager) { - ERR("VolumeManager not initialized. Dropping command '%s'", aCommand->Data()); - return; - } - aCommand->SetPending(true); - - DBG("Sending command '%s'", aCommand->Data()); - // vold can only process one command at a time, so add our command - // to the end of the command queue. - sVolumeManager->mCommands.push(aCommand); - if (!sVolumeManager->mCommandPending) { - // There aren't any commands currently being processed, so go - // ahead and kick this one off. - sVolumeManager->mCommandPending = true; - sVolumeManager->WriteCommandData(); - } -} - -/*************************************************************************** -* The WriteCommandData initiates sending of a command to vold. Since -* we're running on the IOThread and not allowed to block, WriteCommandData -* will write as much data as it can, and if not all of the data can be -* written then it will setup a file descriptor watcher and -* OnFileCanWriteWithoutBlocking will call WriteCommandData to write out -* more of the command data. -*/ -void -VolumeManager::WriteCommandData() -{ - if (mCommands.size() == 0) { - return; - } - - VolumeCommand* cmd = mCommands.front(); - if (cmd->BytesRemaining() == 0) { - // All bytes have been written. We're waiting for a response. - return; - } - // There are more bytes left to write. Try to write them all. - ssize_t bytesWritten = write(mSocket.get(), cmd->Data(), cmd->BytesRemaining()); - if (bytesWritten < 0) { - ERR("Failed to write %d bytes to vold socket", cmd->BytesRemaining()); - Restart(); - return; - } - DBG("Wrote %d bytes (of %d)", bytesWritten, cmd->BytesRemaining()); - cmd->ConsumeBytes(bytesWritten); - if (cmd->BytesRemaining() == 0) { - return; - } - // We were unable to write all of the command bytes. Setup a watcher - // so we'll get called again when we can write without blocking. - if (!MessageLoopForIO::current()-> - WatchFileDescriptor(mSocket.get(), - false, // one-shot - MessageLoopForIO::WATCH_WRITE, - &mWriteWatcher, - this)) { - ERR("Failed to setup write watcher for vold socket"); - Restart(); - } -} - -void -VolumeManager::OnLineRead(int aFd, nsDependentCSubstring& aMessage) -{ - MOZ_ASSERT(aFd == mSocket.get()); - char* endPtr; - int responseCode = strtol(aMessage.Data(), &endPtr, 10); - if (*endPtr == ' ') { - endPtr++; - } - - // Now fish out the rest of the line after the response code - nsDependentCString responseLine(endPtr, aMessage.Length() - (endPtr - aMessage.Data())); - DBG("Rcvd: %d '%s'", responseCode, responseLine.Data()); - - if (responseCode >= ::ResponseCode::UnsolicitedInformational) { - // These are unsolicited broadcasts. We intercept these and process - // them ourselves - HandleBroadcast(responseCode, responseLine); - } else { - // Everything else is considered to be part of the command response. - if (mCommands.size() > 0) { - VolumeCommand* cmd = mCommands.front(); - cmd->HandleResponse(responseCode, responseLine); - if (responseCode >= ::ResponseCode::CommandOkay) { - // That's a terminating response. We can remove the command. - mCommands.pop(); - mCommandPending = false; - // Start the next command, if there is one. - WriteCommandData(); - } - } else { - ERR("Response with no command"); - } - } -} - -void -VolumeManager::OnFileCanWriteWithoutBlocking(int aFd) -{ - MOZ_ASSERT(aFd == mSocket.get()); - WriteCommandData(); -} - -void -VolumeManager::HandleBroadcast(int aResponseCode, nsCString& aResponseLine) -{ - // Format of the line is something like: - // - // Volume sdcard /mnt/sdcard state changed from 7 (Shared-Unmounted) to 1 (Idle-Unmounted) - // - // So we parse out the volume name and the state after the string " to " - nsCWhitespaceTokenizer tokenizer(aResponseLine); - tokenizer.nextToken(); // The word "Volume" - nsDependentCSubstring volName(tokenizer.nextToken()); - - RefPtr<Volume> vol = FindVolumeByName(volName); - if (!vol) { - return; - } - vol->HandleVoldResponse(aResponseCode, tokenizer); -} - -void -VolumeManager::Restart() -{ - mReadWatcher.StopWatchingFileDescriptor(); - mWriteWatcher.StopWatchingFileDescriptor(); - - while (!mCommands.empty()) { - mCommands.pop(); - } - mCommandPending = false; - mSocket.dispose(); - Start(); -} - -//static -void -VolumeManager::Start() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - if (!sVolumeManager) { - return; - } - SetState(STARTING); - if (!sVolumeManager->OpenSocket()) { - // Socket open failed, try again in a second. - MessageLoopForIO::current()-> - PostDelayedTask(NewRunnableFunction(VolumeManager::Start), - 1000); - } -} - -void -VolumeManager::OnError() -{ - Restart(); -} - -/***************************************************************************/ - -static void -InitVolumeManagerIOThread() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - MOZ_ASSERT(!sVolumeManager); - - sVolumeManager = new VolumeManager(); - VolumeManager::Start(); - - InitVolumeServiceTestIOThread(); -} - -static void -ShutdownVolumeManagerIOThread() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - sVolumeManager = nullptr; -} - -/************************************************************************** -* -* Public API -* -* Since the VolumeManager runs in IO Thread context, we need to switch -* to IOThread context before we can do anything. -* -**************************************************************************/ - -void -InitVolumeManager() -{ - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(InitVolumeManagerIOThread)); -} - -void -ShutdownVolumeManager() -{ - ShutdownVolumeServiceTest(); - - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(ShutdownVolumeManagerIOThread)); -} - -} // system -} // mozilla diff --git a/dom/system/gonk/VolumeManager.h b/dom/system/gonk/VolumeManager.h deleted file mode 100644 index 7c0503389..000000000 --- a/dom/system/gonk/VolumeManager.h +++ /dev/null @@ -1,192 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_volumemanager_h__ -#define mozilla_system_volumemanager_h__ - -#include <vector> -#include <queue> - -#include "base/message_loop.h" -#include "mozilla/FileUtils.h" -#include "mozilla/Observer.h" -#include "nsISupportsImpl.h" -#include "nsString.h" -#include "nsTArray.h" - -#include "Volume.h" -#include "VolumeCommand.h" - -namespace mozilla { -namespace system { - -/*************************************************************************** -* -* All of the public API mentioned in this file (unless otherwise -* mentioned) must run from the IOThread. -* -***************************************************************************/ - -/*************************************************************************** -* -* The VolumeManager class is a front-end for android's vold service. -* -* Vold uses a unix socket interface and accepts null-terminated string -* commands. The following commands were determined by examining the vold -* source code: -* -* volume list -* volume mount <volname> -* volume unmount <volname> [force] -* volume debug [on|off] -* volume format <volname> -* volume share <volname> <method> -* volume unshare <volname> <method> -* volume shared <volname> <method> -* -* <volname> is the name of the volume as used in /system/etc/vold.fstab -* <method> is ums -* -* dump -* -* share status <method> (Determines if a particular sharing method is available) -* (GB only - not available in ICS) -* -* storage users (??? always crashes vold ???) -* -* asec list -* asec ...lots more... -* -* obb list -* obb ...lots more... -* -* xwarp enable -* xwarp disable -* xwarp status -* -* There is also a command line tool called vdc, which can be used to send -* the above commands to vold. -* -* Currently, only the volume list, share/unshare, and mount/unmount -* commands are being used. -* -***************************************************************************/ - -class VolumeManager final : public MessageLoopForIO::LineWatcher -{ - virtual ~VolumeManager(); - -public: - NS_INLINE_DECL_REFCOUNTING(VolumeManager) - - typedef nsTArray<RefPtr<Volume>> VolumeArray; - - VolumeManager(); - - //----------------------------------------------------------------------- - // - // State related methods. - // - // The VolumeManager starts off in the STARTING state. Once a connection - // is established with vold, it asks for a list of volumes, and once the - // volume list has been received, then the VolumeManager enters the - // VOLUMES_READY state. - // - // If vold crashes, then the VolumeManager will once again enter the - // STARTING state and try to reestablish a connection with vold. - - enum STATE - { - UNINITIALIZED, - STARTING, - VOLUMES_READY - }; - - static STATE State(); - static const char* StateStr(STATE aState); - static const char* StateStr() { return StateStr(State()); } - - class StateChangedEvent - { - public: - StateChangedEvent() {} - }; - - typedef mozilla::Observer<StateChangedEvent> StateObserver; - typedef mozilla::ObserverList<StateChangedEvent> StateObserverList; - - static void RegisterStateObserver(StateObserver* aObserver); - static void UnregisterStateObserver(StateObserver* aObserver); - - //----------------------------------------------------------------------- - - static void Start(); - static void Dump(const char* aLabel); - - static VolumeArray::size_type NumVolumes(); - static already_AddRefed<Volume> GetVolume(VolumeArray::index_type aIndex); - static already_AddRefed<Volume> FindVolumeByName(const nsCSubstring& aName); - static already_AddRefed<Volume> FindAddVolumeByName(const nsCSubstring& aName); - static bool RemoveVolumeByName(const nsCSubstring& aName); - static void InitConfig(); - - static void PostCommand(VolumeCommand* aCommand); - -protected: - - virtual void OnLineRead(int aFd, nsDependentCSubstring& aMessage); - virtual void OnFileCanWriteWithoutBlocking(int aFd); - virtual void OnError(); - - static void DefaultConfig(); - -private: - bool OpenSocket(); - - friend class VolumeListCallback; // Calls SetState - - static void SetState(STATE aNewState); - - void Restart(); - void WriteCommandData(); - void HandleBroadcast(int aResponseCode, nsCString& aResponseLine); - - typedef std::queue<RefPtr<VolumeCommand> > CommandQueue; - - static STATE mState; - static StateObserverList mStateObserverList; - - static const int kRcvBufSize = 1024; - ScopedClose mSocket; - VolumeArray mVolumeArray; - CommandQueue mCommands; - bool mCommandPending; - MessageLoopForIO::FileDescriptorWatcher mReadWatcher; - MessageLoopForIO::FileDescriptorWatcher mWriteWatcher; - RefPtr<VolumeResponseCallback> mBroadcastCallback; -}; - -/*************************************************************************** -* -* The initialization/shutdown functions do not need to be called from -* the IOThread context. -* -***************************************************************************/ - -/** - * Initialize the Volume Manager. On initialization, the VolumeManager will - * attempt to connect with vold and collect the list of volumes that vold - * knows about. - */ -void InitVolumeManager(); - -/** - * Shuts down the Volume Manager. - */ -void ShutdownVolumeManager(); - -} // system -} // mozilla - -#endif // mozilla_system_volumemanager_h__ diff --git a/dom/system/gonk/VolumeManagerLog.h b/dom/system/gonk/VolumeManagerLog.h deleted file mode 100644 index 793f4889c..000000000 --- a/dom/system/gonk/VolumeManagerLog.h +++ /dev/null @@ -1,27 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_volumemanagerlog_h__ -#define mozilla_system_volumemanagerlog_h__ - -#undef USE_DEBUG -#define USE_DEBUG 0 - -#if !defined(VOLUME_MANAGER_LOG_TAG) -#define VOLUME_MANAGER_LOG_TAG "VolumeManager" -#endif - -#undef LOG -#undef ERR -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, VOLUME_MANAGER_LOG_TAG, ## args) -#define ERR(args...) __android_log_print(ANDROID_LOG_ERROR, VOLUME_MANAGER_LOG_TAG, ## args) - -#undef DBG -#if USE_DEBUG -#define DBG(args...) __android_log_print(ANDROID_LOG_DEBUG, VOLUME_MANAGER_LOG_TAG, ## args) -#else -#define DBG(args...) -#endif - -#endif // mozilla_system_volumemanagerlog_h__ diff --git a/dom/system/gonk/VolumeServiceIOThread.cpp b/dom/system/gonk/VolumeServiceIOThread.cpp deleted file mode 100644 index 7eda843c0..000000000 --- a/dom/system/gonk/VolumeServiceIOThread.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "VolumeServiceIOThread.h" -#include "base/message_loop.h" -#include "nsVolumeService.h" -#include "nsXULAppAPI.h" -#include "Volume.h" -#include "VolumeManager.h" - -namespace mozilla { -namespace system { - -VolumeServiceIOThread::VolumeServiceIOThread(nsVolumeService* aVolumeService) - : mVolumeService(aVolumeService) -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - VolumeManager::RegisterStateObserver(this); - Volume::RegisterVolumeObserver(this, "VolumeServiceIOThread"); - UpdateAllVolumes(); -} - -VolumeServiceIOThread::~VolumeServiceIOThread() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - Volume::UnregisterVolumeObserver(this, "VolumeServiceIOThread"); - VolumeManager::UnregisterStateObserver(this); -} - -void -VolumeServiceIOThread::Notify(Volume* const & aVolume) -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - if (VolumeManager::State() != VolumeManager::VOLUMES_READY) { - return; - } - mVolumeService->UpdateVolumeIOThread(aVolume); -} - -void -VolumeServiceIOThread::Notify(const VolumeManager::StateChangedEvent& aEvent) -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - UpdateAllVolumes(); -} - -void -VolumeServiceIOThread::UpdateAllVolumes() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - if (VolumeManager::State() != VolumeManager::VOLUMES_READY) { - return; - } - VolumeManager::VolumeArray::size_type numVolumes = VolumeManager::NumVolumes(); - VolumeManager::VolumeArray::index_type volIndex; - - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr<Volume> vol = VolumeManager::GetVolume(volIndex); - mVolumeService->UpdateVolumeIOThread(vol); - } -} - -static StaticRefPtr<VolumeServiceIOThread> sVolumeServiceIOThread; - -void -InitVolumeServiceIOThread(nsVolumeService* const & aVolumeService) -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - sVolumeServiceIOThread = new VolumeServiceIOThread(aVolumeService); -} - -void -ShutdownVolumeServiceIOThread() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - sVolumeServiceIOThread = nullptr; -} - -} // system -} // mozilla diff --git a/dom/system/gonk/VolumeServiceIOThread.h b/dom/system/gonk/VolumeServiceIOThread.h deleted file mode 100644 index 0c2a6a62f..000000000 --- a/dom/system/gonk/VolumeServiceIOThread.h +++ /dev/null @@ -1,49 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_volumeserviceiothread_h__ -#define mozilla_system_volumeserviceiothread_h__ - -#include "Volume.h" -#include "VolumeManager.h" -#include "mozilla/RefPtr.h" - -namespace mozilla { -namespace system { - -class nsVolumeService; - -/*************************************************************************** -* The nsVolumeServiceIOThread is a companion class to the nsVolumeService -* class, but whose methods are called from IOThread. -*/ -class VolumeServiceIOThread : public VolumeManager::StateObserver, - public Volume::EventObserver -{ - ~VolumeServiceIOThread(); - -public: - NS_INLINE_DECL_REFCOUNTING(VolumeServiceIOThread) - - VolumeServiceIOThread(nsVolumeService* aVolumeService); - -private: - void UpdateAllVolumes(); - - virtual void Notify(const VolumeManager::StateChangedEvent& aEvent); - virtual void Notify(Volume* const & aVolume); - - RefPtr<nsVolumeService> mVolumeService; -}; - -void InitVolumeServiceIOThread(nsVolumeService* const & aVolumeService); -void ShutdownVolumeServiceIOThread(); -void FormatVolume(const nsCString& aVolume); -void MountVolume(const nsCString& aVolume); -void UnmountVolume(const nsCString& aVolume); - -} // system -} // mozilla - -#endif // mozilla_system_volumeserviceiothread_h__ diff --git a/dom/system/gonk/VolumeServiceTest.cpp b/dom/system/gonk/VolumeServiceTest.cpp deleted file mode 100644 index 4082e3889..000000000 --- a/dom/system/gonk/VolumeServiceTest.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "VolumeServiceTest.h" - -#include "base/message_loop.h" -#include "nsCOMPtr.h" -#include "nsIObserver.h" -#include "nsIObserverService.h" -#include "nsServiceManagerUtils.h" -#include "nsThreadUtils.h" -#include "nsIVolume.h" -#include "nsIVolumeService.h" -#include "nsIVolumeStat.h" -#include "nsXULAppAPI.h" - -#include "mozilla/Services.h" - -#undef VOLUME_MANAGER_LOG_TAG -#define VOLUME_MANAGER_LOG_TAG "VolumeServiceTest" -#include "VolumeManagerLog.h" - -using namespace mozilla::services; - -namespace mozilla { -namespace system { - -#define TEST_NSVOLUME_OBSERVER 0 - -#if TEST_NSVOLUME_OBSERVER - -/*************************************************************************** -* A test class to verify that the Observer stuff is working properly. -*/ -class VolumeTestObserver : public nsIObserver -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER - - VolumeTestObserver() - { - nsCOMPtr<nsIObserverService> obs = GetObserverService(); - if (!obs) { - return; - } - obs->AddObserver(this, NS_VOLUME_STATE_CHANGED, false); - } - ~VolumeTestObserver() - { - nsCOMPtr<nsIObserverService> obs = GetObserverService(); - if (!obs) { - return; - } - obs->RemoveObserver(this, NS_VOLUME_STATE_CHANGED); - } - - void LogVolume(nsIVolume* vol) - { - nsString volName; - nsString mountPoint; - int32_t volState; - - vol->GetName(volName); - vol->GetMountPoint(mountPoint); - vol->GetState(&volState); - - LOG(" Volume: %s MountPoint: %s State: %s", - NS_LossyConvertUTF16toASCII(volName).get(), - NS_LossyConvertUTF16toASCII(mountPoint).get(), - NS_VolumeStateStr(volState)); - - nsCOMPtr<nsIVolumeStat> stat; - nsresult rv = vol->GetStats(getter_AddRefs(stat)); - if (NS_SUCCEEDED(rv)) { - int64_t totalBytes; - int64_t freeBytes; - - stat->GetTotalBytes(&totalBytes); - stat->GetFreeBytes(&freeBytes); - - LOG(" Total Space: %llu Mb Free Bytes: %llu Mb", - totalBytes / (1024LL * 1024LL), freeBytes / (1024LL * 1024LL)); - } - else { - LOG(" Unable to retrieve stats"); - } - } -}; -static nsCOMPtr<VolumeTestObserver> sTestObserver; - -NS_IMPL_ISUPPORTS(VolumeTestObserver, nsIObserver) - -NS_IMETHODIMP -VolumeTestObserver::Observe(nsISupports* aSubject, - const char* aTopic, - const char16_t* aData) -{ - LOG("TestObserver: topic: %s", aTopic); - - if (strcmp(aTopic, NS_VOLUME_STATE_CHANGED) != 0) { - return NS_OK; - } - nsCOMPtr<nsIVolume> vol = do_QueryInterface(aSubject); - if (vol) { - LogVolume(vol); - } - - // Since this observe method was called then we know that the service - // has been initialized so we can do the VolumeService tests. - - nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID); - if (!vs) { - ERR("do_GetService('%s') failed", NS_VOLUMESERVICE_CONTRACTID); - return NS_ERROR_FAILURE; - } - - nsresult rv = vs->GetVolumeByName(NS_LITERAL_STRING("sdcard"), getter_AddRefs(vol)); - if (NS_SUCCEEDED(rv)) { - LOG("GetVolumeByName( 'sdcard' ) succeeded (expected)"); - LogVolume(vol); - } else { - ERR("GetVolumeByName( 'sdcard' ) failed (unexpected)"); - } - - rv = vs->GetVolumeByName(NS_LITERAL_STRING("foo"), getter_AddRefs(vol)); - if (NS_SUCCEEDED(rv)) { - ERR("GetVolumeByName( 'foo' ) succeeded (unexpected)"); - } else { - LOG("GetVolumeByName( 'foo' ) failed (expected)"); - } - - rv = vs->GetVolumeByPath(NS_LITERAL_STRING("/mnt/sdcard"), getter_AddRefs(vol)); - if (NS_SUCCEEDED(rv)) { - LOG("GetVolumeByPath( '/mnt/sdcard' ) succeeded (expected)"); - LogVolume(vol); - } else { - ERR("GetVolumeByPath( '/mnt/sdcard' ) failed (unexpected"); - } - - rv = vs->GetVolumeByPath(NS_LITERAL_STRING("/mnt/sdcard/foo"), getter_AddRefs(vol)); - if (NS_SUCCEEDED(rv)) { - LOG("GetVolumeByPath( '/mnt/sdcard/foo' ) succeeded (expected)"); - LogVolume(vol); - } else { - LOG("GetVolumeByPath( '/mnt/sdcard/foo' ) failed (unexpected)"); - } - - rv = vs->GetVolumeByPath(NS_LITERAL_STRING("/mnt/sdcardfoo"), getter_AddRefs(vol)); - if (NS_SUCCEEDED(rv)) { - ERR("GetVolumeByPath( '/mnt/sdcardfoo' ) succeeded (unexpected)"); - } else { - LOG("GetVolumeByPath( '/mnt/sdcardfoo' ) failed (expected)"); - } - - return NS_OK; -} - -class InitVolumeServiceTestIO : public Runnable -{ -public: - NS_IMETHOD Run() override - { - MOZ_ASSERT(NS_IsMainThread()); - - DBG("InitVolumeServiceTest called"); - nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID); - if (!vs) { - ERR("do_GetService('%s') failed", NS_VOLUMESERVICE_CONTRACTID); - return NS_ERROR_FAILURE; - } - sTestObserver = new VolumeTestObserver(); - - return NS_OK; - } -}; -#endif // TEST_NSVOLUME_OBSERVER - -void -InitVolumeServiceTestIOThread() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - -#if TEST_NSVOLUME_OBSERVER - // Now that the volume manager is initialized we can go - // ahead and do our test (on main thread). - NS_DispatchToMainThread(new InitVolumeServiceTestIO()); -#endif -} - -void -ShutdownVolumeServiceTest() -{ -#if TEST_NSVOLUME_OBSERVER - DBG("ShutdownVolumeServiceTestIOThread called"); - sTestObserver = nullptr; -#endif -} - -} // system -} // mozilla diff --git a/dom/system/gonk/VolumeServiceTest.h b/dom/system/gonk/VolumeServiceTest.h deleted file mode 100644 index 71a92bf6c..000000000 --- a/dom/system/gonk/VolumeServiceTest.h +++ /dev/null @@ -1,19 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_volumeservicetest_h__ -#define mozilla_system_volumeservicetest_h__ - - -namespace mozilla { -namespace system { - -void InitVolumeServiceTestIOThread(); -void ShutdownVolumeServiceTest(); - -} // system -} // mozilla - -#endif // mozilla_system_volumeservicetest_h__ - diff --git a/dom/system/gonk/android_audio/AudioSystem.h b/dom/system/gonk/android_audio/AudioSystem.h deleted file mode 100644 index d5841eaaa..000000000 --- a/dom/system/gonk/android_audio/AudioSystem.h +++ /dev/null @@ -1,1134 +0,0 @@ -/* - * Copyright (C) 2008 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. - */ - -#ifndef ANDROID_AUDIOSYSTEM_H_ -#define ANDROID_AUDIOSYSTEM_H_ - -#pragma GCC visibility push(default) - -#include <utils/RefBase.h> -#include <utils/threads.h> -#include "IAudioFlinger.h" - -#ifndef VANILLA_ANDROID -/* request to open a direct output with get_output() (by opposition to - * sharing an output with other AudioTracks) - */ -typedef enum { - AUDIO_POLICY_OUTPUT_FLAG_INDIRECT = 0x0, - AUDIO_POLICY_OUTPUT_FLAG_DIRECT = 0x1 -} audio_policy_output_flags_t; - -/* device categories used for audio_policy->set_force_use() */ -typedef enum { - AUDIO_POLICY_FORCE_NONE, - AUDIO_POLICY_FORCE_SPEAKER, - AUDIO_POLICY_FORCE_HEADPHONES, - AUDIO_POLICY_FORCE_BT_SCO, - AUDIO_POLICY_FORCE_BT_A2DP, - AUDIO_POLICY_FORCE_WIRED_ACCESSORY, - AUDIO_POLICY_FORCE_BT_CAR_DOCK, - AUDIO_POLICY_FORCE_BT_DESK_DOCK, - AUDIO_POLICY_FORCE_ANALOG_DOCK, - AUDIO_POLICY_FORCE_DIGITAL_DOCK, - AUDIO_POLICY_FORCE_NO_BT_A2DP, - AUDIO_POLICY_FORCE_CFG_CNT, - AUDIO_POLICY_FORCE_CFG_MAX = AUDIO_POLICY_FORCE_CFG_CNT - 1, - - AUDIO_POLICY_FORCE_DEFAULT = AUDIO_POLICY_FORCE_NONE, -} audio_policy_forced_cfg_t; - -/* usages used for audio_policy->set_force_use() */ -typedef enum { - AUDIO_POLICY_FORCE_FOR_COMMUNICATION, - AUDIO_POLICY_FORCE_FOR_MEDIA, - AUDIO_POLICY_FORCE_FOR_RECORD, - AUDIO_POLICY_FORCE_FOR_DOCK, - - AUDIO_POLICY_FORCE_USE_CNT, - AUDIO_POLICY_FORCE_USE_MAX = AUDIO_POLICY_FORCE_USE_CNT - 1, -} audio_policy_force_use_t; - -typedef enum { - AUDIO_STREAM_DEFAULT = -1, - AUDIO_STREAM_VOICE_CALL = 0, - AUDIO_STREAM_SYSTEM = 1, - AUDIO_STREAM_RING = 2, - AUDIO_STREAM_MUSIC = 3, - AUDIO_STREAM_ALARM = 4, - AUDIO_STREAM_NOTIFICATION = 5, - AUDIO_STREAM_BLUETOOTH_SCO = 6, - AUDIO_STREAM_ENFORCED_AUDIBLE = 7, /* Sounds that cannot be muted by user and must be routed to speaker */ - AUDIO_STREAM_DTMF = 8, - AUDIO_STREAM_TTS = 9, -#if ANDROID_VERSION < 19 - AUDIO_STREAM_FM = 10, -#endif - - AUDIO_STREAM_CNT, - AUDIO_STREAM_MAX = AUDIO_STREAM_CNT - 1, -} audio_stream_type_t; - -/* PCM sub formats */ -typedef enum { - AUDIO_FORMAT_PCM_SUB_16_BIT = 0x1, /* DO NOT CHANGE - PCM signed 16 bits */ - AUDIO_FORMAT_PCM_SUB_8_BIT = 0x2, /* DO NOT CHANGE - PCM unsigned 8 bits */ - AUDIO_FORMAT_PCM_SUB_32_BIT = 0x3, /* PCM signed .31 fixed point */ - AUDIO_FORMAT_PCM_SUB_8_24_BIT = 0x4, /* PCM signed 7.24 fixed point */ -} audio_format_pcm_sub_fmt_t; - -/* Audio format consists in a main format field (upper 8 bits) and a sub format - * field (lower 24 bits). - * - * The main format indicates the main codec type. The sub format field - * indicates options and parameters for each format. The sub format is mainly - * used for record to indicate for instance the requested bitrate or profile. - * It can also be used for certain formats to give informations not present in - * the encoded audio stream (e.g. octet alignement for AMR). - */ -typedef enum { - AUDIO_FORMAT_INVALID = 0xFFFFFFFFUL, - AUDIO_FORMAT_DEFAULT = 0, - AUDIO_FORMAT_PCM = 0x00000000UL, /* DO NOT CHANGE */ - AUDIO_FORMAT_MP3 = 0x01000000UL, - AUDIO_FORMAT_AMR_NB = 0x02000000UL, - AUDIO_FORMAT_AMR_WB = 0x03000000UL, - AUDIO_FORMAT_AAC = 0x04000000UL, - AUDIO_FORMAT_HE_AAC_V1 = 0x05000000UL, - AUDIO_FORMAT_HE_AAC_V2 = 0x06000000UL, - AUDIO_FORMAT_VORBIS = 0x07000000UL, - AUDIO_FORMAT_MAIN_MASK = 0xFF000000UL, - AUDIO_FORMAT_SUB_MASK = 0x00FFFFFFUL, - - /* Aliases */ - AUDIO_FORMAT_PCM_16_BIT = (AUDIO_FORMAT_PCM | - AUDIO_FORMAT_PCM_SUB_16_BIT), - AUDIO_FORMAT_PCM_8_BIT = (AUDIO_FORMAT_PCM | - AUDIO_FORMAT_PCM_SUB_8_BIT), - AUDIO_FORMAT_PCM_32_BIT = (AUDIO_FORMAT_PCM | - AUDIO_FORMAT_PCM_SUB_32_BIT), - AUDIO_FORMAT_PCM_8_24_BIT = (AUDIO_FORMAT_PCM | - AUDIO_FORMAT_PCM_SUB_8_24_BIT), -} audio_format_t; - -typedef enum { - /* output channels */ - AUDIO_CHANNEL_OUT_FRONT_LEFT = 0x1, - AUDIO_CHANNEL_OUT_FRONT_RIGHT = 0x2, - AUDIO_CHANNEL_OUT_FRONT_CENTER = 0x4, - AUDIO_CHANNEL_OUT_LOW_FREQUENCY = 0x8, - AUDIO_CHANNEL_OUT_BACK_LEFT = 0x10, - AUDIO_CHANNEL_OUT_BACK_RIGHT = 0x20, - AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x40, - AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x80, - AUDIO_CHANNEL_OUT_BACK_CENTER = 0x100, - AUDIO_CHANNEL_OUT_SIDE_LEFT = 0x200, - AUDIO_CHANNEL_OUT_SIDE_RIGHT = 0x400, - AUDIO_CHANNEL_OUT_TOP_CENTER = 0x800, - AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT = 0x1000, - AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER = 0x2000, - AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT = 0x4000, - AUDIO_CHANNEL_OUT_TOP_BACK_LEFT = 0x8000, - AUDIO_CHANNEL_OUT_TOP_BACK_CENTER = 0x10000, - AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT = 0x20000, - - AUDIO_CHANNEL_OUT_MONO = AUDIO_CHANNEL_OUT_FRONT_LEFT, - AUDIO_CHANNEL_OUT_STEREO = (AUDIO_CHANNEL_OUT_FRONT_LEFT | - AUDIO_CHANNEL_OUT_FRONT_RIGHT), - AUDIO_CHANNEL_OUT_QUAD = (AUDIO_CHANNEL_OUT_FRONT_LEFT | - AUDIO_CHANNEL_OUT_FRONT_RIGHT | - AUDIO_CHANNEL_OUT_BACK_LEFT | - AUDIO_CHANNEL_OUT_BACK_RIGHT), - AUDIO_CHANNEL_OUT_SURROUND = (AUDIO_CHANNEL_OUT_FRONT_LEFT | - AUDIO_CHANNEL_OUT_FRONT_RIGHT | - AUDIO_CHANNEL_OUT_FRONT_CENTER | - AUDIO_CHANNEL_OUT_BACK_CENTER), - AUDIO_CHANNEL_OUT_5POINT1 = (AUDIO_CHANNEL_OUT_FRONT_LEFT | - AUDIO_CHANNEL_OUT_FRONT_RIGHT | - AUDIO_CHANNEL_OUT_FRONT_CENTER | - AUDIO_CHANNEL_OUT_LOW_FREQUENCY | - AUDIO_CHANNEL_OUT_BACK_LEFT | - AUDIO_CHANNEL_OUT_BACK_RIGHT), - // matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND definition for 7.1 - AUDIO_CHANNEL_OUT_7POINT1 = (AUDIO_CHANNEL_OUT_FRONT_LEFT | - AUDIO_CHANNEL_OUT_FRONT_RIGHT | - AUDIO_CHANNEL_OUT_FRONT_CENTER | - AUDIO_CHANNEL_OUT_LOW_FREQUENCY | - AUDIO_CHANNEL_OUT_BACK_LEFT | - AUDIO_CHANNEL_OUT_BACK_RIGHT | - AUDIO_CHANNEL_OUT_SIDE_LEFT | - AUDIO_CHANNEL_OUT_SIDE_RIGHT), - AUDIO_CHANNEL_OUT_ALL = (AUDIO_CHANNEL_OUT_FRONT_LEFT | - AUDIO_CHANNEL_OUT_FRONT_RIGHT | - AUDIO_CHANNEL_OUT_FRONT_CENTER | - AUDIO_CHANNEL_OUT_LOW_FREQUENCY | - AUDIO_CHANNEL_OUT_BACK_LEFT | - AUDIO_CHANNEL_OUT_BACK_RIGHT | - AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER | - AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER | - AUDIO_CHANNEL_OUT_BACK_CENTER| - AUDIO_CHANNEL_OUT_SIDE_LEFT| - AUDIO_CHANNEL_OUT_SIDE_RIGHT| - AUDIO_CHANNEL_OUT_TOP_CENTER| - AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT| - AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER| - AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT| - AUDIO_CHANNEL_OUT_TOP_BACK_LEFT| - AUDIO_CHANNEL_OUT_TOP_BACK_CENTER| - AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT), - - /* input channels */ - AUDIO_CHANNEL_IN_LEFT = 0x4, - AUDIO_CHANNEL_IN_RIGHT = 0x8, - AUDIO_CHANNEL_IN_FRONT = 0x10, - AUDIO_CHANNEL_IN_BACK = 0x20, - AUDIO_CHANNEL_IN_LEFT_PROCESSED = 0x40, - AUDIO_CHANNEL_IN_RIGHT_PROCESSED = 0x80, - AUDIO_CHANNEL_IN_FRONT_PROCESSED = 0x100, - AUDIO_CHANNEL_IN_BACK_PROCESSED = 0x200, - AUDIO_CHANNEL_IN_PRESSURE = 0x400, - AUDIO_CHANNEL_IN_X_AXIS = 0x800, - AUDIO_CHANNEL_IN_Y_AXIS = 0x1000, - AUDIO_CHANNEL_IN_Z_AXIS = 0x2000, - AUDIO_CHANNEL_IN_VOICE_UPLINK = 0x4000, - AUDIO_CHANNEL_IN_VOICE_DNLINK = 0x8000, - - AUDIO_CHANNEL_IN_MONO = AUDIO_CHANNEL_IN_FRONT, - AUDIO_CHANNEL_IN_STEREO = (AUDIO_CHANNEL_IN_LEFT | AUDIO_CHANNEL_IN_RIGHT), - AUDIO_CHANNEL_IN_ALL = (AUDIO_CHANNEL_IN_LEFT | - AUDIO_CHANNEL_IN_RIGHT | - AUDIO_CHANNEL_IN_FRONT | - AUDIO_CHANNEL_IN_BACK| - AUDIO_CHANNEL_IN_LEFT_PROCESSED | - AUDIO_CHANNEL_IN_RIGHT_PROCESSED | - AUDIO_CHANNEL_IN_FRONT_PROCESSED | - AUDIO_CHANNEL_IN_BACK_PROCESSED| - AUDIO_CHANNEL_IN_PRESSURE | - AUDIO_CHANNEL_IN_X_AXIS | - AUDIO_CHANNEL_IN_Y_AXIS | - AUDIO_CHANNEL_IN_Z_AXIS | - AUDIO_CHANNEL_IN_VOICE_UPLINK | - AUDIO_CHANNEL_IN_VOICE_DNLINK), -} audio_channels_t; - -#if ANDROID_VERSION >= 17 -typedef enum { - AUDIO_MODE_INVALID = -2, - AUDIO_MODE_CURRENT = -1, - AUDIO_MODE_NORMAL = 0, - AUDIO_MODE_RINGTONE = 1, - AUDIO_MODE_IN_CALL = 2, - AUDIO_MODE_IN_COMMUNICATION = 3, - - AUDIO_MODE_CNT, - AUDIO_MODE_MAX = AUDIO_MODE_CNT - 1, -} audio_mode_t; -#endif -#endif - -#if ANDROID_VERSION < 17 -typedef enum { - AUDIO_DEVICE_NONE = 0x0, - /* output devices */ - AUDIO_DEVICE_OUT_EARPIECE = 0x1, - AUDIO_DEVICE_OUT_SPEAKER = 0x2, - AUDIO_DEVICE_OUT_WIRED_HEADSET = 0x4, - AUDIO_DEVICE_OUT_WIRED_HEADPHONE = 0x8, - AUDIO_DEVICE_OUT_BLUETOOTH_SCO = 0x10, - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20, - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40, - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP = 0x80, - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100, - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200, - AUDIO_DEVICE_OUT_AUX_DIGITAL = 0x400, - AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800, - AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000, - AUDIO_DEVICE_OUT_FM = 0x2000, - AUDIO_DEVICE_OUT_ANC_HEADSET = 0x4000, - AUDIO_DEVICE_OUT_ANC_HEADPHONE = 0x8000, - AUDIO_DEVICE_OUT_FM_TX = 0x10000, - AUDIO_DEVICE_OUT_DIRECTOUTPUT = 0x20000, - AUDIO_DEVICE_OUT_PROXY = 0x40000, - AUDIO_DEVICE_OUT_DEFAULT = 0x80000, - AUDIO_DEVICE_OUT_ALL = (AUDIO_DEVICE_OUT_EARPIECE | - AUDIO_DEVICE_OUT_SPEAKER | - AUDIO_DEVICE_OUT_WIRED_HEADSET | - AUDIO_DEVICE_OUT_WIRED_HEADPHONE | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | - AUDIO_DEVICE_OUT_AUX_DIGITAL | - AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET | - AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET | - AUDIO_DEVICE_OUT_FM | - AUDIO_DEVICE_OUT_ANC_HEADSET | - AUDIO_DEVICE_OUT_ANC_HEADPHONE | - AUDIO_DEVICE_OUT_FM_TX | - AUDIO_DEVICE_OUT_DIRECTOUTPUT | - AUDIO_DEVICE_OUT_PROXY | - AUDIO_DEVICE_OUT_DEFAULT), - AUDIO_DEVICE_OUT_ALL_A2DP = (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER), - AUDIO_DEVICE_OUT_ALL_SCO = (AUDIO_DEVICE_OUT_BLUETOOTH_SCO | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT), - /* input devices */ - AUDIO_DEVICE_IN_COMMUNICATION = 0x100000, - AUDIO_DEVICE_IN_AMBIENT = 0x200000, - AUDIO_DEVICE_IN_BUILTIN_MIC = 0x400000, - AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x800000, - AUDIO_DEVICE_IN_WIRED_HEADSET = 0x1000000, - AUDIO_DEVICE_IN_AUX_DIGITAL = 0x2000000, - AUDIO_DEVICE_IN_VOICE_CALL = 0x4000000, - AUDIO_DEVICE_IN_BACK_MIC = 0x8000000, - AUDIO_DEVICE_IN_ANC_HEADSET = 0x10000000, - AUDIO_DEVICE_IN_FM_RX = 0x20000000, - AUDIO_DEVICE_IN_FM_RX_A2DP = 0x40000000, - AUDIO_DEVICE_IN_DEFAULT = 0x80000000, - - AUDIO_DEVICE_IN_ALL = (AUDIO_DEVICE_IN_COMMUNICATION | - AUDIO_DEVICE_IN_AMBIENT | - AUDIO_DEVICE_IN_BUILTIN_MIC | - AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET | - AUDIO_DEVICE_IN_WIRED_HEADSET | - AUDIO_DEVICE_IN_AUX_DIGITAL | - AUDIO_DEVICE_IN_VOICE_CALL | - AUDIO_DEVICE_IN_BACK_MIC | - AUDIO_DEVICE_IN_ANC_HEADSET | - AUDIO_DEVICE_IN_FM_RX | - AUDIO_DEVICE_IN_FM_RX_A2DP | - AUDIO_DEVICE_IN_DEFAULT), - AUDIO_DEVICE_IN_ALL_SCO = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, -} audio_devices_t; -#elif ANDROID_VERSION < 21 -enum { - AUDIO_DEVICE_NONE = 0x0, - /* reserved bits */ - AUDIO_DEVICE_BIT_IN = 0x80000000, - AUDIO_DEVICE_BIT_DEFAULT = 0x40000000, - /* output devices */ - AUDIO_DEVICE_OUT_EARPIECE = 0x1, - AUDIO_DEVICE_OUT_SPEAKER = 0x2, - AUDIO_DEVICE_OUT_WIRED_HEADSET = 0x4, - AUDIO_DEVICE_OUT_WIRED_HEADPHONE = 0x8, - AUDIO_DEVICE_OUT_BLUETOOTH_SCO = 0x10, - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20, - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40, - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP = 0x80, - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100, - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200, - AUDIO_DEVICE_OUT_AUX_DIGITAL = 0x400, - AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800, - AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000, - AUDIO_DEVICE_OUT_USB_ACCESSORY = 0x2000, - AUDIO_DEVICE_OUT_USB_DEVICE = 0x4000, - AUDIO_DEVICE_OUT_REMOTE_SUBMIX = 0x8000, - AUDIO_DEVICE_OUT_ANC_HEADSET = 0x10000, - AUDIO_DEVICE_OUT_ANC_HEADPHONE = 0x20000, - AUDIO_DEVICE_OUT_PROXY = 0x40000, - AUDIO_DEVICE_OUT_FM = 0x80000, - AUDIO_DEVICE_OUT_FM_TX = 0x100000, - AUDIO_DEVICE_OUT_DEFAULT = AUDIO_DEVICE_BIT_DEFAULT, - AUDIO_DEVICE_OUT_ALL = (AUDIO_DEVICE_OUT_EARPIECE | - AUDIO_DEVICE_OUT_SPEAKER | - AUDIO_DEVICE_OUT_WIRED_HEADSET | - AUDIO_DEVICE_OUT_WIRED_HEADPHONE | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | - AUDIO_DEVICE_OUT_AUX_DIGITAL | - AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET | - AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET | - AUDIO_DEVICE_OUT_USB_ACCESSORY | - AUDIO_DEVICE_OUT_USB_DEVICE | - AUDIO_DEVICE_OUT_REMOTE_SUBMIX | - AUDIO_DEVICE_OUT_ANC_HEADSET | - AUDIO_DEVICE_OUT_ANC_HEADPHONE | - AUDIO_DEVICE_OUT_PROXY | - AUDIO_DEVICE_OUT_FM | - AUDIO_DEVICE_OUT_FM_TX | - AUDIO_DEVICE_OUT_DEFAULT), - AUDIO_DEVICE_OUT_ALL_A2DP = (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER), - AUDIO_DEVICE_OUT_ALL_SCO = (AUDIO_DEVICE_OUT_BLUETOOTH_SCO | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT), - AUDIO_DEVICE_OUT_ALL_USB = (AUDIO_DEVICE_OUT_USB_ACCESSORY | - AUDIO_DEVICE_OUT_USB_DEVICE), - - /* input devices */ - AUDIO_DEVICE_IN_COMMUNICATION = AUDIO_DEVICE_BIT_IN | 0x1, - AUDIO_DEVICE_IN_AMBIENT = AUDIO_DEVICE_BIT_IN | 0x2, - AUDIO_DEVICE_IN_BUILTIN_MIC = AUDIO_DEVICE_BIT_IN | 0x4, - AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET = AUDIO_DEVICE_BIT_IN | 0x8, - AUDIO_DEVICE_IN_WIRED_HEADSET = AUDIO_DEVICE_BIT_IN | 0x10, - AUDIO_DEVICE_IN_AUX_DIGITAL = AUDIO_DEVICE_BIT_IN | 0x20, - AUDIO_DEVICE_IN_VOICE_CALL = AUDIO_DEVICE_BIT_IN | 0x40, - AUDIO_DEVICE_IN_BACK_MIC = AUDIO_DEVICE_BIT_IN | 0x80, - AUDIO_DEVICE_IN_REMOTE_SUBMIX = AUDIO_DEVICE_BIT_IN | 0x100, - AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET = AUDIO_DEVICE_BIT_IN | 0x200, - AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET = AUDIO_DEVICE_BIT_IN | 0x400, - AUDIO_DEVICE_IN_USB_ACCESSORY = AUDIO_DEVICE_BIT_IN | 0x800, - AUDIO_DEVICE_IN_USB_DEVICE = AUDIO_DEVICE_BIT_IN | 0x1000, - AUDIO_DEVICE_IN_ANC_HEADSET = AUDIO_DEVICE_BIT_IN | 0x2000, - AUDIO_DEVICE_IN_PROXY = AUDIO_DEVICE_BIT_IN | 0x4000, - AUDIO_DEVICE_IN_FM_RX = AUDIO_DEVICE_BIT_IN | 0x8000, - AUDIO_DEVICE_IN_FM_RX_A2DP = AUDIO_DEVICE_BIT_IN | 0x10000, - AUDIO_DEVICE_IN_DEFAULT = AUDIO_DEVICE_BIT_IN | AUDIO_DEVICE_BIT_DEFAULT, - - AUDIO_DEVICE_IN_ALL = (AUDIO_DEVICE_IN_COMMUNICATION | - AUDIO_DEVICE_IN_AMBIENT | - AUDIO_DEVICE_IN_BUILTIN_MIC | - AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET | - AUDIO_DEVICE_IN_WIRED_HEADSET | - AUDIO_DEVICE_IN_AUX_DIGITAL | - AUDIO_DEVICE_IN_VOICE_CALL | - AUDIO_DEVICE_IN_BACK_MIC | - AUDIO_DEVICE_IN_REMOTE_SUBMIX | - AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET | - AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET | - AUDIO_DEVICE_IN_USB_ACCESSORY | - AUDIO_DEVICE_IN_USB_DEVICE | - AUDIO_DEVICE_IN_ANC_HEADSET | - AUDIO_DEVICE_IN_FM_RX | - AUDIO_DEVICE_IN_FM_RX_A2DP | - AUDIO_DEVICE_IN_PROXY | - AUDIO_DEVICE_IN_DEFAULT), - AUDIO_DEVICE_IN_ALL_SCO = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, -}; - -typedef uint32_t audio_devices_t; -#else -enum { - AUDIO_DEVICE_NONE = 0x0, - /* reserved bits */ - AUDIO_DEVICE_BIT_IN = 0x80000000, - AUDIO_DEVICE_BIT_DEFAULT = 0x40000000, - /* output devices */ - AUDIO_DEVICE_OUT_EARPIECE = 0x1, - AUDIO_DEVICE_OUT_SPEAKER = 0x2, - AUDIO_DEVICE_OUT_WIRED_HEADSET = 0x4, - AUDIO_DEVICE_OUT_WIRED_HEADPHONE = 0x8, - AUDIO_DEVICE_OUT_BLUETOOTH_SCO = 0x10, - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20, - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40, - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP = 0x80, - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100, - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200, - AUDIO_DEVICE_OUT_AUX_DIGITAL = 0x400, - AUDIO_DEVICE_OUT_HDMI = AUDIO_DEVICE_OUT_AUX_DIGITAL, - /* uses an analog connection (multiplexed over the USB connector pins for instance) */ - AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800, - AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000, - /* USB accessory mode: your Android device is a USB device and the dock is a USB host */ - AUDIO_DEVICE_OUT_USB_ACCESSORY = 0x2000, - /* USB host mode: your Android device is a USB host and the dock is a USB device */ - AUDIO_DEVICE_OUT_USB_DEVICE = 0x4000, - AUDIO_DEVICE_OUT_REMOTE_SUBMIX = 0x8000, - /* Telephony voice TX path */ - AUDIO_DEVICE_OUT_TELEPHONY_TX = 0x10000, - /* Analog jack with line impedance detected */ - AUDIO_DEVICE_OUT_LINE = 0x20000, - /* HDMI Audio Return Channel */ - AUDIO_DEVICE_OUT_HDMI_ARC = 0x40000, - /* S/PDIF out */ - AUDIO_DEVICE_OUT_SPDIF = 0x80000, - /* FM transmitter out */ - AUDIO_DEVICE_OUT_FM = 0x100000, - /* Line out for av devices */ - AUDIO_DEVICE_OUT_AUX_LINE = 0x200000, - /* limited-output speaker device for acoustic safety */ - AUDIO_DEVICE_OUT_SPEAKER_SAFE = 0x400000, - AUDIO_DEVICE_OUT_DEFAULT = AUDIO_DEVICE_BIT_DEFAULT, - AUDIO_DEVICE_OUT_ALL = (AUDIO_DEVICE_OUT_EARPIECE | - AUDIO_DEVICE_OUT_SPEAKER | - AUDIO_DEVICE_OUT_WIRED_HEADSET | - AUDIO_DEVICE_OUT_WIRED_HEADPHONE | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | - AUDIO_DEVICE_OUT_AUX_DIGITAL | - AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET | - AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET | - AUDIO_DEVICE_OUT_USB_ACCESSORY | - AUDIO_DEVICE_OUT_USB_DEVICE | - AUDIO_DEVICE_OUT_REMOTE_SUBMIX | - AUDIO_DEVICE_OUT_TELEPHONY_TX | - AUDIO_DEVICE_OUT_LINE | - AUDIO_DEVICE_OUT_HDMI_ARC | - AUDIO_DEVICE_OUT_SPDIF | - AUDIO_DEVICE_OUT_FM | - AUDIO_DEVICE_OUT_AUX_LINE | - AUDIO_DEVICE_OUT_SPEAKER_SAFE | - AUDIO_DEVICE_OUT_DEFAULT), - AUDIO_DEVICE_OUT_ALL_A2DP = (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER), - AUDIO_DEVICE_OUT_ALL_SCO = (AUDIO_DEVICE_OUT_BLUETOOTH_SCO | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT), - AUDIO_DEVICE_OUT_ALL_USB = (AUDIO_DEVICE_OUT_USB_ACCESSORY | - AUDIO_DEVICE_OUT_USB_DEVICE), - /* input devices */ - AUDIO_DEVICE_IN_COMMUNICATION = AUDIO_DEVICE_BIT_IN | 0x1, - AUDIO_DEVICE_IN_AMBIENT = AUDIO_DEVICE_BIT_IN | 0x2, - AUDIO_DEVICE_IN_BUILTIN_MIC = AUDIO_DEVICE_BIT_IN | 0x4, - AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET = AUDIO_DEVICE_BIT_IN | 0x8, - AUDIO_DEVICE_IN_WIRED_HEADSET = AUDIO_DEVICE_BIT_IN | 0x10, - AUDIO_DEVICE_IN_AUX_DIGITAL = AUDIO_DEVICE_BIT_IN | 0x20, - AUDIO_DEVICE_IN_HDMI = AUDIO_DEVICE_IN_AUX_DIGITAL, - /* Telephony voice RX path */ - AUDIO_DEVICE_IN_VOICE_CALL = AUDIO_DEVICE_BIT_IN | 0x40, - AUDIO_DEVICE_IN_BACK_MIC = AUDIO_DEVICE_BIT_IN | 0x80, - AUDIO_DEVICE_IN_REMOTE_SUBMIX = AUDIO_DEVICE_BIT_IN | 0x100, - AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET = AUDIO_DEVICE_BIT_IN | 0x200, - AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET = AUDIO_DEVICE_BIT_IN | 0x400, - AUDIO_DEVICE_IN_USB_ACCESSORY = AUDIO_DEVICE_BIT_IN | 0x800, - AUDIO_DEVICE_IN_USB_DEVICE = AUDIO_DEVICE_BIT_IN | 0x1000, - /* FM tuner input */ - AUDIO_DEVICE_IN_FM_TUNER = AUDIO_DEVICE_BIT_IN | 0x2000, - /* TV tuner input */ - AUDIO_DEVICE_IN_TV_TUNER = AUDIO_DEVICE_BIT_IN | 0x4000, - /* Analog jack with line impedance detected */ - AUDIO_DEVICE_IN_LINE = AUDIO_DEVICE_BIT_IN | 0x8000, - /* S/PDIF in */ - AUDIO_DEVICE_IN_SPDIF = AUDIO_DEVICE_BIT_IN | 0x10000, - AUDIO_DEVICE_IN_BLUETOOTH_A2DP = AUDIO_DEVICE_BIT_IN | 0x20000, - AUDIO_DEVICE_IN_LOOPBACK = AUDIO_DEVICE_BIT_IN | 0x40000, - AUDIO_DEVICE_IN_DEFAULT = AUDIO_DEVICE_BIT_IN | AUDIO_DEVICE_BIT_DEFAULT, - AUDIO_DEVICE_IN_ALL = (AUDIO_DEVICE_IN_COMMUNICATION | - AUDIO_DEVICE_IN_AMBIENT | - AUDIO_DEVICE_IN_BUILTIN_MIC | - AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET | - AUDIO_DEVICE_IN_WIRED_HEADSET | - AUDIO_DEVICE_IN_AUX_DIGITAL | - AUDIO_DEVICE_IN_VOICE_CALL | - AUDIO_DEVICE_IN_BACK_MIC | - AUDIO_DEVICE_IN_REMOTE_SUBMIX | - AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET | - AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET | - AUDIO_DEVICE_IN_USB_ACCESSORY | - AUDIO_DEVICE_IN_USB_DEVICE | - AUDIO_DEVICE_IN_FM_TUNER | - AUDIO_DEVICE_IN_TV_TUNER | - AUDIO_DEVICE_IN_LINE | - AUDIO_DEVICE_IN_SPDIF | - AUDIO_DEVICE_IN_BLUETOOTH_A2DP | - AUDIO_DEVICE_IN_LOOPBACK | - AUDIO_DEVICE_IN_DEFAULT), - AUDIO_DEVICE_IN_ALL_SCO = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, - AUDIO_DEVICE_IN_ALL_USB = (AUDIO_DEVICE_IN_USB_ACCESSORY | - AUDIO_DEVICE_IN_USB_DEVICE), -}; - -typedef uint32_t audio_devices_t; -#endif - -static inline bool audio_is_output_device(uint32_t device) -{ -#if ANDROID_VERSION < 17 - if ((__builtin_popcount(device) == 1) && ((device & ~AUDIO_DEVICE_OUT_ALL) == 0)) - return true; - else - return false; -#else - if (((device & AUDIO_DEVICE_BIT_IN) == 0) && - (__builtin_popcount(device) == 1) && ((device & ~AUDIO_DEVICE_OUT_ALL) == 0)) - return true; - else - return false; -#endif -} - -/* device connection states used for audio_policy->set_device_connection_state() - * */ -typedef enum { - AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, - AUDIO_POLICY_DEVICE_STATE_AVAILABLE, - - AUDIO_POLICY_DEVICE_STATE_CNT, - AUDIO_POLICY_DEVICE_STATE_MAX = AUDIO_POLICY_DEVICE_STATE_CNT - 1, -} audio_policy_dev_state_t; - -namespace android { - -typedef void (*audio_error_callback)(status_t err); -typedef int audio_io_handle_t; - -class IAudioPolicyService; -class String8; - -class AudioSystem -{ -public: - - enum stream_type { - DEFAULT =-1, - VOICE_CALL = 0, - SYSTEM = 1, - RING = 2, - MUSIC = 3, - ALARM = 4, - NOTIFICATION = 5, - BLUETOOTH_SCO = 6, - ENFORCED_AUDIBLE = 7, // Sounds that cannot be muted by user and must be routed to speaker - DTMF = 8, - TTS = 9, - FM = 10, - NUM_STREAM_TYPES - }; - - // Audio sub formats (see AudioSystem::audio_format). - enum pcm_sub_format { - PCM_SUB_16_BIT = 0x1, // must be 1 for backward compatibility - PCM_SUB_8_BIT = 0x2, // must be 2 for backward compatibility - }; - - // MP3 sub format field definition : can use 11 LSBs in the same way as MP3 frame header to specify - // bit rate, stereo mode, version... - enum mp3_sub_format { - //TODO - }; - - // AMR NB/WB sub format field definition: specify frame block interleaving, bandwidth efficient or octet aligned, - // encoding mode for recording... - enum amr_sub_format { - //TODO - }; - - // AAC sub format field definition: specify profile or bitrate for recording... - enum aac_sub_format { - //TODO - }; - - // VORBIS sub format field definition: specify quality for recording... - enum vorbis_sub_format { - //TODO - }; - - // Audio format consists in a main format field (upper 8 bits) and a sub format field (lower 24 bits). - // The main format indicates the main codec type. The sub format field indicates options and parameters - // for each format. The sub format is mainly used for record to indicate for instance the requested bitrate - // or profile. It can also be used for certain formats to give informations not present in the encoded - // audio stream (e.g. octet alignement for AMR). - enum audio_format { - INVALID_FORMAT = -1, - FORMAT_DEFAULT = 0, - PCM = 0x00000000, // must be 0 for backward compatibility - MP3 = 0x01000000, - AMR_NB = 0x02000000, - AMR_WB = 0x03000000, - AAC = 0x04000000, - HE_AAC_V1 = 0x05000000, - HE_AAC_V2 = 0x06000000, - VORBIS = 0x07000000, - EVRC = 0x08000000, - QCELP = 0x09000000, - VOIP_PCM_INPUT = 0x0A000000, - MAIN_FORMAT_MASK = 0xFF000000, - SUB_FORMAT_MASK = 0x00FFFFFF, - // Aliases - PCM_16_BIT = (PCM|PCM_SUB_16_BIT), - PCM_8_BIT = (PCM|PCM_SUB_8_BIT) - }; - - - // Channel mask definitions must be kept in sync with JAVA values in /media/java/android/media/AudioFormat.java - enum audio_channels { - // output channels - CHANNEL_OUT_FRONT_LEFT = 0x4, - CHANNEL_OUT_FRONT_RIGHT = 0x8, - CHANNEL_OUT_FRONT_CENTER = 0x10, - CHANNEL_OUT_LOW_FREQUENCY = 0x20, - CHANNEL_OUT_BACK_LEFT = 0x40, - CHANNEL_OUT_BACK_RIGHT = 0x80, - CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x100, - CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x200, - CHANNEL_OUT_BACK_CENTER = 0x400, - CHANNEL_OUT_MONO = CHANNEL_OUT_FRONT_LEFT, - CHANNEL_OUT_STEREO = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT), - CHANNEL_OUT_QUAD = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | - CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT), - CHANNEL_OUT_SURROUND = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | - CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_CENTER), - CHANNEL_OUT_5POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | - CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT), - CHANNEL_OUT_7POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | - CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT | - CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER), - CHANNEL_OUT_ALL = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | - CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT | - CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER | CHANNEL_OUT_BACK_CENTER), - - // input channels - CHANNEL_IN_LEFT = 0x4, - CHANNEL_IN_RIGHT = 0x8, - CHANNEL_IN_FRONT = 0x10, - CHANNEL_IN_BACK = 0x20, - CHANNEL_IN_LEFT_PROCESSED = 0x40, - CHANNEL_IN_RIGHT_PROCESSED = 0x80, - CHANNEL_IN_FRONT_PROCESSED = 0x100, - CHANNEL_IN_BACK_PROCESSED = 0x200, - CHANNEL_IN_PRESSURE = 0x400, - CHANNEL_IN_X_AXIS = 0x800, - CHANNEL_IN_Y_AXIS = 0x1000, - CHANNEL_IN_Z_AXIS = 0x2000, - CHANNEL_IN_VOICE_UPLINK = 0x4000, - CHANNEL_IN_VOICE_DNLINK = 0x8000, - CHANNEL_IN_MONO = CHANNEL_IN_FRONT, - CHANNEL_IN_STEREO = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT), - CHANNEL_IN_ALL = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT | CHANNEL_IN_FRONT | CHANNEL_IN_BACK| - CHANNEL_IN_LEFT_PROCESSED | CHANNEL_IN_RIGHT_PROCESSED | CHANNEL_IN_FRONT_PROCESSED | CHANNEL_IN_BACK_PROCESSED| - CHANNEL_IN_PRESSURE | CHANNEL_IN_X_AXIS | CHANNEL_IN_Y_AXIS | CHANNEL_IN_Z_AXIS | - CHANNEL_IN_VOICE_UPLINK | CHANNEL_IN_VOICE_DNLINK) - }; - - enum audio_mode { - MODE_INVALID = -2, - MODE_CURRENT = -1, - MODE_NORMAL = 0, - MODE_RINGTONE, - MODE_IN_CALL, - MODE_IN_COMMUNICATION, - NUM_MODES // not a valid entry, denotes end-of-list - }; - - enum audio_in_acoustics { - AGC_ENABLE = 0x0001, - AGC_DISABLE = 0, - NS_ENABLE = 0x0002, - NS_DISABLE = 0, - TX_IIR_ENABLE = 0x0004, - TX_DISABLE = 0 - }; - - // special audio session values - enum audio_sessions { - SESSION_OUTPUT_STAGE = -1, // session for effects attached to a particular output stream - // (value must be less than 0) - SESSION_OUTPUT_MIX = 0, // session for effects applied to output mix. These effects can - // be moved by audio policy manager to another output stream - // (value must be 0) - }; - - /* These are static methods to control the system-wide AudioFlinger - * only privileged processes can have access to them - */ - - // mute/unmute microphone - static status_t muteMicrophone(bool state); - static status_t isMicrophoneMuted(bool *state); - - // set/get master volume - static status_t setMasterVolume(float value); - static status_t getMasterVolume(float* volume); - // mute/unmute audio outputs - static status_t setMasterMute(bool mute); - static status_t getMasterMute(bool* mute); - - // set/get stream volume on specified output - static status_t setStreamVolume(int stream, float value, int output); - static status_t getStreamVolume(int stream, float* volume, int output); - - // mute/unmute stream - static status_t setStreamMute(int stream, bool mute); - static status_t getStreamMute(int stream, bool* mute); - - // set audio mode in audio hardware (see AudioSystem::audio_mode) - static status_t setMode(int mode); - - // returns true in *state if tracks are active on the specified stream - static status_t isStreamActive(int stream, bool *state); - - // set/get audio hardware parameters. The function accepts a list of parameters - // key value pairs in the form: key1=value1;key2=value2;... - // Some keys are reserved for standard parameters (See AudioParameter class). - static status_t setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs); - static String8 getParameters(audio_io_handle_t ioHandle, const String8& keys); - - static void setErrorCallback(audio_error_callback cb); - - // helper function to obtain AudioFlinger service handle - static const sp<IAudioFlinger>& get_audio_flinger(); - - static float linearToLog(int volume); - static int logToLinear(float volume); - - static status_t getOutputSamplingRate(int* samplingRate, int stream = DEFAULT); - static status_t getOutputFrameCount(int* frameCount, int stream = DEFAULT); - static status_t getOutputLatency(uint32_t* latency, int stream = DEFAULT); - - static bool routedToA2dpOutput(int streamType); - - static status_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount, - size_t* buffSize); - - static status_t setVoiceVolume(float volume); - - // return the number of audio frames written by AudioFlinger to audio HAL and - // audio dsp to DAC since the output on which the specificed stream is playing - // has exited standby. - // returned status (from utils/Errors.h) can be: - // - NO_ERROR: successful operation, halFrames and dspFrames point to valid data - // - INVALID_OPERATION: Not supported on current hardware platform - // - BAD_VALUE: invalid parameter - // NOTE: this feature is not supported on all hardware platforms and it is - // necessary to check returned status before using the returned values. - static status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int stream = DEFAULT); - - static unsigned int getInputFramesLost(audio_io_handle_t ioHandle); - - static int newAudioSessionId(); - // - // AudioPolicyService interface - // - - enum audio_devices { - // output devices - DEVICE_OUT_EARPIECE = 0x1, - DEVICE_OUT_SPEAKER = 0x2, - DEVICE_OUT_WIRED_HEADSET = 0x4, - DEVICE_OUT_WIRED_HEADPHONE = 0x8, - DEVICE_OUT_BLUETOOTH_SCO = 0x10, - DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20, - DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40, - DEVICE_OUT_BLUETOOTH_A2DP = 0x80, - DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100, - DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200, - DEVICE_OUT_AUX_DIGITAL = 0x400, - DEVICE_OUT_DEFAULT = 0x8000, - DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE | DEVICE_OUT_SPEAKER | DEVICE_OUT_WIRED_HEADSET | - DEVICE_OUT_WIRED_HEADPHONE | DEVICE_OUT_BLUETOOTH_SCO | DEVICE_OUT_BLUETOOTH_SCO_HEADSET | - DEVICE_OUT_BLUETOOTH_SCO_CARKIT | DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | - DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | DEVICE_OUT_AUX_DIGITAL | DEVICE_OUT_DEFAULT), - DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | - DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER), - - // input devices - DEVICE_IN_COMMUNICATION = 0x10000, - DEVICE_IN_AMBIENT = 0x20000, - DEVICE_IN_BUILTIN_MIC = 0x40000, - DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x80000, - DEVICE_IN_WIRED_HEADSET = 0x100000, - DEVICE_IN_AUX_DIGITAL = 0x200000, - DEVICE_IN_VOICE_CALL = 0x400000, - DEVICE_IN_BACK_MIC = 0x800000, - DEVICE_IN_DEFAULT = 0x80000000, - - DEVICE_IN_ALL = (DEVICE_IN_COMMUNICATION | DEVICE_IN_AMBIENT | DEVICE_IN_BUILTIN_MIC | - DEVICE_IN_BLUETOOTH_SCO_HEADSET | DEVICE_IN_WIRED_HEADSET | DEVICE_IN_AUX_DIGITAL | - DEVICE_IN_VOICE_CALL | DEVICE_IN_BACK_MIC | DEVICE_IN_DEFAULT) - }; - - // device connection states used for setDeviceConnectionState() - enum device_connection_state { - DEVICE_STATE_UNAVAILABLE, - DEVICE_STATE_AVAILABLE, - NUM_DEVICE_STATES - }; - - // request to open a direct output with getOutput() (by opposition to sharing an output with other AudioTracks) - enum output_flags { - OUTPUT_FLAG_INDIRECT = 0x0, - OUTPUT_FLAG_DIRECT = 0x1 - }; - - // device categories used for setForceUse() - enum forced_config { - FORCE_NONE, - FORCE_SPEAKER, - FORCE_HEADPHONES, - FORCE_BT_SCO, - FORCE_BT_A2DP, - FORCE_WIRED_ACCESSORY, - FORCE_BT_CAR_DOCK, - FORCE_BT_DESK_DOCK, - FORCE_ANALOG_DOCK, - FORCE_DIGITAL_DOCK, - FORCE_NO_BT_A2DP, - NUM_FORCE_CONFIG, - FORCE_DEFAULT = FORCE_NONE - }; - - // usages used for setForceUse() - enum force_use { - FOR_COMMUNICATION, - FOR_MEDIA, - FOR_RECORD, - FOR_DOCK, - NUM_FORCE_USE - }; - - // types of io configuration change events received with ioConfigChanged() - enum io_config_event { - OUTPUT_OPENED, - OUTPUT_CLOSED, - OUTPUT_CONFIG_CHANGED, - INPUT_OPENED, - INPUT_CLOSED, - INPUT_CONFIG_CHANGED, - STREAM_CONFIG_CHANGED, - NUM_CONFIG_EVENTS - }; - - // audio output descritor used to cache output configurations in client process to avoid frequent calls - // through IAudioFlinger - class OutputDescriptor { - public: - OutputDescriptor() - : samplingRate(0), format(0), channels(0), frameCount(0), latency(0) {} - - uint32_t samplingRate; - int32_t format; - int32_t channels; - size_t frameCount; - uint32_t latency; - }; - - // - // IAudioPolicyService interface (see AudioPolicyInterface for method descriptions) - // - static status_t setDeviceConnectionState(audio_devices device, device_connection_state state, const char *device_address); - static device_connection_state getDeviceConnectionState(audio_devices device, const char *device_address); - static status_t setPhoneState(int state); -#if ANDROID_VERSION >= 17 - static status_t setPhoneState(audio_mode_t state); -#endif - static status_t setRingerMode(uint32_t mode, uint32_t mask); -#ifdef VANILLA_ANDROID - static status_t setForceUse(force_use usage, forced_config config); - static forced_config getForceUse(force_use usage); - static audio_io_handle_t getOutput(stream_type stream, - uint32_t samplingRate = 0, - uint32_t format = FORMAT_DEFAULT, - uint32_t channels = CHANNEL_OUT_STEREO, - output_flags flags = OUTPUT_FLAG_INDIRECT); - static status_t setDeviceConnectionState(audio_devices_t device, audio_policy_dev_state_t state, const char *device_address); - static status_t setFmVolume(float volume); - static audio_policy_dev_state_t getDeviceConnectionState(audio_devices_t device, const char *device_address); -#else - static status_t setForceUse(force_use usage, forced_config config) __attribute__((weak)); - static forced_config getForceUse(force_use usage) __attribute__((weak)); - static audio_io_handle_t getOutput(stream_type stream, - uint32_t samplingRate = 0, - uint32_t format = FORMAT_DEFAULT, - uint32_t channels = CHANNEL_OUT_STEREO, - output_flags flags = OUTPUT_FLAG_INDIRECT) __attribute__((weak)); - - static status_t setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config) __attribute__((weak)); - static audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) __attribute__((weak)); - static audio_io_handle_t getOutput(audio_stream_type_t stream, - uint32_t samplingRate = 0, - uint32_t format = AUDIO_FORMAT_DEFAULT, - uint32_t channels = AUDIO_CHANNEL_OUT_STEREO, - audio_policy_output_flags_t flags = AUDIO_POLICY_OUTPUT_FLAG_INDIRECT) __attribute__((weak)); - static status_t setDeviceConnectionState(audio_devices_t device, audio_policy_dev_state_t state, const char *device_address) __attribute__((weak)); - static status_t setFmVolume(float volume) __attribute__((weak)); - static audio_policy_dev_state_t getDeviceConnectionState(audio_devices_t device, const char *device_address) __attribute__((weak)); - -#endif - static status_t startOutput(audio_io_handle_t output, - AudioSystem::stream_type stream, - int session = 0); - static status_t stopOutput(audio_io_handle_t output, - AudioSystem::stream_type stream, - int session = 0); - static void releaseOutput(audio_io_handle_t output); - static audio_io_handle_t getInput(int inputSource, - uint32_t samplingRate = 0, - uint32_t format = FORMAT_DEFAULT, - uint32_t channels = CHANNEL_IN_MONO, - audio_in_acoustics acoustics = (audio_in_acoustics)0); - static status_t startInput(audio_io_handle_t input); - static status_t stopInput(audio_io_handle_t input); - static void releaseInput(audio_io_handle_t input); - static status_t initStreamVolume(stream_type stream, - int indexMin, - int indexMax); - static status_t initStreamVolume(audio_stream_type_t stream, - int indexMin, - int indexMax); - static status_t setStreamVolumeIndex(stream_type stream, int index); - static status_t setStreamVolumeIndex(audio_stream_type_t stream, int index); -#if ANDROID_VERSION >= 17 - static status_t setStreamVolumeIndex(audio_stream_type_t stream, - int index, - audio_devices_t device); - static status_t getStreamVolumeIndex(audio_stream_type_t stream, - int *index, - audio_devices_t device); -#endif - static status_t getStreamVolumeIndex(stream_type stream, int *index); - static status_t getStreamVolumeIndex(audio_stream_type_t stream, int *index); - - static uint32_t getStrategyForStream(stream_type stream); -#if ANDROID_VERSION >= 17 - static audio_devices_t getDevicesForStream(audio_stream_type_t stream); -#endif - - static audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc); - static status_t registerEffect(effect_descriptor_t *desc, - audio_io_handle_t output, - uint32_t strategy, - int session, - int id); - static status_t unregisterEffect(int id); - - static const sp<IAudioPolicyService>& get_audio_policy_service(); - - // ---------------------------------------------------------------------------- - - static uint32_t popCount(uint32_t u); - static bool isOutputDevice(audio_devices device); - static bool isInputDevice(audio_devices device); - static bool isA2dpDevice(audio_devices device); - static bool isBluetoothScoDevice(audio_devices device); - static bool isSeperatedStream(stream_type stream); - static bool isLowVisibility(stream_type stream); - static bool isOutputChannel(uint32_t channel); - static bool isInputChannel(uint32_t channel); - static bool isValidFormat(uint32_t format); - static bool isLinearPCM(uint32_t format); - static bool isModeInCall(); - -#if ANDROID_VERSION >= 21 - class AudioPortCallback : public RefBase - { - public: - - AudioPortCallback() {} - virtual ~AudioPortCallback() {} - - virtual void onAudioPortListUpdate() = 0; - virtual void onAudioPatchListUpdate() = 0; - virtual void onServiceDied() = 0; - - }; - - static void setAudioPortCallback(sp<AudioPortCallback> callBack); -#endif - -private: - - class AudioFlingerClient: public IBinder::DeathRecipient, public BnAudioFlingerClient - { - public: - AudioFlingerClient() { - } - - // DeathRecipient - virtual void binderDied(const wp<IBinder>& who); - - // IAudioFlingerClient - - // indicate a change in the configuration of an output or input: keeps the cached - // values for output/input parameters upto date in client process - virtual void ioConfigChanged(int event, int ioHandle, void *param2); - }; - - class AudioPolicyServiceClient: public IBinder::DeathRecipient - { - public: - AudioPolicyServiceClient() { - } - - // DeathRecipient - virtual void binderDied(const wp<IBinder>& who); - }; - - static sp<AudioFlingerClient> gAudioFlingerClient; - static sp<AudioPolicyServiceClient> gAudioPolicyServiceClient; - friend class AudioFlingerClient; - friend class AudioPolicyServiceClient; - - static Mutex gLock; - static sp<IAudioFlinger> gAudioFlinger; - static audio_error_callback gAudioErrorCallback; - - static size_t gInBuffSize; - // previous parameters for recording buffer size queries - static uint32_t gPrevInSamplingRate; - static int gPrevInFormat; - static int gPrevInChannelCount; - - static sp<IAudioPolicyService> gAudioPolicyService; - - // mapping between stream types and outputs - static DefaultKeyedVector<int, audio_io_handle_t> gStreamOutputMap; - // list of output descritor containing cached parameters (sampling rate, framecount, channel count...) - static DefaultKeyedVector<audio_io_handle_t, OutputDescriptor *> gOutputs; -}; - -class AudioParameter { - -public: - AudioParameter() {} - AudioParameter(const String8& keyValuePairs); - virtual ~AudioParameter(); - - // reserved parameter keys for changing standard parameters with setParameters() function. - // Using these keys is mandatory for AudioFlinger to properly monitor audio output/input - // configuration changes and act accordingly. - // keyRouting: to change audio routing, value is an int in AudioSystem::audio_devices - // keySamplingRate: to change sampling rate routing, value is an int - // keyFormat: to change audio format, value is an int in AudioSystem::audio_format - // keyChannels: to change audio channel configuration, value is an int in AudioSystem::audio_channels - // keyFrameCount: to change audio output frame count, value is an int - // keyInputSource: to change audio input source, value is an int in audio_source - // (defined in media/mediarecorder.h) - static const char *keyRouting; - static const char *keySamplingRate; - static const char *keyFormat; - static const char *keyChannels; - static const char *keyFrameCount; - static const char *keyInputSource; - - String8 toString(); - - status_t add(const String8& key, const String8& value); - status_t addInt(const String8& key, const int value); - status_t addFloat(const String8& key, const float value); - - status_t remove(const String8& key); - - status_t get(const String8& key, String8& value); - status_t getInt(const String8& key, int& value); - status_t getFloat(const String8& key, float& value); - status_t getAt(size_t index, String8& key, String8& value); - - size_t size() { return mParameters.size(); } - -private: - String8 mKeyValuePairs; - KeyedVector <String8, String8> mParameters; -}; - -}; // namespace android - -#pragma GCC visibility pop - -#endif /*ANDROID_AUDIOSYSTEM_H_*/ diff --git a/dom/system/gonk/android_audio/AudioTrack.h b/dom/system/gonk/android_audio/AudioTrack.h deleted file mode 100644 index 6f8c6bb28..000000000 --- a/dom/system/gonk/android_audio/AudioTrack.h +++ /dev/null @@ -1,489 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -#ifndef ANDROID_AUDIOTRACK_H -#define ANDROID_AUDIOTRACK_H - -#include <stdint.h> -#include <sys/types.h> - -#include "IAudioFlinger.h" -#include "IAudioTrack.h" -#include "AudioSystem.h" - -#include <utils/RefBase.h> -#include <utils/Errors.h> -#include <binder/IInterface.h> -#include <binder/IMemory.h> -#include <utils/threads.h> - - -namespace android { - -// ---------------------------------------------------------------------------- - -class audio_track_cblk_t; - -// ---------------------------------------------------------------------------- - -class AudioTrack -{ -public: - enum channel_index { - MONO = 0, - LEFT = 0, - RIGHT = 1 - }; - - /* Events used by AudioTrack callback function (audio_track_cblk_t). - */ - enum event_type { - EVENT_MORE_DATA = 0, // Request to write more data to PCM buffer. - EVENT_UNDERRUN = 1, // PCM buffer underrun occured. - EVENT_LOOP_END = 2, // Sample loop end was reached; playback restarted from loop start if loop count was not 0. - EVENT_MARKER = 3, // Playback head is at the specified marker position (See setMarkerPosition()). - EVENT_NEW_POS = 4, // Playback head is at a new position (See setPositionUpdatePeriod()). - EVENT_BUFFER_END = 5 // Playback head is at the end of the buffer. - }; - - /* Create Buffer on the stack and pass it to obtainBuffer() - * and releaseBuffer(). - */ - - class Buffer - { - public: - enum { - MUTE = 0x00000001 - }; - uint32_t flags; - int channelCount; - int format; - size_t frameCount; - size_t size; - union { - void* raw; - short* i16; - int8_t* i8; - }; - }; - - - /* As a convenience, if a callback is supplied, a handler thread - * is automatically created with the appropriate priority. This thread - * invokes the callback when a new buffer becomes availlable or an underrun condition occurs. - * Parameters: - * - * event: type of event notified (see enum AudioTrack::event_type). - * user: Pointer to context for use by the callback receiver. - * info: Pointer to optional parameter according to event type: - * - EVENT_MORE_DATA: pointer to AudioTrack::Buffer struct. The callback must not write - * more bytes than indicated by 'size' field and update 'size' if less bytes are - * written. - * - EVENT_UNDERRUN: unused. - * - EVENT_LOOP_END: pointer to an int indicating the number of loops remaining. - * - EVENT_MARKER: pointer to an uin32_t containing the marker position in frames. - * - EVENT_NEW_POS: pointer to an uin32_t containing the new position in frames. - * - EVENT_BUFFER_END: unused. - */ - - typedef void (*callback_t)(int event, void* user, void *info); - - /* Returns the minimum frame count required for the successful creation of - * an AudioTrack object. - * Returned status (from utils/Errors.h) can be: - * - NO_ERROR: successful operation - * - NO_INIT: audio server or audio hardware not initialized - */ - - static status_t getMinFrameCount(int* frameCount, - int streamType =-1, - uint32_t sampleRate = 0); - - /* Constructs an uninitialized AudioTrack. No connection with - * AudioFlinger takes place. - */ - AudioTrack(); - - /* Creates an audio track and registers it with AudioFlinger. - * Once created, the track needs to be started before it can be used. - * Unspecified values are set to the audio hardware's current - * values. - * - * Parameters: - * - * streamType: Select the type of audio stream this track is attached to - * (e.g. AudioSystem::MUSIC). - * sampleRate: Track sampling rate in Hz. - * format: Audio format (e.g AudioSystem::PCM_16_BIT for signed - * 16 bits per sample). - * channels: Channel mask: see AudioSystem::audio_channels. - * frameCount: Total size of track PCM buffer in frames. This defines the - * latency of the track. - * flags: Reserved for future use. - * cbf: Callback function. If not null, this function is called periodically - * to request new PCM data. - * notificationFrames: The callback function is called each time notificationFrames PCM - * frames have been comsumed from track input buffer. - * user Context for use by the callback receiver. - */ - - AudioTrack( int streamType, - uint32_t sampleRate = 0, - int format = 0, - int channels = 0, - int frameCount = 0, - uint32_t flags = 0, - callback_t cbf = 0, - void* user = 0, - int notificationFrames = 0, - int sessionId = 0); - - /* Creates an audio track and registers it with AudioFlinger. With this constructor, - * The PCM data to be rendered by AudioTrack is passed in a shared memory buffer - * identified by the argument sharedBuffer. This prototype is for static buffer playback. - * PCM data must be present into memory before the AudioTrack is started. - * The Write() and Flush() methods are not supported in this case. - * It is recommented to pass a callback function to be notified of playback end by an - * EVENT_UNDERRUN event. - */ - - AudioTrack( int streamType, - uint32_t sampleRate = 0, - int format = 0, - int channels = 0, - const sp<IMemory>& sharedBuffer = 0, - uint32_t flags = 0, - callback_t cbf = 0, - void* user = 0, - int notificationFrames = 0, - int sessionId = 0); - - /* Terminates the AudioTrack and unregisters it from AudioFlinger. - * Also destroys all resources assotiated with the AudioTrack. - */ - ~AudioTrack(); - - - /* Initialize an uninitialized AudioTrack. - * Returned status (from utils/Errors.h) can be: - * - NO_ERROR: successful intialization - * - INVALID_OPERATION: AudioTrack is already intitialized - * - BAD_VALUE: invalid parameter (channels, format, sampleRate...) - * - NO_INIT: audio server or audio hardware not initialized - * */ - status_t set(int streamType =-1, - uint32_t sampleRate = 0, - int format = 0, - int channels = 0, - int frameCount = 0, - uint32_t flags = 0, - callback_t cbf = 0, - void* user = 0, - int notificationFrames = 0, - const sp<IMemory>& sharedBuffer = 0, - bool threadCanCallJava = false, - int sessionId = 0); - - - /* Result of constructing the AudioTrack. This must be checked - * before using any AudioTrack API (except for set()), using - * an uninitialized AudioTrack produces undefined results. - * See set() method above for possible return codes. - */ - status_t initCheck() const; - - /* Returns this track's latency in milliseconds. - * This includes the latency due to AudioTrack buffer size, AudioMixer (if any) - * and audio hardware driver. - */ - uint32_t latency() const; - - /* getters, see constructor */ - - int streamType() const; - int format() const; - int channelCount() const; - uint32_t frameCount() const; - int frameSize() const; - sp<IMemory>& sharedBuffer(); - - - /* After it's created the track is not active. Call start() to - * make it active. If set, the callback will start being called. - */ - void start(); - - /* Stop a track. If set, the callback will cease being called and - * obtainBuffer returns STOPPED. Note that obtainBuffer() still works - * and will fill up buffers until the pool is exhausted. - */ - void stop(); - bool stopped() const; - - /* flush a stopped track. All pending buffers are discarded. - * This function has no effect if the track is not stoped. - */ - void flush(); - - /* Pause a track. If set, the callback will cease being called and - * obtainBuffer returns STOPPED. Note that obtainBuffer() still works - * and will fill up buffers until the pool is exhausted. - */ - void pause(); - - /* mute or unmutes this track. - * While mutted, the callback, if set, is still called. - */ - void mute(bool); - bool muted() const; - - - /* set volume for this track, mostly used for games' sound effects - * left and right volumes. Levels must be <= 1.0. - */ - status_t setVolume(float left, float right); - void getVolume(float* left, float* right); - - /* set the send level for this track. An auxiliary effect should be attached - * to the track with attachEffect(). Level must be <= 1.0. - */ - status_t setAuxEffectSendLevel(float level); - void getAuxEffectSendLevel(float* level); - - /* set sample rate for this track, mostly used for games' sound effects - */ - status_t setSampleRate(int sampleRate); - uint32_t getSampleRate(); - - /* Enables looping and sets the start and end points of looping. - * - * Parameters: - * - * loopStart: loop start expressed as the number of PCM frames played since AudioTrack start. - * loopEnd: loop end expressed as the number of PCM frames played since AudioTrack start. - * loopCount: number of loops to execute. Calling setLoop() with loopCount == 0 cancels any pending or - * active loop. loopCount = -1 means infinite looping. - * - * For proper operation the following condition must be respected: - * (loopEnd-loopStart) <= framecount() - */ - status_t setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount); - status_t getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount); - - - /* Sets marker position. When playback reaches the number of frames specified, a callback with event - * type EVENT_MARKER is called. Calling setMarkerPosition with marker == 0 cancels marker notification - * callback. - * If the AudioTrack has been opened with no callback function associated, the operation will fail. - * - * Parameters: - * - * marker: marker position expressed in frames. - * - * Returned status (from utils/Errors.h) can be: - * - NO_ERROR: successful operation - * - INVALID_OPERATION: the AudioTrack has no callback installed. - */ - status_t setMarkerPosition(uint32_t marker); - status_t getMarkerPosition(uint32_t *marker); - - - /* Sets position update period. Every time the number of frames specified has been played, - * a callback with event type EVENT_NEW_POS is called. - * Calling setPositionUpdatePeriod with updatePeriod == 0 cancels new position notification - * callback. - * If the AudioTrack has been opened with no callback function associated, the operation will fail. - * - * Parameters: - * - * updatePeriod: position update notification period expressed in frames. - * - * Returned status (from utils/Errors.h) can be: - * - NO_ERROR: successful operation - * - INVALID_OPERATION: the AudioTrack has no callback installed. - */ - status_t setPositionUpdatePeriod(uint32_t updatePeriod); - status_t getPositionUpdatePeriod(uint32_t *updatePeriod); - - - /* Sets playback head position within AudioTrack buffer. The new position is specified - * in number of frames. - * This method must be called with the AudioTrack in paused or stopped state. - * Note that the actual position set is <position> modulo the AudioTrack buffer size in frames. - * Therefore using this method makes sense only when playing a "static" audio buffer - * as opposed to streaming. - * The getPosition() method on the other hand returns the total number of frames played since - * playback start. - * - * Parameters: - * - * position: New playback head position within AudioTrack buffer. - * - * Returned status (from utils/Errors.h) can be: - * - NO_ERROR: successful operation - * - INVALID_OPERATION: the AudioTrack is not stopped. - * - BAD_VALUE: The specified position is beyond the number of frames present in AudioTrack buffer - */ - status_t setPosition(uint32_t position); - status_t getPosition(uint32_t *position); - - /* Forces AudioTrack buffer full condition. When playing a static buffer, this method avoids - * rewriting the buffer before restarting playback after a stop. - * This method must be called with the AudioTrack in paused or stopped state. - * - * Returned status (from utils/Errors.h) can be: - * - NO_ERROR: successful operation - * - INVALID_OPERATION: the AudioTrack is not stopped. - */ - status_t reload(); - - /* returns a handle on the audio output used by this AudioTrack. - * - * Parameters: - * none. - * - * Returned value: - * handle on audio hardware output - */ - audio_io_handle_t getOutput(); - - /* returns the unique ID associated to this track. - * - * Parameters: - * none. - * - * Returned value: - * AudioTrack ID. - */ - int getSessionId(); - - - /* Attach track auxiliary output to specified effect. Used effectId = 0 - * to detach track from effect. - * - * Parameters: - * - * effectId: effectId obtained from AudioEffect::id(). - * - * Returned status (from utils/Errors.h) can be: - * - NO_ERROR: successful operation - * - INVALID_OPERATION: the effect is not an auxiliary effect. - * - BAD_VALUE: The specified effect ID is invalid - */ - status_t attachAuxEffect(int effectId); - - /* obtains a buffer of "frameCount" frames. The buffer must be - * filled entirely. If the track is stopped, obtainBuffer() returns - * STOPPED instead of NO_ERROR as long as there are buffers availlable, - * at which point NO_MORE_BUFFERS is returned. - * Buffers will be returned until the pool (buffercount()) - * is exhausted, at which point obtainBuffer() will either block - * or return WOULD_BLOCK depending on the value of the "blocking" - * parameter. - */ - - enum { - NO_MORE_BUFFERS = 0x80000001, - STOPPED = 1 - }; - - status_t obtainBuffer(Buffer* audioBuffer, int32_t waitCount); - void releaseBuffer(Buffer* audioBuffer); - - - /* As a convenience we provide a write() interface to the audio buffer. - * This is implemented on top of lockBuffer/unlockBuffer. For best - * performance - * - */ - ssize_t write(const void* buffer, size_t size); - - /* - * Dumps the state of an audio track. - */ - status_t dump(int fd, const Vector<String16>& args) const; - -private: - /* copying audio tracks is not allowed */ - AudioTrack(const AudioTrack& other); - AudioTrack& operator = (const AudioTrack& other); - - /* a small internal class to handle the callback */ - class AudioTrackThread : public Thread - { - public: - AudioTrackThread(AudioTrack& receiver, bool bCanCallJava = false); - private: - friend class AudioTrack; - virtual bool threadLoop(); - virtual status_t readyToRun(); - virtual void onFirstRef(); - AudioTrack& mReceiver; - Mutex mLock; - }; - - bool processAudioBuffer(const sp<AudioTrackThread>& thread); - status_t createTrack(int streamType, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount, - uint32_t flags, - const sp<IMemory>& sharedBuffer, - audio_io_handle_t output, - bool enforceFrameCount); - - sp<IAudioTrack> mAudioTrack; - sp<IMemory> mCblkMemory; - sp<AudioTrackThread> mAudioTrackThread; - - float mVolume[2]; - float mSendLevel; - uint32_t mFrameCount; - - audio_track_cblk_t* mCblk; - uint8_t mStreamType; - uint8_t mFormat; - uint8_t mChannelCount; - uint8_t mMuted; - uint32_t mChannels; - status_t mStatus; - uint32_t mLatency; - - volatile int32_t mActive; - - callback_t mCbf; - void* mUserData; - uint32_t mNotificationFramesReq; // requested number of frames between each notification callback - uint32_t mNotificationFramesAct; // actual number of frames between each notification callback - sp<IMemory> mSharedBuffer; - int mLoopCount; - uint32_t mRemainingFrames; - uint32_t mMarkerPosition; - bool mMarkerReached; - uint32_t mNewPosition; - uint32_t mUpdatePeriod; - uint32_t mFlags; - int mSessionId; - int mAuxEffectId; - uint32_t mPadding[8]; -}; - - -}; // namespace android - -#endif // ANDROID_AUDIOTRACK_H diff --git a/dom/system/gonk/android_audio/EffectApi.h b/dom/system/gonk/android_audio/EffectApi.h deleted file mode 100644 index 729545d0c..000000000 --- a/dom/system/gonk/android_audio/EffectApi.h +++ /dev/null @@ -1,798 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#ifndef ANDROID_EFFECTAPI_H_ -#define ANDROID_EFFECTAPI_H_ - -#include <errno.h> -#include <stdint.h> -#include <sys/types.h> - -#if __cplusplus -extern "C" { -#endif - -///////////////////////////////////////////////// -// Effect control interface -///////////////////////////////////////////////// - -// The effect control interface is exposed by each effect engine implementation. It consists of -// a set of functions controlling the configuration, activation and process of the engine. -// The functions are grouped in a structure of type effect_interface_s: -// struct effect_interface_s { -// effect_process_t process; -// effect_command_t command; -// }; - - -// effect_interface_t: Effect control interface handle. -// The effect_interface_t serves two purposes regarding the implementation of the effect engine: -// - 1 it is the address of a pointer to an effect_interface_s structure where the functions -// of the effect control API for a particular effect are located. -// - 2 it is the address of the context of a particular effect instance. -// A typical implementation in the effect library would define a structure as follows: -// struct effect_module_s { -// const struct effect_interface_s *itfe; -// effect_config_t config; -// effect_context_t context; -// } -// The implementation of EffectCreate() function would then allocate a structure of this -// type and return its address as effect_interface_t -typedef struct effect_interface_s **effect_interface_t; - - -// Effect API version 1.0 -#define EFFECT_API_VERSION 0x0100 // Format 0xMMmm MM: Major version, mm: minor version - -// Maximum length of character strings in structures defines by this API. -#define EFFECT_STRING_LEN_MAX 64 - -// -//--- Effect descriptor structure effect_descriptor_t -// - -// Unique effect ID (can be generated from the following site: -// http://www.itu.int/ITU-T/asn1/uuid.html) -// This format is used for both "type" and "uuid" fields of the effect descriptor structure. -// - When used for effect type and the engine is implementing and effect corresponding to a standard -// OpenSL ES interface, this ID must be the one defined in OpenSLES_IID.h for that interface. -// - When used as uuid, it should be a unique UUID for this particular implementation. -typedef struct effect_uuid_s { - uint32_t timeLow; - uint16_t timeMid; - uint16_t timeHiAndVersion; - uint16_t clockSeq; - uint8_t node[6]; -} effect_uuid_t; - -// NULL UUID definition (matches SL_IID_NULL_) -#define EFFECT_UUID_INITIALIZER { 0xec7178ec, 0xe5e1, 0x4432, 0xa3f4, \ - { 0x46, 0x57, 0xe6, 0x79, 0x52, 0x10 } } -static const effect_uuid_t EFFECT_UUID_NULL_ = EFFECT_UUID_INITIALIZER; -const effect_uuid_t * const EFFECT_UUID_NULL = &EFFECT_UUID_NULL_; -const char * const EFFECT_UUID_NULL_STR = "ec7178ec-e5e1-4432-a3f4-4657e6795210"; - -// The effect descriptor contains necessary information to facilitate the enumeration of the effect -// engines present in a library. -typedef struct effect_descriptor_s { - effect_uuid_t type; // UUID of to the OpenSL ES interface implemented by this effect - effect_uuid_t uuid; // UUID for this particular implementation - uint16_t apiVersion; // Version of the effect API implemented: matches EFFECT_API_VERSION - uint32_t flags; // effect engine capabilities/requirements flags (see below) - uint16_t cpuLoad; // CPU load indication (see below) - uint16_t memoryUsage; // Data Memory usage (see below) - char name[EFFECT_STRING_LEN_MAX]; // human readable effect name - char implementor[EFFECT_STRING_LEN_MAX]; // human readable effect implementor name -} effect_descriptor_t; - -// CPU load and memory usage indication: each effect implementation must provide an indication of -// its CPU and memory usage for the audio effect framework to limit the number of effects -// instantiated at a given time on a given platform. -// The CPU load is expressed in 0.1 MIPS units as estimated on an ARM9E core (ARMv5TE) with 0 WS. -// The memory usage is expressed in KB and includes only dynamically allocated memory - -// Definitions for flags field of effect descriptor. -// +---------------------------+-----------+----------------------------------- -// | description | bits | values -// +---------------------------+-----------+----------------------------------- -// | connection mode | 0..1 | 0 insert: after track process -// | | | 1 auxiliary: connect to track auxiliary -// | | | output and use send level -// | | | 2 replace: replaces track process function; -// | | | must implement SRC, volume and mono to stereo. -// | | | 3 reserved -// +---------------------------+-----------+----------------------------------- -// | insertion preference | 2..4 | 0 none -// | | | 1 first of the chain -// | | | 2 last of the chain -// | | | 3 exclusive (only effect in the insert chain) -// | | | 4..7 reserved -// +---------------------------+-----------+----------------------------------- -// | Volume management | 5..6 | 0 none -// | | | 1 implements volume control -// | | | 2 requires volume indication -// | | | 3 reserved -// +---------------------------+-----------+----------------------------------- -// | Device indication | 7..8 | 0 none -// | | | 1 requires device updates -// | | | 2..3 reserved -// +---------------------------+-----------+----------------------------------- -// | Sample input mode | 9..10 | 0 direct: process() function or EFFECT_CMD_CONFIGURE -// | | | command must specify a buffer descriptor -// | | | 1 provider: process() function uses the -// | | | bufferProvider indicated by the -// | | | EFFECT_CMD_CONFIGURE command to request input. -// | | | buffers. -// | | | 2 both: both input modes are supported -// | | | 3 reserved -// +---------------------------+-----------+----------------------------------- -// | Sample output mode | 11..12 | 0 direct: process() function or EFFECT_CMD_CONFIGURE -// | | | command must specify a buffer descriptor -// | | | 1 provider: process() function uses the -// | | | bufferProvider indicated by the -// | | | EFFECT_CMD_CONFIGURE command to request output -// | | | buffers. -// | | | 2 both: both output modes are supported -// | | | 3 reserved -// +---------------------------+-----------+----------------------------------- -// | Hardware acceleration | 13..15 | 0 No hardware acceleration -// | | | 1 non tunneled hw acceleration: the process() function -// | | | reads the samples, send them to HW accelerated -// | | | effect processor, reads back the processed samples -// | | | and returns them to the output buffer. -// | | | 2 tunneled hw acceleration: the process() function is -// | | | transparent. The effect interface is only used to -// | | | control the effect engine. This mode is relevant for -// | | | global effects actually applied by the audio -// | | | hardware on the output stream. -// +---------------------------+-----------+----------------------------------- -// | Audio Mode indication | 16..17 | 0 none -// | | | 1 requires audio mode updates -// | | | 2..3 reserved -// +---------------------------+-----------+----------------------------------- - -// Insert mode -#define EFFECT_FLAG_TYPE_MASK 0x00000003 -#define EFFECT_FLAG_TYPE_INSERT 0x00000000 -#define EFFECT_FLAG_TYPE_AUXILIARY 0x00000001 -#define EFFECT_FLAG_TYPE_REPLACE 0x00000002 - -// Insert preference -#define EFFECT_FLAG_INSERT_MASK 0x0000001C -#define EFFECT_FLAG_INSERT_ANY 0x00000000 -#define EFFECT_FLAG_INSERT_FIRST 0x00000004 -#define EFFECT_FLAG_INSERT_LAST 0x00000008 -#define EFFECT_FLAG_INSERT_EXCLUSIVE 0x0000000C - - -// Volume control -#define EFFECT_FLAG_VOLUME_MASK 0x00000060 -#define EFFECT_FLAG_VOLUME_CTRL 0x00000020 -#define EFFECT_FLAG_VOLUME_IND 0x00000040 -#define EFFECT_FLAG_VOLUME_NONE 0x00000000 - -// Device indication -#define EFFECT_FLAG_DEVICE_MASK 0x00000180 -#define EFFECT_FLAG_DEVICE_IND 0x00000080 -#define EFFECT_FLAG_DEVICE_NONE 0x00000000 - -// Sample input modes -#define EFFECT_FLAG_INPUT_MASK 0x00000600 -#define EFFECT_FLAG_INPUT_DIRECT 0x00000000 -#define EFFECT_FLAG_INPUT_PROVIDER 0x00000200 -#define EFFECT_FLAG_INPUT_BOTH 0x00000400 - -// Sample output modes -#define EFFECT_FLAG_OUTPUT_MASK 0x00001800 -#define EFFECT_FLAG_OUTPUT_DIRECT 0x00000000 -#define EFFECT_FLAG_OUTPUT_PROVIDER 0x00000800 -#define EFFECT_FLAG_OUTPUT_BOTH 0x00001000 - -// Hardware acceleration mode -#define EFFECT_FLAG_HW_ACC_MASK 0x00006000 -#define EFFECT_FLAG_HW_ACC_SIMPLE 0x00002000 -#define EFFECT_FLAG_HW_ACC_TUNNEL 0x00004000 - -// Audio mode indication -#define EFFECT_FLAG_AUDIO_MODE_MASK 0x00018000 -#define EFFECT_FLAG_AUDIO_MODE_IND 0x00008000 -#define EFFECT_FLAG_AUDIO_MODE_NONE 0x00000000 - -// Forward definition of type audio_buffer_t -typedef struct audio_buffer_s audio_buffer_t; - -//////////////////////////////////////////////////////////////////////////////// -// -// Function: process -// -// Description: Effect process function. Takes input samples as specified -// (count and location) in input buffer descriptor and output processed -// samples as specified in output buffer descriptor. If the buffer descriptor -// is not specified the function must use either the buffer or the -// buffer provider function installed by the EFFECT_CMD_CONFIGURE command. -// The effect framework will call the process() function after the EFFECT_CMD_ENABLE -// command is received and until the EFFECT_CMD_DISABLE is received. When the engine -// receives the EFFECT_CMD_DISABLE command it should turn off the effect gracefully -// and when done indicate that it is OK to stop calling the process() function by -// returning the -ENODATA status. -// -// NOTE: the process() function implementation should be "real-time safe" that is -// it should not perform blocking calls: malloc/free, sleep, read/write/open/close, -// pthread_cond_wait/pthread_mutex_lock... -// -// Input: -// effect_interface_t: handle to the effect interface this function -// is called on. -// inBuffer: buffer descriptor indicating where to read samples to process. -// If NULL, use the configuration passed by EFFECT_CMD_CONFIGURE command. -// -// inBuffer: buffer descriptor indicating where to write processed samples. -// If NULL, use the configuration passed by EFFECT_CMD_CONFIGURE command. -// -// Output: -// returned value: 0 successful operation -// -ENODATA the engine has finished the disable phase and the framework -// can stop calling process() -// -EINVAL invalid interface handle or -// invalid input/output buffer description -//////////////////////////////////////////////////////////////////////////////// -typedef int32_t (*effect_process_t)(effect_interface_t self, - audio_buffer_t *inBuffer, - audio_buffer_t *outBuffer); - -//////////////////////////////////////////////////////////////////////////////// -// -// Function: command -// -// Description: Send a command and receive a response to/from effect engine. -// -// Input: -// effect_interface_t: handle to the effect interface this function -// is called on. -// cmdCode: command code: the command can be a standardized command defined in -// effect_command_e (see below) or a proprietary command. -// cmdSize: size of command in bytes -// pCmdData: pointer to command data -// pReplyData: pointer to reply data -// -// Input/Output: -// replySize: maximum size of reply data as input -// actual size of reply data as output -// -// Output: -// returned value: 0 successful operation -// -EINVAL invalid interface handle or -// invalid command/reply size or format according to command code -// The return code should be restricted to indicate problems related to the this -// API specification. Status related to the execution of a particular command should be -// indicated as part of the reply field. -// -// *pReplyData updated with command response -// -//////////////////////////////////////////////////////////////////////////////// -typedef int32_t (*effect_command_t)(effect_interface_t self, - uint32_t cmdCode, - uint32_t cmdSize, - void *pCmdData, - uint32_t *replySize, - void *pReplyData); - - -// Effect control interface definition -struct effect_interface_s { - effect_process_t process; - effect_command_t command; -}; - - -// -//--- Standardized command codes for command() function -// -enum effect_command_e { - EFFECT_CMD_INIT, // initialize effect engine - EFFECT_CMD_CONFIGURE, // configure effect engine (see effect_config_t) - EFFECT_CMD_RESET, // reset effect engine - EFFECT_CMD_ENABLE, // enable effect process - EFFECT_CMD_DISABLE, // disable effect process - EFFECT_CMD_SET_PARAM, // set parameter immediately (see effect_param_t) - EFFECT_CMD_SET_PARAM_DEFERRED, // set parameter deferred - EFFECT_CMD_SET_PARAM_COMMIT, // commit previous set parameter deferred - EFFECT_CMD_GET_PARAM, // get parameter - EFFECT_CMD_SET_DEVICE, // set audio device (see audio_device_e) - EFFECT_CMD_SET_VOLUME, // set volume - EFFECT_CMD_SET_AUDIO_MODE, // set the audio mode (normal, ring, ...) - EFFECT_CMD_FIRST_PROPRIETARY = 0x10000 // first proprietary command code -}; - -//================================================================================================== -// command: EFFECT_CMD_INIT -//-------------------------------------------------------------------------------------------------- -// description: -// Initialize effect engine: All configurations return to default -//-------------------------------------------------------------------------------------------------- -// command format: -// size: 0 -// data: N/A -//-------------------------------------------------------------------------------------------------- -// reply format: -// size: sizeof(int) -// data: status -//================================================================================================== -// command: EFFECT_CMD_CONFIGURE -//-------------------------------------------------------------------------------------------------- -// description: -// Apply new audio parameters configurations for input and output buffers -//-------------------------------------------------------------------------------------------------- -// command format: -// size: sizeof(effect_config_t) -// data: effect_config_t -//-------------------------------------------------------------------------------------------------- -// reply format: -// size: sizeof(int) -// data: status -//================================================================================================== -// command: EFFECT_CMD_RESET -//-------------------------------------------------------------------------------------------------- -// description: -// Reset the effect engine. Keep configuration but resets state and buffer content -//-------------------------------------------------------------------------------------------------- -// command format: -// size: 0 -// data: N/A -//-------------------------------------------------------------------------------------------------- -// reply format: -// size: 0 -// data: N/A -//================================================================================================== -// command: EFFECT_CMD_ENABLE -//-------------------------------------------------------------------------------------------------- -// description: -// Enable the process. Called by the framework before the first call to process() -//-------------------------------------------------------------------------------------------------- -// command format: -// size: 0 -// data: N/A -//-------------------------------------------------------------------------------------------------- -// reply format: -// size: sizeof(int) -// data: status -//================================================================================================== -// command: EFFECT_CMD_DISABLE -//-------------------------------------------------------------------------------------------------- -// description: -// Disable the process. Called by the framework after the last call to process() -//-------------------------------------------------------------------------------------------------- -// command format: -// size: 0 -// data: N/A -//-------------------------------------------------------------------------------------------------- -// reply format: -// size: sizeof(int) -// data: status -//================================================================================================== -// command: EFFECT_CMD_SET_PARAM -//-------------------------------------------------------------------------------------------------- -// description: -// Set a parameter and apply it immediately -//-------------------------------------------------------------------------------------------------- -// command format: -// size: sizeof(effect_param_t) + size of param and value -// data: effect_param_t + param + value. See effect_param_t definition below for value offset -//-------------------------------------------------------------------------------------------------- -// reply format: -// size: sizeof(int) -// data: status -//================================================================================================== -// command: EFFECT_CMD_SET_PARAM_DEFERRED -//-------------------------------------------------------------------------------------------------- -// description: -// Set a parameter but apply it only when receiving EFFECT_CMD_SET_PARAM_COMMIT command -//-------------------------------------------------------------------------------------------------- -// command format: -// size: sizeof(effect_param_t) + size of param and value -// data: effect_param_t + param + value. See effect_param_t definition below for value offset -//-------------------------------------------------------------------------------------------------- -// reply format: -// size: 0 -// data: N/A -//================================================================================================== -// command: EFFECT_CMD_SET_PARAM_COMMIT -//-------------------------------------------------------------------------------------------------- -// description: -// Apply all previously received EFFECT_CMD_SET_PARAM_DEFERRED commands -//-------------------------------------------------------------------------------------------------- -// command format: -// size: 0 -// data: N/A -//-------------------------------------------------------------------------------------------------- -// reply format: -// size: sizeof(int) -// data: status -//================================================================================================== -// command: EFFECT_CMD_GET_PARAM -//-------------------------------------------------------------------------------------------------- -// description: -// Get a parameter value -//-------------------------------------------------------------------------------------------------- -// command format: -// size: sizeof(effect_param_t) + size of param -// data: effect_param_t + param -//-------------------------------------------------------------------------------------------------- -// reply format: -// size: sizeof(effect_param_t) + size of param and value -// data: effect_param_t + param + value. See effect_param_t definition below for value offset -//================================================================================================== -// command: EFFECT_CMD_SET_DEVICE -//-------------------------------------------------------------------------------------------------- -// description: -// Set the rendering device the audio output path is connected to. See audio_device_e for device -// values. -// The effect implementation must set EFFECT_FLAG_DEVICE_IND flag in its descriptor to receive this -// command when the device changes -//-------------------------------------------------------------------------------------------------- -// command format: -// size: sizeof(uint32_t) -// data: audio_device_e -//-------------------------------------------------------------------------------------------------- -// reply format: -// size: 0 -// data: N/A -//================================================================================================== -// command: EFFECT_CMD_SET_VOLUME -//-------------------------------------------------------------------------------------------------- -// description: -// Set and get volume. Used by audio framework to delegate volume control to effect engine. -// The effect implementation must set EFFECT_FLAG_VOLUME_IND or EFFECT_FLAG_VOLUME_CTRL flag in -// its descriptor to receive this command before every call to process() function -// If EFFECT_FLAG_VOLUME_CTRL flag is set in the effect descriptor, the effect engine must return -// the volume that should be applied before the effect is processed. The overall volume (the volume -// actually applied by the effect engine multiplied by the returned value) should match the value -// indicated in the command. -//-------------------------------------------------------------------------------------------------- -// command format: -// size: n * sizeof(uint32_t) -// data: volume for each channel defined in effect_config_t for output buffer expressed in -// 8.24 fixed point format -//-------------------------------------------------------------------------------------------------- -// reply format: -// size: n * sizeof(uint32_t) / 0 -// data: - if EFFECT_FLAG_VOLUME_CTRL is set in effect descriptor: -// volume for each channel defined in effect_config_t for output buffer expressed in -// 8.24 fixed point format -// - if EFFECT_FLAG_VOLUME_CTRL is not set in effect descriptor: -// N/A -// It is legal to receive a null pointer as pReplyData in which case the effect framework has -// delegated volume control to another effect -//================================================================================================== -// command: EFFECT_CMD_SET_AUDIO_MODE -//-------------------------------------------------------------------------------------------------- -// description: -// Set the audio mode. The effect implementation must set EFFECT_FLAG_AUDIO_MODE_IND flag in its -// descriptor to receive this command when the audio mode changes. -//-------------------------------------------------------------------------------------------------- -// command format: -// size: sizeof(uint32_t) -// data: audio_mode_e -//-------------------------------------------------------------------------------------------------- -// reply format: -// size: 0 -// data: N/A -//================================================================================================== -// command: EFFECT_CMD_FIRST_PROPRIETARY -//-------------------------------------------------------------------------------------------------- -// description: -// All proprietary effect commands must use command codes above this value. The size and format of -// command and response fields is free in this case -//================================================================================================== - - -// Audio buffer descriptor used by process(), bufferProvider() functions and buffer_config_t -// structure. Multi-channel audio is always interleaved. The channel order is from LSB to MSB with -// regard to the channel mask definition in audio_channels_e e.g : -// Stereo: left, right -// 5 point 1: front left, front right, front center, low frequency, back left, back right -// The buffer size is expressed in frame count, a frame being composed of samples for all -// channels at a given time. Frame size for unspecified format (AUDIO_FORMAT_OTHER) is 8 bit by -// definition -struct audio_buffer_s { - size_t frameCount; // number of frames in buffer - union { - void* raw; // raw pointer to start of buffer - int32_t* s32; // pointer to signed 32 bit data at start of buffer - int16_t* s16; // pointer to signed 16 bit data at start of buffer - uint8_t* u8; // pointer to unsigned 8 bit data at start of buffer - }; -}; - -// The buffer_provider_s structure contains functions that can be used -// by the effect engine process() function to query and release input -// or output audio buffer. -// The getBuffer() function is called to retrieve a buffer where data -// should read from or written to by process() function. -// The releaseBuffer() function MUST be called when the buffer retrieved -// with getBuffer() is not needed anymore. -// The process function should use the buffer provider mechanism to retrieve -// input or output buffer if the inBuffer or outBuffer passed as argument is NULL -// and the buffer configuration (buffer_config_t) given by the EFFECT_CMD_CONFIGURE -// command did not specify an audio buffer. - -typedef int32_t (* buffer_function_t)(void *cookie, audio_buffer_t *buffer); - -typedef struct buffer_provider_s { - buffer_function_t getBuffer; // retrieve next buffer - buffer_function_t releaseBuffer; // release used buffer - void *cookie; // for use by client of buffer provider functions -} buffer_provider_t; - - -// The buffer_config_s structure specifies the input or output audio format -// to be used by the effect engine. It is part of the effect_config_t -// structure that defines both input and output buffer configurations and is -// passed by the EFFECT_CMD_CONFIGURE command. -typedef struct buffer_config_s { - audio_buffer_t buffer; // buffer for use by process() function if not passed explicitly - uint32_t samplingRate; // sampling rate - uint32_t channels; // channel mask (see audio_channels_e) - buffer_provider_t bufferProvider; // buffer provider - uint8_t format; // Audio format (see audio_format_e) - uint8_t accessMode; // read/write or accumulate in buffer (effect_buffer_access_e) - uint16_t mask; // indicates which of the above fields is valid -} buffer_config_t; - -// Sample format -enum audio_format_e { - SAMPLE_FORMAT_PCM_S15, // PCM signed 16 bits - SAMPLE_FORMAT_PCM_U8, // PCM unsigned 8 bits - SAMPLE_FORMAT_PCM_S7_24, // PCM signed 7.24 fixed point representation - SAMPLE_FORMAT_OTHER // other format (e.g. compressed) -}; - -// Channel mask -enum audio_channels_e { - CHANNEL_FRONT_LEFT = 0x1, // front left channel - CHANNEL_FRONT_RIGHT = 0x2, // front right channel - CHANNEL_FRONT_CENTER = 0x4, // front center channel - CHANNEL_LOW_FREQUENCY = 0x8, // low frequency channel - CHANNEL_BACK_LEFT = 0x10, // back left channel - CHANNEL_BACK_RIGHT = 0x20, // back right channel - CHANNEL_FRONT_LEFT_OF_CENTER = 0x40, // front left of center channel - CHANNEL_FRONT_RIGHT_OF_CENTER = 0x80, // front right of center channel - CHANNEL_BACK_CENTER = 0x100, // back center channel - CHANNEL_MONO = CHANNEL_FRONT_LEFT, - CHANNEL_STEREO = (CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT), - CHANNEL_QUAD = (CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | - CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT), - CHANNEL_SURROUND = (CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | - CHANNEL_FRONT_CENTER | CHANNEL_BACK_CENTER), - CHANNEL_5POINT1 = (CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | - CHANNEL_FRONT_CENTER | CHANNEL_LOW_FREQUENCY | CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT), - CHANNEL_7POINT1 = (CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | - CHANNEL_FRONT_CENTER | CHANNEL_LOW_FREQUENCY | CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT | - CHANNEL_FRONT_LEFT_OF_CENTER | CHANNEL_FRONT_RIGHT_OF_CENTER), -}; - -// Render device -enum audio_device_e { - DEVICE_EARPIECE = 0x1, // earpiece - DEVICE_SPEAKER = 0x2, // speaker - DEVICE_WIRED_HEADSET = 0x4, // wired headset, with microphone - DEVICE_WIRED_HEADPHONE = 0x8, // wired headphone, without microphone - DEVICE_BLUETOOTH_SCO = 0x10, // generic bluetooth SCO - DEVICE_BLUETOOTH_SCO_HEADSET = 0x20, // bluetooth SCO headset - DEVICE_BLUETOOTH_SCO_CARKIT = 0x40, // bluetooth SCO car kit - DEVICE_BLUETOOTH_A2DP = 0x80, // generic bluetooth A2DP - DEVICE_BLUETOOTH_A2DP_HEADPHONES = 0x100, // bluetooth A2DP headphones - DEVICE_BLUETOOTH_A2DP_SPEAKER = 0x200, // bluetooth A2DP speakers - DEVICE_AUX_DIGITAL = 0x400, // digital output - DEVICE_EXTERNAL_SPEAKER = 0x800 // external speaker (stereo and High quality) -}; - -#if ANDROID_VERSION < 17 -// Audio mode -enum audio_mode_e { - AUDIO_MODE_NORMAL, // device idle - AUDIO_MODE_RINGTONE, // device ringing - AUDIO_MODE_IN_CALL // audio call connected (VoIP or telephony) -}; -#endif - -// Values for "accessMode" field of buffer_config_t: -// overwrite, read only, accumulate (read/modify/write) -enum effect_buffer_access_e { - EFFECT_BUFFER_ACCESS_WRITE, - EFFECT_BUFFER_ACCESS_READ, - EFFECT_BUFFER_ACCESS_ACCUMULATE - -}; - -// Values for bit field "mask" in buffer_config_t. If a bit is set, the corresponding field -// in buffer_config_t must be taken into account when executing the EFFECT_CMD_CONFIGURE command -#define EFFECT_CONFIG_BUFFER 0x0001 // buffer field must be taken into account -#define EFFECT_CONFIG_SMP_RATE 0x0002 // samplingRate field must be taken into account -#define EFFECT_CONFIG_CHANNELS 0x0004 // channels field must be taken into account -#define EFFECT_CONFIG_FORMAT 0x0008 // format field must be taken into account -#define EFFECT_CONFIG_ACC_MODE 0x0010 // accessMode field must be taken into account -#define EFFECT_CONFIG_PROVIDER 0x0020 // bufferProvider field must be taken into account -#define EFFECT_CONFIG_ALL (EFFECT_CONFIG_BUFFER | EFFECT_CONFIG_SMP_RATE | \ - EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT | \ - EFFECT_CONFIG_ACC_MODE | EFFECT_CONFIG_PROVIDER) - - -// effect_config_s structure describes the format of the pCmdData argument of EFFECT_CMD_CONFIGURE -// command to configure audio parameters and buffers for effect engine input and output. -typedef struct effect_config_s { - buffer_config_t inputCfg; - buffer_config_t outputCfg;; -} effect_config_t; - - -// effect_param_s structure describes the format of the pCmdData argument of EFFECT_CMD_SET_PARAM -// command and pCmdData and pReplyData of EFFECT_CMD_GET_PARAM command. -// psize and vsize represent the actual size of parameter and value. -// -// NOTE: the start of value field inside the data field is always on a 32 bit boundary: -// -// +-----------+ -// | status | sizeof(int) -// +-----------+ -// | psize | sizeof(int) -// +-----------+ -// | vsize | sizeof(int) -// +-----------+ -// | | | | -// ~ parameter ~ > psize | -// | | | > ((psize - 1)/sizeof(int) + 1) * sizeof(int) -// +-----------+ | -// | padding | | -// +-----------+ -// | | | -// ~ value ~ > vsize -// | | | -// +-----------+ - -typedef struct effect_param_s { - int32_t status; // Transaction status (unused for command, used for reply) - uint32_t psize; // Parameter size - uint32_t vsize; // Value size - char data[]; // Start of Parameter + Value data -} effect_param_t; - - -///////////////////////////////////////////////// -// Effect library interface -///////////////////////////////////////////////// - -// An effect library is required to implement and expose the following functions -// to enable effect enumeration and instantiation. The name of these functions must be as -// specified here as the effect framework will get the function address with dlsym(): -// -// - effect_QueryNumberEffects_t EffectQueryNumberEffects; -// - effect_QueryEffect_t EffectQueryEffect; -// - effect_CreateEffect_t EffectCreate; -// - effect_ReleaseEffect_t EffectRelease; - - -//////////////////////////////////////////////////////////////////////////////// -// -// Function: EffectQueryNumberEffects -// -// Description: Returns the number of different effects exposed by the -// library. Each effect must have a unique effect uuid (see -// effect_descriptor_t). This function together with EffectQueryEffect() -// is used to enumerate all effects present in the library. -// -// Input/Output: -// pNumEffects: address where the number of effects should be returned. -// -// Output: -// returned value: 0 successful operation. -// -ENODEV library failed to initialize -// -EINVAL invalid pNumEffects -// *pNumEffects: updated with number of effects in library -// -//////////////////////////////////////////////////////////////////////////////// -typedef int32_t (*effect_QueryNumberEffects_t)(uint32_t *pNumEffects); - -//////////////////////////////////////////////////////////////////////////////// -// -// Function: EffectQueryEffect -// -// Description: Returns the descriptor of the effect engine which index is -// given as first argument. -// See effect_descriptor_t for details on effect descriptors. -// This function together with EffectQueryNumberEffects() is used to enumerate all -// effects present in the library. The enumeration sequence is: -// EffectQueryNumberEffects(&num_effects); -// for (i = 0; i < num_effects; i++) -// EffectQueryEffect(i,...); -// -// Input/Output: -// index: index of the effect -// pDescriptor: address where to return the effect descriptor. -// -// Output: -// returned value: 0 successful operation. -// -ENODEV library failed to initialize -// -EINVAL invalid pDescriptor or index -// -ENOSYS effect list has changed since last execution of -// EffectQueryNumberEffects() -// -ENOENT no more effect available -// *pDescriptor: updated with the effect descriptor. -// -//////////////////////////////////////////////////////////////////////////////// -typedef int32_t (*effect_QueryEffect_t)(uint32_t index, - effect_descriptor_t *pDescriptor); - -//////////////////////////////////////////////////////////////////////////////// -// -// Function: EffectCreate -// -// Description: Creates an effect engine of the specified type and returns an -// effect control interface on this engine. The function will allocate the -// resources for an instance of the requested effect engine and return -// a handle on the effect control interface. -// -// Input: -// uuid: pointer to the effect uuid. -// sessionId: audio session to which this effect instance will be attached. All effects -// created with the same session ID are connected in series and process the same signal -// stream. Knowing that two effects are part of the same effect chain can help the -// library implement some kind of optimizations. -// ioId: identifies the output or input stream this effect is directed to at audio HAL. -// For future use especially with tunneled HW accelerated effects -// -// Input/Output: -// pInterface: address where to return the effect interface. -// -// Output: -// returned value: 0 successful operation. -// -ENODEV library failed to initialize -// -EINVAL invalid pEffectUuid or pInterface -// -ENOENT no effect with this uuid found -// *pInterface: updated with the effect interface handle. -// -//////////////////////////////////////////////////////////////////////////////// -typedef int32_t (*effect_CreateEffect_t)(effect_uuid_t *uuid, - int32_t sessionId, - int32_t ioId, - effect_interface_t *pInterface); - -//////////////////////////////////////////////////////////////////////////////// -// -// Function: EffectRelease -// -// Description: Releases the effect engine whose handle is given as argument. -// All resources allocated to this particular instance of the effect are -// released. -// -// Input: -// interface: handle on the effect interface to be released. -// -// Output: -// returned value: 0 successful operation. -// -ENODEV library failed to initialize -// -EINVAL invalid interface handle -// -//////////////////////////////////////////////////////////////////////////////// -typedef int32_t (*effect_ReleaseEffect_t)(effect_interface_t interface); - - -#if __cplusplus -} // extern "C" -#endif - - -#endif /*ANDROID_EFFECTAPI_H_*/ diff --git a/dom/system/gonk/android_audio/IAudioFlinger.h b/dom/system/gonk/android_audio/IAudioFlinger.h deleted file mode 100644 index b10d3ab93..000000000 --- a/dom/system/gonk/android_audio/IAudioFlinger.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -#ifndef ANDROID_IAUDIOFLINGER_H -#define ANDROID_IAUDIOFLINGER_H - -#include <stdint.h> -#include <sys/types.h> -#include <unistd.h> - -#include <utils/RefBase.h> -#include <utils/Errors.h> -#include <binder/IInterface.h> -#include "IAudioTrack.h" -#include "IAudioRecord.h" -#include "IAudioFlingerClient.h" -#include "EffectApi.h" -#include "IEffect.h" -#include "IEffectClient.h" -#include <utils/String8.h> - -namespace android { - -// ---------------------------------------------------------------------------- - -class IAudioFlinger : public IInterface -{ -public: - DECLARE_META_INTERFACE(AudioFlinger); - - /* create an audio track and registers it with AudioFlinger. - * return null if the track cannot be created. - */ - virtual sp<IAudioTrack> createTrack( - pid_t pid, - int streamType, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount, - uint32_t flags, - const sp<IMemory>& sharedBuffer, - int output, - int *sessionId, - status_t *status) = 0; - - virtual sp<IAudioRecord> openRecord( - pid_t pid, - int input, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount, - uint32_t flags, - int *sessionId, - status_t *status) = 0; - - /* query the audio hardware state. This state never changes, - * and therefore can be cached. - */ - virtual uint32_t sampleRate(int output) const = 0; - virtual int channelCount(int output) const = 0; - virtual int format(int output) const = 0; - virtual size_t frameCount(int output) const = 0; - virtual uint32_t latency(int output) const = 0; - - /* set/get the audio hardware state. This will probably be used by - * the preference panel, mostly. - */ - virtual status_t setMasterVolume(float value) = 0; - virtual status_t setMasterMute(bool muted) = 0; - - virtual float masterVolume() const = 0; - virtual bool masterMute() const = 0; - - /* set/get stream type state. This will probably be used by - * the preference panel, mostly. - */ - virtual status_t setStreamVolume(int stream, float value, int output) = 0; - virtual status_t setStreamMute(int stream, bool muted) = 0; - - virtual float streamVolume(int stream, int output) const = 0; - virtual bool streamMute(int stream) const = 0; - - // set audio mode - virtual status_t setMode(int mode) = 0; - - // mic mute/state - virtual status_t setMicMute(bool state) = 0; - virtual bool getMicMute() const = 0; - - // is any track active on this stream? - virtual bool isStreamActive(int stream) const = 0; - - virtual status_t setParameters(int ioHandle, const String8& keyValuePairs) = 0; - virtual String8 getParameters(int ioHandle, const String8& keys) = 0; - - // register a current process for audio output change notifications - virtual void registerClient(const sp<IAudioFlingerClient>& client) = 0; - - // retrieve the audio recording buffer size - virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount) = 0; - - virtual int openOutput(uint32_t *pDevices, - uint32_t *pSamplingRate, - uint32_t *pFormat, - uint32_t *pChannels, - uint32_t *pLatencyMs, - uint32_t flags) = 0; - virtual int openDuplicateOutput(int output1, int output2) = 0; - virtual status_t closeOutput(int output) = 0; - virtual status_t suspendOutput(int output) = 0; - virtual status_t restoreOutput(int output) = 0; - - virtual int openInput(uint32_t *pDevices, - uint32_t *pSamplingRate, - uint32_t *pFormat, - uint32_t *pChannels, - uint32_t acoustics) = 0; - virtual status_t closeInput(int input) = 0; - - virtual status_t setStreamOutput(uint32_t stream, int output) = 0; - - virtual status_t setVoiceVolume(float volume) = 0; - - virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output) = 0; - - virtual unsigned int getInputFramesLost(int ioHandle) = 0; - - virtual int newAudioSessionId() = 0; - - virtual status_t loadEffectLibrary(const char *libPath, int *handle) = 0; - - virtual status_t unloadEffectLibrary(int handle) = 0; - - virtual status_t queryNumberEffects(uint32_t *numEffects) = 0; - - virtual status_t queryEffect(uint32_t index, effect_descriptor_t *pDescriptor) = 0; - - virtual status_t getEffectDescriptor(effect_uuid_t *pEffectUUID, effect_descriptor_t *pDescriptor) = 0; - - virtual sp<IEffect> createEffect(pid_t pid, - effect_descriptor_t *pDesc, - const sp<IEffectClient>& client, - int32_t priority, - int output, - int sessionId, - status_t *status, - int *id, - int *enabled) = 0; - - virtual status_t moveEffects(int session, int srcOutput, int dstOutput) = 0; -}; - - -// ---------------------------------------------------------------------------- - -class BnAudioFlinger : public BnInterface<IAudioFlinger> -{ -public: - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); -}; - -// ---------------------------------------------------------------------------- - -}; // namespace android - -#endif // ANDROID_IAUDIOFLINGER_H diff --git a/dom/system/gonk/android_audio/IAudioFlingerClient.h b/dom/system/gonk/android_audio/IAudioFlingerClient.h deleted file mode 100644 index aa0cdcff1..000000000 --- a/dom/system/gonk/android_audio/IAudioFlingerClient.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2009 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. - */ - -#ifndef ANDROID_IAUDIOFLINGERCLIENT_H -#define ANDROID_IAUDIOFLINGERCLIENT_H - - -#include <utils/RefBase.h> -#include <binder/IInterface.h> -#include <utils/KeyedVector.h> - -namespace android { - -// ---------------------------------------------------------------------------- - -class IAudioFlingerClient : public IInterface -{ -public: - DECLARE_META_INTERFACE(AudioFlingerClient); - - // Notifies a change of audio input/output configuration. - virtual void ioConfigChanged(int event, int ioHandle, void *param2) = 0; - -}; - - -// ---------------------------------------------------------------------------- - -class BnAudioFlingerClient : public BnInterface<IAudioFlingerClient> -{ -public: - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); -}; - -// ---------------------------------------------------------------------------- - -}; // namespace android - -#endif // ANDROID_IAUDIOFLINGERCLIENT_H diff --git a/dom/system/gonk/android_audio/IAudioRecord.h b/dom/system/gonk/android_audio/IAudioRecord.h deleted file mode 100644 index 46735def2..000000000 --- a/dom/system/gonk/android_audio/IAudioRecord.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -#ifndef IAUDIORECORD_H_ -#define IAUDIORECORD_H_ - -#include <stdint.h> -#include <sys/types.h> - -#include <utils/RefBase.h> -#include <utils/Errors.h> -#include <binder/IInterface.h> -#include <binder/IMemory.h> - - -namespace android { - -// ---------------------------------------------------------------------------- - -class IAudioRecord : public IInterface -{ -public: - DECLARE_META_INTERFACE(AudioRecord); - - /* After it's created the track is not active. Call start() to - * make it active. If set, the callback will start being called. - */ - virtual status_t start() = 0; - - /* Stop a track. If set, the callback will cease being called and - * obtainBuffer will return an error. Buffers that are already released - * will be processed, unless flush() is called. - */ - virtual void stop() = 0; - - /* get this tracks control block */ - virtual sp<IMemory> getCblk() const = 0; -}; - -// ---------------------------------------------------------------------------- - -class BnAudioRecord : public BnInterface<IAudioRecord> -{ -public: - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); -}; - -// ---------------------------------------------------------------------------- - -}; // namespace android - -#endif /*IAUDIORECORD_H_*/ diff --git a/dom/system/gonk/android_audio/IAudioTrack.h b/dom/system/gonk/android_audio/IAudioTrack.h deleted file mode 100644 index 47d530be5..000000000 --- a/dom/system/gonk/android_audio/IAudioTrack.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -#ifndef ANDROID_IAUDIOTRACK_H -#define ANDROID_IAUDIOTRACK_H - -#include <stdint.h> -#include <sys/types.h> - -#include <utils/RefBase.h> -#include <utils/Errors.h> -#include <binder/IInterface.h> -#include <binder/IMemory.h> - - -namespace android { - -// ---------------------------------------------------------------------------- - -class IAudioTrack : public IInterface -{ -public: - DECLARE_META_INTERFACE(AudioTrack); - - /* After it's created the track is not active. Call start() to - * make it active. If set, the callback will start being called. - */ - virtual status_t start() = 0; - - /* Stop a track. If set, the callback will cease being called and - * obtainBuffer will return an error. Buffers that are already released - * will be processed, unless flush() is called. - */ - virtual void stop() = 0; - - /* flush a stopped track. All pending buffers are discarded. - * This function has no effect if the track is not stoped. - */ - virtual void flush() = 0; - - /* mute or unmutes this track. - * While mutted, the callback, if set, is still called. - */ - virtual void mute(bool) = 0; - - /* Pause a track. If set, the callback will cease being called and - * obtainBuffer will return an error. Buffers that are already released - * will be processed, unless flush() is called. - */ - virtual void pause() = 0; - - /* Attach track auxiliary output to specified effect. Use effectId = 0 - * to detach track from effect. - */ - virtual status_t attachAuxEffect(int effectId) = 0; - - /* get this tracks control block */ - virtual sp<IMemory> getCblk() const = 0; -}; - -// ---------------------------------------------------------------------------- - -class BnAudioTrack : public BnInterface<IAudioTrack> -{ -public: - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); -}; - -// ---------------------------------------------------------------------------- - -}; // namespace android - -#endif // ANDROID_IAUDIOTRACK_H diff --git a/dom/system/gonk/android_audio/IEffect.h b/dom/system/gonk/android_audio/IEffect.h deleted file mode 100644 index ff04869e0..000000000 --- a/dom/system/gonk/android_audio/IEffect.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#ifndef ANDROID_IEFFECT_H -#define ANDROID_IEFFECT_H - -#include <utils/RefBase.h> -#include <binder/IInterface.h> -#include <binder/Parcel.h> -#include <binder/IMemory.h> - -namespace android { - -class IEffect: public IInterface -{ -public: - DECLARE_META_INTERFACE(Effect); - - virtual status_t enable() = 0; - - virtual status_t disable() = 0; - - virtual status_t command(uint32_t cmdCode, - uint32_t cmdSize, - void *pCmdData, - uint32_t *pReplySize, - void *pReplyData) = 0; - - virtual void disconnect() = 0; - - virtual sp<IMemory> getCblk() const = 0; -}; - -// ---------------------------------------------------------------------------- - -class BnEffect: public BnInterface<IEffect> -{ -public: - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); -}; - -}; // namespace android - -#endif // ANDROID_IEFFECT_H diff --git a/dom/system/gonk/android_audio/IEffectClient.h b/dom/system/gonk/android_audio/IEffectClient.h deleted file mode 100644 index 2f78c98f1..000000000 --- a/dom/system/gonk/android_audio/IEffectClient.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#ifndef ANDROID_IEFFECTCLIENT_H -#define ANDROID_IEFFECTCLIENT_H - -#include <utils/RefBase.h> -#include <binder/IInterface.h> -#include <binder/Parcel.h> -#include <binder/IMemory.h> - -namespace android { - -class IEffectClient: public IInterface -{ -public: - DECLARE_META_INTERFACE(EffectClient); - - virtual void controlStatusChanged(bool controlGranted) = 0; - virtual void enableStatusChanged(bool enabled) = 0; - virtual void commandExecuted(uint32_t cmdCode, - uint32_t cmdSize, - void *pCmdData, - uint32_t replySize, - void *pReplyData) = 0; -}; - -// ---------------------------------------------------------------------------- - -class BnEffectClient: public BnInterface<IEffectClient> -{ -public: - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); -}; - -}; // namespace android - -#endif // ANDROID_IEFFECTCLIENT_H diff --git a/dom/system/gonk/moz.build b/dom/system/gonk/moz.build deleted file mode 100644 index 229baaab4..000000000 --- a/dom/system/gonk/moz.build +++ /dev/null @@ -1,107 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# Copyright 2013 Mozilla Foundation and Mozilla contributors -# -# 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. - -XPIDL_SOURCES += [ - 'nsIAudioManager.idl', - 'nsINetworkInterface.idl', - 'nsINetworkInterfaceListService.idl', - 'nsINetworkManager.idl', - 'nsINetworkService.idl', - 'nsINetworkWorker.idl', - 'nsISystemWorkerManager.idl', - 'nsITetheringService.idl', - 'nsIVolume.idl', - 'nsIVolumeMountLock.idl', - 'nsIVolumeService.idl', - 'nsIVolumeStat.idl', - 'nsIWorkerHolder.idl', -] - -XPIDL_MODULE = 'dom_system_gonk' - -EXPORTS += [ - 'GeolocationUtil.h', - 'GonkGPSGeolocationProvider.h', - 'nsVolume.h', - 'nsVolumeService.h', - 'SystemProperty.h', -] -UNIFIED_SOURCES += [ - 'AudioChannelManager.cpp', - 'AudioManager.cpp', - 'AutoMounter.cpp', - 'AutoMounterSetting.cpp', - 'GeolocationUtil.cpp', - 'GonkGPSGeolocationProvider.cpp', - 'MozMtpDatabase.cpp', - 'MozMtpServer.cpp', - 'MozMtpStorage.cpp', - 'NetIdManager.cpp', - 'NetworkUtils.cpp', - 'NetworkWorker.cpp', - 'nsVolume.cpp', - 'nsVolumeMountLock.cpp', - 'nsVolumeService.cpp', - 'nsVolumeStat.cpp', - 'OpenFileFinder.cpp', - 'SystemProperty.cpp', - 'SystemWorkerManager.cpp', - 'TimeZoneSettingObserver.cpp', - 'Volume.cpp', - 'VolumeCommand.cpp', - 'VolumeManager.cpp', - 'VolumeServiceIOThread.cpp', - 'VolumeServiceTest.cpp', -] - -if CONFIG['ANDROID_VERSION'] >= '17': - LOCAL_INCLUDES += ['%' + '%s/frameworks/av/media/mtp' % CONFIG['ANDROID_SOURCE']] -else: - LOCAL_INCLUDES += ['%' + '%s/frameworks/base/media/mtp' % CONFIG['ANDROID_SOURCE']] - -if CONFIG['ENABLE_TESTS']: - XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell.ini'] - -EXTRA_COMPONENTS += [ - 'NetworkInterfaceListService.js', - 'NetworkInterfaceListService.manifest', - 'NetworkManager.js', - 'NetworkManager.manifest', - 'NetworkService.js', - 'NetworkService.manifest', - 'TetheringService.js', - 'TetheringService.manifest', -] -EXTRA_JS_MODULES += [ - 'systemlibs.js', -] - -include('/ipc/chromium/chromium-config.mozbuild') - -DEFINES['HAVE_ANDROID_OS'] = True - -LOCAL_INCLUDES += [ - '/dom/base', - '/dom/bluetooth/common', - '/dom/geolocation', - '/dom/wifi', -] - -FINAL_LIBRARY = 'xul' - -FINAL_TARGET_FILES.modules.workers += [ - 'worker_buf.js', -] diff --git a/dom/system/gonk/mozstumbler/MozStumbler.cpp b/dom/system/gonk/mozstumbler/MozStumbler.cpp deleted file mode 100644 index 61e09e705..000000000 --- a/dom/system/gonk/mozstumbler/MozStumbler.cpp +++ /dev/null @@ -1,426 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "MozStumbler.h" -#include "nsDataHashtable.h" -#include "nsGeoPosition.h" -#include "nsNetCID.h" -#include "nsPrintfCString.h" -#include "StumblerLogging.h" -#include "WriteStumbleOnThread.h" -#include "../GeolocationUtil.h" - -#include "nsIInterfaceRequestor.h" -#include "nsIInterfaceRequestorUtils.h" -#include "nsIMobileConnectionInfo.h" -#include "nsIMobileConnectionService.h" -#include "nsIMobileCellInfo.h" -#include "nsIMobileNetworkInfo.h" -#include "nsINetworkInterface.h" -#include "nsIRadioInterfaceLayer.h" - -using namespace mozilla; -using namespace mozilla::dom; - - -NS_IMPL_ISUPPORTS(StumblerInfo, nsICellInfoListCallback, nsIWifiScanResultsReady) - -class RequestCellInfoEvent : public Runnable { -public: - RequestCellInfoEvent(StumblerInfo *callback) - : mRequestCallback(callback) - {} - - NS_IMETHOD Run() override { - MOZ_ASSERT(NS_IsMainThread()); - // Get Cell Info - nsCOMPtr<nsIMobileConnectionService> service = - do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID); - - if (!service) { - STUMBLER_ERR("Stumbler-can not get nsIMobileConnectionService \n"); - return NS_OK; - } - nsCOMPtr<nsIMobileConnection> connection; - uint32_t numberOfRilServices = 1, cellInfoNum = 0; - - service->GetNumItems(&numberOfRilServices); - for (uint32_t rilNum = 0; rilNum < numberOfRilServices; rilNum++) { - service->GetItemByServiceId(rilNum /* Client Id */, getter_AddRefs(connection)); - if (!connection) { - STUMBLER_ERR("Stumbler-can not get nsIMobileConnection by ServiceId %d \n", rilNum); - } else { - cellInfoNum++; - connection->GetCellInfoList(mRequestCallback); - } - } - mRequestCallback->SetCellInfoResponsesExpected(cellInfoNum); - - // Get Wifi AP Info - nsCOMPtr<nsIInterfaceRequestor> ir = do_GetService("@mozilla.org/telephony/system-worker-manager;1"); - nsCOMPtr<nsIWifi> wifi = do_GetInterface(ir); - if (!wifi) { - mRequestCallback->SetWifiInfoResponseReceived(); - STUMBLER_ERR("Stumbler-can not get nsIWifi interface\n"); - return NS_OK; - } - wifi->GetWifiScanResults(mRequestCallback); - return NS_OK; - } -private: - RefPtr<StumblerInfo> mRequestCallback; -}; - -void -MozStumble(nsGeoPosition* position) -{ - if (WriteStumbleOnThread::IsFileWaitingForUpload()) { - nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); - MOZ_ASSERT(target); - // Knowing that file is waiting to upload, and no collection will take place, - // just trigger the thread with an empty string. - nsCOMPtr<nsIRunnable> event = new WriteStumbleOnThread(EmptyCString()); - target->Dispatch(event, NS_DISPATCH_NORMAL); - return; - } - - nsCOMPtr<nsIDOMGeoPositionCoords> coords; - position->GetCoords(getter_AddRefs(coords)); - if (!coords) { - return; - } - - double latitude, longitude; - coords->GetLatitude(&latitude); - coords->GetLongitude(&longitude); - - const double kMinChangeInMeters = 30; - static int64_t lastTime_ms = 0; - static double sLastLat = 0; - static double sLastLon = 0; - double delta = -1.0; - int64_t timediff = (PR_Now() / PR_USEC_PER_MSEC) - lastTime_ms; - - if (0 != sLastLon || 0 != sLastLat) { - delta = CalculateDeltaInMeter(latitude, longitude, sLastLat, sLastLon); - } - STUMBLER_DBG("Stumbler-Location. [%f , %f] time_diff:%lld, delta : %f\n", - longitude, latitude, timediff, delta); - - // Consecutive GPS locations must be 30 meters and 3 seconds apart - if (lastTime_ms == 0 || ((timediff >= STUMBLE_INTERVAL_MS) && (delta > kMinChangeInMeters))){ - lastTime_ms = (PR_Now() / PR_USEC_PER_MSEC); - sLastLat = latitude; - sLastLon = longitude; - RefPtr<StumblerInfo> requestCallback = new StumblerInfo(position); - RefPtr<RequestCellInfoEvent> runnable = new RequestCellInfoEvent(requestCallback); - NS_DispatchToMainThread(runnable); - } else { - STUMBLER_DBG("Stumbler-GPS locations less than 30 meters and 3 seconds. Ignore!\n"); - } -} - -void -StumblerInfo::SetWifiInfoResponseReceived() -{ - mIsWifiInfoResponseReceived = true; - - if (mIsWifiInfoResponseReceived && mCellInfoResponsesReceived == mCellInfoResponsesExpected) { - STUMBLER_DBG("Call DumpStumblerInfo from SetWifiInfoResponseReceived\n"); - DumpStumblerInfo(); - } -} - -void -StumblerInfo::SetCellInfoResponsesExpected(uint8_t count) -{ - mCellInfoResponsesExpected = count; - STUMBLER_DBG("SetCellInfoNum (%d)\n", count); - - if (mIsWifiInfoResponseReceived && mCellInfoResponsesReceived == mCellInfoResponsesExpected) { - STUMBLER_DBG("Call DumpStumblerInfo from SetCellInfoResponsesExpected\n"); - DumpStumblerInfo(); - } -} - - -#define TEXT_LAT NS_LITERAL_CSTRING("latitude") -#define TEXT_LON NS_LITERAL_CSTRING("longitude") -#define TEXT_ACC NS_LITERAL_CSTRING("accuracy") -#define TEXT_ALT NS_LITERAL_CSTRING("altitude") -#define TEXT_ALTACC NS_LITERAL_CSTRING("altitudeAccuracy") -#define TEXT_HEAD NS_LITERAL_CSTRING("heading") -#define TEXT_SPD NS_LITERAL_CSTRING("speed") - -nsresult -StumblerInfo::LocationInfoToString(nsACString& aLocDesc) -{ - nsCOMPtr<nsIDOMGeoPositionCoords> coords; - mPosition->GetCoords(getter_AddRefs(coords)); - if (!coords) { - return NS_ERROR_FAILURE; - } - - nsDataHashtable<nsCStringHashKey, double> info; - - double val; - coords->GetLatitude(&val); - info.Put(TEXT_LAT, val); - coords->GetLongitude(&val); - info.Put(TEXT_LON, val); - coords->GetAccuracy(&val); - info.Put(TEXT_ACC, val); - coords->GetAltitude(&val); - info.Put(TEXT_ALT, val); - coords->GetAltitudeAccuracy(&val); - info.Put(TEXT_ALTACC, val); - coords->GetHeading(&val); - info.Put(TEXT_HEAD, val); - coords->GetSpeed(&val); - info.Put(TEXT_SPD, val); - - for (auto it = info.Iter(); !it.Done(); it.Next()) { - const nsACString& key = it.Key(); - val = it.UserData(); - if (!IsNaN(val)) { - aLocDesc += nsPrintfCString("\"%s\":%f,", key.BeginReading(), val); - } - } - - aLocDesc += nsPrintfCString("\"timestamp\":%lld,", PR_Now() / PR_USEC_PER_MSEC).get(); - return NS_OK; -} - -#define TEXT_RADIOTYPE NS_LITERAL_CSTRING("radioType") -#define TEXT_MCC NS_LITERAL_CSTRING("mobileCountryCode") -#define TEXT_MNC NS_LITERAL_CSTRING("mobileNetworkCode") -#define TEXT_LAC NS_LITERAL_CSTRING("locationAreaCode") -#define TEXT_CID NS_LITERAL_CSTRING("cellId") -#define TEXT_PSC NS_LITERAL_CSTRING("psc") -#define TEXT_STRENGTH_ASU NS_LITERAL_CSTRING("asu") -#define TEXT_STRENGTH_DBM NS_LITERAL_CSTRING("signalStrength") -#define TEXT_REGISTERED NS_LITERAL_CSTRING("serving") -#define TEXT_TIMEING_ADVANCE NS_LITERAL_CSTRING("timingAdvance") - -template <class T> void -ExtractCommonNonCDMACellInfoItems(nsCOMPtr<T>& cell, nsDataHashtable<nsCStringHashKey, int32_t>& info) -{ - int32_t mcc, mnc, cid, sig; - - cell->GetMcc(&mcc); - cell->GetMnc(&mnc); - cell->GetCid(&cid); - cell->GetSignalStrength(&sig); - - info.Put(TEXT_MCC, mcc); - info.Put(TEXT_MNC, mnc); - info.Put(TEXT_CID, cid); - info.Put(TEXT_STRENGTH_ASU, sig); -} - -void -StumblerInfo::CellNetworkInfoToString(nsACString& aCellDesc) -{ - aCellDesc += "\"cellTowers\": ["; - - for (uint32_t idx = 0; idx < mCellInfo.Length() ; idx++) { - const char* radioType = 0; - int32_t type; - mCellInfo[idx]->GetType(&type); - bool registered; - mCellInfo[idx]->GetRegistered(®istered); - if (idx) { - aCellDesc += ",{"; - } else { - aCellDesc += "{"; - } - - STUMBLER_DBG("type=%d\n", type); - - nsDataHashtable<nsCStringHashKey, int32_t> info; - info.Put(TEXT_REGISTERED, registered); - - if(type == nsICellInfo::CELL_INFO_TYPE_GSM) { - radioType = "gsm"; - nsCOMPtr<nsIGsmCellInfo> gsmCellInfo = do_QueryInterface(mCellInfo[idx]); - ExtractCommonNonCDMACellInfoItems(gsmCellInfo, info); - int32_t lac; - gsmCellInfo->GetLac(&lac); - info.Put(TEXT_LAC, lac); - } else if (type == nsICellInfo::CELL_INFO_TYPE_WCDMA) { - radioType = "wcdma"; - nsCOMPtr<nsIWcdmaCellInfo> wcdmaCellInfo = do_QueryInterface(mCellInfo[idx]); - ExtractCommonNonCDMACellInfoItems(wcdmaCellInfo, info); - int32_t lac, psc; - wcdmaCellInfo->GetLac(&lac); - wcdmaCellInfo->GetPsc(&psc); - info.Put(TEXT_LAC, lac); - info.Put(TEXT_PSC, psc); - } else if (type == nsICellInfo::CELL_INFO_TYPE_CDMA) { - radioType = "cdma"; - nsCOMPtr<nsICdmaCellInfo> cdmaCellInfo = do_QueryInterface(mCellInfo[idx]); - int32_t mnc, lac, cid, sig; - cdmaCellInfo->GetSystemId(&mnc); - cdmaCellInfo->GetNetworkId(&lac); - cdmaCellInfo->GetBaseStationId(&cid); - info.Put(TEXT_MNC, mnc); - info.Put(TEXT_LAC, lac); - info.Put(TEXT_CID, cid); - - cdmaCellInfo->GetEvdoDbm(&sig); - if (sig < 0 || sig == nsICellInfo::UNKNOWN_VALUE) { - cdmaCellInfo->GetCdmaDbm(&sig); - } - if (sig > -1 && sig != nsICellInfo::UNKNOWN_VALUE) { - sig *= -1; - info.Put(TEXT_STRENGTH_DBM, sig); - } - } else if (type == nsICellInfo::CELL_INFO_TYPE_LTE) { - radioType = "lte"; - nsCOMPtr<nsILteCellInfo> lteCellInfo = do_QueryInterface(mCellInfo[idx]); - ExtractCommonNonCDMACellInfoItems(lteCellInfo, info); - int32_t lac, timingAdvance, pcid, rsrp; - lteCellInfo->GetTac(&lac); - lteCellInfo->GetTimingAdvance(&timingAdvance); - lteCellInfo->GetPcid(&pcid); - lteCellInfo->GetRsrp(&rsrp); - info.Put(TEXT_LAC, lac); - info.Put(TEXT_TIMEING_ADVANCE, timingAdvance); - info.Put(TEXT_PSC, pcid); - if (rsrp != nsICellInfo::UNKNOWN_VALUE) { - info.Put(TEXT_STRENGTH_DBM, rsrp * -1); - } - } - - aCellDesc += nsPrintfCString("\"%s\":\"%s\"", TEXT_RADIOTYPE.get(), radioType); - for (auto it = info.Iter(); !it.Done(); it.Next()) { - const nsACString& key = it.Key(); - int32_t value = it.UserData(); - if (value != nsICellInfo::UNKNOWN_VALUE) { - aCellDesc += nsPrintfCString(",\"%s\":%d", key.BeginReading(), value); - } - } - - aCellDesc += "}"; - } - aCellDesc += "]"; -} - -void -StumblerInfo::DumpStumblerInfo() -{ - if (!mIsWifiInfoResponseReceived || mCellInfoResponsesReceived != mCellInfoResponsesExpected) { - STUMBLER_DBG("CellInfoReceived=%d (Expected=%d), WifiInfoResponseReceived=%d\n", - mCellInfoResponsesReceived, mCellInfoResponsesExpected, mIsWifiInfoResponseReceived); - return; - } - mIsWifiInfoResponseReceived = false; - mCellInfoResponsesReceived = 0; - - nsAutoCString desc; - nsresult rv = LocationInfoToString(desc); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("LocationInfoToString failed, skip this dump"); - return; - } - - CellNetworkInfoToString(desc); - desc += mWifiDesc; - - STUMBLER_DBG("dispatch write event to thread\n"); - nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); - MOZ_ASSERT(target); - - nsCOMPtr<nsIRunnable> event = new WriteStumbleOnThread(desc); - target->Dispatch(event, NS_DISPATCH_NORMAL); -} - -NS_IMETHODIMP -StumblerInfo::NotifyGetCellInfoList(uint32_t count, nsICellInfo** aCellInfos) -{ - MOZ_ASSERT(NS_IsMainThread()); - STUMBLER_DBG("There are %d cellinfo in the result\n", count); - - for (uint32_t i = 0; i < count; i++) { - mCellInfo.AppendElement(aCellInfos[i]); - } - mCellInfoResponsesReceived++; - DumpStumblerInfo(); - return NS_OK; -} - -NS_IMETHODIMP StumblerInfo::NotifyGetCellInfoListFailed(const nsAString& error) -{ - MOZ_ASSERT(NS_IsMainThread()); - mCellInfoResponsesReceived++; - STUMBLER_ERR("NotifyGetCellInfoListFailedm CellInfoReadyNum=%d, mCellInfoResponsesExpected=%d, mIsWifiInfoResponseReceived=%d", - mCellInfoResponsesReceived, mCellInfoResponsesExpected, mIsWifiInfoResponseReceived); - DumpStumblerInfo(); - return NS_OK; -} - -NS_IMETHODIMP -StumblerInfo::Onready(uint32_t count, nsIWifiScanResult** results) -{ - MOZ_ASSERT(NS_IsMainThread()); - STUMBLER_DBG("There are %d wifiAPinfo in the result\n",count); - - mWifiDesc += ",\"wifiAccessPoints\": ["; - bool firstItem = true; - for (uint32_t i = 0 ; i < count ; i++) { - nsString ssid; - results[i]->GetSsid(ssid); - if (ssid.IsEmpty()) { - STUMBLER_DBG("no ssid, skip this AP\n"); - continue; - } - - if (ssid.Length() >= 6) { - if (StringEndsWith(ssid, NS_LITERAL_STRING("_nomap"))) { - STUMBLER_DBG("end with _nomap. skip this AP(ssid :%s)\n", ssid.get()); - continue; - } - } - - if (firstItem) { - mWifiDesc += "{"; - firstItem = false; - } else { - mWifiDesc += ",{"; - } - - // mac address - nsString bssid; - results[i]->GetBssid(bssid); - // 00:00:00:00:00:00 --> 000000000000 - bssid.StripChars(":"); - mWifiDesc += "\"macAddress\":\""; - mWifiDesc += NS_ConvertUTF16toUTF8(bssid); - - uint32_t signal; - results[i]->GetSignalStrength(&signal); - mWifiDesc += "\",\"signalStrength\":"; - mWifiDesc.AppendInt(signal); - - mWifiDesc += "}"; - } - mWifiDesc += "]"; - - mIsWifiInfoResponseReceived = true; - DumpStumblerInfo(); - return NS_OK; -} - -NS_IMETHODIMP -StumblerInfo::Onfailure() -{ - MOZ_ASSERT(NS_IsMainThread()); - STUMBLER_ERR("GetWifiScanResults Onfailure\n"); - mIsWifiInfoResponseReceived = true; - DumpStumblerInfo(); - return NS_OK; -} - diff --git a/dom/system/gonk/mozstumbler/MozStumbler.h b/dom/system/gonk/mozstumbler/MozStumbler.h deleted file mode 100644 index 41ee4e5e1..000000000 --- a/dom/system/gonk/mozstumbler/MozStumbler.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_mozstumbler_h__ -#define mozilla_system_mozstumbler_h__ - -#include "nsIDOMEventTarget.h" -#include "nsICellInfo.h" -#include "nsIWifi.h" - -#define STUMBLE_INTERVAL_MS 3000 - -class nsGeoPosition; - -void MozStumble(nsGeoPosition* position); - -class StumblerInfo final : public nsICellInfoListCallback, - public nsIWifiScanResultsReady -{ -public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSICELLINFOLISTCALLBACK - NS_DECL_NSIWIFISCANRESULTSREADY - - explicit StumblerInfo(nsGeoPosition* position) - : mPosition(position), mCellInfoResponsesExpected(0), mCellInfoResponsesReceived(0), mIsWifiInfoResponseReceived(0) - {} - void SetWifiInfoResponseReceived(); - void SetCellInfoResponsesExpected(uint8_t count); - -private: - ~StumblerInfo() {} - void DumpStumblerInfo(); - nsresult LocationInfoToString(nsACString& aLocDesc); - void CellNetworkInfoToString(nsACString& aCellDesc); - nsTArray<RefPtr<nsICellInfo>> mCellInfo; - nsCString mWifiDesc; - RefPtr<nsGeoPosition> mPosition; - int mCellInfoResponsesExpected; - int mCellInfoResponsesReceived; - bool mIsWifiInfoResponseReceived; -}; -#endif // mozilla_system_mozstumbler_h__ - diff --git a/dom/system/gonk/mozstumbler/StumblerLogging.cpp b/dom/system/gonk/mozstumbler/StumblerLogging.cpp deleted file mode 100644 index acf23b3b1..000000000 --- a/dom/system/gonk/mozstumbler/StumblerLogging.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "StumblerLogging.h" - -mozilla::LogModule* GetLog() -{ - static mozilla::LazyLogModule log("mozstumbler"); - return log; -} diff --git a/dom/system/gonk/mozstumbler/StumblerLogging.h b/dom/system/gonk/mozstumbler/StumblerLogging.h deleted file mode 100644 index 038f44f8f..000000000 --- a/dom/system/gonk/mozstumbler/StumblerLogging.h +++ /dev/null @@ -1,18 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef STUMBLERLOGGING_H -#define STUMBLERLOGGING_H - -#include "mozilla/Logging.h" - -mozilla::LogModule* GetLog(); - -#define STUMBLER_DBG(arg, ...) MOZ_LOG(GetLog(), mozilla::LogLevel::Debug, ("STUMBLER - %s: " arg, __func__, ##__VA_ARGS__)) -#define STUMBLER_LOG(arg, ...) MOZ_LOG(GetLog(), mozilla::LogLevel::Info, ("STUMBLER - %s: " arg, __func__, ##__VA_ARGS__)) -#define STUMBLER_ERR(arg, ...) MOZ_LOG(GetLog(), mozilla::LogLevel::Error, ("STUMBLER -%s: " arg, __func__, ##__VA_ARGS__)) - -#endif diff --git a/dom/system/gonk/mozstumbler/UploadStumbleRunnable.cpp b/dom/system/gonk/mozstumbler/UploadStumbleRunnable.cpp deleted file mode 100644 index d97aa9712..000000000 --- a/dom/system/gonk/mozstumbler/UploadStumbleRunnable.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "UploadStumbleRunnable.h" -#include "StumblerLogging.h" -#include "mozilla/dom/Event.h" -#include "nsIInputStream.h" -#include "nsIScriptSecurityManager.h" -#include "nsIURLFormatter.h" -#include "nsIXMLHttpRequest.h" -#include "nsNetUtil.h" -#include "nsVariant.h" - -UploadStumbleRunnable::UploadStumbleRunnable(nsIInputStream* aUploadData) -: mUploadInputStream(aUploadData) -{ -} - -NS_IMETHODIMP -UploadStumbleRunnable::Run() -{ - MOZ_ASSERT(NS_IsMainThread()); - nsresult rv = Upload(); - if (NS_FAILED(rv)) { - WriteStumbleOnThread::UploadEnded(false); - } - return NS_OK; -} - -nsresult -UploadStumbleRunnable::Upload() -{ - nsresult rv; - RefPtr<nsVariant> variant = new nsVariant(); - - rv = variant->SetAsISupports(mUploadInputStream); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr<nsIXMLHttpRequest> xhr = do_CreateInstance(NS_XMLHTTPREQUEST_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr<nsIScriptSecurityManager> secman = - do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr<nsIPrincipal> systemPrincipal; - rv = secman->GetSystemPrincipal(getter_AddRefs(systemPrincipal)); - NS_ENSURE_SUCCESS(rv, rv); - - rv = xhr->Init(systemPrincipal, nullptr, nullptr, nullptr); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr<nsIURLFormatter> formatter = - do_CreateInstance("@mozilla.org/toolkit/URLFormatterService;1", &rv); - NS_ENSURE_SUCCESS(rv, rv); - nsString url; - rv = formatter->FormatURLPref(NS_LITERAL_STRING("geo.stumbler.url"), url); - NS_ENSURE_SUCCESS(rv, rv); - - rv = xhr->Open(NS_LITERAL_CSTRING("POST"), NS_ConvertUTF16toUTF8(url), false, EmptyString(), EmptyString()); - NS_ENSURE_SUCCESS(rv, rv); - - xhr->SetRequestHeader(NS_LITERAL_CSTRING("Content-Type"), NS_LITERAL_CSTRING("gzip")); - xhr->SetMozBackgroundRequest(true); - // 60s timeout - xhr->SetTimeout(60 * 1000); - - nsCOMPtr<EventTarget> target(do_QueryInterface(xhr)); - RefPtr<nsIDOMEventListener> listener = new UploadEventListener(xhr); - - const char* const sEventStrings[] = { - // nsIXMLHttpRequestEventTarget event types - "abort", - "error", - "load", - "timeout" - }; - - for (uint32_t index = 0; index < MOZ_ARRAY_LENGTH(sEventStrings); index++) { - nsAutoString eventType = NS_ConvertASCIItoUTF16(sEventStrings[index]); - rv = target->AddEventListener(eventType, listener, false); - NS_ENSURE_SUCCESS(rv, rv); - } - - rv = xhr->Send(variant); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; -} - -NS_IMPL_ISUPPORTS(UploadEventListener, nsIDOMEventListener) - -UploadEventListener::UploadEventListener(nsIXMLHttpRequest* aXHR) -: mXHR(aXHR) -{ -} - -NS_IMETHODIMP -UploadEventListener::HandleEvent(nsIDOMEvent* aEvent) -{ - nsString type; - if (NS_FAILED(aEvent->GetType(type))) { - STUMBLER_ERR("Failed to get event type"); - WriteStumbleOnThread::UploadEnded(false); - return NS_ERROR_FAILURE; - } - - if (type.EqualsLiteral("load")) { - STUMBLER_DBG("Got load Event\n"); - } else if (type.EqualsLiteral("error") && mXHR) { - STUMBLER_ERR("Upload Error"); - } else { - STUMBLER_DBG("Receive %s Event", NS_ConvertUTF16toUTF8(type).get()); - } - - uint32_t statusCode = 0; - bool doDelete = false; - if (!mXHR) { - return NS_OK; - } - nsresult rv = mXHR->GetStatus(&statusCode); - if (NS_SUCCEEDED(rv)) { - STUMBLER_DBG("statuscode %d \n", statusCode); - } - - if (200 == statusCode || 400 == statusCode) { - doDelete = true; - } - - WriteStumbleOnThread::UploadEnded(doDelete); - nsCOMPtr<EventTarget> target(do_QueryInterface(mXHR)); - - const char* const sEventStrings[] = { - // nsIXMLHttpRequestEventTarget event types - "abort", - "error", - "load", - "timeout" - }; - - for (uint32_t index = 0; index < MOZ_ARRAY_LENGTH(sEventStrings); index++) { - nsAutoString eventType = NS_ConvertASCIItoUTF16(sEventStrings[index]); - rv = target->RemoveEventListener(eventType, this, false); - } - - mXHR = nullptr; - return NS_OK; -} diff --git a/dom/system/gonk/mozstumbler/UploadStumbleRunnable.h b/dom/system/gonk/mozstumbler/UploadStumbleRunnable.h deleted file mode 100644 index 462665a86..000000000 --- a/dom/system/gonk/mozstumbler/UploadStumbleRunnable.h +++ /dev/null @@ -1,46 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - - -#ifndef UPLOADSTUMBLERUNNABLE_H -#define UPLOADSTUMBLERUNNABLE_H - -#include "nsIDOMEventListener.h" - -class nsIXMLHttpRequest; -class nsIInputStream; - -/* - This runnable is managed by WriteStumbleOnThread only, see that class - for how this is scheduled. - */ -class UploadStumbleRunnable final : public Runnable -{ -public: - explicit UploadStumbleRunnable(nsIInputStream* aUploadInputStream); - - NS_IMETHOD Run() override; -private: - virtual ~UploadStumbleRunnable() {} - nsCOMPtr<nsIInputStream> mUploadInputStream; - nsresult Upload(); -}; - - -class UploadEventListener : public nsIDOMEventListener -{ -public: - UploadEventListener(nsIXMLHttpRequest* aXHR); - - NS_DECL_ISUPPORTS - NS_DECL_NSIDOMEVENTLISTENER - -protected: - virtual ~UploadEventListener() {} - nsCOMPtr<nsIXMLHttpRequest> mXHR; -}; - -#endif diff --git a/dom/system/gonk/mozstumbler/WriteStumbleOnThread.cpp b/dom/system/gonk/mozstumbler/WriteStumbleOnThread.cpp deleted file mode 100644 index e58e771c4..000000000 --- a/dom/system/gonk/mozstumbler/WriteStumbleOnThread.cpp +++ /dev/null @@ -1,321 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "WriteStumbleOnThread.h" -#include "StumblerLogging.h" -#include "UploadStumbleRunnable.h" -#include "nsDumpUtils.h" -#include "nsGZFileWriter.h" -#include "nsIFileStreams.h" -#include "nsIInputStream.h" -#include "nsPrintfCString.h" - -#define MAXFILESIZE_KB (15 * 1024) -#define ONEDAY_IN_MSEC (24 * 60 * 60 * 1000) -#define MAX_UPLOAD_ATTEMPTS 20 - -mozilla::Atomic<bool> WriteStumbleOnThread::sIsFileWaitingForUpload(false); -mozilla::Atomic<bool> WriteStumbleOnThread::sIsAlreadyRunning(false); -WriteStumbleOnThread::UploadFreqGuard WriteStumbleOnThread::sUploadFreqGuard = {0}; - -#define FILENAME_INPROGRESS NS_LITERAL_CSTRING("stumbles.json.gz") -#define FILENAME_COMPLETED NS_LITERAL_CSTRING("stumbles.done.json.gz") -#define OUTPUT_DIR NS_LITERAL_CSTRING("mozstumbler") - -class DeleteRunnable : public Runnable -{ - public: - DeleteRunnable() {} - - NS_IMETHOD - Run() override - { - nsCOMPtr<nsIFile> tmpFile; - nsresult rv = nsDumpUtils::OpenTempFile(FILENAME_COMPLETED, - getter_AddRefs(tmpFile), - OUTPUT_DIR, - nsDumpUtils::CREATE); - if (NS_SUCCEEDED(rv)) { - tmpFile->Remove(true); - } - // critically, this sets this flag to false so writing can happen again - WriteStumbleOnThread::sIsAlreadyRunning = false; - WriteStumbleOnThread::sIsFileWaitingForUpload = false; - return NS_OK; - } - - private: - ~DeleteRunnable() {} -}; - -bool -WriteStumbleOnThread::IsFileWaitingForUpload() -{ - return sIsFileWaitingForUpload; -} - -void -WriteStumbleOnThread::UploadEnded(bool deleteUploadFile) -{ - if (!deleteUploadFile) { - sIsAlreadyRunning = false; - return; - } - - nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); - MOZ_ASSERT(target); - nsCOMPtr<nsIRunnable> event = new DeleteRunnable(); - target->Dispatch(event, NS_DISPATCH_NORMAL); -} - -void -WriteStumbleOnThread::WriteJSON(Partition aPart) -{ - MOZ_ASSERT(!NS_IsMainThread()); - - nsCOMPtr<nsIFile> tmpFile; - nsresult rv; - rv = nsDumpUtils::OpenTempFile(FILENAME_INPROGRESS, getter_AddRefs(tmpFile), - OUTPUT_DIR, nsDumpUtils::CREATE); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("Open a file for stumble failed"); - return; - } - - RefPtr<nsGZFileWriter> gzWriter = new nsGZFileWriter(nsGZFileWriter::Append); - rv = gzWriter->Init(tmpFile); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("gzWriter init failed"); - return; - } - - /* - The json format is like below. - {items:[ - {item}, - {item}, - {item} - ]} - */ - - // Need to add "]}" after the last item - if (aPart == Partition::End) { - rv = gzWriter->Write("]}"); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("gzWriter Write failed"); - } - - rv = gzWriter->Finish(); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("ostream finish failed"); - } - - nsCOMPtr<nsIFile> targetFile; - nsresult rv = nsDumpUtils::OpenTempFile(FILENAME_COMPLETED, getter_AddRefs(targetFile), - OUTPUT_DIR, nsDumpUtils::CREATE); - nsAutoString targetFilename; - rv = targetFile->GetLeafName(targetFilename); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("Get Filename failed"); - return; - } - rv = targetFile->Remove(true); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("Remove File failed"); - return; - } - // Rename tmpfile - rv = tmpFile->MoveTo(/* directory */ nullptr, targetFilename); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("Rename File failed"); - return; - } - return; - } - - // Need to add "{items:[" before the first item - if (aPart == Partition::Begining) { - rv = gzWriter->Write("{\"items\":[{"); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("ostream write begining failed"); - } - } else if (aPart == Partition::Middle) { - rv = gzWriter->Write(",{"); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("ostream write middle failed"); - } - } - rv = gzWriter->Write(mDesc.get()); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("ostream write mDesc failed"); - } - // one item is ended with '}' (e.g. {item}) - rv = gzWriter->Write("}"); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("ostream write end failed"); - } - - rv = gzWriter->Finish(); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("ostream finish failed"); - } - - // check if it is the end of this file - int64_t fileSize = 0; - rv = tmpFile->GetFileSize(&fileSize); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("GetFileSize failed"); - return; - } - if (fileSize >= MAXFILESIZE_KB) { - WriteJSON(Partition::End); - return; - } -} - -WriteStumbleOnThread::Partition -WriteStumbleOnThread::GetWritePosition() -{ - MOZ_ASSERT(!NS_IsMainThread()); - - nsCOMPtr<nsIFile> tmpFile; - nsresult rv = nsDumpUtils::OpenTempFile(FILENAME_INPROGRESS, getter_AddRefs(tmpFile), - OUTPUT_DIR, nsDumpUtils::CREATE); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("Open a file for stumble failed"); - return Partition::Unknown; - } - - int64_t fileSize = 0; - rv = tmpFile->GetFileSize(&fileSize); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("GetFileSize failed"); - return Partition::Unknown; - } - - if (fileSize == 0) { - return Partition::Begining; - } else if (fileSize >= MAXFILESIZE_KB) { - return Partition::End; - } else { - return Partition::Middle; - } -} - -NS_IMETHODIMP -WriteStumbleOnThread::Run() -{ - MOZ_ASSERT(!NS_IsMainThread()); - - bool b = sIsAlreadyRunning.exchange(true); - if (b) { - return NS_OK; - } - - UploadFileStatus status = GetUploadFileStatus(); - - if (UploadFileStatus::NoFile != status) { - if (UploadFileStatus::ExistsAndReadyToUpload == status) { - sIsFileWaitingForUpload = true; - Upload(); - return NS_OK; - } - } else { - Partition partition = GetWritePosition(); - if (partition == Partition::Unknown) { - STUMBLER_ERR("GetWritePosition failed, skip once"); - } else { - WriteJSON(partition); - } - } - - sIsFileWaitingForUpload = false; - sIsAlreadyRunning = false; - return NS_OK; -} - - -/* - If the upload file exists, then check if it is one day old. - • if it is a day old -> ExistsAndReadyToUpload - • if it is less than the current day old -> Exists - • otherwise -> NoFile - - The Exists case means that the upload and the stumbling is rate limited - per-day to the size of the one file. - */ -WriteStumbleOnThread::UploadFileStatus -WriteStumbleOnThread::GetUploadFileStatus() -{ - nsCOMPtr<nsIFile> tmpFile; - nsresult rv = nsDumpUtils::OpenTempFile(FILENAME_COMPLETED, getter_AddRefs(tmpFile), - OUTPUT_DIR, nsDumpUtils::CREATE); - int64_t fileSize; - rv = tmpFile->GetFileSize(&fileSize); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("GetFileSize failed"); - return UploadFileStatus::NoFile; - } - if (fileSize <= 0) { - tmpFile->Remove(true); - return UploadFileStatus::NoFile; - } - - PRTime lastModifiedTime; - tmpFile->GetLastModifiedTime(&lastModifiedTime); - if ((PR_Now() / PR_USEC_PER_MSEC) - lastModifiedTime >= ONEDAY_IN_MSEC) { - return UploadFileStatus::ExistsAndReadyToUpload; - } - return UploadFileStatus::Exists; -} - -void -WriteStumbleOnThread::Upload() -{ - MOZ_ASSERT(!NS_IsMainThread()); - - time_t seconds = time(0); - int day = seconds / (60 * 60 * 24); - - if (sUploadFreqGuard.daySinceEpoch < day) { - sUploadFreqGuard.daySinceEpoch = day; - sUploadFreqGuard.attempts = 0; - } - - sUploadFreqGuard.attempts++; - if (sUploadFreqGuard.attempts > MAX_UPLOAD_ATTEMPTS) { - STUMBLER_ERR("Too many upload attempts today"); - sIsAlreadyRunning = false; - return; - } - - nsCOMPtr<nsIFile> tmpFile; - nsresult rv = nsDumpUtils::OpenTempFile(FILENAME_COMPLETED, getter_AddRefs(tmpFile), - OUTPUT_DIR, nsDumpUtils::CREATE); - int64_t fileSize; - rv = tmpFile->GetFileSize(&fileSize); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("GetFileSize failed"); - sIsAlreadyRunning = false; - return; - } - - if (fileSize <= 0) { - sIsAlreadyRunning = false; - return; - } - - // prepare json into nsIInputStream - nsCOMPtr<nsIInputStream> inStream; - rv = NS_NewLocalFileInputStream(getter_AddRefs(inStream), tmpFile); - if (NS_FAILED(rv)) { - sIsAlreadyRunning = false; - return; - } - - RefPtr<nsIRunnable> uploader = new UploadStumbleRunnable(inStream); - NS_DispatchToMainThread(uploader); -} diff --git a/dom/system/gonk/mozstumbler/WriteStumbleOnThread.h b/dom/system/gonk/mozstumbler/WriteStumbleOnThread.h deleted file mode 100644 index 104cf9bdd..000000000 --- a/dom/system/gonk/mozstumbler/WriteStumbleOnThread.h +++ /dev/null @@ -1,91 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef WriteStumbleOnThread_H -#define WriteStumbleOnThread_H - -#include "mozilla/Atomics.h" - -class DeleteRunnable; - -/* - This class is the entry point to stumbling, in that it - receives the location+cell+wifi string and writes it - to disk, or instead, it calls UploadStumbleRunnable - to upload the data. - - Writes will happen until the file is a max size, then stop. - Uploads will happen only when the file is one day old. - The purpose of these decisions is to have very simple rate-limiting - on the writes, as well as the uploads. - - There is only one file active; it is either being used for writing, - or for uploading. If the file is ready for uploading, no further - writes will take place until this file has been uploaded. - This can mean writing might not take place for days until the uploaded - file is processed. This is correct by-design. - - A notable limitation is that the upload is triggered by a location event, - this is used as an arbitrary and simple trigger. In future, there are - better events that can be used, such as detecting network activity. - - This thread is guarded so that only one instance is active (see the - mozilla::Atomics used for this). - */ -class WriteStumbleOnThread : public mozilla::Runnable -{ -public: - explicit WriteStumbleOnThread(const nsCString& aDesc) - : mDesc(aDesc) - {} - - NS_IMETHOD Run() override; - - static void UploadEnded(bool deleteUploadFile); - - // Used externally to determine if cell+wifi scans should happen - // (returns false for that case). - static bool IsFileWaitingForUpload(); - -private: - friend class DeleteRunnable; - - enum class Partition { - Begining, - Middle, - End, - Unknown - }; - - enum class UploadFileStatus { - NoFile, Exists, ExistsAndReadyToUpload - }; - - ~WriteStumbleOnThread() {} - - Partition GetWritePosition(); - UploadFileStatus GetUploadFileStatus(); - void WriteJSON(Partition aPart); - void Upload(); - - nsCString mDesc; - - // Only run one instance of this - static mozilla::Atomic<bool> sIsAlreadyRunning; - - static mozilla::Atomic<bool> sIsFileWaitingForUpload; - - // Limit the upload attempts per day. If the device is rebooted - // this resets the allowed attempts, which is acceptable. - struct UploadFreqGuard { - int attempts; - int daySinceEpoch; - }; - static UploadFreqGuard sUploadFreqGuard; - -}; - -#endif diff --git a/dom/system/gonk/nsIAudioManager.idl b/dom/system/gonk/nsIAudioManager.idl deleted file mode 100644 index c2eb62b21..000000000 --- a/dom/system/gonk/nsIAudioManager.idl +++ /dev/null @@ -1,58 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -[scriptable, builtinclass, uuid(df31c280-1ef1-11e5-867f-0800200c9a66)] -interface nsIAudioManager : nsISupports -{ - /** - * Microphone muted? - */ - attribute boolean microphoneMuted; - - /** - * Set the phone's audio mode. - */ - const long PHONE_STATE_INVALID = -2; - const long PHONE_STATE_CURRENT = -1; - const long PHONE_STATE_NORMAL = 0; - const long PHONE_STATE_RINGTONE = 1; - const long PHONE_STATE_IN_CALL = 2; - const long PHONE_STATE_IN_COMMUNICATION = 3; - - attribute long phoneState; - - /** - * Configure a particular device ("force") to be used for one of the uses - * (communication, media playback, etc.) - */ - const long FORCE_NONE = 0; // the default - const long FORCE_SPEAKER = 1; - const long FORCE_HEADPHONES = 2; - const long FORCE_BT_SCO = 3; - const long FORCE_BT_A2DP = 4; - const long FORCE_WIRED_ACCESSORY = 5; - const long FORCE_BT_CAR_DOCK = 6; - const long FORCE_BT_DESK_DOCK = 7; - const long FORCE_ANALOG_DOCK = 8; - const long FORCE_DIGITAL_DOCK = 9; - const long FORCE_NO_BT_A2DP = 10; - const long USE_COMMUNICATION = 0; - const long USE_MEDIA = 1; - const long USE_RECORD = 2; - const long USE_DOCK = 3; - - void setForceForUse(in long usage, in long force); - long getForceForUse(in long usage); - - /** - * These functions would be used when we enable the new volume control API - * (mozAudioChannelManager). The range of volume index is from 0 to N. - * More details on : https://gist.github.com/evanxd/41d8e2d91c5201a42bfa - */ - void setAudioChannelVolume(in unsigned long channel, in unsigned long index); - unsigned long getAudioChannelVolume(in unsigned long channel); - unsigned long getMaxAudioChannelVolume(in unsigned long channel); -}; diff --git a/dom/system/gonk/nsIDataCallInterfaceService.idl b/dom/system/gonk/nsIDataCallInterfaceService.idl deleted file mode 100644 index c387879fa..000000000 --- a/dom/system/gonk/nsIDataCallInterfaceService.idl +++ /dev/null @@ -1,268 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -[scriptable, uuid(6b66446a-7000-438f-8e1b-b56b4cbf4fa9)] -interface nsIDataCall : nsISupports -{ - /** - * Data call fail cause. One of the nsIDataCallInterface.DATACALL_FAIL_* - * values. - */ - readonly attribute long failCause; - - /** - * If failCause != nsIDataCallInterface.DATACALL_FAIL_NONE, this field - * indicates the suggested retry back-off timer. The unit is milliseconds. - */ - readonly attribute long suggestedRetryTime; - - /** - * Context ID, uniquely identifies this call. - */ - readonly attribute long cid; - - /** - * Data call network state. One of the nsIDataCallInterface.DATACALL_STATE_* - * values. - */ - readonly attribute long active; - - /** - * Data call connection type. One of the - * nsIDataCallInterface.DATACALL_PDP_TYPE_* values. - */ - readonly attribute long pdpType; - - /** - * The network interface name. - */ - readonly attribute DOMString ifname; - - /** - * A space-delimited list of addresses with optional "/" prefix length. - */ - readonly attribute DOMString addresses; - - /** - * A space-delimited list of DNS server addresses. - */ - readonly attribute DOMString dnses; - - /** - * A space-delimited list of default gateway addresses. - */ - readonly attribute DOMString gateways; - - /** - * A space-delimited list of Proxy Call State Control Function addresses for - * IMS client. - */ - readonly attribute DOMString pcscf; - - /** - * MTU received from network, -1 if not set or invalid. - */ - readonly attribute long mtu; -}; - -[scriptable, uuid(e119c54b-9354-4ad6-a1ee-18608bde9320)] -interface nsIDataCallInterfaceListener : nsISupports -{ - /** - * Notify data call interface listeners about unsolicited data call state - * changes. - */ - void notifyDataCallListChanged(in uint32_t count, - [array, size_is(count)] in nsIDataCall - dataCalls); -}; - -[scriptable, uuid(db0b640a-3b3a-4f48-84dc-256e176876c2)] -interface nsIDataCallCallback : nsISupports -{ - /** - * Called when setupDataCall() returns succesfully. - */ - void notifySetupDataCallSuccess(in nsIDataCall dataCall); - - /** - * Called when getDataCallList() returns succesfully. - */ - void notifyGetDataCallListSuccess(in uint32_t count, - [array, size_is(count)] in nsIDataCall - dataCalls); - /** - * Called when request returns succesfully. - */ - void notifySuccess(); - - /** - * Called when request returns error. - */ - void notifyError(in AString errorMsg); -}; - -[scriptable, uuid(ec219021-8623-4b9f-aba5-4db58c60684f)] -interface nsIDataCallInterface : nsISupports -{ - /** - * Data fail causes, defined in TS 24.008. - */ - const long DATACALL_FAIL_NONE = 0; - const long DATACALL_FAIL_OPERATOR_BARRED = 0x08; - const long DATACALL_FAIL_INSUFFICIENT_RESOURCES = 0x1A; - const long DATACALL_FAIL_MISSING_UKNOWN_APN = 0x1B; - const long DATACALL_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C; - const long DATACALL_FAIL_USER_AUTHENTICATION = 0x1D; - const long DATACALL_FAIL_ACTIVATION_REJECT_GGSN = 0x1E; - const long DATACALL_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F; - const long DATACALL_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20; - const long DATACALL_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21; - const long DATACALL_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22; - const long DATACALL_FAIL_NSAPI_IN_USE = 0x23; - const long DATACALL_FAIL_ONLY_IPV4_ALLOWED = 0x32; - const long DATACALL_FAIL_ONLY_IPV6_ALLOWED = 0x33; - const long DATACALL_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34; - const long DATACALL_FAIL_PROTOCOL_ERRORS = 0x6F; - /* Not mentioned in the specification */ - const long DATACALL_FAIL_VOICE_REGISTRATION_FAIL = -1; - const long DATACALL_FAIL_DATA_REGISTRATION_FAIL = -2; - const long DATACALL_FAIL_SIGNAL_LOST = -3; - const long DATACALL_FAIL_PREF_RADIO_TECH_CHANGED = -4; - const long DATACALL_FAIL_RADIO_POWER_OFF = -5; - const long DATACALL_FAIL_TETHERED_CALL_ACTIVE = -6; - const long DATACALL_FAIL_ERROR_UNSPECIFIED = 0xFFFF; - - /** - * Data call network state. - */ - const long DATACALL_STATE_INACTIVE = 0; - const long DATACALL_STATE_ACTIVE_DOWN = 1; - const long DATACALL_STATE_ACTIVE_UP = 2; - - /** - * Data call authentication type. Must match the values in ril_consts - * RIL_DATACALL_AUTH_TO_GECKO array. - */ - const long DATACALL_AUTH_NONE = 0; - const long DATACALL_AUTH_PAP = 1; - const long DATACALL_AUTH_CHAP = 2; - const long DATACALL_AUTH_PAP_OR_CHAP = 3; - - /** - * Data call protocol type. Must match the values in ril_consts - * RIL_DATACALL_PDP_TYPES array. - */ - const long DATACALL_PDP_TYPE_IPV4 = 0; - const long DATACALL_PDP_TYPE_IPV4V6 = 1; - const long DATACALL_PDP_TYPE_IPV6 = 2; - - /** - * Reason for deactivating data call. - */ - const long DATACALL_DEACTIVATE_NO_REASON = 0; - const long DATACALL_DEACTIVATE_RADIO_SHUTDOWN = 1; - - /** - * Setup data call. - * - * @param apn - * Apn to connect to. - * @param username - * Username for apn. - * @param password - * Password for apn. - * @param authType - * Authentication type. One of the DATACALL_AUTH_* values. - * @param pdpType - * Connection type. One of the DATACALL_PDP_TYPE_* values. - * @param nsIDataCallCallback - * Called when request is finished. - * - * If successful, the notifySetupDataCallSuccess() will be called with the - * new nsIDataCall. - * - * Otherwise, the notifyError() will be called, and the error will be either - * 'RadioNotAvailable', 'OpNotAllowedBeforeRegToNw', - * 'OpNotAllowedDuringVoiceCall', 'RequestNotSupported' or 'GenericFailure'. - */ - void setupDataCall(in AString apn, in AString username, - in AString password, in long authType, - in long pdpType, - in nsIDataCallCallback callback); - - /** - * Deactivate data call. - * - * @param cid - * Context id. - * @param reason - * Disconnect Reason. One of the DATACALL_DEACTIVATE_* values. - * @param nsIDataCallCallback - * Called when request is finished. - * - * If successful, the notifySuccess() will be called. - * - * Otherwise, the notifyError() will be called, and the error will be either - * 'RadioNotAvailable' or 'GenericFailure'. - */ - void deactivateDataCall(in long cid, - in long reason, - in nsIDataCallCallback callback); - - /** - * Get current data call list. - * - * @param nsIDataCallCallback - * Called when request is finished. - * - * If successful, the notifyGetDataCallListSuccess() will be called with the - * list of nsIDataCall(s). - * - * Otherwise, the notifyError() will be called, and the error will be either - * 'RadioNotAvailable' or 'GenericFailure'. - */ - void getDataCallList(in nsIDataCallCallback callback); - - /** - * Set data registration state. - * - * @param attach - * whether to attach data registration or not. - * @param nsIDataCallCallback - * Called when request is finished. - * - * If successful, the notifySuccess() will be called. - * - * Otherwise, the notifyError() will be called, and the error will be either - * 'RadioNotAvailable', 'SubscriptionNotAvailable' or 'GenericFailure'. - */ - void setDataRegistration(in boolean attach, - in nsIDataCallCallback callback); - - /** - * Register to receive unsolicited events from this nsIDataCallInterface. - */ - void registerListener(in nsIDataCallInterfaceListener listener); - - /** - * Unregister to stop receiving unsolicited events from this - * nsIDataCallInterface. - */ - void unregisterListener(in nsIDataCallInterfaceListener listener); -}; - -[scriptable, uuid(64700406-7429-4743-a6ae-f82e9877fd0d)] -interface nsIDataCallInterfaceService : nsISupports -{ - /** - * Get the corresponding data call interface. - * - * @param clientId - * clientId of the data call interface to get. - */ - nsIDataCallInterface getDataCallInterface(in long clientId); -};
\ No newline at end of file diff --git a/dom/system/gonk/nsIDataCallManager.idl b/dom/system/gonk/nsIDataCallManager.idl deleted file mode 100644 index de8477801..000000000 --- a/dom/system/gonk/nsIDataCallManager.idl +++ /dev/null @@ -1,81 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" -#include "nsINetworkInterface.idl" - -[scriptable, uuid(b8bcd6aa-5b06-4362-a68c-317878429e51)] -interface nsIRilNetworkInfo : nsINetworkInfo -{ - readonly attribute unsigned long serviceId; - readonly attribute DOMString iccId; - - /* The following attributes are for MMS proxy settings. */ - readonly attribute DOMString mmsc; // Empty string if not set. - readonly attribute DOMString mmsProxy; // Empty string if not set. - readonly attribute long mmsPort; // -1 if not set. - - /** - * Get the list of pcscf addresses, could be IPv4 or IPv6. - * - * @param count - * The length of the list of pcscf addresses. - * - * @returns the list of pcscf addresses. - */ - void getPcscf([optional] out unsigned long count, - [array, size_is(count), retval] out wstring pcscf); -}; - -[scriptable, function, uuid(cb2f0f5b-67f4-4c14-93e8-01e66b630464)] -interface nsIDeactivateDataCallsCallback : nsISupports -{ - /** - * Callback function used to notify when all data calls are disconnected. - */ - void notifyDataCallsDisconnected(); -}; - -[scriptable, uuid(e3feec20-36b4-47de-a7a5-e32a65f20186)] -interface nsIDataCallHandler : nsISupports -{ - /** - * PDP APIs - * - * @param networkType - * Mobile network type, that is, - * nsINetworkInterface.NETWORK_TYPE_MOBILE or one of the - * nsINetworkInterface.NETWORK_TYPE_MOBILE_* values. - */ - void setupDataCallByType(in long networkType); - void deactivateDataCallByType(in long networkType); - long getDataCallStateByType(in long networkType); - - /** - * Deactivate all data calls. - * - * @param callback - * Callback to notify when all data calls are disconnected. - */ - void deactivateDataCalls(in nsIDeactivateDataCallsCallback callback); - - /** - * Called to reconsider data call state. - */ - void updateRILNetworkInterface(); -}; - -[scriptable, uuid(2c46e37d-88dc-4d25-bb37-e1c0d3e9cb5f)] -interface nsIDataCallManager : nsISupports -{ - readonly attribute long dataDefaultServiceId; - - /** - * Get the corresponding data call handler. - * - * @param clientId - * clientId of the data call handler to get. - */ - nsIDataCallHandler getDataCallHandler(in unsigned long clientId); -};
\ No newline at end of file diff --git a/dom/system/gonk/nsIGonkDataCallInterfaceService.idl b/dom/system/gonk/nsIGonkDataCallInterfaceService.idl deleted file mode 100644 index 240ca6bab..000000000 --- a/dom/system/gonk/nsIGonkDataCallInterfaceService.idl +++ /dev/null @@ -1,18 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsIDataCallInterfaceService.idl" - -[scriptable, uuid(f008d00c-e2b8-49b2-8f88-19111577938e)] -interface nsIGonkDataCallInterfaceService : nsIDataCallInterfaceService -{ - /** - * Called by RadioInterface or lower layer to notify about data call list - * changes. - */ - void notifyDataCallListChanged(in unsigned long clientId, - in uint32_t count, - [array, size_is(count)] in nsIDataCall - dataCalls); -};
\ No newline at end of file diff --git a/dom/system/gonk/nsINetworkInterface.idl b/dom/system/gonk/nsINetworkInterface.idl deleted file mode 100644 index bd40e751a..000000000 --- a/dom/system/gonk/nsINetworkInterface.idl +++ /dev/null @@ -1,108 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -[scriptable, uuid(4816a559-5620-4cb5-8433-ff0b25e6622f)] -interface nsINetworkInfo : nsISupports -{ - const long NETWORK_STATE_UNKNOWN = -1; - const long NETWORK_STATE_CONNECTING = 0; - const long NETWORK_STATE_CONNECTED = 1; - const long NETWORK_STATE_DISCONNECTING = 2; - const long NETWORK_STATE_DISCONNECTED = 3; - const long NETWORK_STATE_ENABLED = 4; - const long NETWORK_STATE_DISABLED = 5; - - /** - * Current network state, one of the NETWORK_STATE_* constants. - * - * When this changes, network interface implementations notify with - * updateNetworkInterface() API. - */ - readonly attribute long state; - - const long NETWORK_TYPE_UNKNOWN = -1; - const long NETWORK_TYPE_WIFI = 0; - const long NETWORK_TYPE_MOBILE = 1; - const long NETWORK_TYPE_MOBILE_MMS = 2; - const long NETWORK_TYPE_MOBILE_SUPL = 3; - const long NETWORK_TYPE_WIFI_P2P = 4; - const long NETWORK_TYPE_MOBILE_IMS = 5; - const long NETWORK_TYPE_MOBILE_DUN = 6; - const long NETWORK_TYPE_MOBILE_FOTA = 7; - const long NETWORK_TYPE_ETHERNET = 8; - - /** - * Network type. One of the NETWORK_TYPE_* constants. - */ - readonly attribute long type; - - /** - * Interface name of the network interface this network info belongs to. - */ - readonly attribute DOMString name; - - /** - * Get the list of ip addresses and prefix lengths, ip address could be IPv4 - * or IPv6, typically 1 IPv4 or 1 IPv6 or one of each. - * - * @param ips - * The list of ip addresses retrieved. - * @param prefixLengths - * The list of prefix lengths retrieved. - * - * @returns the length of the lists. - */ - void getAddresses([array, size_is(count)] out wstring ips, - [array, size_is(count)] out unsigned long prefixLengths, - [retval] out unsigned long count); - - /** - * Get the list of gateways, could be IPv4 or IPv6, typically 1 IPv4 or 1 - * IPv6 or one of each. - * - * @param count - * The length of the list of gateways - * - * @returns the list of gateways. - */ - void getGateways([optional] out unsigned long count, - [array, size_is(count), retval] out wstring gateways); - - /** - * Get the list of dnses, could be IPv4 or IPv6. - * - * @param count - * The length of the list of dnses. - * - * @returns the list of dnses. - */ - void getDnses([optional] out unsigned long count, - [array, size_is(count), retval] out wstring dnses); -}; - -[scriptable, uuid(8b1345fa-b34c-41b3-8d21-09f961bf8887)] -interface nsINetworkInterface : nsISupports -{ - /** - * The network information about this network interface. - */ - readonly attribute nsINetworkInfo info; - - /** - * The host name of the http proxy server. - */ - readonly attribute DOMString httpProxyHost; - - /* - * The port number of the http proxy server. - */ - readonly attribute long httpProxyPort; - - /* - * The Maximun Transmit Unit for this network interface, -1 if not set. - */ - readonly attribute long mtu; -}; diff --git a/dom/system/gonk/nsINetworkInterfaceListService.idl b/dom/system/gonk/nsINetworkInterfaceListService.idl deleted file mode 100644 index 0c224842e..000000000 --- a/dom/system/gonk/nsINetworkInterfaceListService.idl +++ /dev/null @@ -1,40 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -interface nsINetworkInfo; - -[scriptable, uuid(55779d32-1e28-4f43-af87-09d04bc3cce9)] -interface nsINetworkInterfaceList : nsISupports -{ - /** - * Number of the network interfaces that is available. - */ - long getNumberOfInterface(); - - /** - * Get the i-th interface info info from the list. - * @param interfaceIndex index of interface, from 0 to number of interface - 1. - */ - nsINetworkInfo getInterfaceInfo(in long interfaceIndex); -}; - -[scriptable, uuid(21d7fc8b-28c4-4a4f-a15e-1f9defbc2cec)] -interface nsINetworkInterfaceListService : nsISupports -{ - const long LIST_NOT_INCLUDE_MMS_INTERFACES = (1 << 0); - const long LIST_NOT_INCLUDE_SUPL_INTERFACES = (1 << 1); - const long LIST_NOT_INCLUDE_IMS_INTERFACES = (1 << 2); - const long LIST_NOT_INCLUDE_DUN_INTERFACES = (1 << 3); - const long LIST_NOT_INCLUDE_FOTA_INTERFACES = (1 << 4); - - /** - * Obtain a list of network interfaces that satisfy the specified condition. - * @param condition flags that specify the interfaces to be returned. This - * can be OR combination of LIST_* flags, or zero to make all available - * interfaces returned. - */ - nsINetworkInterfaceList getDataInterfaceList(in long condition); -}; diff --git a/dom/system/gonk/nsINetworkManager.idl b/dom/system/gonk/nsINetworkManager.idl deleted file mode 100644 index 0da123796..000000000 --- a/dom/system/gonk/nsINetworkManager.idl +++ /dev/null @@ -1,135 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -interface nsINetworkInfo; -interface nsINetworkInterface; - -/** - * Manage network interfaces. - */ -[scriptable, uuid(1ba9346b-53b5-4660-9dc6-58f0b258d0a6)] -interface nsINetworkManager : nsISupports -{ - /** - * Register the given network interface with the network manager. - * - * Consumers will be notified with the 'network-interface-registered' - * observer notification. - * - * Throws if there's already an interface registered with the same network id. - * - * @param network - * Network interface to register. - */ - void registerNetworkInterface(in nsINetworkInterface network); - - /** - * Update the routes and DNSes according the state of the given network. - * - * Consumers will be notified with the 'network-connection-state-changed' - * observer notification. - * - * Throws an exception if the specified network interface object isn't - * registered. - * - * @param network - * Network interface to update. - */ - void updateNetworkInterface(in nsINetworkInterface network); - - /** - * Unregister the given network interface from the network manager. - * - * Consumers will be notified with the 'network-interface-unregistered' - * observer notification. - * - * Throws an exception if the specified network interface object isn't - * registered. - * - * @param network - * Network interface to unregister. - */ - void unregisterNetworkInterface(in nsINetworkInterface network); - - /** - * Object containing all known network information, keyed by their - * network id. Network id is composed of a sub-id + '-' + network - * type. For mobile network types, sub-id is 'ril' + service id; for - * non-mobile network types, sub-id is always 'device'. - */ - readonly attribute jsval allNetworkInfo; - - /** - * Priority list of network types. An array of - * nsINetworkInterface::NETWORK_TYPE_* constants. - * - * The piror position of the type indicates the higher priority. The priority - * is used to determine route when there are multiple connected networks. - */ - attribute jsval networkTypePriorityList; - - /** - * The preferred network type. One of the - * nsINetworkInterface::NETWORK_TYPE_* constants. - * - * This attribute is used for setting default route to favor - * interfaces with given type. This can be overriden by calling - * overrideDefaultRoute(). - */ - attribute long preferredNetworkType; - - /** - * The network information of the network interface handling all network - * traffic. - * - * When this changes, the 'network-active-changed' observer - * notification is dispatched. - */ - readonly attribute nsINetworkInfo activeNetworkInfo; - - /** - * Override the default behaviour for preferredNetworkType and route - * all network traffic through the the specified interface. - * - * Consumers can observe changes to the active network by subscribing to - * the 'network-active-changed' observer notification. - * - * @param network - * Network to route all network traffic to. If this is null, - * a previous override is canceled. - */ - long overrideActive(in nsINetworkInterface network); - - /** - * Add host route to the specified network into routing table. - * - * @param network - * The network information for the host to be routed to. - * @param host - * The host to be added. - * The host will be resolved in advance if it's not an ip-address. - * - * @return a Promise - * resolved if added; rejected, otherwise. - */ - jsval addHostRoute(in nsINetworkInfo network, - in DOMString host); - - /** - * Remove host route to the specified network from routing table. - * - * @param network - * The network information for the routing to be removed from. - * @param host - * The host routed to the network. - * The host will be resolved in advance if it's not an ip-address. - * - * @return a Promise - * resolved if removed; rejected, otherwise. - */ - jsval removeHostRoute(in nsINetworkInfo network, - in DOMString host); -}; diff --git a/dom/system/gonk/nsINetworkService.idl b/dom/system/gonk/nsINetworkService.idl deleted file mode 100644 index 50a468494..000000000 --- a/dom/system/gonk/nsINetworkService.idl +++ /dev/null @@ -1,619 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -[scriptable, function, uuid(91824160-fb25-11e1-a21f-0800200c9a66)] -interface nsIWifiTetheringCallback : nsISupports -{ - /** - * Callback function used to report status to WifiManager. - * - * @param error - * An error message if the operation wasn't successful, - * or `null` if it was. - */ - void wifiTetheringEnabledChange(in jsval error); -}; - -[scriptable, function, uuid(9c128e68-5e4b-4626-bb88-84ec54cce5d8)] -interface nsINetworkStatsCallback : nsISupports -{ - void networkStatsAvailable(in boolean success, - in unsigned long rxBytes, - in unsigned long txBytes, - in unsigned long long timestamp); -}; - -[scriptable, function, uuid(0706bfa2-ac2d-11e2-9a8d-7b6d988d4767)] -interface nsINetworkUsageAlarmCallback : nsISupports -{ - void networkUsageAlarmResult(in jsval error); -}; - -[scriptable, function, uuid(9ede8720-f8bc-11e2-b778-0800200c9a66)] -interface nsIWifiOperationModeCallback : nsISupports -{ - /** - * Callback function used to report result to WifiManager. - * - * @param error - * An error message if the operation wasn't successful, - * or `null` if it was. - */ - void wifiOperationModeResult(in jsval error); -}; - -[scriptable, function, uuid(097878b0-19fc-11e3-8ffd-0800200c9a66)] -interface nsISetDhcpServerCallback : nsISupports -{ - /** - * Callback function used to report the DHCP server set result - * - * @param error - * An error message if the operation wasn't successful, - * or `null` if it was. - */ - void dhcpServerResult(in jsval error); -}; - -[scriptable, function, uuid(32407c50-46c7-11e3-8f96-0800200c9a66)] -interface nsIUsbTetheringCallback : nsISupports -{ - /** - * Callback function used to report status of enabling usb tethering. - * - * @param error - * An error message if the operation wasn't successful, - * or `null` if it was. - */ - void usbTetheringEnabledChange(in jsval error); -}; - -[scriptable, function, uuid(055fd560-46ad-11e3-8f96-0800200c9a66)] -interface nsIEnableUsbRndisCallback : nsISupports -{ - /** - * Callback function used to report the status of enabling/disabling usb rndis. - * - * @param success - * Boolean to indicate the operation is successful or not. - * @param enable - * Boolean to indicate if we are enabling or disabling usb rndis. - */ - void enableUsbRndisResult(in boolean success, in boolean enable); -}; - -[scriptable, function, uuid(4f08cc30-46ad-11e3-8f96-0800200c9a66)] -interface nsIUpdateUpStreamCallback : nsISupports -{ - /** - * Callback function used to report the result of updating upstream. - * - * @param success - * Boolean to indicate the operation is successful or not. - * @param externalIfname - * The external interface name. - */ - void updateUpStreamResult(in boolean success, in DOMString externalIfname); -}; - -[scriptable, function, uuid(eedca6c0-1310-11e4-9191-0800200c9a66)] -interface nsISetDnsCallback : nsISupports -{ - /** - * Callback function used to report the result of setting DNS server. - * - * @param error - * An error message if the operation wasn't successful, - * or `null` if it was. - */ - void setDnsResult(in jsval error); -}; - -[scriptable, function, uuid(5d0e1a60-1187-11e4-9191-0800200c9a66)] -interface nsINativeCommandCallback : nsISupports -{ - /** - * Callback function used to report the result of a network native command. - * - * @param success - * Boolean to indicate the operation is successful or not. - */ - void nativeCommandResult(in boolean success); -}; - -[scriptable, function, uuid(694abb80-1187-11e4-9191-0800200c9a66)] -interface nsIDhcpRequestCallback : nsISupports -{ - /** - * Callback function used to report the result of DHCP client request. - * - * @param success - * Boolean to indicate the operation is successful or not. - * - * @param dhcpInfo - * An object to represent the successful DHCP request: - * - * - gateway_str: string - * - dns1_str: string - * - dns2_str: string - * - mask_str: string - * - server_str: string - * - vendor_str: string - * - lease: long - * - mask: long - * - ipaddr: long - * - gateway: long - * - dns1: long - * - dns2: long - * - server: long - */ - void dhcpRequestResult(in boolean success, in jsval dhcpInfo); -}; - -[scriptable, function, uuid(88e3ee22-f1b3-4fa0-8a5d-793fb827c42c)] -interface nsIGetInterfacesCallback : nsISupports -{ - /** - * Callback function used to return the list of existing network interfaces. - * - * @param success - * Boolean to indicate the operation is successful or not. - * @param interfaceList - * An array of interface name. - */ - void getInterfacesResult(in boolean success, in jsval interfaceList); -}; - -[scriptable, function, uuid(064e02a3-d2c0-42c5-a293-1efa84056100)] -interface nsIGetInterfaceConfigCallback : nsISupports -{ - /** - * Callback function used to return the network config of a given interface. - * - * @param success - * Boolean to indicate the operation is successful or not. - * @param result - * .ip: Ip address. - * .prefix: mask length. - * .link: network link properties. - * .mac: mac address. - */ - void getInterfaceConfigResult(in boolean success, in jsval result); -}; - -[scriptable, function, uuid(b370f360-6ba8-4517-a4f9-31e8f004ee91)] -interface nsISetInterfaceConfigCallback : nsISupports -{ - /** - * Callback function used to set network config for a specified interface. - * - * @param success - * Boolean to indicate the operation is successful or not. - */ - void setInterfaceConfigResult(in boolean success); -}; - -/** - * Provide network services. - */ -[scriptable, uuid(e16fe98f-9f63-48fe-82ba-8d1a1b7c6a57)] -interface nsINetworkService : nsISupports -{ - const long MODIFY_ROUTE_ADD = 0; - const long MODIFY_ROUTE_REMOVE = 1; - - /** - * Enable or disable Wifi Tethering - * - * @param enabled - * Boolean that indicates whether tethering should be enabled (true) or disabled (false). - * @param config - * The Wifi Tethering configuration from settings db. - * @param callback - * Callback function used to report status to WifiManager. - */ - void setWifiTethering(in boolean enabled, - in jsval config, - in nsIWifiTetheringCallback callback); - - /** - * Enable or disable DHCP server - * - * @param enabled - * Boolean that indicates enabling or disabling DHCP server. - * - * @param config - * Config used to enable the DHCP server. It contains - * .startIp start of the ip lease range (string) - * .endIp end of the ip lease range (string) - * .serverIp ip of the DHCP server (string) - * .maskLength the length of the subnet mask - * .ifname the interface name - * - * As for disabling the DHCP server, put this value |null|. - * - * @param callback - * Callback function used to report status. - */ - void setDhcpServer(in boolean enabled, - in jsval config, - in nsISetDhcpServerCallback callback); - - - /** - * Retrieve network interface stats. - * - * @param networkName - * Select the Network interface to request estats. - * - * @param callback - * Callback to notify result and provide stats, connectionType - * and the date when stats are retrieved - */ - void getNetworkInterfaceStats(in DOMString networkName, in nsINetworkStatsCallback callback); - - /** - * Set Alarm of usage per interface - * - * @param networkName - * Select the Network interface to set an alarm. - * - * @param threshold - * Amount of data that will trigger the alarm. - * - * @param callback - * Callback to notify the result. - * - * @return false if there is no interface registered for the networkType param. - */ - boolean setNetworkInterfaceAlarm(in DOMString networkName, - in long long threshold, - in nsINetworkUsageAlarmCallback callback); - - /** - * Reload Wifi firmware to specific operation mode. - * - * @param interfaceName - * Wifi Network interface name. - * - * @param mode - * AP - Access pointer mode. - * P2P - Peer to peer connection mode. - * STA - Station mode. - * - * @param callback - * Callback to notify Wifi firmware reload result. - */ - void setWifiOperationMode(in DOMString interfaceName, - in DOMString mode, - in nsIWifiOperationModeCallback callback); - - /** - * Set USB tethering. - * - * @param enabled - * Boolean to indicate we are going to enable or disable usb tethering. - * @param config - * The usb tethering configuration. - * @param callback - * Callback function used to report the result enabling/disabling usb tethering. - */ - void setUSBTethering(in boolean enabled, - in jsval config, - in nsIUsbTetheringCallback callback); - - /** - * Reset routing table. - * - * @param interfaceName - * The name of the network interface we want to remove from the routing - * table. - * - * @param callback - * Callback to notify the result of resetting routing table. - */ - void resetRoutingTable(in DOMString interfaceName, - in nsINativeCommandCallback callback); - - /** - * Set DNS. - * - * @param interfaceName - * The network interface name of the DNS we want to set. - * @param dnsesCount - * Number of elements in dnses. - * @param dnses - * Dnses to set. - * @param gatewaysCount - * Number of elements in gateways. - * @param gateways - * Gateways for the dnses, the most suitable, usually the one with the - * same address family, will be selected for each dns. - * - * @param callback - * Callback to notify the result of setting DNS server. - */ - void setDNS(in DOMString interfaceName, - in unsigned long dnsesCount, - [array, size_is(dnsesCount)] in wstring dnses, - in unsigned long gatewaysCount, - [array, size_is(gatewaysCount)] in wstring gateways, - in nsISetDnsCallback callback); - - /** - * Set default route. - * - * @param interfaceName - * The network interface name of the default route we want to set. - * @param count - * Number of elements in gateways. - * @param gateways - * Default gateways for setting default route. - * - * @param callback - * Callback to notify the result of setting default route. - */ - void setDefaultRoute(in DOMString interfaceName, - in unsigned long count, - [array, size_is(count)] in wstring gateways, - in nsINativeCommandCallback callback); - - /** - * Remove default route. - * - * @param interfaceName - * The network interface name of the default route we want to remove. - * @param count - * Number of elements in gateways. - * @param gatways - * Default gateways for removing default route. - * - * @param callback - * Callback to notify the result of removing default route. - */ - void removeDefaultRoute(in DOMString interfaceName, - in unsigned long count, - [array, size_is(count)] in wstring gateways, - in nsINativeCommandCallback callback); - - /** - * Modify route. - * - * @param action - * nsINetworkService.MODIFY_ROUTE_ADD to add route and - * nsINetworkService.MODIFY_ROUTE_REMOVE to remove. - * @param interfaceName - * Network interface name for the output of the host route. - * @param host - * Host ip we want to remove route for. - * @param prefixLength - * The prefix length of the route we'd like to modify. - * @param [optional] gateway - * Gateway ip for the output of the host route. - * - * @return A deferred promise that resolves on success or rejects with a - * specified reason otherwise. - */ - jsval modifyRoute(in long action, - in DOMString interfaceName, - in DOMString host, - in long prefixLength, - [optional] in DOMString gateway); - - /** - * Add route to secondary routing table. - * - * @param interfaceName - * The network interface for this route. - * @param route - * The route info should have the following fields: - * .ip: destination ip address - * .prefix: destination prefix - * .gateway: gateway ip address - */ - void addSecondaryRoute(in DOMString interfaceName, in jsval route, - in nsINativeCommandCallback callback); - - /** - * Remove route from secondary routing table. - * - * @param interfaceName - * The network interface for the route we want to remove. - * @param route - * The route info should have the following fields: - * .ip: destination ip address - * .prefix: destination prefix - * .gateway: gateway ip address - */ - void removeSecondaryRoute(in DOMString interfaceName, in jsval route, - in nsINativeCommandCallback callback); - - /** - * Enable or disable usb rndis. - * - * @param enable - * Boolean to indicate we want enable or disable usb rndis. - * @param callback - * Callback function to report the result. - */ - void enableUsbRndis(in boolean enable, - in nsIEnableUsbRndisCallback callback); - - /** - * Update upstream. - * - * @param previous - * The previous internal and external interface. - * @param current - * The current internal and external interface. - * @param callback - * Callback function to report the result. - */ - void updateUpStream(in jsval previous, - in jsval current, - in nsIUpdateUpStreamCallback callback); - - /* - * Obtain interfaces list. - * - * @param callback - * Callback function to return the result. - */ - void getInterfaces(in nsIGetInterfacesCallback callback); - - /** - * Get config of a network interface. - * - * @param ifname - * Target interface. - * @param callback - * Callback function to report the result. - */ - void getInterfaceConfig(in DOMString ifname, in nsIGetInterfaceConfigCallback callback); - - /** - * Set config for a network interface. - * - * @param config - * .ifname: Target interface. - * .ip: Ip address. - * .prefix: mask length. - * .link: network link properties. - * @param callback - * Callback function to report the result. - */ - void setInterfaceConfig(in jsval config, in nsISetInterfaceConfigCallback callback); - - /** - * Configure a network interface. - * - * @param config - * An object containing the detail that we want to configure the interface: - * - * - ifname: string - * - ipaddr: long - * - mask: long - * - gateway: long - * - dns1: long - * - dns2: long - * - * @param callback - * Callback to notify the result of configurating network interface. - */ - void configureInterface(in jsval config, - in nsINativeCommandCallback callback); - - /** - * Issue a DHCP client request. - * - * @param networkInterface - * The network interface which we wnat to do the DHCP request on. - * - * @param callback - * Callback to notify the result of the DHCP request. - */ - void dhcpRequest(in DOMString interfaceName, - in nsIDhcpRequestCallback callback); - - /** - * Stop Dhcp daemon. - * - * @param ifname - * Target interface. - * - * @param callback - * Callback to notify the result of stopping dhcp request. - */ - void stopDhcp(in DOMString ifname, - in nsINativeCommandCallback callback); - - /** - * Enable a network interface. - * - * @param networkInterface - * The network interface name which we want to enable. - * - * @param callback - * Callback to notify the result of disabling network interface. - */ - void enableInterface(in DOMString interfaceName, - in nsINativeCommandCallback callback); - - /** - * Disable a network interface. - * - * @param networkInterface - * The network interface name which we want to disable. - * - * @param callback - * Callback to notify the result of disabling network interface. - */ - void disableInterface(in DOMString interfaceName, - in nsINativeCommandCallback callback); - - /** - * Reset all connections on a specified network interface. - * - * @param interfaceName - * The network interface name which we want to reset. - * - * @param callback - * Callback to notify the result of resetting connections. - */ - void resetConnections(in DOMString interfaceName, - in nsINativeCommandCallback callback); - - /** - * Create network (required to call prior to any networking operation). - * - * @param interfaceName - * The network interface name which we want to create network for. - * - * @param callback - * Callback to notify the result of creating network. - */ - void createNetwork(in DOMString interfaceName, - in nsINativeCommandCallback callback); - - /** - * Destroy network. - * - * @param interfaceName - * The network interface name of the network we want to destroy. - * - * @param callback - * Callback to notify the result of destroying network. - */ - void destroyNetwork(in DOMString interfaceName, - in nsINativeCommandCallback callback); - - /** - * Query the netId associated with given network interface name. - * - * @param interfaceName - * The network interface name which we want to query. - * - * @return A deferred promise that resolves with a string to indicate. - * the queried netId on success and rejects if the interface name - * is invalid. - * - */ - jsval getNetId(in DOMString interfaceName); - - /** - * Set maximum transmission unit on a network interface. - * - * @param interfaceName - * The name of the network interface that we want to set mtu. - * @param mtu - * Size of maximum tranmission unit. - * - * @param callback - * Callback to notify the result of setting mtu. - */ - void setMtu(in DOMString interfaceName, in long mtu, - in nsINativeCommandCallback callback); -}; diff --git a/dom/system/gonk/nsINetworkWorker.idl b/dom/system/gonk/nsINetworkWorker.idl deleted file mode 100644 index 8fe19be69..000000000 --- a/dom/system/gonk/nsINetworkWorker.idl +++ /dev/null @@ -1,18 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -[scriptable, uuid(98e31d3b-6cad-4cab-b4b3-4afff566ea65)] -interface nsINetworkEventListener : nsISupports { - void onEvent(in jsval result); -}; - -[scriptable, uuid(f9d9c694-0aac-4f9a-98ac-7788f954239a)] -interface nsINetworkWorker : nsISupports { - void start(in nsINetworkEventListener listener); - void shutdown(); - [implicit_jscontext] - void postMessage(in jsval options); -}; diff --git a/dom/system/gonk/nsIRadioInterfaceLayer.idl b/dom/system/gonk/nsIRadioInterfaceLayer.idl deleted file mode 100644 index 168fe3894..000000000 --- a/dom/system/gonk/nsIRadioInterfaceLayer.idl +++ /dev/null @@ -1,53 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -interface nsIIccInfo; -interface nsIMobileConnectionInfo; -interface nsIMobileMessageCallback; - -[scriptable, function, uuid(3bc96351-53b0-47a1-a888-c74c64b60f25)] -interface nsIRilSendWorkerMessageCallback : nsISupports -{ - boolean handleResponse(in jsval response); -}; - -[scriptable, uuid(1a3ef88a-e4d1-11e4-8512-176220f2b32b)] -interface nsIRadioInterface : nsISupports -{ - /** - * PDP APIs - * - * @param networkType - * Mobile network type, that is, nsINetworkInterface.NETWORK_TYPE_MOBILE - * or one of the nsINetworkInterface.NETWORK_TYPE_MOBILE_* values. - */ - void setupDataCallByType(in long networkType); - void deactivateDataCallByType(in long networkType); - long getDataCallStateByType(in long networkType); - - void updateRILNetworkInterface(); - - void sendWorkerMessage(in DOMString type, - [optional] in jsval message, - [optional] in nsIRilSendWorkerMessageCallback callback); -}; - -%{C++ -#define NS_RADIOINTERFACELAYER_CID \ - { 0x2d831c8d, 0x6017, 0x435b, \ - { 0xa8, 0x0c, 0xe5, 0xd4, 0x22, 0x81, 0x0c, 0xea } } -#define NS_RADIOINTERFACELAYER_CONTRACTID "@mozilla.org/ril;1" -%} - -[scriptable, uuid(09730e0d-75bb-4f21-8540-062a2eadc8ff)] -interface nsIRadioInterfaceLayer : nsISupports -{ - readonly attribute unsigned long numRadioInterfaces; - - nsIRadioInterface getRadioInterface(in unsigned long clientId); - - void setMicrophoneMuted(in boolean muted); -}; diff --git a/dom/system/gonk/nsISystemWorkerManager.idl b/dom/system/gonk/nsISystemWorkerManager.idl deleted file mode 100644 index a77e253e4..000000000 --- a/dom/system/gonk/nsISystemWorkerManager.idl +++ /dev/null @@ -1,16 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -/** - * Information about networks that is exposed to network manager API consumers. - */ -[scriptable, builtinclass, uuid(4984b669-0ee0-4809-ae96-3358a325a6b0)] -interface nsISystemWorkerManager : nsISupports -{ - [implicit_jscontext] - void registerRilWorker(in unsigned long aClientId, - in jsval aWorker); -}; diff --git a/dom/system/gonk/nsITetheringService.idl b/dom/system/gonk/nsITetheringService.idl deleted file mode 100644 index 530ab0069..000000000 --- a/dom/system/gonk/nsITetheringService.idl +++ /dev/null @@ -1,39 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -interface nsINetworkInterface; -interface nsIWifiTetheringCallback; - -[scriptable, uuid(779de2d3-6d29-4ee6-b069-6251839f757a)] -interface nsITetheringService : nsISupports -{ - const long TETHERING_STATE_INACTIVE = 0; - const long TETHERING_STATE_WIFI = 1; - const long TETHERING_STATE_USB = 2; - - /** - * Current tethering state. One of the TETHERING_STATE_* constants. - */ - readonly attribute long state; - - /** - * Enable or disable Wifi Tethering. - * - * @param enabled - * Boolean that indicates whether tethering should be enabled (true) or - * disabled (false). - * @param interfaceName - * The Wifi network interface name for internal interface. - * @param config - * The Wifi Tethering configuration from settings db. - * @param callback - * Callback function used to report status to WifiManager. - */ - void setWifiTethering(in boolean enabled, - in DOMString interfaceName, - in jsval config, - in nsIWifiTetheringCallback callback); -};
\ No newline at end of file diff --git a/dom/system/gonk/nsIVolume.idl b/dom/system/gonk/nsIVolume.idl deleted file mode 100644 index 60785f0a4..000000000 --- a/dom/system/gonk/nsIVolume.idl +++ /dev/null @@ -1,114 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" -#include "nsIVolumeStat.idl" - -[scriptable, uuid(EE752CB8-8FD7-11E4-A602-70221D5D46B0)] -interface nsIVolume : nsISupports -{ - // These MUST match the states from android's system/vold/Volume.h header - // Note: Changes made to the STATE_xxx names should also be reflected in the - // NS_VolumeStateStr function found in Volume.cpp - const long STATE_INIT = -1; - const long STATE_NOMEDIA = 0; - const long STATE_IDLE = 1; - const long STATE_PENDING = 2; - const long STATE_CHECKING = 3; - const long STATE_MOUNTED = 4; - const long STATE_UNMOUNTING = 5; - const long STATE_FORMATTING = 6; - const long STATE_SHARED = 7; - const long STATE_SHAREDMNT = 8; - const long STATE_CHECKMNT = 100; - const long STATE_MOUNT_FAIL = 101; - - // The name of the volume. Often there is only one volume, called sdcard. - // But some phones support multiple volumes. - readonly attribute DOMString name; - - // The mount point is the path on the system where the volume is mounted - // and is only valid when state == STATE_MOUNTED. - readonly attribute DOMString mountPoint; - - // Reflects the current state of the volume, using STATE_xxx constants - // from above. - readonly attribute long state; - - // mountGeneration is a unique number which is used distinguish between - // periods of time that a volume is in the mounted state. Each time a - // volume transitions to the mounted state, the mountGeneration will - // be different from the last time it transitioned to the mounted state. - readonly attribute long mountGeneration; - - // While a volume is mounted, it can be locked, preventing it from being - // shared with the PC. To lock a volume, acquire an MozWakeLock - // using the name of this attribute. Note that mountLockName changes - // every time the mountGeneration changes, so you'll need to reacquire - // the wakelock every time the volume becomes mounted. - readonly attribute DOMString mountLockName; - - // Determines if a mountlock is currently being held against this volume. - readonly attribute boolean isMountLocked; - - // Determines if media is actually present or not. Note, that when an sdcard - // is ejected, it may go through several tranistory states before finally - // arriving at STATE_NOMEDIA. So isMediaPresent may be false even when the - // current state isn't STATE_NOMEDIA. - readonly attribute boolean isMediaPresent; - - // Determines if the volume is currently being shared. This covers off - // more than just state == STATE_SHARED. isSharing will return true from the - // time that the volume leaves the mounted state, until it gets back to - // mounted, nomedia, or formatting states. This attribute is to allow - // device storage to suppress unwanted 'unavailable' status when - // transitioning from mounted to sharing and back again. - readonly attribute boolean isSharing; - - // Determines if the volume is currently formatting. This sets true once - // mFormatRequest == true and mState == STATE_MOUNTED, and sets false - // once the volume has been formatted and mounted again. - readonly attribute boolean isFormatting; - - readonly attribute boolean isUnmounting; - - nsIVolumeStat getStats(); - - // Formats the volume in IO thread, if the volume is ready to be formatted. - // Automounter will unmount it, format it and then mount it again. - void format(); - - // Mounts the volume in IO thread, if the volume is already unmounted. - // Automounter will mount it. Otherwise Automounter will skip this. - void mount(); - - // Unmounts the volume in IO thread, if the volume is already mounted. - // Automounter will unmount it. Otherwise Automounter will skip this. - void unmount(); - - // Whether this is a fake volume. - readonly attribute boolean isFake; - - // Whether this is a removable volume - readonly attribute boolean isRemovable; - - // Whether this is a hot-swappable volume - readonly attribute boolean isHotSwappable; - -}; - -%{C++ -// For use with the ObserverService -#define NS_VOLUME_STATE_CHANGED "volume-state-changed" -#define NS_VOLUME_REMOVED "volume-removed" - -namespace mozilla { -namespace system { - -// Convert a state into a loggable/printable string. -const char* NS_VolumeStateStr(int32_t aState); - -} // system -} // mozilla -%} diff --git a/dom/system/gonk/nsIVolumeMountLock.idl b/dom/system/gonk/nsIVolumeMountLock.idl deleted file mode 100644 index 0a9a1a5c2..000000000 --- a/dom/system/gonk/nsIVolumeMountLock.idl +++ /dev/null @@ -1,12 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -[scriptable, uuid(44449f34-5ca1-4aff-bce6-22c79263de24)] -interface nsIVolumeMountLock : nsISupports -{ - void unlock(); -}; - diff --git a/dom/system/gonk/nsIVolumeService.idl b/dom/system/gonk/nsIVolumeService.idl deleted file mode 100644 index d3752e201..000000000 --- a/dom/system/gonk/nsIVolumeService.idl +++ /dev/null @@ -1,36 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" -#include "nsIVolume.idl" -#include "nsIVolumeMountLock.idl" - -interface nsIArray; - -[scriptable, uuid(cfbf9880-cba5-11e4-8830-0800200c9a66)] -interface nsIVolumeService : nsISupports -{ - nsIVolume getVolumeByName(in DOMString volName); - nsIVolume getVolumeByPath(in DOMString path); - nsIVolume createOrGetVolumeByPath(in DOMString path); - - nsIVolumeMountLock createMountLock(in DOMString volName); - - nsIArray getVolumeNames(); - - void Dump(in DOMString label); - - /* for test case only to simulate sdcard insertion/removal */ - void createFakeVolume(in DOMString name, in DOMString path); - void SetFakeVolumeState(in DOMString name, in long state); - - /* for test case only to test removal of storage area */ - void removeFakeVolume(in DOMString name); -}; - -%{C++ -#define NS_VOLUMESERVICE_CID \ - {0x7c179fb7, 0x67a0, 0x43a3, {0x93, 0x37, 0x29, 0x4e, 0x03, 0x60, 0xb8, 0x58}} -#define NS_VOLUMESERVICE_CONTRACTID "@mozilla.org/telephony/volume-service;1" -%} diff --git a/dom/system/gonk/nsIVolumeStat.idl b/dom/system/gonk/nsIVolumeStat.idl deleted file mode 100644 index 1d725689d..000000000 --- a/dom/system/gonk/nsIVolumeStat.idl +++ /dev/null @@ -1,12 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -[scriptable, uuid(b4c050d0-c57a-11e1-9b21-0800200c9a66)] -interface nsIVolumeStat : nsISupports -{ - readonly attribute long long totalBytes; - readonly attribute long long freeBytes; -}; diff --git a/dom/system/gonk/nsIWorkerHolder.idl b/dom/system/gonk/nsIWorkerHolder.idl deleted file mode 100644 index e5cc82c9e..000000000 --- a/dom/system/gonk/nsIWorkerHolder.idl +++ /dev/null @@ -1,11 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -[scriptable, uuid(c04f3102-1ce8-4d57-9c27-8aece9c2740a)] -interface nsIWorkerHolder : nsISupports -{ - readonly attribute jsval worker; -}; diff --git a/dom/system/gonk/nsVolume.cpp b/dom/system/gonk/nsVolume.cpp deleted file mode 100644 index 77a1628e4..000000000 --- a/dom/system/gonk/nsVolume.cpp +++ /dev/null @@ -1,467 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsVolume.h" - -#include "base/message_loop.h" -#include "base/task.h" -#include "nsIPowerManagerService.h" -#include "nsISupportsUtils.h" -#include "nsIVolume.h" -#include "nsServiceManagerUtils.h" -#include "nsThreadUtils.h" -#include "nsVolumeStat.h" -#include "nsXULAppAPI.h" -#include "Volume.h" -#include "AutoMounter.h" -#include "VolumeManager.h" - -#undef VOLUME_MANAGER_LOG_TAG -#define VOLUME_MANAGER_LOG_TAG "nsVolume" -#include "VolumeManagerLog.h" - -namespace mozilla { -namespace system { - -const char * -NS_VolumeStateStr(int32_t aState) -{ - switch (aState) { - case nsIVolume::STATE_INIT: return "Init"; - case nsIVolume::STATE_NOMEDIA: return "NoMedia"; - case nsIVolume::STATE_IDLE: return "Idle"; - case nsIVolume::STATE_PENDING: return "Pending"; - case nsIVolume::STATE_CHECKING: return "Checking"; - case nsIVolume::STATE_MOUNTED: return "Mounted"; - case nsIVolume::STATE_UNMOUNTING: return "Unmounting"; - case nsIVolume::STATE_FORMATTING: return "Formatting"; - case nsIVolume::STATE_SHARED: return "Shared"; - case nsIVolume::STATE_SHAREDMNT: return "Shared-Mounted"; - case nsIVolume::STATE_CHECKMNT: return "Check-Mounted"; - case nsIVolume::STATE_MOUNT_FAIL: return "Mount-Fail"; - } - return "???"; -} - -// While nsVolumes can only be used on the main thread, in the -// UpdateVolumeRunnable constructor (which is called from IOThread) we -// allocate an nsVolume which is then passed to MainThread. Since we -// have a situation where we allocate on one thread and free on another -// we use a thread safe AddRef implementation. -NS_IMPL_ISUPPORTS(nsVolume, nsIVolume) - -nsVolume::nsVolume(const Volume* aVolume) - : mName(NS_ConvertUTF8toUTF16(aVolume->Name())), - mMountPoint(NS_ConvertUTF8toUTF16(aVolume->MountPoint())), - mState(aVolume->State()), - mMountGeneration(aVolume->MountGeneration()), - mMountLocked(aVolume->IsMountLocked()), - mIsFake(!aVolume->CanBeShared()), - mIsMediaPresent(aVolume->MediaPresent()), - mIsSharing(aVolume->IsSharing()), - mIsFormatting(aVolume->IsFormatting()), - mIsUnmounting(aVolume->IsUnmounting()), - mIsRemovable(aVolume->IsRemovable()), - mIsHotSwappable(aVolume->IsHotSwappable()) -{ -} - -nsVolume::nsVolume(const nsVolume* aVolume) - : mName(aVolume->mName), - mMountPoint(aVolume->mMountPoint), - mState(aVolume->mState), - mMountGeneration(aVolume->mMountGeneration), - mMountLocked(aVolume->mMountLocked), - mIsFake(aVolume->mIsFake), - mIsMediaPresent(aVolume->mIsMediaPresent), - mIsSharing(aVolume->mIsSharing), - mIsFormatting(aVolume->mIsFormatting), - mIsUnmounting(aVolume->mIsUnmounting), - mIsRemovable(aVolume->mIsRemovable), - mIsHotSwappable(aVolume->mIsHotSwappable) -{ -} - -void nsVolume::Dump(const char* aLabel) const -{ - LOG("%s: Volume: %s is %s and %s @ %s gen %d locked %d", - aLabel, - NameStr().get(), - StateStr(), - IsMediaPresent() ? "inserted" : "missing", - MountPointStr().get(), - MountGeneration(), - (int)IsMountLocked()); - LOG("%s: IsSharing %s IsFormating %s IsUnmounting %s", - aLabel, - (IsSharing() ? "y" : "n"), - (IsFormatting() ? "y" : "n"), - (IsUnmounting() ? "y" : "n")); -} - -bool nsVolume::Equals(nsIVolume* aVolume) -{ - nsString volName; - aVolume->GetName(volName); - if (!mName.Equals(volName)) { - return false; - } - - nsString volMountPoint; - aVolume->GetMountPoint(volMountPoint); - if (!mMountPoint.Equals(volMountPoint)) { - return false; - } - - int32_t volState; - aVolume->GetState(&volState); - if (mState != volState){ - return false; - } - - int32_t volMountGeneration; - aVolume->GetMountGeneration(&volMountGeneration); - if (mMountGeneration != volMountGeneration) { - return false; - } - - bool volIsMountLocked; - aVolume->GetIsMountLocked(&volIsMountLocked); - if (mMountLocked != volIsMountLocked) { - return false; - } - - bool isFake; - aVolume->GetIsFake(&isFake); - if (mIsFake != isFake) { - return false; - } - - bool isSharing; - aVolume->GetIsSharing(&isSharing); - if (mIsSharing != isSharing) { - return false; - } - - bool isFormatting; - aVolume->GetIsFormatting(&isFormatting); - if (mIsFormatting != isFormatting) { - return false; - } - - bool isUnmounting; - aVolume->GetIsUnmounting(&isUnmounting); - if (mIsUnmounting != isUnmounting) { - return false; - } - - bool isRemovable; - aVolume->GetIsRemovable(&isRemovable); - if (mIsRemovable != isRemovable) { - return false; - } - - bool isHotSwappable; - aVolume->GetIsHotSwappable(&isHotSwappable); - if (mIsHotSwappable != isHotSwappable) { - return false; - } - - return true; -} - -NS_IMETHODIMP nsVolume::GetIsMediaPresent(bool* aIsMediaPresent) -{ - *aIsMediaPresent = mIsMediaPresent; - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetIsMountLocked(bool* aIsMountLocked) -{ - *aIsMountLocked = mMountLocked; - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetIsSharing(bool* aIsSharing) -{ - *aIsSharing = mIsSharing; - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetIsFormatting(bool* aIsFormatting) -{ - *aIsFormatting = mIsFormatting; - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetIsUnmounting(bool* aIsUnmounting) -{ - *aIsUnmounting = mIsUnmounting; - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetName(nsAString& aName) -{ - aName = mName; - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetMountGeneration(int32_t* aMountGeneration) -{ - *aMountGeneration = mMountGeneration; - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetMountLockName(nsAString& aMountLockName) -{ - aMountLockName = NS_LITERAL_STRING("volume-") + Name(); - aMountLockName.AppendPrintf("-%d", mMountGeneration); - - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetMountPoint(nsAString& aMountPoint) -{ - aMountPoint = mMountPoint; - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetState(int32_t* aState) -{ - *aState = mState; - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetStats(nsIVolumeStat **aResult) -{ - if (mState != STATE_MOUNTED) { - return NS_ERROR_NOT_AVAILABLE; - } - - NS_IF_ADDREF(*aResult = new nsVolumeStat(mMountPoint)); - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetIsFake(bool *aIsFake) -{ - *aIsFake = mIsFake; - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetIsRemovable(bool *aIsRemovable) -{ - *aIsRemovable = mIsRemovable; - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetIsHotSwappable(bool *aIsHotSwappable) -{ - *aIsHotSwappable = mIsHotSwappable; - return NS_OK; -} - -NS_IMETHODIMP nsVolume::Format() -{ - MOZ_ASSERT(XRE_IsParentProcess()); - - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(FormatVolumeIOThread, NameStr())); - - return NS_OK; -} - -/* static */ -void nsVolume::FormatVolumeIOThread(const nsCString& aVolume) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - if (VolumeManager::State() != VolumeManager::VOLUMES_READY) { - return; - } - - AutoMounterFormatVolume(aVolume); -} - -NS_IMETHODIMP nsVolume::Mount() -{ - MOZ_ASSERT(XRE_IsParentProcess()); - - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(MountVolumeIOThread, NameStr())); - - return NS_OK; -} - -/* static */ -void nsVolume::MountVolumeIOThread(const nsCString& aVolume) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - if (VolumeManager::State() != VolumeManager::VOLUMES_READY) { - return; - } - - AutoMounterMountVolume(aVolume); -} - -NS_IMETHODIMP nsVolume::Unmount() -{ - MOZ_ASSERT(XRE_IsParentProcess()); - - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(UnmountVolumeIOThread, NameStr())); - - return NS_OK; -} - -/* static */ -void nsVolume::UnmountVolumeIOThread(const nsCString& aVolume) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - if (VolumeManager::State() != VolumeManager::VOLUMES_READY) { - return; - } - - AutoMounterUnmountVolume(aVolume); -} - -void -nsVolume::LogState() const -{ - if (mState == nsIVolume::STATE_MOUNTED) { - LOG("nsVolume: %s state %s @ '%s' gen %d locked %d fake %d " - "media %d sharing %d formatting %d unmounting %d removable %d hotswappable %d", - NameStr().get(), StateStr(), MountPointStr().get(), - MountGeneration(), (int)IsMountLocked(), (int)IsFake(), - (int)IsMediaPresent(), (int)IsSharing(), - (int)IsFormatting(), (int)IsUnmounting(), - (int)IsRemovable(), (int)IsHotSwappable()); - return; - } - - LOG("nsVolume: %s state %s", NameStr().get(), StateStr()); -} - -void nsVolume::UpdateMountLock(nsVolume* aOldVolume) -{ - MOZ_ASSERT(NS_IsMainThread()); - - bool oldMountLocked = aOldVolume ? aOldVolume->mMountLocked : false; - if (mState != nsIVolume::STATE_MOUNTED) { - // Since we're not in the mounted state, we need to - // forgot whatever mount generation we may have had. - mMountGeneration = -1; - mMountLocked = oldMountLocked; - return; - } - - int32_t oldMountGeneration = aOldVolume ? aOldVolume->mMountGeneration : -1; - if (mMountGeneration == oldMountGeneration) { - // No change in mount generation, nothing else to do - mMountLocked = oldMountLocked; - return; - } - - if (!XRE_IsParentProcess()) { - // Child processes just track the state, not maintain it. - return; - } - - // Notify the Volume on IOThread whether the volume is locked or not. - nsCOMPtr<nsIPowerManagerService> pmService = - do_GetService(POWERMANAGERSERVICE_CONTRACTID); - if (!pmService) { - return; - } - nsString mountLockName; - GetMountLockName(mountLockName); - nsString mountLockState; - pmService->GetWakeLockState(mountLockName, mountLockState); - UpdateMountLock(mountLockState); -} - -void -nsVolume::UpdateMountLock(const nsAString& aMountLockState) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(NS_IsMainThread()); - - // There are 3 states, unlocked, locked-background, and locked-foreground - // I figured it was easier to use negtive logic and compare for unlocked. - UpdateMountLock(!aMountLockState.EqualsLiteral("unlocked")); -} - -void -nsVolume::UpdateMountLock(bool aMountLocked) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(NS_IsMainThread()); - - if (aMountLocked == mMountLocked) { - return; - } - // The locked/unlocked state changed. Tell IOThread about it. - mMountLocked = aMountLocked; - LogState(); - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(Volume::UpdateMountLock, - NS_LossyConvertUTF16toASCII(Name()), - MountGeneration(), aMountLocked)); -} - -void -nsVolume::SetIsFake(bool aIsFake) -{ - mIsFake = aIsFake; - if (mIsFake) { - // The media is always present for fake volumes. - mIsMediaPresent = true; - MOZ_ASSERT(!mIsSharing); - } -} - -void -nsVolume::SetIsRemovable(bool aIsRemovable) -{ - mIsRemovable = aIsRemovable; - if (!mIsRemovable) { - mIsHotSwappable = false; - } -} - -void -nsVolume::SetIsHotSwappable(bool aIsHotSwappable) -{ - mIsHotSwappable = aIsHotSwappable; - if (mIsHotSwappable) { - mIsRemovable = true; - } -} - -void -nsVolume::SetState(int32_t aState) -{ - static int32_t sMountGeneration = 0; - - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(IsFake()); - - if (aState == mState) { - return; - } - - if (aState == nsIVolume::STATE_MOUNTED) { - mMountGeneration = ++sMountGeneration; - } - - mState = aState; -} - -} // system -} // mozilla diff --git a/dom/system/gonk/nsVolume.h b/dom/system/gonk/nsVolume.h deleted file mode 100644 index 88be425f6..000000000 --- a/dom/system/gonk/nsVolume.h +++ /dev/null @@ -1,114 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_nsvolume_h__ -#define mozilla_system_nsvolume_h__ - -#include "nsCOMPtr.h" -#include "nsIVolume.h" -#include "nsString.h" -#include "nsTArray.h" - -namespace mozilla { -namespace system { - -class Volume; - -class nsVolume : public nsIVolume -{ -public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIVOLUME - - // This constructor is used by the UpdateVolumeRunnable constructor - nsVolume(const Volume* aVolume); - - // This constructor is used by nsVolumeService::SetFakeVolumeState - nsVolume(const nsVolume* aVolume); - - // This constructor is used by ContentChild::RecvFileSystemUpdate which is - // used to update the volume cache maintained in the child process. - nsVolume(const nsAString& aName, const nsAString& aMountPoint, - const int32_t& aState, const int32_t& aMountGeneration, - const bool& aIsMediaPresent, const bool& aIsSharing, - const bool& aIsFormatting, const bool& aIsFake, - const bool& aIsUnmounting, const bool& aIsRemovable, - const bool& aIsHotSwappable) - : mName(aName), - mMountPoint(aMountPoint), - mState(aState), - mMountGeneration(aMountGeneration), - mMountLocked(false), - mIsFake(aIsFake), - mIsMediaPresent(aIsMediaPresent), - mIsSharing(aIsSharing), - mIsFormatting(aIsFormatting), - mIsUnmounting(aIsUnmounting), - mIsRemovable(aIsRemovable), - mIsHotSwappable(aIsHotSwappable) - { - } - - bool Equals(nsIVolume* aVolume); - void UpdateMountLock(nsVolume* aOldVolume); - - void LogState() const; - - const nsString& Name() const { return mName; } - nsCString NameStr() const { return NS_LossyConvertUTF16toASCII(mName); } - - void Dump(const char* aLabel) const; - - int32_t MountGeneration() const { return mMountGeneration; } - bool IsMountLocked() const { return mMountLocked; } - - const nsString& MountPoint() const { return mMountPoint; } - nsCString MountPointStr() const { return NS_LossyConvertUTF16toASCII(mMountPoint); } - - int32_t State() const { return mState; } - const char* StateStr() const { return NS_VolumeStateStr(mState); } - - bool IsFake() const { return mIsFake; } - bool IsMediaPresent() const { return mIsMediaPresent; } - bool IsSharing() const { return mIsSharing; } - bool IsFormatting() const { return mIsFormatting; } - bool IsUnmounting() const { return mIsUnmounting; } - bool IsRemovable() const { return mIsRemovable; } - bool IsHotSwappable() const { return mIsHotSwappable; } - - typedef nsTArray<RefPtr<nsVolume> > Array; - -private: - virtual ~nsVolume() {} // MozExternalRefCountType complains if this is non-virtual - - friend class nsVolumeService; // Calls the following XxxMountLock functions - void UpdateMountLock(const nsAString& aMountLockState); - void UpdateMountLock(bool aMountLocked); - - void SetIsFake(bool aIsFake); - void SetIsRemovable(bool aIsRemovable); - void SetIsHotSwappable(bool aIsHotSwappble); - void SetState(int32_t aState); - static void FormatVolumeIOThread(const nsCString& aVolume); - static void MountVolumeIOThread(const nsCString& aVolume); - static void UnmountVolumeIOThread(const nsCString& aVolume); - - nsString mName; - nsString mMountPoint; - int32_t mState; - int32_t mMountGeneration; - bool mMountLocked; - bool mIsFake; - bool mIsMediaPresent; - bool mIsSharing; - bool mIsFormatting; - bool mIsUnmounting; - bool mIsRemovable; - bool mIsHotSwappable; -}; - -} // system -} // mozilla - -#endif // mozilla_system_nsvolume_h__ diff --git a/dom/system/gonk/nsVolumeMountLock.cpp b/dom/system/gonk/nsVolumeMountLock.cpp deleted file mode 100644 index 288c0f689..000000000 --- a/dom/system/gonk/nsVolumeMountLock.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsVolumeMountLock.h" - -#include "mozilla/dom/ContentChild.h" -#include "mozilla/Services.h" - -#include "nsIObserverService.h" -#include "nsIPowerManagerService.h" -#include "nsIVolume.h" -#include "nsIVolumeService.h" -#include "nsString.h" -#include "nsXULAppAPI.h" - -#undef VOLUME_MANAGER_LOG_TAG -#define VOLUME_MANAGER_LOG_TAG "nsVolumeMountLock" -#include "VolumeManagerLog.h" -#include "nsServiceManagerUtils.h" -#include "mozilla/dom/power/PowerManagerService.h" - -using namespace mozilla::dom; -using namespace mozilla::services; - -namespace mozilla { -namespace system { - -NS_IMPL_ISUPPORTS(nsVolumeMountLock, nsIVolumeMountLock, - nsIObserver, nsISupportsWeakReference) - -// static -already_AddRefed<nsVolumeMountLock> -nsVolumeMountLock::Create(const nsAString& aVolumeName) -{ - DBG("nsVolumeMountLock::Create called"); - - RefPtr<nsVolumeMountLock> mountLock = new nsVolumeMountLock(aVolumeName); - nsresult rv = mountLock->Init(); - NS_ENSURE_SUCCESS(rv, nullptr); - - return mountLock.forget(); -} - -nsVolumeMountLock::nsVolumeMountLock(const nsAString& aVolumeName) - : mVolumeName(aVolumeName), - mVolumeGeneration(-1), - mUnlocked(false) -{ -} - -//virtual -nsVolumeMountLock::~nsVolumeMountLock() -{ - Unlock(); -} - -nsresult nsVolumeMountLock::Init() -{ - LOG("nsVolumeMountLock created for '%s'", - NS_LossyConvertUTF16toASCII(mVolumeName).get()); - - // Add ourselves as an Observer. It's important that we use a weak - // reference here. If we used a strong reference, then that reference - // would prevent this object from being destructed. - nsCOMPtr<nsIObserverService> obs = GetObserverService(); - obs->AddObserver(this, NS_VOLUME_STATE_CHANGED, true /*weak*/); - - // Get the initial mountGeneration and grab a lock. - nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID); - NS_ENSURE_TRUE(vs, NS_ERROR_FAILURE); - - nsCOMPtr<nsIVolume> vol; - nsresult rv = vs->GetVolumeByName(mVolumeName, getter_AddRefs(vol)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - rv = vol->GetMountGeneration(&mVolumeGeneration); - NS_ENSURE_SUCCESS(rv, rv); - - return Lock(vol); -} - -NS_IMETHODIMP nsVolumeMountLock::Unlock() -{ - LOG("nsVolumeMountLock released for '%s'", - NS_LossyConvertUTF16toASCII(mVolumeName).get()); - - mUnlocked = true; - mWakeLock = nullptr; - - // While we don't really need to remove weak observers, we do so anyways - // since it will reduce the number of times Observe gets called. - nsCOMPtr<nsIObserverService> obs = GetObserverService(); - obs->RemoveObserver(this, NS_VOLUME_STATE_CHANGED); - return NS_OK; -} - -NS_IMETHODIMP nsVolumeMountLock::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) -{ - if (strcmp(aTopic, NS_VOLUME_STATE_CHANGED) != 0) { - return NS_OK; - } - if (mUnlocked) { - // We're not locked anymore, so we don't need to look at the notifications. - return NS_OK; - } - - nsCOMPtr<nsIVolume> vol = do_QueryInterface(aSubject); - if (!vol) { - return NS_OK; - } - nsString volName; - vol->GetName(volName); - if (!volName.Equals(mVolumeName)) { - return NS_OK; - } - int32_t state; - nsresult rv = vol->GetState(&state); - NS_ENSURE_SUCCESS(rv, rv); - - if (state != nsIVolume::STATE_MOUNTED) { - mWakeLock = nullptr; - mVolumeGeneration = -1; - return NS_OK; - } - - int32_t mountGeneration; - rv = vol->GetMountGeneration(&mountGeneration); - NS_ENSURE_SUCCESS(rv, rv); - - DBG("nsVolumeMountLock::Observe mountGeneration = %d mVolumeGeneration = %d", - mountGeneration, mVolumeGeneration); - - if (mVolumeGeneration == mountGeneration) { - return NS_OK; - } - - // The generation changed, which means that any wakelock we may have - // been holding is now invalid. Grab a new wakelock for the new generation - // number. - - mWakeLock = nullptr; - mVolumeGeneration = mountGeneration; - - return Lock(vol); -} - -nsresult -nsVolumeMountLock::Lock(nsIVolume* aVolume) -{ - RefPtr<power::PowerManagerService> pmService = - power::PowerManagerService::GetInstance(); - NS_ENSURE_TRUE(pmService, NS_ERROR_FAILURE); - - nsString mountLockName; - aVolume->GetMountLockName(mountLockName); - - ErrorResult err; - mWakeLock = pmService->NewWakeLock(mountLockName, nullptr, err); - if (err.Failed()) { - return err.StealNSResult(); - } - - LOG("nsVolumeMountLock acquired for '%s' gen %d", - NS_LossyConvertUTF16toASCII(mVolumeName).get(), mVolumeGeneration); - return NS_OK; -} - -} // namespace system -} // namespace mozilla diff --git a/dom/system/gonk/nsVolumeMountLock.h b/dom/system/gonk/nsVolumeMountLock.h deleted file mode 100644 index caf5b2ad5..000000000 --- a/dom/system/gonk/nsVolumeMountLock.h +++ /dev/null @@ -1,56 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_nsvolumemountlock_h__ -#define mozilla_system_nsvolumemountlock_h__ - -#include "nsIVolumeMountLock.h" - -#include "mozilla/dom/WakeLock.h" -#include "nsIObserver.h" -#include "nsString.h" -#include "nsTArray.h" -#include "nsWeakReference.h" - -class nsIVolume; - -namespace mozilla { -namespace system { - -/* The VolumeMountLock is designed so that it can be used in the Child or - * Parent process. While the VolumeMountLock object exists, then the - * VolumeManager/AutoMounter will prevent a mounted volume from being - * shared with the PC. - */ - -class nsVolumeMountLock final : public nsIVolumeMountLock, - public nsIObserver, - public nsSupportsWeakReference -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER - NS_DECL_NSIVOLUMEMOUNTLOCK - - static already_AddRefed<nsVolumeMountLock> Create(const nsAString& volumeName); - - const nsString& VolumeName() const { return mVolumeName; } - -private: - nsVolumeMountLock(const nsAString& aVolumeName); - ~nsVolumeMountLock(); - - nsresult Init(); - nsresult Lock(nsIVolume* aVolume); - - RefPtr<dom::WakeLock> mWakeLock; - nsString mVolumeName; - int32_t mVolumeGeneration; - bool mUnlocked; -}; - -} // namespace system -} // namespace mozilla - -#endif // mozilla_system_nsvolumemountlock_h__ diff --git a/dom/system/gonk/nsVolumeService.cpp b/dom/system/gonk/nsVolumeService.cpp deleted file mode 100644 index 48d95c26a..000000000 --- a/dom/system/gonk/nsVolumeService.cpp +++ /dev/null @@ -1,553 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsVolumeService.h" - -#include "Volume.h" -#include "VolumeManager.h" -#include "VolumeServiceIOThread.h" - -#include "nsCOMPtr.h" -#include "nsDependentSubstring.h" -#include "nsIDOMWakeLockListener.h" -#include "nsIMutableArray.h" -#include "nsIObserver.h" -#include "nsIObserverService.h" -#include "nsIPowerManagerService.h" -#include "nsISupportsPrimitives.h" -#include "nsISupportsUtils.h" -#include "nsIVolume.h" -#include "nsIVolumeService.h" -#include "nsLocalFile.h" -#include "nsServiceManagerUtils.h" -#include "nsString.h" -#include "nsTArray.h" -#include "nsThreadUtils.h" -#include "nsVolumeMountLock.h" -#include "nsXULAppAPI.h" -#include "mozilla/dom/ContentChild.h" -#include "mozilla/Services.h" -#include "base/task.h" - -#undef VOLUME_MANAGER_LOG_TAG -#define VOLUME_MANAGER_LOG_TAG "nsVolumeService" -#include "VolumeManagerLog.h" - -#include <stdlib.h> - -using namespace mozilla::dom; -using namespace mozilla::services; - -namespace mozilla { -namespace system { - -NS_IMPL_ISUPPORTS(nsVolumeService, - nsIVolumeService, - nsIDOMMozWakeLockListener) - -StaticRefPtr<nsVolumeService> nsVolumeService::sSingleton; - -// static -already_AddRefed<nsVolumeService> -nsVolumeService::GetSingleton() -{ - MOZ_ASSERT(NS_IsMainThread()); - - if (!sSingleton) { - sSingleton = new nsVolumeService(); - } - RefPtr<nsVolumeService> volumeService = sSingleton.get(); - return volumeService.forget(); -} - -// static -void -nsVolumeService::Shutdown() -{ - if (!sSingleton) { - return; - } - if (!XRE_IsParentProcess()) { - sSingleton = nullptr; - return; - } - - nsCOMPtr<nsIPowerManagerService> pmService = - do_GetService(POWERMANAGERSERVICE_CONTRACTID); - if (pmService) { - pmService->RemoveWakeLockListener(sSingleton.get()); - } - - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(ShutdownVolumeServiceIOThread)); - - sSingleton = nullptr; -} - -nsVolumeService::nsVolumeService() - : mArrayMonitor("nsVolumeServiceArray"), - mGotVolumesFromParent(false) -{ - sSingleton = this; - - if (!XRE_IsParentProcess()) { - // VolumeServiceIOThread and the WakeLock listener should only run in the - // parent, so we return early. - return; - } - - // Startup the IOThread side of things. The actual volume changes - // are captured by the IOThread and forwarded to main thread. - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(InitVolumeServiceIOThread, this)); - - nsCOMPtr<nsIPowerManagerService> pmService = - do_GetService(POWERMANAGERSERVICE_CONTRACTID); - if (!pmService) { - return; - } - pmService->AddWakeLockListener(this); -} - -nsVolumeService::~nsVolumeService() -{ -} - -// Callback for nsIDOMMozWakeLockListener -NS_IMETHODIMP -nsVolumeService::Callback(const nsAString& aTopic, const nsAString& aState) -{ - CheckMountLock(aTopic, aState); - return NS_OK; -} - -void nsVolumeService::DumpNoLock(const char* aLabel) -{ - mArrayMonitor.AssertCurrentThreadOwns(); - - nsVolume::Array::size_type numVolumes = mVolumeArray.Length(); - - if (numVolumes == 0) { - LOG("%s: No Volumes!", aLabel); - return; - } - nsVolume::Array::index_type volIndex; - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr<nsVolume> vol = mVolumeArray[volIndex]; - vol->Dump(aLabel); - } -} - -NS_IMETHODIMP -nsVolumeService::Dump(const nsAString& aLabel) -{ - MonitorAutoLock autoLock(mArrayMonitor); - DumpNoLock(NS_LossyConvertUTF16toASCII(aLabel).get()); - return NS_OK; -} - -NS_IMETHODIMP nsVolumeService::GetVolumeByName(const nsAString& aVolName, nsIVolume **aResult) -{ - MonitorAutoLock autoLock(mArrayMonitor); - - RefPtr<nsVolume> vol = FindVolumeByName(aVolName); - if (!vol) { - return NS_ERROR_NOT_AVAILABLE; - } - - vol.forget(aResult); - return NS_OK; -} - -NS_IMETHODIMP -nsVolumeService::GetVolumeByPath(const nsAString& aPath, nsIVolume **aResult) -{ - NS_ConvertUTF16toUTF8 utf8Path(aPath); - char realPathBuf[PATH_MAX]; - - while (realpath(utf8Path.get(), realPathBuf) < 0) { - if (errno != ENOENT) { - ERR("GetVolumeByPath: realpath on '%s' failed: %d", utf8Path.get(), errno); - return NSRESULT_FOR_ERRNO(); - } - // The pathname we were passed doesn't exist, so we try stripping off trailing - // components until we get a successful call to realpath, or until we run out - // of components (if we finally get to /something then we also stop). - int32_t slashIndex = utf8Path.RFindChar('/'); - if ((slashIndex == kNotFound) || (slashIndex == 0)) { - errno = ENOENT; - ERR("GetVolumeByPath: realpath on '%s' failed.", utf8Path.get()); - return NSRESULT_FOR_ERRNO(); - } - utf8Path.Assign(Substring(utf8Path, 0, slashIndex)); - } - - // The volume mount point is always a directory. Something like /mnt/sdcard - // Once we have a full qualified pathname with symlinks removed (which is - // what realpath does), we basically check if aPath starts with the mount - // point, but we don't want to have /mnt/sdcard match /mnt/sdcardfoo but we - // do want it to match /mnt/sdcard/foo - // So we add a trailing slash to the mount point and the pathname passed in - // prior to doing the comparison. - - strlcat(realPathBuf, "/", sizeof(realPathBuf)); - - MonitorAutoLock autoLock(mArrayMonitor); - - nsVolume::Array::size_type numVolumes = mVolumeArray.Length(); - nsVolume::Array::index_type volIndex; - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr<nsVolume> vol = mVolumeArray[volIndex]; - NS_ConvertUTF16toUTF8 volMountPointSlash(vol->MountPoint()); - volMountPointSlash.Append('/'); - nsDependentCSubstring testStr(realPathBuf, volMountPointSlash.Length()); - if (volMountPointSlash.Equals(testStr)) { - vol.forget(aResult); - return NS_OK; - } - } - return NS_ERROR_FILE_NOT_FOUND; -} - -NS_IMETHODIMP -nsVolumeService::CreateOrGetVolumeByPath(const nsAString& aPath, nsIVolume** aResult) -{ - nsresult rv = GetVolumeByPath(aPath, aResult); - if (rv == NS_OK) { - return NS_OK; - } - - // In order to support queries by the updater, we will fabricate a volume - // from the pathname, so that the caller can determine the volume size. - nsCOMPtr<nsIVolume> vol = new nsVolume(NS_LITERAL_STRING("fake"), - aPath, nsIVolume::STATE_MOUNTED, - -1 /* generation */, - true /* isMediaPresent*/, - false /* isSharing */, - false /* isFormatting */, - true /* isFake */, - false /* isUnmounting */, - false /* isRemovable */, - false /* isHotSwappable*/); - vol.forget(aResult); - return NS_OK; -} - -NS_IMETHODIMP -nsVolumeService::GetVolumeNames(nsIArray** aVolNames) -{ - NS_ENSURE_ARG_POINTER(aVolNames); - MonitorAutoLock autoLock(mArrayMonitor); - - *aVolNames = nullptr; - - nsresult rv; - nsCOMPtr<nsIMutableArray> volNames = - do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - nsVolume::Array::size_type numVolumes = mVolumeArray.Length(); - nsVolume::Array::index_type volIndex; - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr<nsVolume> vol = mVolumeArray[volIndex]; - nsCOMPtr<nsISupportsString> isupportsString = - do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - rv = isupportsString->SetData(vol->Name()); - NS_ENSURE_SUCCESS(rv, rv); - - rv = volNames->AppendElement(isupportsString, false); - NS_ENSURE_SUCCESS(rv, rv); - } - - volNames.forget(aVolNames); - return NS_OK; -} - -void -nsVolumeService::GetVolumesForIPC(nsTArray<VolumeInfo>* aResult) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(NS_IsMainThread()); - - MonitorAutoLock autoLock(mArrayMonitor); - - nsVolume::Array::size_type numVolumes = mVolumeArray.Length(); - nsVolume::Array::index_type volIndex; - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr<nsVolume> vol = mVolumeArray[volIndex]; - VolumeInfo* volInfo = aResult->AppendElement(); - - volInfo->name() = vol->mName; - volInfo->mountPoint() = vol->mMountPoint; - volInfo->volState() = vol->mState; - volInfo->mountGeneration() = vol->mMountGeneration; - volInfo->isMediaPresent() = vol->mIsMediaPresent; - volInfo->isSharing() = vol->mIsSharing; - volInfo->isFormatting() = vol->mIsFormatting; - volInfo->isFake() = vol->mIsFake; - volInfo->isUnmounting() = vol->mIsUnmounting; - volInfo->isRemovable() = vol->mIsRemovable; - volInfo->isHotSwappable() = vol->mIsHotSwappable; - } -} - -void -nsVolumeService::RecvVolumesFromParent(const nsTArray<VolumeInfo>& aVolumes) -{ - if (XRE_IsParentProcess()) { - // We are the parent. Therefore our volumes are already correct. - return; - } - if (mGotVolumesFromParent) { - // We've already done this, no need to do it again. - return; - } - - for (uint32_t i = 0; i < aVolumes.Length(); i++) { - const VolumeInfo& volInfo(aVolumes[i]); - RefPtr<nsVolume> vol = new nsVolume(volInfo.name(), - volInfo.mountPoint(), - volInfo.volState(), - volInfo.mountGeneration(), - volInfo.isMediaPresent(), - volInfo.isSharing(), - volInfo.isFormatting(), - volInfo.isFake(), - volInfo.isUnmounting(), - volInfo.isRemovable(), - volInfo.isHotSwappable()); - UpdateVolume(vol, false); - } -} - -NS_IMETHODIMP -nsVolumeService::CreateMountLock(const nsAString& aVolumeName, nsIVolumeMountLock **aResult) -{ - nsCOMPtr<nsIVolumeMountLock> mountLock = nsVolumeMountLock::Create(aVolumeName); - if (!mountLock) { - return NS_ERROR_NOT_AVAILABLE; - } - mountLock.forget(aResult); - return NS_OK; -} - -void -nsVolumeService::CheckMountLock(const nsAString& aMountLockName, - const nsAString& aMountLockState) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(NS_IsMainThread()); - - RefPtr<nsVolume> vol = FindVolumeByMountLockName(aMountLockName); - if (vol) { - vol->UpdateMountLock(aMountLockState); - } -} - -already_AddRefed<nsVolume> -nsVolumeService::FindVolumeByMountLockName(const nsAString& aMountLockName) -{ - MonitorAutoLock autoLock(mArrayMonitor); - - nsVolume::Array::size_type numVolumes = mVolumeArray.Length(); - nsVolume::Array::index_type volIndex; - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr<nsVolume> vol = mVolumeArray[volIndex]; - nsString mountLockName; - vol->GetMountLockName(mountLockName); - if (mountLockName.Equals(aMountLockName)) { - return vol.forget(); - } - } - return nullptr; -} - -already_AddRefed<nsVolume> -nsVolumeService::FindVolumeByName(const nsAString& aName, nsVolume::Array::index_type* aIndex) -{ - mArrayMonitor.AssertCurrentThreadOwns(); - - nsVolume::Array::size_type numVolumes = mVolumeArray.Length(); - nsVolume::Array::index_type volIndex; - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr<nsVolume> vol = mVolumeArray[volIndex]; - if (vol->Name().Equals(aName)) { - if (aIndex) { - *aIndex = volIndex; - } - return vol.forget(); - } - } - return nullptr; -} - -void -nsVolumeService::UpdateVolume(nsVolume* aVolume, bool aNotifyObservers) -{ - MOZ_ASSERT(NS_IsMainThread()); - - { - MonitorAutoLock autoLock(mArrayMonitor); - nsVolume::Array::index_type volIndex; - RefPtr<nsVolume> vol = FindVolumeByName(aVolume->Name(), &volIndex); - if (!vol) { - mVolumeArray.AppendElement(aVolume); - } else if (vol->Equals(aVolume) || (!vol->IsFake() && aVolume->IsFake())) { - // Ignore if nothing changed or if a fake tries to override a real volume. - return; - } else { - mVolumeArray.ReplaceElementAt(volIndex, aVolume); - } - aVolume->UpdateMountLock(vol); - } - - if (!aNotifyObservers) { - return; - } - - nsCOMPtr<nsIObserverService> obs = GetObserverService(); - if (!obs) { - return; - } - NS_ConvertUTF8toUTF16 stateStr(aVolume->StateStr()); - obs->NotifyObservers(aVolume, NS_VOLUME_STATE_CHANGED, stateStr.get()); -} - -NS_IMETHODIMP -nsVolumeService::CreateFakeVolume(const nsAString& name, const nsAString& path) -{ - if (XRE_IsParentProcess()) { - RefPtr<nsVolume> vol = new nsVolume(name, path, nsIVolume::STATE_INIT, - -1 /* mountGeneration */, - true /* isMediaPresent */, - false /* isSharing */, - false /* isFormatting */, - true /* isFake */, - false /* isUnmounting */, - false /* isRemovable */, - false /* isHotSwappable */); - vol->SetState(nsIVolume::STATE_MOUNTED); - vol->LogState(); - UpdateVolume(vol.get()); - return NS_OK; - } - - ContentChild::GetSingleton()->SendCreateFakeVolume(nsString(name), nsString(path)); - return NS_OK; -} - -NS_IMETHODIMP -nsVolumeService::SetFakeVolumeState(const nsAString& name, int32_t state) -{ - if (XRE_IsParentProcess()) { - RefPtr<nsVolume> vol; - { - MonitorAutoLock autoLock(mArrayMonitor); - vol = FindVolumeByName(name); - } - if (!vol || !vol->IsFake()) { - return NS_ERROR_NOT_AVAILABLE; - } - - // Clone the existing volume so we can replace it - RefPtr<nsVolume> volume = new nsVolume(vol); - volume->SetState(state); - volume->LogState(); - UpdateVolume(volume.get()); - return NS_OK; - } - - ContentChild::GetSingleton()->SendSetFakeVolumeState(nsString(name), state); - return NS_OK; -} - -NS_IMETHODIMP -nsVolumeService::RemoveFakeVolume(const nsAString& name) -{ - if (XRE_IsParentProcess()) { - SetFakeVolumeState(name, nsIVolume::STATE_NOMEDIA); - RemoveVolumeByName(name); - return NS_OK; - } - - ContentChild::GetSingleton()->SendRemoveFakeVolume(nsString(name)); - return NS_OK; -} - -void -nsVolumeService::RemoveVolumeByName(const nsAString& aName) -{ - { - MonitorAutoLock autoLock(mArrayMonitor); - nsVolume::Array::index_type volIndex; - RefPtr<nsVolume> vol = FindVolumeByName(aName, &volIndex); - if (!vol) { - return; - } - mVolumeArray.RemoveElementAt(volIndex); - } - - if (XRE_IsParentProcess()) { - nsCOMPtr<nsIObserverService> obs = GetObserverService(); - if (!obs) { - return; - } - obs->NotifyObservers(nullptr, NS_VOLUME_REMOVED, nsString(aName).get()); - } -} - -/*************************************************************************** -* The UpdateVolumeRunnable creates an nsVolume and updates the main thread -* data structure while running on the main thread. -*/ -class UpdateVolumeRunnable : public Runnable -{ -public: - UpdateVolumeRunnable(nsVolumeService* aVolumeService, const Volume* aVolume) - : mVolumeService(aVolumeService), - mVolume(new nsVolume(aVolume)) - { - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - } - - NS_IMETHOD Run() override - { - MOZ_ASSERT(NS_IsMainThread()); - DBG("UpdateVolumeRunnable::Run '%s' state %s gen %d locked %d " - "media %d sharing %d formatting %d unmounting %d removable %d hotswappable %d", - mVolume->NameStr().get(), mVolume->StateStr(), - mVolume->MountGeneration(), (int)mVolume->IsMountLocked(), - (int)mVolume->IsMediaPresent(), mVolume->IsSharing(), - mVolume->IsFormatting(), mVolume->IsUnmounting(), - (int)mVolume->IsRemovable(), (int)mVolume->IsHotSwappable()); - - mVolumeService->UpdateVolume(mVolume); - mVolumeService = nullptr; - mVolume = nullptr; - return NS_OK; - } - -private: - RefPtr<nsVolumeService> mVolumeService; - RefPtr<nsVolume> mVolume; -}; - -void -nsVolumeService::UpdateVolumeIOThread(const Volume* aVolume) -{ - DBG("UpdateVolumeIOThread: Volume '%s' state %s mount '%s' gen %d locked %d " - "media %d sharing %d formatting %d unmounting %d removable %d hotswappable %d", - aVolume->NameStr(), aVolume->StateStr(), aVolume->MountPoint().get(), - aVolume->MountGeneration(), (int)aVolume->IsMountLocked(), - (int)aVolume->MediaPresent(), (int)aVolume->IsSharing(), - (int)aVolume->IsFormatting(), (int)aVolume->IsUnmounting(), - (int)aVolume->IsRemovable(), (int)aVolume->IsHotSwappable()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - NS_DispatchToMainThread(new UpdateVolumeRunnable(this, aVolume)); -} - -} // namespace system -} // namespace mozilla diff --git a/dom/system/gonk/nsVolumeService.h b/dom/system/gonk/nsVolumeService.h deleted file mode 100644 index 9bddc0b8f..000000000 --- a/dom/system/gonk/nsVolumeService.h +++ /dev/null @@ -1,78 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_nsvolumeservice_h__ -#define mozilla_system_nsvolumeservice_h__ - -#include "mozilla/Monitor.h" -#include "mozilla/RefPtr.h" -#include "mozilla/StaticPtr.h" -#include "nsCOMPtr.h" -#include "nsIDOMWakeLockListener.h" -#include "nsIVolume.h" -#include "nsIVolumeService.h" -#include "nsVolume.h" - -namespace mozilla { - -namespace dom { -class VolumeInfo; -} // dom - -namespace system { - -class Volume; - -/*************************************************************************** -* The nsVolumeData class encapsulates the data that is updated/maintained -* on the main thread in order to support the nsIVolume and nsIVolumeService -* classes. -*/ - -class nsVolumeService final : public nsIVolumeService, - public nsIDOMMozWakeLockListener -{ -public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIVOLUMESERVICE - NS_DECL_NSIDOMMOZWAKELOCKLISTENER - - nsVolumeService(); - - static already_AddRefed<nsVolumeService> GetSingleton(); - //static nsVolumeService* GetSingleton(); - static void Shutdown(); - - void DumpNoLock(const char* aLabel); - - // To use this function, you have to create a new volume and pass it in. - void UpdateVolume(nsVolume* aVolume, bool aNotifyObservers = true); - void UpdateVolumeIOThread(const Volume* aVolume); - - void RecvVolumesFromParent(const nsTArray<dom::VolumeInfo>& aVolumes); - void GetVolumesForIPC(nsTArray<dom::VolumeInfo>* aResult); - - void RemoveVolumeByName(const nsAString& aName); - -private: - ~nsVolumeService(); - - void CheckMountLock(const nsAString& aMountLockName, - const nsAString& aMountLockState); - already_AddRefed<nsVolume> FindVolumeByMountLockName(const nsAString& aMountLockName); - - already_AddRefed<nsVolume> FindVolumeByName(const nsAString& aName, - nsVolume::Array::index_type* aIndex = nullptr); - - Monitor mArrayMonitor; - nsVolume::Array mVolumeArray; - - static StaticRefPtr<nsVolumeService> sSingleton; - bool mGotVolumesFromParent; -}; - -} // system -} // mozilla - -#endif // mozilla_system_nsvolumeservice_h__ diff --git a/dom/system/gonk/nsVolumeStat.cpp b/dom/system/gonk/nsVolumeStat.cpp deleted file mode 100644 index 11976237f..000000000 --- a/dom/system/gonk/nsVolumeStat.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsVolumeStat.h" -#include "nsString.h" - -namespace mozilla { -namespace system { - -NS_IMPL_ISUPPORTS(nsVolumeStat, nsIVolumeStat) - -nsVolumeStat::nsVolumeStat(const nsAString& aPath) -{ - if (statfs(NS_ConvertUTF16toUTF8(aPath).get(), &mStat) != 0) { - memset(&mStat, 0, sizeof(mStat)); - } -} - -NS_IMETHODIMP nsVolumeStat::GetTotalBytes(int64_t* aTotalBytes) -{ - *aTotalBytes = mStat.f_blocks * mStat.f_bsize; - return NS_OK; -} - -NS_IMETHODIMP nsVolumeStat::GetFreeBytes(int64_t* aFreeBytes) -{ - *aFreeBytes = mStat.f_bfree * mStat.f_bsize; - return NS_OK; -} - -} // system -} // mozilla diff --git a/dom/system/gonk/nsVolumeStat.h b/dom/system/gonk/nsVolumeStat.h deleted file mode 100644 index 2ca03ed46..000000000 --- a/dom/system/gonk/nsVolumeStat.h +++ /dev/null @@ -1,33 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_nsvolumestat_h__ -#define mozilla_system_nsvolumestat_h__ - -#include "nsIVolumeStat.h" -#include "nsString.h" -#include <sys/statfs.h> - -namespace mozilla { -namespace system { - -class nsVolumeStat final : public nsIVolumeStat -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIVOLUMESTAT - - nsVolumeStat(const nsAString& aPath); - -protected: - ~nsVolumeStat() {} - -private: - struct statfs mStat; -}; - -} // system -} // mozilla - -#endif // mozilla_system_nsvolumestat_h__ diff --git a/dom/system/gonk/ril_consts.js b/dom/system/gonk/ril_consts.js deleted file mode 100644 index af5b9d8e1..000000000 --- a/dom/system/gonk/ril_consts.js +++ /dev/null @@ -1,3338 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -// Set to true to debug all RIL layers -this.DEBUG_ALL = false; - -// Set individually to debug specific layers -this.DEBUG_WORKER = false || DEBUG_ALL; -this.DEBUG_CONTENT_HELPER = false || DEBUG_ALL; -this.DEBUG_RIL = false || DEBUG_ALL; - -this.REQUEST_GET_SIM_STATUS = 1; -this.REQUEST_ENTER_SIM_PIN = 2; -this.REQUEST_ENTER_SIM_PUK = 3; -this.REQUEST_ENTER_SIM_PIN2 = 4; -this.REQUEST_ENTER_SIM_PUK2 = 5; -this.REQUEST_CHANGE_SIM_PIN = 6; -this.REQUEST_CHANGE_SIM_PIN2 = 7; -this.REQUEST_ENTER_NETWORK_DEPERSONALIZATION_CODE = 8; -this.REQUEST_GET_CURRENT_CALLS = 9; -this.REQUEST_DIAL = 10; -this.REQUEST_GET_IMSI = 11; -this.REQUEST_HANGUP = 12; -this.REQUEST_HANGUP_WAITING_OR_BACKGROUND = 13; -this.REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND = 14; -this.REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE = 15; -this.REQUEST_CONFERENCE = 16; -this.REQUEST_UDUB = 17; -this.REQUEST_LAST_CALL_FAIL_CAUSE = 18; -this.REQUEST_SIGNAL_STRENGTH = 19; -this.REQUEST_VOICE_REGISTRATION_STATE = 20; -this.REQUEST_DATA_REGISTRATION_STATE = 21; -this.REQUEST_OPERATOR = 22; -this.REQUEST_RADIO_POWER = 23; -this.REQUEST_DTMF = 24; -this.REQUEST_SEND_SMS = 25; -this.REQUEST_SEND_SMS_EXPECT_MORE = 26; -this.REQUEST_SETUP_DATA_CALL = 27; -this.REQUEST_SIM_IO = 28; -this.REQUEST_SEND_USSD = 29; -this.REQUEST_CANCEL_USSD = 30; -this.REQUEST_GET_CLIR = 31; -this.REQUEST_SET_CLIR = 32; -this.REQUEST_QUERY_CALL_FORWARD_STATUS = 33; -this.REQUEST_SET_CALL_FORWARD = 34; -this.REQUEST_QUERY_CALL_WAITING = 35; -this.REQUEST_SET_CALL_WAITING = 36; -this.REQUEST_SMS_ACKNOWLEDGE = 37; -this.REQUEST_GET_IMEI = 38; -this.REQUEST_GET_IMEISV = 39; -this.REQUEST_ANSWER = 40; -this.REQUEST_DEACTIVATE_DATA_CALL = 41; -this.REQUEST_QUERY_FACILITY_LOCK = 42; -this.REQUEST_SET_FACILITY_LOCK = 43; -this.REQUEST_CHANGE_BARRING_PASSWORD = 44; -this.REQUEST_QUERY_NETWORK_SELECTION_MODE = 45; -this.REQUEST_SET_NETWORK_SELECTION_AUTOMATIC = 46; -this.REQUEST_SET_NETWORK_SELECTION_MANUAL = 47; -this.REQUEST_QUERY_AVAILABLE_NETWORKS = 48; -this.REQUEST_DTMF_START = 49; -this.REQUEST_DTMF_STOP = 50; -this.REQUEST_BASEBAND_VERSION = 51; -this.REQUEST_SEPARATE_CONNECTION = 52; -this.REQUEST_SET_MUTE = 53; -this.REQUEST_GET_MUTE = 54; -this.REQUEST_QUERY_CLIP = 55; -this.REQUEST_LAST_DATA_CALL_FAIL_CAUSE = 56; -this.REQUEST_DATA_CALL_LIST = 57; -this.REQUEST_RESET_RADIO = 58; -this.REQUEST_OEM_HOOK_RAW = 59; -this.REQUEST_OEM_HOOK_STRINGS = 60; -this.REQUEST_SCREEN_STATE = 61; -this.REQUEST_SET_SUPP_SVC_NOTIFICATION = 62; -this.REQUEST_WRITE_SMS_TO_SIM = 63; -this.REQUEST_DELETE_SMS_ON_SIM = 64; -this.REQUEST_SET_BAND_MODE = 65; -this.REQUEST_QUERY_AVAILABLE_BAND_MODE = 66; -this.REQUEST_STK_GET_PROFILE = 67; -this.REQUEST_STK_SET_PROFILE = 68; -this.REQUEST_STK_SEND_ENVELOPE_COMMAND = 69; -this.REQUEST_STK_SEND_TERMINAL_RESPONSE = 70; -this.REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM = 71; -this.REQUEST_EXPLICIT_CALL_TRANSFER = 72; -this.REQUEST_SET_PREFERRED_NETWORK_TYPE = 73; -this.REQUEST_GET_PREFERRED_NETWORK_TYPE = 74; -this.REQUEST_GET_NEIGHBORING_CELL_IDS = 75; -this.REQUEST_SET_LOCATION_UPDATES = 76; -this.REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE = 77; -this.REQUEST_CDMA_SET_ROAMING_PREFERENCE = 78; -this.REQUEST_CDMA_QUERY_ROAMING_PREFERENCE = 79; -this.REQUEST_SET_TTY_MODE = 80; -this.REQUEST_QUERY_TTY_MODE = 81; -this.REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE = 82; -this.REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE = 83; -this.REQUEST_CDMA_FLASH = 84; -this.REQUEST_CDMA_BURST_DTMF = 85; -this.REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY = 86; -this.REQUEST_CDMA_SEND_SMS = 87; -this.REQUEST_CDMA_SMS_ACKNOWLEDGE = 88; -this.REQUEST_GSM_GET_BROADCAST_SMS_CONFIG = 89; -this.REQUEST_GSM_SET_BROADCAST_SMS_CONFIG = 90; -this.REQUEST_GSM_SMS_BROADCAST_ACTIVATION = 91; -this.REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG = 92; -this.REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG = 93; -this.REQUEST_CDMA_SMS_BROADCAST_ACTIVATION = 94; -this.REQUEST_CDMA_SUBSCRIPTION = 95; -this.REQUEST_CDMA_WRITE_SMS_TO_RUIM = 96; -this.REQUEST_CDMA_DELETE_SMS_ON_RUIM = 97; -this.REQUEST_DEVICE_IDENTITY = 98; -this.REQUEST_EXIT_EMERGENCY_CALLBACK_MODE = 99; -this.REQUEST_GET_SMSC_ADDRESS = 100; -this.REQUEST_SET_SMSC_ADDRESS = 101; -this.REQUEST_REPORT_SMS_MEMORY_STATUS = 102; -this.REQUEST_REPORT_STK_SERVICE_IS_RUNNING = 103; -this.REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE = 104; -this.REQUEST_ISIM_AUTHENTICATION = 105; -this.REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU = 106; -this.REQUEST_STK_SEND_ENVELOPE_WITH_STATUS = 107; -this.REQUEST_VOICE_RADIO_TECH = 108; -this.REQUEST_GET_CELL_INFO_LIST = 109; -this.REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE = 110; -this.REQUEST_SET_INITIAL_ATTACH_APN = 111; -this.REQUEST_IMS_REGISTRATION_STATE = 112; -this.REQUEST_IMS_SEND_SMS = 113; -this.REQUEST_SIM_TRANSMIT_APDU_BASIC = 114; -this.REQUEST_SIM_OPEN_CHANNEL = 115; -this.REQUEST_SIM_CLOSE_CHANNEL = 116; -this.REQUEST_SIM_TRANSMIT_APDU_CHANNEL = 117; -this.REQUEST_NV_READ_ITEM = 118; -this.REQUEST_NV_WRITE_ITEM = 119; -this.REQUEST_NV_WRITE_CDMA_PRL = 120; -this.REQUEST_NV_RESET_CONFIG = 121; -this.REQUEST_SET_UICC_SUBSCRIPTION = 122; -this.REQUEST_ALLOW_DATA = 123; -this.REQUEST_GET_HARDWARE_CONFIG = 124; -this.REQUEST_SIM_AUTHENTICATION = 125; -this.REQUEST_GET_DC_RT_INFO = 126; -this.REQUEST_SET_DC_RT_INFO_RATE = 127; -this.REQUEST_SET_DATA_PROFILE = 128; -this.REQUEST_SHUTDOWN = 129; - -// CAF specific parcel type. It should be synced with latest version. But CAF -// doesn't have l version for b2g yet, so we set REQUEST_SET_DATA_SUBSCRIPTION -// to a value that won't get conflict with known AOSP parcel. -this.REQUEST_SET_DATA_SUBSCRIPTION = 130; - -// Mozilla specific parcel type. -this.REQUEST_GET_UNLOCK_RETRY_COUNT = 150; - -// Fugu specific parcel types. -this.RIL_REQUEST_GPRS_ATTACH = 5018; -this.RIL_REQUEST_GPRS_DETACH = 5019; - -// Galaxy S2 specific parcel type. -this.REQUEST_DIAL_EMERGENCY_CALL = 10016; - -this.RESPONSE_TYPE_SOLICITED = 0; -this.RESPONSE_TYPE_UNSOLICITED = 1; - -this.UNSOLICITED_RESPONSE_BASE = 1000; -this.UNSOLICITED_RESPONSE_RADIO_STATE_CHANGED = 1000; -this.UNSOLICITED_RESPONSE_CALL_STATE_CHANGED = 1001; -this.UNSOLICITED_RESPONSE_VOICE_NETWORK_STATE_CHANGED = 1002; -this.UNSOLICITED_RESPONSE_NEW_SMS = 1003; -this.UNSOLICITED_RESPONSE_NEW_SMS_STATUS_REPORT = 1004; -this.UNSOLICITED_RESPONSE_NEW_SMS_ON_SIM = 1005; -this.UNSOLICITED_ON_USSD = 1006; -this.UNSOLICITED_ON_USSD_REQUEST = 1007; -this.UNSOLICITED_NITZ_TIME_RECEIVED = 1008; -this.UNSOLICITED_SIGNAL_STRENGTH = 1009; -this.UNSOLICITED_DATA_CALL_LIST_CHANGED = 1010; -this.UNSOLICITED_SUPP_SVC_NOTIFICATION = 1011; -this.UNSOLICITED_STK_SESSION_END = 1012; -this.UNSOLICITED_STK_PROACTIVE_COMMAND = 1013; -this.UNSOLICITED_STK_EVENT_NOTIFY = 1014; -this.UNSOLICITED_STK_CALL_SETUP = 1015; -this.UNSOLICITED_SIM_SMS_STORAGE_FULL = 1016; -this.UNSOLICITED_SIM_REFRESH = 1017; -this.UNSOLICITED_CALL_RING = 1018; -this.UNSOLICITED_RESPONSE_SIM_STATUS_CHANGED = 1019; -this.UNSOLICITED_RESPONSE_CDMA_NEW_SMS = 1020; -this.UNSOLICITED_RESPONSE_NEW_BROADCAST_SMS = 1021; -this.UNSOLICITED_CDMA_RUIM_SMS_STORAGE_FULL = 1022; -this.UNSOLICITED_RESTRICTED_STATE_CHANGED = 1023; -this.UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE = 1024; -this.UNSOLICITED_CDMA_CALL_WAITING = 1025; -this.UNSOLICITED_CDMA_OTA_PROVISION_STATUS = 1026; -this.UNSOLICITED_CDMA_INFO_REC = 1027; -this.UNSOLICITED_OEM_HOOK_RAW = 1028; -this.UNSOLICITED_RINGBACK_TONE = 1029; -this.UNSOLICITED_RESEND_INCALL_MUTE = 1030; -this.UNSOLICITED_CDMA_SUBSCRIPTION_SOURCE_CHANGED = 1031; -this.UNSOLICITED_CDMA_PRL_CHANGED = 1032; -this.UNSOLICITED_EXIT_EMERGENCY_CALLBACK_MODE = 1033; -this.UNSOLICITED_RIL_CONNECTED = 1034; -this.UNSOLICITED_VOICE_RADIO_TECH_CHANGED = 1035; -this.UNSOLICITED_CELL_INFO_LIST = 1036; -this.UNSOLICITED_RESPONSE_IMS_NETWORK_STATE_CHANGED = 1037; -this.UNSOLICITED_UICC_SUBSCRIPTION_STATUS_CHANGED = 1038; -this.UNSOLICITED_SRVCC_STATE_NOTIFY = 1039; -this.UNSOLICITED_HARDWARE_CONFIG_CHANGED = 1040; -this.UNSOLICITED_DC_RT_INFO_CHANGED = 1041; - -this.ERROR_SUCCESS = 0; -this.ERROR_RADIO_NOT_AVAILABLE = 1; -this.ERROR_GENERIC_FAILURE = 2; -this.ERROR_PASSWORD_INCORRECT = 3; -this.ERROR_SIM_PIN2 = 4; -this.ERROR_SIM_PUK2 = 5; -this.ERROR_REQUEST_NOT_SUPPORTED = 6; -this.ERROR_CANCELLED = 7; -this.ERROR_OP_NOT_ALLOWED_DURING_VOICE_CALL = 8; -this.ERROR_OP_NOT_ALLOWED_BEFORE_REG_TO_NW = 9; -this.ERROR_SMS_SEND_FAIL_RETRY = 10; -this.ERROR_SIM_ABSENT = 11; -this.ERROR_SUBSCRIPTION_NOT_AVAILABLE = 12; -this.ERROR_MODE_NOT_SUPPORTED = 13; -this.ERROR_FDN_CHECK_FAILURE = 14; -this.ERROR_ILLEGAL_SIM_OR_ME = 15; -this.ERROR_MISSING_RESOURCE = 16; -this.ERROR_NO_SUCH_ELEMENT = 17; - -this.GECKO_ERROR_RADIO_NOT_AVAILABLE = "RadioNotAvailable"; -this.GECKO_ERROR_GENERIC_FAILURE = "GenericFailure"; -this.GECKO_ERROR_PASSWORD_INCORRECT = "IncorrectPassword"; -this.GECKO_ERROR_SIM_PIN2 = "SimPin2"; -this.GECKO_ERROR_SIM_PUK2 = "SimPuk2"; -this.GECKO_ERROR_REQUEST_NOT_SUPPORTED = "RequestNotSupported"; -this.GECKO_ERROR_CANCELLED = "Cancelled"; -this.GECKO_ERROR_OP_NOT_ALLOWED_DURING_VOICE_CALL = "OpNotAllowedDuringVoiceCall"; -this.GECKO_ERROR_OP_NOT_ALLOWED_BEFORE_REG_TO_NW = "OpNotAllowedBeforeRegToNw"; -this.GECKO_ERROR_SMS_SEND_FAIL_RETRY = "SmsSendFailRetry"; -this.GECKO_ERROR_SIM_ABSENT = "SimAbsent"; -this.GECKO_ERROR_SUBSCRIPTION_NOT_AVAILABLE = "SubscriptionNotAvailable"; -this.GECKO_ERROR_MODE_NOT_SUPPORTED = "ModeNotSupported"; -this.GECKO_ERROR_FDN_CHECK_FAILURE = "FdnCheckFailure"; -this.GECKO_ERROR_ILLEGAL_SIM_OR_ME = "IllegalSIMorME"; -this.GECKO_ERROR_MISSING_RESOURCE = "MissingResource"; -this.GECKO_ERROR_NO_SUCH_ELEMENT = "NoSuchElement"; -this.GECKO_ERROR_INVALID_PARAMETER = "InvalidParameter"; -this.GECKO_ERROR_UNSPECIFIED_ERROR = "UnspecifiedError"; - -this.RIL_ERROR_TO_GECKO_ERROR = {}; -RIL_ERROR_TO_GECKO_ERROR[ERROR_RADIO_NOT_AVAILABLE] = GECKO_ERROR_RADIO_NOT_AVAILABLE; -RIL_ERROR_TO_GECKO_ERROR[ERROR_GENERIC_FAILURE] = GECKO_ERROR_GENERIC_FAILURE; -RIL_ERROR_TO_GECKO_ERROR[ERROR_PASSWORD_INCORRECT] = GECKO_ERROR_PASSWORD_INCORRECT; -RIL_ERROR_TO_GECKO_ERROR[ERROR_SIM_PIN2] = GECKO_ERROR_SIM_PIN2; -RIL_ERROR_TO_GECKO_ERROR[ERROR_SIM_PUK2] = GECKO_ERROR_SIM_PUK2; -RIL_ERROR_TO_GECKO_ERROR[ERROR_REQUEST_NOT_SUPPORTED] = GECKO_ERROR_REQUEST_NOT_SUPPORTED; -RIL_ERROR_TO_GECKO_ERROR[ERROR_CANCELLED] = GECKO_ERROR_CANCELLED; -RIL_ERROR_TO_GECKO_ERROR[ERROR_OP_NOT_ALLOWED_DURING_VOICE_CALL] = GECKO_ERROR_OP_NOT_ALLOWED_DURING_VOICE_CALL; -RIL_ERROR_TO_GECKO_ERROR[ERROR_OP_NOT_ALLOWED_BEFORE_REG_TO_NW] = GECKO_ERROR_OP_NOT_ALLOWED_BEFORE_REG_TO_NW; -RIL_ERROR_TO_GECKO_ERROR[ERROR_SMS_SEND_FAIL_RETRY] = GECKO_ERROR_SMS_SEND_FAIL_RETRY; -RIL_ERROR_TO_GECKO_ERROR[ERROR_SIM_ABSENT] = GECKO_ERROR_SIM_ABSENT; -RIL_ERROR_TO_GECKO_ERROR[ERROR_SUBSCRIPTION_NOT_AVAILABLE] = GECKO_ERROR_SUBSCRIPTION_NOT_AVAILABLE; -RIL_ERROR_TO_GECKO_ERROR[ERROR_MODE_NOT_SUPPORTED] = GECKO_ERROR_MODE_NOT_SUPPORTED; -RIL_ERROR_TO_GECKO_ERROR[ERROR_FDN_CHECK_FAILURE] = GECKO_ERROR_FDN_CHECK_FAILURE; -RIL_ERROR_TO_GECKO_ERROR[ERROR_ILLEGAL_SIM_OR_ME] = GECKO_ERROR_ILLEGAL_SIM_OR_ME; -RIL_ERROR_TO_GECKO_ERROR[ERROR_MISSING_RESOURCE] = GECKO_ERROR_MISSING_RESOURCE; -RIL_ERROR_TO_GECKO_ERROR[ERROR_NO_SUCH_ELEMENT] = GECKO_ERROR_NO_SUCH_ELEMENT; - -// 3GPP 23.040 clause 9.2.3.6 TP-Message-Reference(TP-MR): -// The number of times the MS automatically repeats the SMS-SUBMIT shall be in -// the range 1 to 3 but the precise number is an implementation matter. -this.SMS_RETRY_MAX = 3; - -this.RADIO_STATE_OFF = 0; -this.RADIO_STATE_UNAVAILABLE = 1; -this.RADIO_STATE_ON = 10; // since RIL v7 - -this.CARD_STATE_ABSENT = 0; -this.CARD_STATE_PRESENT = 1; -this.CARD_STATE_ERROR = 2; - -this.CARD_PERSOSUBSTATE_UNKNOWN = 0; -this.CARD_PERSOSUBSTATE_IN_PROGRESS = 1; -this.CARD_PERSOSUBSTATE_READY = 2; -this.CARD_PERSOSUBSTATE_SIM_NETWORK = 3; -this.CARD_PERSOSUBSTATE_SIM_NETWORK_SUBSET = 4; -this.CARD_PERSOSUBSTATE_SIM_CORPORATE = 5; -this.CARD_PERSOSUBSTATE_SIM_SERVICE_PROVIDER = 6; -this.CARD_PERSOSUBSTATE_SIM_SIM = 7; -this.CARD_PERSOSUBSTATE_SIM_NETWORK_PUK = 8; -this.CARD_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK = 9; -this.CARD_PERSOSUBSTATE_SIM_CORPORATE_PUK = 10; -this.CARD_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK = 11; -this.CARD_PERSOSUBSTATE_SIM_SIM_PUK = 12; -this.CARD_PERSOSUBSTATE_RUIM_NETWORK1 = 13; -this.CARD_PERSOSUBSTATE_RUIM_NETWORK2 = 14; -this.CARD_PERSOSUBSTATE_RUIM_HRPD = 15; -this.CARD_PERSOSUBSTATE_RUIM_CORPORATE = 16; -this.CARD_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER = 17; -this.CARD_PERSOSUBSTATE_RUIM_RUIM = 18; -this.CARD_PERSOSUBSTATE_RUIM_NETWORK1_PUK = 19; -this.CARD_PERSOSUBSTATE_RUIM_NETWORK2_PUK = 20; -this.CARD_PERSOSUBSTATE_RUIM_HRPD_PUK = 21; -this.CARD_PERSOSUBSTATE_RUIM_CORPORATE_PUK = 22; -this.CARD_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK = 23; -this.CARD_PERSOSUBSTATE_RUIM_RUIM_PUK = 24; - -this.CARD_APPSTATE_ILLEGAL = -1; -this.CARD_APPSTATE_UNKNOWN = 0; -this.CARD_APPSTATE_DETECTED = 1; -this.CARD_APPSTATE_PIN = 2; // If PIN1 or UPin is required. -this.CARD_APPSTATE_PUK = 3; // If PUK1 or Puk for UPin is required. -this.CARD_APPSTATE_SUBSCRIPTION_PERSO = 4; // perso_substate should be looked - // at when app_state is assigned - // to this value. -this.CARD_APPSTATE_READY = 5; - -this.CARD_PINSTATE_UNKNOWN = 0; -this.CARD_PINSTATE_ENABLED_NOT_VERIFIED = 1; -this.CARD_PINSTATE_ENABLED_VERIFIED = 2; -this.CARD_PINSTATE_DISABLED = 3; -this.CARD_PINSTATE_ENABLED_BLOCKED = 4; -this.CARD_PINSTATE_ENABLED_PERM_BLOCKED = 5; - -this.CARD_APPTYPE_UNKNOWN = 0; -this.CARD_APPTYPE_SIM = 1; -this.CARD_APPTYPE_USIM = 2; -this.CARD_APPTYPE_RUIM = 3; -this.CARD_APPTYPE_CSIM = 4; -this.CARD_APPTYPE_ISIM = 5; - -this.CARD_MAX_APPS = 8; - -this.GECKO_CARD_TYPE = [ - null, - "sim", - "usim", - "ruim", - "csim", - "isim" -]; - - -// Used for QUERY_AVAILABLE_NETWORKS status. -this.QAN_STATE_UNKNOWN = "unknown"; -this.QAN_STATE_AVAILABLE = "available"; -this.QAN_STATE_CURRENT = "current"; -this.QAN_STATE_FORBIDDEN = "forbidden"; - -// Must be in sync with MobileNetworkState of MozMobileNetworkInfo.webidl -this.GECKO_QAN_STATE_UNKNOWN = null; -this.GECKO_QAN_STATE_AVAILABLE = "available"; -this.GECKO_QAN_STATE_CONNECTED = "connected"; -this.GECKO_QAN_STATE_FORBIDDEN = "forbidden"; - -this.RIL_QAN_STATE_TO_GECKO_STATE = {}; -this.RIL_QAN_STATE_TO_GECKO_STATE[this.QAN_STATE_UNKNOWN] = this.GECKO_QAN_STATE_UNKNOWN; -this.RIL_QAN_STATE_TO_GECKO_STATE[this.QAN_STATE_AVAILABLE] = this.GECKO_QAN_STATE_AVAILABLE; -this.RIL_QAN_STATE_TO_GECKO_STATE[this.QAN_STATE_CURRENT] = this.GECKO_QAN_STATE_CONNECTED; -this.RIL_QAN_STATE_TO_GECKO_STATE[this.QAN_STATE_FORBIDDEN] = this.GECKO_QAN_STATE_FORBIDDEN; - -this.NETWORK_SELECTION_MODE_AUTOMATIC = 0; -this.NETWORK_SELECTION_MODE_MANUAL = 1; - -this.NETWORK_INFO_VOICE_REGISTRATION_STATE = "voiceRegistrationState"; -this.NETWORK_INFO_DATA_REGISTRATION_STATE = "dataRegistrationState"; -this.NETWORK_INFO_OPERATOR = "operator"; -this.NETWORK_INFO_NETWORK_SELECTION_MODE = "networkSelectionMode"; -this.NETWORK_INFO_SIGNAL = "signal"; -this.NETWORK_INFO_MESSAGE_TYPES = [ - NETWORK_INFO_VOICE_REGISTRATION_STATE, - NETWORK_INFO_DATA_REGISTRATION_STATE, - NETWORK_INFO_OPERATOR, - NETWORK_INFO_NETWORK_SELECTION_MODE, - NETWORK_INFO_SIGNAL -]; - -this.GECKO_PREFERRED_NETWORK_TYPE_WCDMA_GSM = "wcdma/gsm"; -this.GECKO_PREFERRED_NETWORK_TYPE_GSM_ONLY = "gsm"; -this.GECKO_PREFERRED_NETWORK_TYPE_WCDMA_ONLY = "wcdma"; -this.GECKO_PREFERRED_NETWORK_TYPE_WCDMA_GSM_AUTO = "wcdma/gsm-auto"; -this.GECKO_PREFERRED_NETWORK_TYPE_CDMA_EVDO = "cdma/evdo"; -this.GECKO_PREFERRED_NETWORK_TYPE_CDMA_ONLY = "cdma"; -this.GECKO_PREFERRED_NETWORK_TYPE_EVDO_ONLY = "evdo"; -this.GECKO_PREFERRED_NETWORK_TYPE_WCDMA_GSM_CDMA_EVDO = "wcdma/gsm/cdma/evdo"; -this.GECKO_PREFERRED_NETWORK_TYPE_LTE_CDMA_EVDO = "lte/cdma/evdo"; -this.GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA_GSM = "lte/wcdma/gsm"; -this.GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA = "lte/wcdma"; -this.GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA_GSM_CDMA_EVDO = "lte/wcdma/gsm/cdma/evdo"; -this.GECKO_PREFERRED_NETWORK_TYPE_LTE_ONLY = "lte"; -this.RIL_PREFERRED_NETWORK_TYPE_TO_GECKO = [ - GECKO_PREFERRED_NETWORK_TYPE_WCDMA_GSM, - GECKO_PREFERRED_NETWORK_TYPE_GSM_ONLY, - GECKO_PREFERRED_NETWORK_TYPE_WCDMA_ONLY, - GECKO_PREFERRED_NETWORK_TYPE_WCDMA_GSM_AUTO, - GECKO_PREFERRED_NETWORK_TYPE_CDMA_EVDO, - GECKO_PREFERRED_NETWORK_TYPE_CDMA_ONLY, - GECKO_PREFERRED_NETWORK_TYPE_EVDO_ONLY, - GECKO_PREFERRED_NETWORK_TYPE_WCDMA_GSM_CDMA_EVDO, - GECKO_PREFERRED_NETWORK_TYPE_LTE_CDMA_EVDO, - GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA_GSM, - GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA_GSM_CDMA_EVDO, - GECKO_PREFERRED_NETWORK_TYPE_LTE_ONLY, - GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA -]; - -this.GECKO_SUPPORTED_NETWORK_TYPES_DEFAULT = "gsm,wcdma"; -// Index-item pair must be in sync with nsIMobileConnection.MOBILE_NETWORK_TYPE_* -this.GECKO_SUPPORTED_NETWORK_TYPES = [ - "gsm", - "wcdma", - "cdma", - "evdo", - "lte" -]; - -// Network registration states. See TS 27.007 7.2 -this.NETWORK_CREG_STATE_NOT_SEARCHING = 0; -this.NETWORK_CREG_STATE_REGISTERED_HOME = 1; -this.NETWORK_CREG_STATE_SEARCHING = 2; -this.NETWORK_CREG_STATE_DENIED = 3; -this.NETWORK_CREG_STATE_UNKNOWN = 4; -this.NETWORK_CREG_STATE_REGISTERED_ROAMING = 5; -this.NETWORK_CREG_STATE_NOT_SEARCHING_EMERGENCY_CALLS = 10; -this.NETWORK_CREG_STATE_SEARCHING_EMERGENCY_CALLS = 12; -this.NETWORK_CREG_STATE_DENIED_EMERGENCY_CALLS = 13; -this.NETWORK_CREG_STATE_UNKNOWN_EMERGENCY_CALLS = 14; - -this.NETWORK_CREG_TECH_UNKNOWN = 0; -this.NETWORK_CREG_TECH_GPRS = 1; -this.NETWORK_CREG_TECH_EDGE = 2; -this.NETWORK_CREG_TECH_UMTS = 3; -this.NETWORK_CREG_TECH_IS95A = 4; -this.NETWORK_CREG_TECH_IS95B = 5; -this.NETWORK_CREG_TECH_1XRTT = 6; -this.NETWORK_CREG_TECH_EVDO0 = 7; -this.NETWORK_CREG_TECH_EVDOA = 8; -this.NETWORK_CREG_TECH_HSDPA = 9; -this.NETWORK_CREG_TECH_HSUPA = 10; -this.NETWORK_CREG_TECH_HSPA = 11; -this.NETWORK_CREG_TECH_EVDOB = 12; -this.NETWORK_CREG_TECH_EHRPD = 13; -this.NETWORK_CREG_TECH_LTE = 14; -this.NETWORK_CREG_TECH_HSPAP = 15; -this.NETWORK_CREG_TECH_GSM = 16; -this.NETWORK_CREG_TECH_DCHSPAP_1 = 18; // Some devices reports as 18 -this.NETWORK_CREG_TECH_DCHSPAP_2 = 19; // Some others report it as 19 - -this.CELL_INFO_TYPE_GSM = 1; -this.CELL_INFO_TYPE_CDMA = 2; -this.CELL_INFO_TYPE_LTE = 3; -this.CELL_INFO_TYPE_WCDMA = 4; - -this.CALL_STATE_UNKNOWN = -1; -this.CALL_STATE_ACTIVE = 0; -this.CALL_STATE_HOLDING = 1; -this.CALL_STATE_DIALING = 2; -this.CALL_STATE_ALERTING = 3; -this.CALL_STATE_INCOMING = 4; -this.CALL_STATE_WAITING = 5; - -this.TOA_INTERNATIONAL = 0x91; -this.TOA_UNKNOWN = 0x81; - -this.CALL_PRESENTATION_ALLOWED = 0; -this.CALL_PRESENTATION_RESTRICTED = 1; -this.CALL_PRESENTATION_UNKNOWN = 2; -this.CALL_PRESENTATION_PAYPHONE = 3; - -// Call forwarding actions, see TS 27.007 7.11 "mode" -this.CALL_FORWARD_ACTION_QUERY_STATUS = 2; - -// ICC commands, see TS 27.007 +CRSM commands -this.ICC_COMMAND_SEEK = 0xa2; -this.ICC_COMMAND_READ_BINARY = 0xb0; -this.ICC_COMMAND_READ_RECORD = 0xb2; -this.ICC_COMMAND_GET_RESPONSE = 0xc0; -this.ICC_COMMAND_UPDATE_BINARY = 0xd6; -this.ICC_COMMAND_UPDATE_RECORD = 0xdc; - -// ICC constants, GSM SIM file ids from TS 51.011 -this.ICC_EF_ICCID = 0x2fe2; -this.ICC_EF_IMG = 0x4f20; -this.ICC_EF_PBR = 0x4f30; -this.ICC_EF_PLMNsel = 0x6f30; // PLMN for SIM -this.ICC_EF_SST = 0x6f38; -this.ICC_EF_UST = 0x6f38; // For USIM -this.ICC_EF_ADN = 0x6f3a; -this.ICC_EF_FDN = 0x6f3b; -this.ICC_EF_SMS = 0x6f3c; -this.ICC_EF_GID1 = 0x6f3e; -this.ICC_EF_MSISDN = 0x6f40; -this.ICC_EF_CBMI = 0x6f45; -this.ICC_EF_SPN = 0x6f46; -this.ICC_EF_CBMID = 0x6f48; -this.ICC_EF_SDN = 0x6f49; -this.ICC_EF_EXT1 = 0x6f4a; -this.ICC_EF_EXT2 = 0x6f4b; -this.ICC_EF_EXT3 = 0x6f4c; -this.ICC_EF_CBMIR = 0x6f50; -this.ICC_EF_AD = 0x6fad; -this.ICC_EF_PHASE = 0x6fae; -this.ICC_EF_PNN = 0x6fc5; -this.ICC_EF_OPL = 0x6fc6; -this.ICC_EF_MBDN = 0x6fc7; -this.ICC_EF_EXT6 = 0x6fc8; // Ext record for EF[MBDN] -this.ICC_EF_MBI = 0x6fc9; -this.ICC_EF_MWIS = 0x6fca; -this.ICC_EF_CFIS = 0x6fcb; -this.ICC_EF_SPDI = 0x6fcd; - -// CPHS files to be supported -this.ICC_EF_CPHS_INFO = 0x6f16; // CPHS Information -this.ICC_EF_CPHS_MBN = 0x6f17; // Mailbox Numbers - -// CSIM files -this.ICC_EF_CSIM_IMSI_M = 0x6f22; -this.ICC_EF_CSIM_CDMAHOME = 0x6f28; -this.ICC_EF_CSIM_CST = 0x6f32; // CDMA Service table -this.ICC_EF_CSIM_SPN = 0x6f41; - -this.ICC_PHASE_1 = 0x00; -this.ICC_PHASE_2 = 0x02; -this.ICC_PHASE_2_PROFILE_DOWNLOAD_REQUIRED = 0x03; - -// Types of files TS 11.11 9.3 -this.TYPE_RFU = 0; -this.TYPE_MF = 1; -this.TYPE_DF = 2; -this.TYPE_EF = 4; - -this.RESPONSE_DATA_FILE_SIZE = 2; -this.RESPONSE_DATA_FILE_ID_1 = 4; -this.RESPONSE_DATA_FILE_ID_2 = 5; -this.RESPONSE_DATA_FILE_TYPE = 6; -this.RESPONSE_DATA_RFU_3 = 7; -this.RESPONSE_DATA_ACCESS_CONDITION_1 = 8; -this.RESPONSE_DATA_ACCESS_CONDITION_2 = 9; -this.RESPONSE_DATA_ACCESS_CONDITION_3 = 10; -this.RESPONSE_DATA_FILE_STATUS = 11; -this.RESPONSE_DATA_LENGTH = 12; -this.RESPONSE_DATA_STRUCTURE = 13; -this.RESPONSE_DATA_RECORD_LENGTH = 14; - -// Structure of files TS 11.11 9.3 -this.EF_STRUCTURE_TRANSPARENT = 0; -this.EF_STRUCTURE_LINEAR_FIXED = 1; -this.EF_STRUCTURE_CYCLIC = 3; - -// TS 102.221 11.1.1.4.3 Table 11.5: File descriptor byte. -this.UICC_EF_STRUCTURE = {}; -this.UICC_EF_STRUCTURE[this.EF_STRUCTURE_TRANSPARENT]= 1; -this.UICC_EF_STRUCTURE[this.EF_STRUCTURE_LINEAR_FIXED]= 2; -this.UICC_EF_STRUCTURE[this.EF_STRUCTURE_CYCLIC]= 6; - -// Status code of EFsms -// see 3GPP TS 51.011 clause 10.5.3 -this.EFSMS_STATUS_FREE = 0x00; -this.EFSMS_STATUS_READ = 0x01; -this.EFSMS_STATUS_TO_BE_READ = 0x03; -this.EFSMS_STATUS_TO_BE_SENT = 0x07; - -// Total size of ADN footer(the size of Alpha identifier excluded). -// See TS 151.011 clause 10.5.1 EF_ADN. -this.ADN_FOOTER_SIZE_BYTES = 14; -// Maximum size of BCD numbers in ADN. -// See TS 151.011 clause 10.5.1 EF_ADN, 'Length of BCD number/SSC contents'. -this.ADN_MAX_BCD_NUMBER_BYTES = 11; -// Maximum digits of the Dialling Number in ADN. -// See TS 151.011 clause 10.5.1 EF_ADN, 'Dialling Number'. -this.ADN_MAX_NUMBER_DIGITS = 20; -// Maximum size of BCD numbers in EXT. -// See TS 151.011 clause 10.5.10 EF_EXT1, 'Extension data'. -this.EXT_MAX_BCD_NUMBER_BYTES = 10; -// Maximum digits of the Dialling Number in EXT. -// See TS 151.011 clause 10.5.10 EF_EXT1, 'Extension data'. -this.EXT_MAX_NUMBER_DIGITS = 20; - -// READ_RECORD mode, TS 102.221 -this.READ_RECORD_ABSOLUTE_MODE = 4; - -// TS 102.221 Table 11.2, return FCP template -this.GET_RESPONSE_FCP_TEMPLATE = 4; - -// GET_RESPONSE mandatory response size for EF, see TS 51.011 clause 9, -// 'Response data in case of an EF.' -this.GET_RESPONSE_EF_SIZE_BYTES = 15; - -// EF path -this.EF_PATH_MF_SIM = "3f00"; -this.EF_PATH_DF_PHONEBOOK = "5f3a"; -this.EF_PATH_GRAPHICS = "5f50"; -this.EF_PATH_DF_TELECOM = "7f10"; -this.EF_PATH_DF_GSM = "7f20"; -this.EF_PATH_DF_CDMA = "7f25"; -this.EF_PATH_ADF_USIM = "7fff"; - -// Status code of sw1 for ICC I/O, -// see GSM11.11 and TS 51.011 clause 9.4, and ISO 7816-4 -this.ICC_STATUS_NORMAL_ENDING = 0x90; -this.ICC_STATUS_NORMAL_ENDING_WITH_EXTRA = 0x91; -this.ICC_STATUS_SAT_BUSY = 0x93; -this.ICC_STATUS_WITH_SIM_DATA = 0x9e; -this.ICC_STATUS_WITH_RESPONSE_DATA = 0x9f; -this.ICC_STATUS_ERROR_WRONG_LENGTH = 0x67; -this.ICC_STATUS_ERROR_COMMAND_NOT_ALLOWED = 0x69; -this.ICC_STATUS_ERROR_WRONG_PARAMETERS = 0x6a; - -// ICC call barring facility. -// TS 27.007, clause 7.4, +CLCK -this.ICC_CB_FACILITY_SIM = "SC"; -this.ICC_CB_FACILITY_FDN = "FD"; -this.ICC_CB_FACILITY_BAOC = "AO"; -this.ICC_CB_FACILITY_BAOIC = "OI"; -this.ICC_CB_FACILITY_BAOICxH = "OX"; -this.ICC_CB_FACILITY_BAIC = "AI"; -this.ICC_CB_FACILITY_BAICr = "IR"; -this.ICC_CB_FACILITY_BA_ALL = "AB"; -this.ICC_CB_FACILITY_BA_MO = "AG"; -this.ICC_CB_FACILITY_BA_MT = "AC"; - -// ICC service class -// TS 27.007, clause 7.4, +CLCK -this.ICC_SERVICE_CLASS_NONE = 0; // no user input -this.ICC_SERVICE_CLASS_VOICE = (1 << 0); -this.ICC_SERVICE_CLASS_DATA = (1 << 1); -this.ICC_SERVICE_CLASS_FAX = (1 << 2); -this.ICC_SERVICE_CLASS_SMS = (1 << 3); -this.ICC_SERVICE_CLASS_DATA_SYNC = (1 << 4); -this.ICC_SERVICE_CLASS_DATA_ASYNC = (1 << 5); -this.ICC_SERVICE_CLASS_PACKET = (1 << 6); -this.ICC_SERVICE_CLASS_PAD = (1 << 7); -this.ICC_SERVICE_CLASS_MAX = (1 << 7); // Max ICC_SERVICE_CLASS value - -// ICC lock-selection codes -// TS 27.007, clause 8.65, +CPINR -this.ICC_SEL_CODE_SIM_PIN = "SIM PIN"; -this.ICC_SEL_CODE_SIM_PUK = "SIM PUK"; -this.ICC_SEL_CODE_PH_SIM_PIN = "PH-SIM PIN"; -this.ICC_SEL_CODE_PH_FSIM_PIN = "PH-FSIM PIN"; -this.ICC_SEL_CODE_PH_FSIM_PUK = "PH-FSIM PUK"; -this.ICC_SEL_CODE_SIM_PIN2 = "SIM PIN2"; -this.ICC_SEL_CODE_SIM_PUK2 = "SIM PUK2"; -this.ICC_SEL_CODE_PH_NET_PIN = "PH-NET PIN"; -this.ICC_SEL_CODE_PH_NET_PUK = "PH-NET PUK"; -this.ICC_SEL_CODE_PH_NETSUB_PIN = "PH-NETSUB PIN"; -this.ICC_SEL_CODE_PH_NETSUB_PUK = "PH-NETSUB PUK"; -this.ICC_SEL_CODE_PH_SP_PIN = "PH-SP PIN"; -this.ICC_SEL_CODE_PH_SP_PUK = "PH-SP PUK"; -this.ICC_SEL_CODE_PH_CORP_PIN = "PH-CORP PIN"; -this.ICC_SEL_CODE_PH_CORP_PUK = "PH-CORP PUK"; -// TODO: Bug 1116072: identify the mapping between RIL_PERSOSUBSTATE_SIM_SIM @ -// ril.h and TS 27.007, clause 8.65 for GECKO_CARDLOCK_PCK. - -this.ICC_USIM_TYPE1_TAG = 0xa8; -this.ICC_USIM_TYPE2_TAG = 0xa9; -this.ICC_USIM_TYPE3_TAG = 0xaa; -this.ICC_USIM_EFADN_TAG = 0xc0; -this.ICC_USIM_EFIAP_TAG = 0xc1; -this.ICC_USIM_EFEXT1_TAG = 0xc2; -this.ICC_USIM_EFSNE_TAG = 0xc3; -this.ICC_USIM_EFANR_TAG = 0xc4; -this.ICC_USIM_EFPBC_TAG = 0xc5; -this.ICC_USIM_EFGRP_TAG = 0xc6; -this.ICC_USIM_EFAAS_TAG = 0xc7; -this.ICC_USIM_EFGSD_TAG = 0xc8; -this.ICC_USIM_EFUID_TAG = 0xc9; -this.ICC_USIM_EFEMAIL_TAG = 0xca; -this.ICC_USIM_EFCCP1_TAG = 0xcb; - -// ICC image coding scheme -// TS 31.102, sub-clause 4.6.1.1 -this.ICC_IMG_CODING_SCHEME_BASIC = 0x11; -this.ICC_IMG_CODING_SCHEME_COLOR = 0x21; -this.ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY = 0x22; - -// Must be in sync with enum IccImageCodingScheme in MozStkCommandEvent.webidl. -this.GECKO_IMG_CODING_SCHEME_BASIC = "basic"; -this.GECKO_IMG_CODING_SCHEME_COLOR = "color"; -this.GECKO_IMG_CODING_SCHEME_COLOR_TRANSPARENCY = "color-transparency"; - -this.ICC_IMG_CODING_SCHEME_TO_GECKO = {}; -ICC_IMG_CODING_SCHEME_TO_GECKO[ICC_IMG_CODING_SCHEME_BASIC] = GECKO_IMG_CODING_SCHEME_BASIC; -ICC_IMG_CODING_SCHEME_TO_GECKO[ICC_IMG_CODING_SCHEME_COLOR] = GECKO_IMG_CODING_SCHEME_COLOR; -ICC_IMG_CODING_SCHEME_TO_GECKO[ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY] = GECKO_IMG_CODING_SCHEME_COLOR_TRANSPARENCY; - -// ICC image header size per coding scheme -// TS 31.102, Annex B -this.ICC_IMG_HEADER_SIZE_BASIC = 2; -this.ICC_IMG_HEADER_SIZE_COLOR = 6; - -this.ICC_CLUT_ENTRY_SIZE = 3; - -this.USIM_PBR_ANR = "anr"; -this.USIM_PBR_ANR0 = "anr0"; -this.USIM_PBR_EMAIL = "email"; - -// Current supported fields. Adding more fields to read will increasing I/O -// time dramatically, do check the performance is acceptable when you add -// more fields. -this.USIM_PBR_FIELDS = [USIM_PBR_EMAIL, USIM_PBR_ANR0]; - -this.USIM_TAG_NAME = {}; -this.USIM_TAG_NAME[ICC_USIM_EFADN_TAG] = "adn"; -this.USIM_TAG_NAME[ICC_USIM_EFIAP_TAG] ="iap"; -this.USIM_TAG_NAME[ICC_USIM_EFEXT1_TAG] = "ext1"; -this.USIM_TAG_NAME[ICC_USIM_EFSNE_TAG] = "sne"; -this.USIM_TAG_NAME[ICC_USIM_EFANR_TAG] = "anr"; -this.USIM_TAG_NAME[ICC_USIM_EFPBC_TAG] = "pbc"; -this.USIM_TAG_NAME[ICC_USIM_EFGRP_TAG] = "grp"; -this.USIM_TAG_NAME[ICC_USIM_EFAAS_TAG] = "aas"; -this.USIM_TAG_NAME[ICC_USIM_EFGSD_TAG] = "gsd"; -this.USIM_TAG_NAME[ICC_USIM_EFUID_TAG] = "uid"; -this.USIM_TAG_NAME[ICC_USIM_EFEMAIL_TAG] = "email"; -this.USIM_TAG_NAME[ICC_USIM_EFCCP1_TAG] = "ccp1"; - -// Error message for ICC contact. -this.CONTACT_ERR_REQUEST_NOT_SUPPORTED = GECKO_ERROR_REQUEST_NOT_SUPPORTED; -this.CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED = "ContactTypeNotSupported"; -this.CONTACT_ERR_FIELD_NOT_SUPPORTED = "FieldNotSupported"; -this.CONTACT_ERR_NO_FREE_RECORD_FOUND = "NoFreeRecordFound"; -this.CONTACT_ERR_CANNOT_ACCESS_PHONEBOOK = "CannotAccessPhoneBook"; - -// CDMA IMSI_M's byte const. -// 3GPP2 C.S0065 Sec. 5.2.2 -this.CSIM_IMSI_M_MIN2_BYTE = 1; -this.CSIM_IMSI_M_MIN1_BYTE = 3; -this.CSIM_IMSI_M_MNC_BYTE = 6; -this.CSIM_IMSI_M_PROGRAMMED_BYTE = 7; -this.CSIM_IMSI_M_MCC_BYTE = 8; - -/** - * Tags for Ber Tlv. - * See 3GPP TS 101 220 clause 7.2 - Assigned TLV tag values. - */ -this.BER_UNKNOWN_TAG = 0x00; -this.BER_FCP_TEMPLATE_TAG = 0x62; -this.BER_FCP_FILE_SIZE_DATA_TAG = 0x80; -this.BER_FCP_FILE_SIZE_TOTAL_TAG = 0x81; -this.BER_FCP_FILE_DESCRIPTOR_TAG = 0x82; -this.BER_FCP_FILE_IDENTIFIER_TAG = 0x83; -this.BER_FCP_DF_NAME_TAG = 0x84; // AID. -this.BER_FCP_PROPRIETARY_PRIMITIVE_TAG = 0x85; -this.BER_FCP_SFI_SUPPORT_TAG = 0x88; -this.BER_FCP_LIFE_CYCLE_STATUS_TAG = 0x8a; -this.BER_FCP_SA_REFERENCE_FORMAT_TAG = 0x8b; // Security Attribute - Reference Format. -this.BER_FCP_SA_COMPACT_FORMAT_TAG = 0x8c; // Security Attribute - Compact Format. -this.BER_FCP_SAT_EXPANDED_FORMAT_TAG = 0xab; // Security Attribute Template - Expanded Format. -this.BER_FCP_PROPRIETARY_TEMPLATE_TAG = 0xa5; -this.BER_FCP_PIN_STATUS_DATA_OBJECTS_TAG = 0xc6; -this.BER_PROACTIVE_COMMAND_TAG = 0xd0; -this.BER_SMS_PP_DOWNLOAD_TAG = 0xd1; -this.BER_MENU_SELECTION_TAG = 0xd3; -this.BER_EVENT_DOWNLOAD_TAG = 0xd6; -this.BER_TIMER_EXPIRATION_TAG = 0xd7; - -// Flags in Comprehension TLV. -this.COMPREHENSIONTLV_FLAG_CR = 0x80; // Comprehension required. - -// Tags for Comprehension TLV. -this.COMPREHENSIONTLV_TAG_COMMAND_DETAILS = 0x01; -this.COMPREHENSIONTLV_TAG_DEVICE_ID = 0x02; -this.COMPREHENSIONTLV_TAG_RESULT = 0x03; -this.COMPREHENSIONTLV_TAG_DURATION = 0x04; -this.COMPREHENSIONTLV_TAG_ALPHA_ID = 0x05; -this.COMPREHENSIONTLV_TAG_ADDRESS = 0x06; -this.COMPREHENSIONTLV_TAG_SUBADDRESS = 0x08; -this.COMPREHENSIONTLV_TAG_SMS_TPDU = 0x0b; -this.COMPREHENSIONTLV_TAG_TEXT_STRING = 0x0d; -this.COMPREHENSIONTLV_TAG_TONE = 0x0e; -this.COMPREHENSIONTLV_TAG_ITEM = 0x0f; -this.COMPREHENSIONTLV_TAG_ITEM_ID = 0x10; -this.COMPREHENSIONTLV_TAG_RESPONSE_LENGTH = 0x11; -this.COMPREHENSIONTLV_TAG_FILE_LIST = 0x12; -this.COMPREHENSIONTLV_TAG_LOCATION_INFO = 0x13; -this.COMPREHENSIONTLV_TAG_IMEI = 0x14; -this.COMPREHENSIONTLV_TAG_HELP_REQUEST = 0x15; -this.COMPREHENSIONTLV_TAG_NMR = 0x16; -this.COMPREHENSIONTLV_TAG_DEFAULT_TEXT = 0x17; -this.COMPREHENSIONTLV_TAG_NEXT_ACTION_IND = 0x18; -this.COMPREHENSIONTLV_TAG_CAUSE = 0x1a; -this.COMPREHENSIONTLV_TAG_LOCATION_STATUS = 0x1b; -this.COMPREHENSIONTLV_TAG_TRANSACTION_ID = 0x1c; -this.COMPREHENSIONTLV_TAG_EVENT_LIST = 0x19; -this.COMPREHENSIONTLV_TAG_ICON_ID = 0x1e; -this.COMPREHENSIONTLV_TAG_ICON_ID_LIST = 0x1f; -this.COMPREHENSIONTLV_TAG_TIMER_IDENTIFIER = 0x24; -this.COMPREHENSIONTLV_TAG_TIMER_VALUE = 0x25; -this.COMPREHENSIONTLV_TAG_DATE_TIME_ZONE = 0x26; -this.COMPREHENSIONTLV_TAG_IMMEDIATE_RESPONSE = 0x2b; -this.COMPREHENSIONTLV_TAG_LANGUAGE = 0x2d; -this.COMPREHENSIONTLV_TAG_URL = 0x31; -this.COMPREHENSIONTLV_TAG_BROWSER_TERMINATION_CAUSE = 0x34; -this.COMPREHENSIONTLV_TAG_ACCESS_TECH = 0x3f; -this.COMPREHENSIONTLV_TAG_SERVICE_RECORD = 0x41; -this.COMPREHENSIONTLV_TAG_IMEISV = 0x62; -this.COMPREHENSIONTLV_TAG_BATTERY_STATE = 0x63; -this.COMPREHENSIONTLV_TAG_NETWORK_SEARCH_MODE = 0x65; -this.COMPREHENSIONTLV_TAG_MEID = 0x6d; -this.COMPREHENSIONTLV_TAG_BROADCAST_NETWORK_INFO = 0x7a; - -// Tags for Service Provider Display Information TLV -this.SPDI_TAG_SPDI = 0xa3; -this.SPDI_TAG_PLMN_LIST = 0x80; - -// MM INFORMATION message content IEIs -// See 3GPP TS 24.008 table 9.2.18 -this.PNN_IEI_FULL_NETWORK_NAME = 0x43; -this.PNN_IEI_SHORT_NETWORK_NAME = 0x45; - -// Device identifiers, see TS 11.14, clause 12.7 -this.STK_DEVICE_ID_KEYPAD = 0x01; -this.STK_DEVICE_ID_DISPLAY = 0x02; -this.STK_DEVICE_ID_EARPIECE = 0x03; -this.STK_DEVICE_ID_SIM = 0x81; -this.STK_DEVICE_ID_ME = 0x82; -this.STK_DEVICE_ID_NETWORK = 0x83; - -// STK Proactive commands. -this.STK_CMD_REFRESH = 0x01; -this.STK_CMD_MORE_TIME = 0x02; -this.STK_CMD_POLL_INTERVAL = 0x03; -this.STK_CMD_POLL_OFF = 0x04; -this.STK_CMD_SET_UP_EVENT_LIST = 0x05; -this.STK_CMD_SET_UP_CALL = 0x10; -this.STK_CMD_SEND_SS = 0x11; -this.STK_CMD_SEND_USSD = 0x12; -this.STK_CMD_SEND_SMS = 0x13; -this.STK_CMD_SEND_DTMF = 0x14; -this.STK_CMD_LAUNCH_BROWSER = 0x15; -this.STK_CMD_PLAY_TONE = 0x20; -this.STK_CMD_DISPLAY_TEXT = 0x21; -this.STK_CMD_GET_INKEY = 0x22; -this.STK_CMD_GET_INPUT = 0x23; -this.STK_CMD_SELECT_ITEM = 0x24; -this.STK_CMD_SET_UP_MENU = 0x25; -this.STK_CMD_PROVIDE_LOCAL_INFO = 0x26; -this.STK_CMD_TIMER_MANAGEMENT = 0x27; -this.STK_CMD_SET_UP_IDLE_MODE_TEXT = 0x28; -this.STK_CMD_OPEN_CHANNEL = 0x40; -this.STK_CMD_CLOSE_CHANNEL = 0x41; -this.STK_CMD_RECEIVE_DATA = 0x42; -this.STK_CMD_SEND_DATA = 0x43; - -// STK Result code. -// TS 11.14, clause 12.12 - -// Results '0X' and '1X' indicate that the command has been performed. - -// Command performed successfully. -this.STK_RESULT_OK = 0x00; - -// Command performed with partial comprehension. -this.STK_RESULT_PRFRMD_WITH_PARTIAL_COMPREHENSION = 0x01; - -// Command performed, with missing information. -this.STK_RESULT_PRFRMD_WITH_MISSING_INFO = 0x02; - -// REFRESH performed with additional EFs read. -this.STK_RESULT_PRFRMD_WITH_ADDITIONAL_EFS_READ = 0x03; - -// Command performed successfully, but requested icon could not be -// displayed. -this.STK_RESULT_PRFRMD_ICON_NOT_DISPLAYED = 0x04; - -// Command performed, but modified by call control by NAA. -this.STK_RESULT_PRFRMD_MODIFIED_BY_NAA = 0x05; - -// Command performed successfully, limited service. -this.STK_RESULT_PRFRMD_LIMITED_SERVICE = 0x06; - -// Command performed with modification. -this.STK_RESULT_PRFRMD_WITH_MODIFICATION = 0x07; - -// REFRESH performed but indicated NAA was not active. -this.STK_RESULT_PRFRMD_NAA_NOT_ACTIVE = 0x08; - -// Command performed successfully; tone not played. -this.STK_RESULT_PRFRMD_TONE_NOT_PLAYED = 0x09; - -// Proactive UICC session terminated by the user. -this.STK_RESULT_UICC_SESSION_TERM_BY_USER = 0x10; - -// Backward move in the proactive UICC session requested by the user. -this.STK_RESULT_BACKWARD_MOVE_BY_USER = 0x11; - -// No response from user. -this.STK_RESULT_NO_RESPONSE_FROM_USER = 0x12; - -// Help information required by the user. -this.STK_RESULT_HELP_INFO_REQUIRED = 0x13; - -// USSD or SS transaction terminated by the user. -this.STK_RESULT_USSD_SS_SESSION_TERM_BY_USER = 0x14; - -// Results '2X' indicate to the UICC that it may be worth re-trying the -// command at a later opportunity. - -// Terminal currently unable to process command. -this.STK_RESULT_TERMINAL_CRNTLY_UNABLE_TO_PROCESS = 0x20; - -// Network currently unable to process command. -this.STK_RESULT_NETWORK_CRNTLY_UNABLE_TO_PROCESS = 0x21; - -// User did not accept the proactive command. -this.STK_RESULT_USER_NOT_ACCEPT = 0x22; - -// User cleared down call before connection or network release. -this.STK_RESULT_USER_CLEAR_DOWN_CALL = 0x23; - -// Action in contradiction with the current timer state. -this.STK_RESULT_CONTRADICTION_WITH_TIMER = 0x24; - -// Interaction with call control by NAA; temporary problem. -this.STK_RESULT_NAA_CALL_CONTROL_TEMPORARY = 0x25; - -// Launch browser generic error code. -this.STK_RESULT_LAUNCH_BROWSER_ERROR = 0x26; - -// MMS temporary problem. -this.STK_RESULT_MMS_TEMPORARY = 0x27; - -// Results '3X' indicate that it is not worth the UICC re-trying with an -// identical command; as it will only get the same response. However, the -// decision to retry lies with the application. - -// Command beyond terminal's capabilities. -this.STK_RESULT_BEYOND_TERMINAL_CAPABILITY = 0x30; - -// Command type not understood by terminal. -this.STK_RESULT_CMD_TYPE_NOT_UNDERSTOOD = 0x31; - -// Command data not understood by terminal. -this.STK_RESULT_CMD_DATA_NOT_UNDERSTOOD = 0x32; - -// Command number not known by terminal. -this.STK_RESULT_CMD_NUM_NOT_KNOWN = 0x33; - -// SS Return Error. -this.STK_RESULT_SS_RETURN_ERROR = 0x34; - -// SMS RP-ERROR. -this.STK_RESULT_SMS_RP_ERROR = 0x35; - -// Error, required values are missing. -this.STK_RESULT_REQUIRED_VALUES_MISSING = 0x36; - -// USSD Return Error. -this.STK_RESULT_USSD_RETURN_ERROR = 0x37; - -// MultipleCard commands error. -this.STK_RESULT_MULTI_CARDS_CMD_ERROR = 0x38; - -// Interaction with call control by USIM or MO short message control by -// USIM; permanent problem. -this.STK_RESULT_USIM_CALL_CONTROL_PERMANENT = 0x39; - -// Bearer Independent Protocol error. -this.STK_RESULT_BIP_ERROR = 0x3a; - -// Access Technology unable to process command. -this.STK_RESULT_ACCESS_TECH_UNABLE_TO_PROCESS = 0x3b; - -// Frames error. -this.STK_RESULT_FRAMES_ERROR = 0x3c; - -// MMS Error. -this.STK_RESULT_MMS_ERROR = 0x3d; - -// STK presentation types, TS 11.14, clause 12.6, Command Qualifier: Select Item -this.STK_PRESENTATION_TYPE_NOT_SPECIFIED = 0x00; // Bit 1 is 0. -this.STK_PRESENTATION_TYPE_DATA_VALUES = 0x01; // Bit 1 is 1, bit 2 is 0. -this.STK_PRESENTATION_TYPE_NAVIGATION_OPTIONS = 0x03; // Bit 1 is 1, bit 2 is 1. - -// STK Coding Scheme. -this.STK_TEXT_CODING_GSM_7BIT_PACKED = 0x00; -this.STK_TEXT_CODING_GSM_8BIT = 0x04; -this.STK_TEXT_CODING_UCS2 = 0x08; - -// STK Event List. -this.STK_EVENT_TYPE_MT_CALL = 0x00; -this.STK_EVENT_TYPE_CALL_CONNECTED = 0x01; -this.STK_EVENT_TYPE_CALL_DISCONNECTED = 0x02; -this.STK_EVENT_TYPE_LOCATION_STATUS = 0x03; -this.STK_EVENT_TYPE_USER_ACTIVITY = 0x04; -this.STK_EVENT_TYPE_IDLE_SCREEN_AVAILABLE = 0x05; -this.STK_EVENT_TYPE_CARD_READER_STATUS = 0x06; -this.STK_EVENT_TYPE_LANGUAGE_SELECTION = 0x07; -this.STK_EVENT_TYPE_BROWSER_TERMINATION = 0x08; -this.STK_EVENT_TYPE_DATA_AVAILABLE = 0x09; -this.STK_EVENT_TYPE_CHANNEL_STATUS = 0x0a; -this.STK_EVENT_TYPE_SINGLE_ACCESS_TECHNOLOGY_CHANGED = 0x0b; -this.STK_EVENT_TYPE_DISPLAY_PARAMETER_CHANGED = 0x0c; -this.STK_EVENT_TYPE_LOCAL_CONNECTION = 0x0d; -this.STK_EVENT_TYPE_NETWORK_SEARCH_MODE_CHANGED = 0x0e; -this.STK_EVENT_TYPE_BROWSING_STATUS = 0x0f; - -// STK Service state of Location Status. -this.STK_SERVICE_STATE_NORMAL = 0x00; -this.STK_SERVICE_STATE_LIMITED = 0x01; -this.STK_SERVICE_STATE_UNAVAILABLE = 0x02; - -// Refresh mode. -this.STK_REFRESH_NAA_INIT_AND_FULL_FILE_CHANGE = 0x00; -this.STK_REFRESH_FILE_CHANGE = 0x01; -this.STK_REFRESH_NAA_INIT_AND_FILE_CHANGE = 0x02; -this.STK_REFRESH_NAA_INIT = 0x03; -this.STK_REFRESH_UICC_RESET = 0x04; - -// Tone type. -this.STK_TONE_TYPE_DIAL_TONE = 0x01; -this.STK_TONE_TYPE_CALLED_SUBSCRIBER_BUSY = 0x02; -this.STK_TONE_TYPE_CONGESTION = 0x03; -this.STK_TONE_TYPE_RADIO_PATH_ACK = 0x04; -this.STK_TONE_TYPE_RADIO_PATH_NOT_AVAILABLE = 0x05; -this.STK_TONE_TYPE_ERROR = 0x06; -this.STK_TONE_TYPE_CALL_WAITING_TONE = 0x07; -this.STK_TONE_TYPE_RINGING_TONE = 0x08; -this.STK_TONE_TYPE_GENERAL_BEEP = 0x10; -this.STK_TONE_TYPE_POSITIVE_ACK_TONE = 0x11; -this.STK_TONE_TYPE_NEGATIVE_ACK_TONE = 0x12; - -// Time unit. -this.STK_TIME_UNIT_MINUTE = 0x00; -this.STK_TIME_UNIT_SECOND = 0x01; -this.STK_TIME_UNIT_TENTH_SECOND = 0x02; - -// Local Information type. -this.STK_LOCAL_INFO_NNA = 0x00; -this.STK_LOCAL_INFO_IMEI = 0x01; -this.STK_LOCAL_INFO_NMR_FOR_NNA = 0x02; -this.STK_LOCAL_INFO_DATE_TIME_ZONE = 0x03; -this.STK_LOCAL_INFO_LANGUAGE = 0x04; -this.STK_LOCAL_INFO_ACCESS_TECH = 0x06; -this.STK_LOCAL_INFO_ESN = 0x07; -this.STK_LOCAL_INFO_IMEISV = 0x08; -this.STK_LOCAL_INFO_SEARCH_MODE = 0x09; -this.STK_LOCAL_INFO_CHARGE_STATE = 0x0A; -this.STK_LOCAL_INFO_MEID = 0x0B; -this.STK_LOCAL_INFO_BROADCAST_NETWORK_INFO = 0x0D; -this.STK_LOCAL_INFO_MULTIPLE_ACCESS_TECH = 0x0E; -this.STK_LOCAL_INFO_INFO_FOR_MULTIPLE_ACCESS_TECH = 0x0F; -this.STK_LOCAL_INFO_NMR_FOR_MULTIPLE_ACCESS_TECH = 0x10; - -// Timer Management. -this.STK_TIMER_START = 0x00; -this.STK_TIMER_DEACTIVATE = 0x01; -this.STK_TMIER_GET_CURRENT_VALUE = 0x02; - -// Browser Launch Mode. -this.STK_BROWSER_MODE_LAUNCH_IF_NOT_ALREADY_LAUNCHED = 0x00; -this.STK_BROWSER_MODE_USING_EXISTING_BROWSER = 0x02; -this.STK_BROWSER_MODE_USING_NEW_BROWSER = 0x03; - -// Browser Termination Cause. -this.STK_BROWSER_TERMINATION_CAUSE_USER = 0x00; -this.STK_BROWSER_TERMINATION_CAUSE_ERROR = 0x01; - -// Next Action Indicator. -this.STK_NEXT_ACTION_NULL = 0x00; -this.STK_NEXT_ACTION_END_PROACTIVE_SESSION = 0x81; - -/** - * Supported Terminal Facilities. - * - * value = 1, supported. - * 0, not supported. - */ -this.STK_TERMINAL_SUPPORT_PROFILE_DOWNLOAD = 1; -this.STK_TERMINAL_SUPPORT_SMS_PP_DOWNLOAD = 1; -this.STK_TERMINAL_SUPPORT_CELL_BROADCAST_DATA_DOWNLOAD = 0; -this.STK_TERMINAL_SUPPORT_MENU_SELECTION = 1; -this.STK_TERMINAL_SUPPORT_SIM_DATA_DOWNLOAD_ERROR = 0; -this.STK_TERMINAL_SUPPORT_TIMER_EXPIRATION = 1; -this.STK_TERMINAL_SUPPORT_USSD_IN_CALL_CONTROL = 0; -this.STK_TERMINAL_SUPPORT_CALL_CONTROL_IN_REDIAL = 0; - -this.STK_TERMINAL_SUPPORT_COMMAND_RESULT = 1; -this.STK_TERMINAL_SUPPORT_CALL_CONTROL = 1; -this.STK_TERMINAL_SUPPORT_CALL_ID_INCLUDED = 0; -this.STK_TERMINAL_SUPPORT_MO_SMS_CONTROL = 0; -this.STK_TERMINAL_SUPPORT_ALPHA_ID_INDICATION = 0; -this.STK_TERMINAL_SUPPORT_UCS2_ENTRY = 1; -this.STK_TERMINAL_SUPPORT_UCS2_DISPLAY = 1; -this.STK_TERMINAL_SUPPORT_EXTENSION_TEXT = 1; - -this.STK_TERMINAL_SUPPORT_PROACTIVE_DISPLAY_TEXT = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_GET_INKEY = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_GET_INPUT = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_MORE_TIME = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_PLAY_TONE = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_POLL_INTERVAL = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_POLL_OFF = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_REFRESH = 1; - -this.STK_TERMINAL_SUPPORT_PROACTIVE_SELECT_ITEM = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_SEND_SMS = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_SEND_SS = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_SEND_USSD = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_SET_UP_CALL = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_SET_UP_MENU = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_NMR = 0; - -this.STK_TERMINAL_SUPPORT_PROACTIVE_SET_UP_EVENT_LIST = 1; -this.STK_TERMINAL_SUPPORT_EVENT_MT_CALL = 1; -this.STK_TERMINAL_SUPPORT_EVENT_CALL_CONNECTED = 1; -this.STK_TERMINAL_SUPPORT_EVENT_CALL_DISCONNECTED = 1; -this.STK_TERMINAL_SUPPORT_EVENT_LOCATION_STATUS = 1; -this.STK_TERMINAL_SUPPORT_EVENT_USER_ACTIVITY = 1; -this.STK_TERMINAL_SUPPORT_EVENT_IDLE_SCREEN_AVAILABLE = 1; -this.STK_TERMINAL_SUPPORT_EVENT_CARD_READER_STATUS = 0; - -this.STK_TERMINAL_SUPPORT_EVENT_LANGUAGE_SELECTION = 1; -this.STK_TERMINAL_SUPPORT_EVENT_BROWSER_TERMINATION = 1; -this.STK_TERMINAL_SUPPORT_EVENT_DATA_AVAILABLE = 0; -this.STK_TERMINAL_SUPPORT_EVENT_CHANNEL_STATUS = 0; - -this.STK_TERMINAL_SUPPORT_PROACTIVE_TIMER_START_STOP = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_TIMER_GET_CURRENT = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_DATE = 1; -this.STK_TERMINAL_SUPPORT_GET_INKEY = 1; -this.STK_TERMINAL_SUPPORT_SET_UP_IDLE_MODE_TEXT = 1; -this.STK_TERMINAL_SUPPORT_RUN_AT_COMMAND = 0; -this.STK_TERMINAL_SUPPORT_SET_UP_CALL = 1; -this.STK_TERMINAL_SUPPORT_CALL_CONTROL_BY_NNA = 0; - -this.STK_TERMINAL_SUPPORT_DISPLAY_TEXT = 1; -this.STK_TERMINAL_SUPPORT_SEND_DTMF_COMMAND = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_NMR = 0; -this.STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_LANGUAGE = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_TIME_ADVANCE = 0; -this.STK_TERMINAL_SUPPORT_PROACTIVE_LANGUAGE_NOTIFICATION = 0; -this.STK_TERMINAL_SUPPORT_PROACTIVE_LAUNCH_BROWSER = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_ACCESS_TECH = 0; - -this.STK_TERMINAL_SUPPORT_BIP_COMMAND_OPEN_CHANNEL = 1; -this.STK_TERMINAL_SUPPORT_BIP_COMMAND_CLOSE_CHANNEL = 1; -this.STK_TERMINAL_SUPPORT_BIP_COMMAND_RECEIVE_DATA = 1; -this.STK_TERMINAL_SUPPORT_BIP_COMMAND_SEND_DATA = 1; -this.STK_TERMINAL_SUPPORT_BIP_COMMAND_GET_CHANNEL_STATUS = 0; - -/** - * SAT profile - * - * @see ETSI TS 101.267, section 5.2. - */ -this.STK_TERMINAL_PROFILE_DOWNLOAD = - (STK_TERMINAL_SUPPORT_PROFILE_DOWNLOAD << 0) | - (STK_TERMINAL_SUPPORT_SMS_PP_DOWNLOAD << 1) | - (STK_TERMINAL_SUPPORT_CELL_BROADCAST_DATA_DOWNLOAD << 2) | - (STK_TERMINAL_SUPPORT_MENU_SELECTION << 3) | - (STK_TERMINAL_SUPPORT_SIM_DATA_DOWNLOAD_ERROR << 4) | - (STK_TERMINAL_SUPPORT_TIMER_EXPIRATION << 5) | - (STK_TERMINAL_SUPPORT_USSD_IN_CALL_CONTROL << 6) | - (STK_TERMINAL_SUPPORT_CALL_CONTROL_IN_REDIAL << 7); - -this.STK_TERMINAL_PROFILE_OTHER = - (STK_TERMINAL_SUPPORT_COMMAND_RESULT << 0) | - (STK_TERMINAL_SUPPORT_CALL_CONTROL << 1) | - (STK_TERMINAL_SUPPORT_CALL_ID_INCLUDED << 2) | - (STK_TERMINAL_SUPPORT_MO_SMS_CONTROL << 3) | - (STK_TERMINAL_SUPPORT_ALPHA_ID_INDICATION << 4) | - (STK_TERMINAL_SUPPORT_UCS2_ENTRY << 5) | - (STK_TERMINAL_SUPPORT_UCS2_DISPLAY << 6) | - (STK_TERMINAL_SUPPORT_EXTENSION_TEXT << 7); - -this.STK_TERMINAL_PROFILE_PROACTIVE_1 = - (STK_TERMINAL_SUPPORT_PROACTIVE_DISPLAY_TEXT << 0) | - (STK_TERMINAL_SUPPORT_PROACTIVE_GET_INKEY << 1) | - (STK_TERMINAL_SUPPORT_PROACTIVE_GET_INPUT << 2) | - (STK_TERMINAL_SUPPORT_PROACTIVE_MORE_TIME << 3) | - (STK_TERMINAL_SUPPORT_PROACTIVE_PLAY_TONE << 4) | - (STK_TERMINAL_SUPPORT_PROACTIVE_POLL_INTERVAL << 5) | - (STK_TERMINAL_SUPPORT_PROACTIVE_POLL_OFF << 6) | - (STK_TERMINAL_SUPPORT_PROACTIVE_REFRESH << 7); - -this.STK_TERMINAL_PROFILE_PROACTIVE_2 = - (STK_TERMINAL_SUPPORT_PROACTIVE_SELECT_ITEM << 0) | - (STK_TERMINAL_SUPPORT_PROACTIVE_SEND_SMS << 1) | - (STK_TERMINAL_SUPPORT_PROACTIVE_SEND_SS << 2) | - (STK_TERMINAL_SUPPORT_PROACTIVE_SEND_USSD << 3) | - (STK_TERMINAL_SUPPORT_PROACTIVE_SET_UP_CALL << 4) | - (STK_TERMINAL_SUPPORT_PROACTIVE_SET_UP_MENU << 5) | - (STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO << 6) | - (STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_NMR << 7); - -this.STK_TERMINAL_PROFILE_EVENT = - (STK_TERMINAL_SUPPORT_PROACTIVE_SET_UP_EVENT_LIST << 0) | - (STK_TERMINAL_SUPPORT_EVENT_MT_CALL << 1) | - (STK_TERMINAL_SUPPORT_EVENT_CALL_CONNECTED << 2) | - (STK_TERMINAL_SUPPORT_EVENT_CALL_DISCONNECTED << 3) | - (STK_TERMINAL_SUPPORT_EVENT_LOCATION_STATUS << 4) | - (STK_TERMINAL_SUPPORT_EVENT_USER_ACTIVITY << 5) | - (STK_TERMINAL_SUPPORT_EVENT_IDLE_SCREEN_AVAILABLE << 6) | - (STK_TERMINAL_SUPPORT_EVENT_CARD_READER_STATUS << 7); - -this.STK_TERMINAL_PROFILE_EVENT_EXT = - (STK_TERMINAL_SUPPORT_EVENT_LANGUAGE_SELECTION << 0) | - (STK_TERMINAL_SUPPORT_EVENT_BROWSER_TERMINATION << 1) | - (STK_TERMINAL_SUPPORT_EVENT_DATA_AVAILABLE << 2) | - (STK_TERMINAL_SUPPORT_EVENT_CHANNEL_STATUS << 3); - -this.STK_TERMINAL_PROFILE_PROACTIVE_3 = - (STK_TERMINAL_SUPPORT_PROACTIVE_TIMER_START_STOP << 0) | - (STK_TERMINAL_SUPPORT_PROACTIVE_TIMER_GET_CURRENT << 1) | - (STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_DATE << 2) | - (STK_TERMINAL_SUPPORT_GET_INKEY << 3) | - (STK_TERMINAL_SUPPORT_SET_UP_IDLE_MODE_TEXT << 4) | - (STK_TERMINAL_SUPPORT_RUN_AT_COMMAND << 5) | - (STK_TERMINAL_SUPPORT_SET_UP_CALL << 6) | - (STK_TERMINAL_SUPPORT_CALL_CONTROL_BY_NNA << 7); - -this.STK_TERMINAL_PROFILE_PROACTIVE_4 = - (STK_TERMINAL_SUPPORT_DISPLAY_TEXT << 0) | - (STK_TERMINAL_SUPPORT_SEND_DTMF_COMMAND << 1) | - (STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_NMR << 2) | - (STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_LANGUAGE << 3) | - (STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_TIME_ADVANCE << 4) | - (STK_TERMINAL_SUPPORT_PROACTIVE_LANGUAGE_NOTIFICATION << 5) | - (STK_TERMINAL_SUPPORT_PROACTIVE_LAUNCH_BROWSER << 6) | - (STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_ACCESS_TECH << 7); - -this.STK_TERMINAL_PROFILE_BIP_COMMAND = - (STK_TERMINAL_SUPPORT_BIP_COMMAND_OPEN_CHANNEL << 0) | - (STK_TERMINAL_SUPPORT_BIP_COMMAND_CLOSE_CHANNEL << 1) | - (STK_TERMINAL_SUPPORT_BIP_COMMAND_RECEIVE_DATA << 2) | - (STK_TERMINAL_SUPPORT_BIP_COMMAND_SEND_DATA << 3) | - (STK_TERMINAL_SUPPORT_BIP_COMMAND_GET_CHANNEL_STATUS << 4); - -this.STK_SUPPORTED_TERMINAL_PROFILE = [ - STK_TERMINAL_PROFILE_DOWNLOAD, - STK_TERMINAL_PROFILE_OTHER, - STK_TERMINAL_PROFILE_PROACTIVE_1, - STK_TERMINAL_PROFILE_PROACTIVE_2, - STK_TERMINAL_PROFILE_EVENT, - STK_TERMINAL_PROFILE_EVENT_EXT, // Event extension - 0x00, // Multiple card proactive commands - STK_TERMINAL_PROFILE_PROACTIVE_3, - STK_TERMINAL_PROFILE_PROACTIVE_4, - 0x00, // Softkey support - 0x00, // Softkey information - STK_TERMINAL_PROFILE_BIP_COMMAND, - 0x00, // BIP supported bearers - 0x00, // Screen height - 0x00, // Screen width - 0x00, // 16, Screen effects - 0x00, // 17, BIP supported transport interface - 0x00, // 18, RFU - 0x00, // 19, RFU - 0x00, // 20, RFU -]; - -/** - * ICC Services Table. - * - * @see 3GPP TS 51.011 10.3.7 (SIM) and 3GPP TS 31.102 4.2.8 (USIM). - */ -this.GECKO_ICC_SERVICES = { - // @see 3GPP TS 51.011 10.3.7 (SIM). - sim: { - ADN: 2, - FDN: 3, - PLMNSEL: 7, - MSISDN: 9, - EXT1: 10, - EXT2: 11, - CBMI: 14, - GID1: 15, - SPN: 17, - SDN: 18, - EXT3: 19, - DATA_DOWNLOAD_SMS_CB: 25, - DATA_DOWNLOAD_SMS_PP: 26, - CBMIR: 30, - BDN: 31, - IMG: 39, - PNN: 51, - OPL: 52, - MDN: 53, - MWIS: 54, - SPDI: 56 - }, - // @see 3GPP TS 31.102 4.2.8 (USIM). - usim: { - FDN: 2, - EXT2: 3, - SDN: 4, - EXT3: 5, - BDN: 6, - CBMI: 15, - CBMIR: 16, - GID1: 17, - SPN: 19, - MSISDN: 21, - IMG: 22, - DATA_DOWNLOAD_SMS_PP: 28, - DATA_DOWNLOAD_SMS_CB: 29, - PNN: 45, - OPL: 46, - MDN: 47, - MWIS: 48, - SPDI: 51 - }, - // @see 3GPP2 C.S0023-D 3.4.18 (RUIM). - ruim: { - FDN: 3, - ENHANCED_PHONEBOOK: 6, - EXT1: 10, - EXT2: 11, - SPN: 17, - SDN: 18, - EXT3: 19, - }, - // @see B.3.1.1 CPHS Information in CPHS Phase 2: - // Indicates which of the CPHS 'optional' data-fields are present in the SIM card: - // EF_CPHS_CSP, EF_CPHS_SST, EF_CPHS_MBN, EF_CPHS_ONSF, EF_CPHS_INFO_NUM - // Note: Mandatory EFs are: (B.3.1 Enhanced SIM Requirements) - // EF_CPHS_CFF, EF_CPHS_VMI, EF_CPHS_ONS, EF_CPHS_INFO - cphs: { - CSP: 1, - SST: 2, - MBN: 3, - ONSF: 4, - INFO_NUM: 5 - } -}; - -/** - * Cell Broadcast constants - */ - -this.CB_FORMAT_GSM = 0; -this.CB_FORMAT_ETWS = 1; -this.CB_FORMAT_CMAS = 2; -this.CB_FORMAT_UMTS = 3; - -// CBS Data Coding Scheme: Language groups -// see 3GPP TS 23.038 section 5 -this.CB_DCS_LANG_GROUP_1 = [ - "de", "en", "it", "fr", "es", "nl", "sv", "da", "pt", "fi", - "no", "el", "tr", "hu", "pl", null -]; -this.CB_DCS_LANG_GROUP_2 = [ - "cs", "he", "ar", "ru", "is", null, null, null, null, null, - null, null, null, null, null, null -]; - -// See 3GPP TS 23.041 v11.2.0 section 9.4.1.2.2 -this.CB_NON_MMI_SETTABLE_RANGES = [ - /*0x1000 - 0x107F*/4096, 4224, /*0x1080 - 0x10FF*/4224, 4352, - /*0x1112 - 0x1112*/4370, 4371, /*0x111F - 0x111F*/4383, 4384, - /*0xF000 - 0xFFFE*/61440, 65535, /*0xFFFF - 0xFFFF*/65535, 65536 -]; - -// User Data max length in septets -this.CB_MAX_CONTENT_7BIT = 93; -// User Data max length in octets -this.CB_MAX_CONTENT_8BIT = 82; -// User Data max length in chars -this.CB_MAX_CONTENT_UCS2 = 41; - -// See 3GPP TS 23.041 v11.6.0 senction 9.3.19 -this.CB_MSG_PAGE_INFO_SIZE = 82; - -this.CB_MESSAGE_SIZE_ETWS = 56; -this.CB_MESSAGE_SIZE_GSM = 88; -this.CB_MESSAGE_SIZE_UMTS_MIN = 90; -this.CB_MESSAGE_SIZE_UMTS_MAX = 1252; - - - -// GSM Cell Broadcast Geographical Scope -// See 3GPP TS 23.041 clause 9.4.1.2.1 -this.CB_GSM_GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE = 0; -this.CB_GSM_GEOGRAPHICAL_SCOPE_PLMN_WIDE = 1; -this.CB_GSM_GEOGRAPHICAL_SCOPE_LOCATION_AREA_WIDE = 2; -this.CB_GSM_GEOGRAPHICAL_SCOPE_CELL_WIDE = 3; - -// GSM Cell Broadcast Geographical Scope -// See 3GPP TS 23.041 clause 9.4.1.2.1 -this.CB_GSM_GEOGRAPHICAL_SCOPE_NAMES = [ - "cell-immediate", - "plmn", - "location-area", - "cell" -]; - -// GSM Cell Broadcast Message Identifiers -// see 3GPP TS 23.041 clause 9.4.1.2.2 -this.CB_GSM_MESSAGEID_ETWS_BEGIN = 0x1100; -this.CB_GSM_MESSAGEID_ETWS_END = 0x1107; - -// ETWS Warning-Type -// see 3GPP TS 23.041 clause 9.3.24 -this.CB_ETWS_WARNING_TYPE_NAMES = [ - "earthquake", - "tsunami", - "earthquake-tsunami", - "test", - "other" -]; - -// UMTS Message Type -// see 3GPP TS 25.324 section 11.1 -this.CB_UMTS_MESSAGE_TYPE_CBS = 1; -this.CB_UMTS_MESSAGE_TYPE_SCHEDULE = 2; -this.CB_UMTS_MESSAGE_TYPE_CBS41 = 3; - -/** - * Number plan identification defined in - * |Table 10.5.118: Called party BCD number| of 3GPP TS 24.008. - */ -this.CALLED_PARTY_BCD_NPI_UNKNOWN = 0; -this.CALLED_PARTY_BCD_NPI_ISDN = 1; -this.CALLED_PARTY_BCD_NPI_DATA = 3; -this.CALLED_PARTY_BCD_NPI_TELEX = 4; -this.CALLED_PARTY_BCD_NPI_NATIONAL = 8; -this.CALLED_PARTY_BCD_NPI_PRIVATE = 9; - -/** - * Array of number plan identification values which can be used to map an - * enumeration to the corresponding value. The indices should be consistent - * with nsISmsService::NUMBER_PLAN_IDENTIFICATION_* constants. - */ -this.CALLED_PARTY_BCD_NPI = [ - CALLED_PARTY_BCD_NPI_UNKNOWN, - CALLED_PARTY_BCD_NPI_ISDN, - CALLED_PARTY_BCD_NPI_DATA, - CALLED_PARTY_BCD_NPI_TELEX, - CALLED_PARTY_BCD_NPI_NATIONAL, - CALLED_PARTY_BCD_NPI_PRIVATE -]; - -/** - * GSM PDU constants - */ - -// PDU TYPE-OF-ADDRESS -this.PDU_TOA_UNKNOWN = 0x80; // Unknown. This is used when the user or - // network has no a priori information - // about the numbering plan. -this.PDU_TOA_ISDN = 0x81; // ISDN/Telephone numbering -this.PDU_TOA_DATA_NUM = 0x83; // Data numbering plan -this.PDU_TOA_TELEX_NUM = 0x84; // Telex numbering plan -this.PDU_TOA_NATIONAL_NUM = 0x88; // National numbering plan -this.PDU_TOA_PRIVATE_NUM = 0x89; // Private numbering plan -this.PDU_TOA_ERMES_NUM = 0x8A; // Ermes numbering plan -this.PDU_TOA_INTERNATIONAL = 0x90; // International number -this.PDU_TOA_NATIONAL = 0xA0; // National number. Prefix or escape digits - // shall not be included -this.PDU_TOA_NETWORK_SPEC = 0xB0; // Network specific number This is used to - // indicate administration/service number - // specific to the serving network -this.PDU_TOA_SUBSCRIBER = 0xC0; // Subscriber number. This is used when a - // specific short number representation is - // stored in one or more SCs as part of a - // higher layer application -this.PDU_TOA_ALPHANUMERIC = 0xD0; // Alphanumeric, (coded according to GSM TS - // 03.38 7-bit default alphabet) -this.PDU_TOA_ABBREVIATED = 0xE0; // Abbreviated number - -/** - * First octet of the SMS-DELIVER PDU - * - * RP: 0 Reply Path parameter is not set in this PDU - * 1 Reply Path parameter is set in this PDU - * - * UDHI: 0 The UD field contains only the short message - * 1 The beginning of the UD field contains a header in addition of - * the short message - * - * SRI: (is only set by the SMSC) - * 0 A status report will not be returned to the SME - * 1 A status report will be returned to the SME - * - * MMS: (is only set by the SMSC) - * 0 More messages are waiting for the MS in the SMSC - * 1 No more messages are waiting for the MS in the SMSC - * - * MTI: bit1 bit0 Message type - * 0 0 SMS-DELIVER (SMSC ==> MS) - * 0 0 SMS-DELIVER REPORT (MS ==> SMSC, is generated - * automatically by the M20, after receiving a - * SMS-DELIVER) - * 0 1 SMS-SUBMIT (MS ==> SMSC) - * 0 1 SMS-SUBMIT REPORT (SMSC ==> MS) - * 1 0 SMS-STATUS REPORT (SMSC ==> MS) - * 1 0 SMS-COMMAND (MS ==> SMSC) - * 1 1 Reserved - */ -this.PDU_RP = 0x80; // Reply path. Parameter indicating that - // reply path exists. -this.PDU_UDHI = 0x40; // User data header indicator. This bit is - // set to 1 if the User Data field starts - // with a header -this.PDU_SRI_SRR = 0x20; // Status report indication (SMS-DELIVER) - // or request (SMS-SUBMIT) -this.PDU_VPF_ABSOLUTE = 0x18;// Validity period aboslute format - // (SMS-SUBMIT only) -this.PDU_VPF_RELATIVE = 0x10;// Validity period relative format - // (SMS-SUBMIT only) -this.PDU_VPF_ENHANCED = 0x8; // Validity period enhance format - // (SMS-SUBMIT only) -this.PDU_MMS_RD = 0x04;// More messages to send. (SMS-DELIVER only) or - // Reject duplicates (SMS-SUBMIT only) - -// MTI - Message Type Indicator -this.PDU_MTI_SMS_RESERVED = 0x03; -this.PDU_MTI_SMS_STATUS_REPORT = 0x02; -this.PDU_MTI_SMS_COMMAND = 0x02; -this.PDU_MTI_SMS_SUBMIT = 0x01; -this.PDU_MTI_SMS_DELIVER = 0x00; - -// PI - Parameter Indicator -this.PDU_PI_EXTENSION = 0x80; -this.PDU_PI_USER_DATA_LENGTH = 0x04; -this.PDU_PI_DATA_CODING_SCHEME = 0x02; -this.PDU_PI_PROTOCOL_IDENTIFIER = 0x01; -this.PDU_PI_RESERVED = 0x78; - -// FCS - Failure Cause -// 0...127 see 3GPP TS 24.011 clause E.2 -// 128...255 see 3GPP TS 23.040 clause 9.2.3.22 -// others see 3GPP TS 27.005 clause 3.2.5 -this.PDU_FCS_OK = 0x00; -this.PDU_FCS_PROTOCOL_ERROR = 0x6F; -this.PDU_FCS_MEMORY_CAPACITY_EXCEEDED = 0XD3; -this.PDU_FCS_USAT_BUSY = 0XD4; -this.PDU_FCS_USIM_DATA_DOWNLOAD_ERROR = 0xD5; -this.PDU_FCS_RESERVED = 0xE0; -this.PDU_FCS_UNSPECIFIED = 0xFF; -// Special internal value that means we should not acknowledge an -// incoming text right away, but need to wait for other components -// (e.g. storage) to complete. This can be any value, so long it -// doesn't conflict with the PDU_FCS_* constants above. -this.MOZ_FCS_WAIT_FOR_EXPLICIT_ACK = 0x0F; - -// ST - Status -// Bit 7..0 = 000xxxxx, short message transaction completed -this.PDU_ST_0_RECEIVED = 0x00; -this.PDU_ST_0_FORWARDED_NO_CONFIRM = 0x01; -this.PDU_ST_0_REPLACED_BY_SC = 0x02; -this.PDU_ST_0_RESERVED_BEGIN = 0x03; -this.PDU_ST_0_SC_SPECIFIC_BEGIN = 0x10; -this.PDU_ST_0_SC_SPECIFIC_END = 0x1F; -// Bit 7..0 = 001xxxxx, temporary error, SC still trying to transfer SM -this.PDU_ST_1_CONGESTION = 0x20; -this.PDU_ST_1_SME_BUSY = 0x21; -this.PDU_ST_1_SME_NO_RESPONSE = 0x22; -this.PDU_ST_1_SERVICE_REJECTED = 0x23; -this.PDU_ST_1_QOS_UNAVAILABLE = 0x24; -this.PDU_ST_1_SME_ERROR = 0x25; -this.PDU_ST_1_RESERVED_BEGIN = 0x26; -this.PDU_ST_1_SC_SPECIFIC_BEGIN = 0x30; -this.PDU_ST_1_SC_SPECIFIC_END = 0x3F; -// Bit 7..0 = 010xxxxx, permanent error, SC is not making any more transfer -// attempts -this.PDU_ST_2_RPC_ERROR = 0x40; -this.PDU_ST_2_DEST_INCOMPATIBLE = 0x41; -this.PDU_ST_2_CONNECTION_REJECTED = 0x42; -this.PDU_ST_2_NOT_OBTAINABLE = 0x43; -this.PDU_ST_2_QOS_UNAVAILABLE = 0x44; -this.PDU_ST_2_INTERWORKING_UNAVALIABLE = 0x45; -this.PDU_ST_2_VALIDITY_EXPIRED = 0x46; -this.PDU_ST_2_DELETED_BY_SME = 0x47; -this.PDU_ST_2_DELETED_BY_SC = 0x48; -this.PDU_ST_2_SM_MISSING = 0x49; -this.PDU_ST_2_RESERVED_BEGIN = 0x4A; -this.PDU_ST_2_SC_SPECIFIC_BEGIN = 0x50; -this.PDU_ST_2_SC_SPECIFIC_END = 0x5F; -// Bit 7..0 = 011xxxxx, temporary error, SC is not making any more transfer -// attempts -this.PDU_ST_3_CONGESTION = 0x60; -this.PDU_ST_3_SME_BUSY = 0x61; -this.PDU_ST_3_SME_NO_RESPONSE = 0x62; -this.PDU_ST_3_SERVICE_REJECTED = 0x63; -this.PDU_ST_3_QOS_UNAVAILABLE = 0x64; -this.PDU_ST_3_SME_ERROR = 0x65; -this.PDU_ST_3_RESERVED_BEGIN = 0x66; -this.PDU_ST_3_SC_SPECIFIC_BEGIN = 0x70; -this.PDU_ST_3_SC_SPECIFIC_END = 0x7F; - -this.GECKO_SMS_DELIVERY_STATUS_NOT_APPLICABLE = "not-applicable"; -this.GECKO_SMS_DELIVERY_STATUS_SUCCESS = "success"; -this.GECKO_SMS_DELIVERY_STATUS_PENDING = "pending"; -this.GECKO_SMS_DELIVERY_STATUS_ERROR = "error"; - -// User Data max length in septets -this.PDU_MAX_USER_DATA_7BIT = 160; -// User Data max length in octets -this.PDU_MAX_USER_DATA_8BIT = 140; -// User Data max length in chars -this.PDU_MAX_USER_DATA_UCS2 = 70; - -// PID - Protocol Indicator -this.PDU_PID_DEFAULT = 0x00; -this.PDU_PID_TELEMATIC_INTERWORKING = 0x20; -this.PDU_PID_SHORT_MESSAGE_TYPE_0 = 0x40; -this.PDU_PID_REPLACE_SHORT_MESSAGE_TYPE_1 = 0x41; -this.PDU_PID_REPLACE_SHORT_MESSAGE_TYPE_2 = 0x42; -this.PDU_PID_REPLACE_SHORT_MESSAGE_TYPE_3 = 0x43; -this.PDU_PID_REPLACE_SHORT_MESSAGE_TYPE_4 = 0x44; -this.PDU_PID_REPLACE_SHORT_MESSAGE_TYPE_5 = 0x45; -this.PDU_PID_REPLACE_SHORT_MESSAGE_TYPE_6 = 0x46; -this.PDU_PID_REPLACE_SHORT_MESSAGE_TYPE_7 = 0x47; -this.PDU_PID_ENHANDED_MESSAGE_SERVICE = 0x5E; -this.PDU_PID_RETURN_CALL_MESSAGE = 0x5F; -this.PDU_PID_ANSI_136_R_DATA = 0x7C; -this.PDU_PID_ME_DATA_DOWNLOAD = 0x7D; -this.PDU_PID_ME_DEPERSONALIZATION = 0x7E; -this.PDU_PID_USIM_DATA_DOWNLOAD = 0x7F; - -// DCS - Data Coding Scheme -this.PDU_DCS_MSG_CODING_7BITS_ALPHABET = 0x00; -this.PDU_DCS_MSG_CODING_8BITS_ALPHABET = 0x04; -this.PDU_DCS_MSG_CODING_16BITS_ALPHABET = 0x08; -this.PDU_DCS_MSG_CLASS_0 = 0x00; -this.PDU_DCS_MSG_CLASS_1 = 0x01; -this.PDU_DCS_MSG_CLASS_2 = 0x02; -this.PDU_DCS_MSG_CLASS_3 = 0x03; -this.PDU_DCS_MSG_CLASS_USER_1 = 0x04; -this.PDU_DCS_MSG_CLASS_USER_2 = 0x05; -this.PDU_DCS_MSG_CLASS_NORMAL = 0x06; -this.PDU_DCS_CODING_GROUP_BITS = 0xF0; -this.PDU_DCS_MSG_CLASS_BITS = 0x03; -this.PDU_DCS_MWI_ACTIVE_BITS = 0x08; -this.PDU_DCS_MWI_ACTIVE_VALUE = 0x08; -this.PDU_DCS_MWI_TYPE_BITS = 0x03; -this.PDU_DCS_MWI_TYPE_VOICEMAIL = 0x00; -this.PDU_DCS_MWI_TYPE_FAX = 0x01; -this.PDU_DCS_MWI_TYPE_EMAIL = 0x02; -this.PDU_DCS_MWI_TYPE_OTHER = 0x03; - -// Set as Array instead of Object for reversed-mapping with Array.indexOf(). -this.GECKO_SMS_MESSAGE_CLASSES = []; -GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0] = "class-0"; -GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_1] = "class-1"; -GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2] = "class-2"; -GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_3] = "class-3"; -GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_USER_1] = "user-1"; -GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_USER_2] = "user-2"; -GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL] = "normal"; - -// Because service center timestamp omit the century. Yay. -this.PDU_TIMESTAMP_YEAR_OFFSET = 2000; - -// See 9.2.3.24 TP‑User Data (TP‑UD) -this.PDU_IEI_CONCATENATED_SHORT_MESSAGES_8BIT = 0x00; -this.PDU_IEI_SPECIAL_SMS_MESSAGE_INDICATION = 0x01; -this.PDU_IEI_APPLICATION_PORT_ADDRESSING_SCHEME_8BIT = 0x04; -this.PDU_IEI_APPLICATION_PORT_ADDRESSING_SCHEME_16BIT = 0x05; -this.PDU_IEI_SMSC_CONTROL_PARAMS = 0x06; -this.PDU_IEI_UDH_SOURCE_INDICATOR = 0x07; -this.PDU_IEI_CONCATENATED_SHORT_MESSAGES_16BIT = 0x08; -this.PDU_IEI_WIRELESS_CONTROL_MESSAGE_PROTOCOL = 0x09; -this.PDU_IEI_TEXT_FORMATING = 0x0A; -this.PDU_IEI_PREDEFINED_SOUND = 0x0B; -this.PDU_IEI_USER_DATA_SOUND = 0x0C; -this.PDU_IEI_PREDEFINED_ANIMATION = 0x0D; -this.PDU_IEI_LARGE_ANIMATION = 0x0E; -this.PDU_IEI_SMALL_ANIMATION = 0x0F; -this.PDU_IEI_LARGE_PICTURE = 0x10; -this.PDU_IEI_SMALL_PICTURE = 0x11; -this.PDU_IEI_VARIABLE_PICTURE = 0x12; -this.PDU_IEI_USER_PROMPT_INDICATOR = 0x13; -this.PDU_IEI_EXTENDED_OBJECT = 0x14; -this.PDU_IEI_REUSED_EXTENDED_OBJECT = 0x15; -this.PDU_IEI_COMPRESS_CONTROL = 0x16; -this.PDU_IEI_OBJECT_DISTRIBUTION_INDICATOR = 0x17; -this.PDU_IEI_STANDARD_WVG_OBJECT = 0x18; -this.PDU_IEI_CHARACTER_SIZE_WVG_OBJECT = 0x19; -this.PDU_IEI_EXTENDED_OBJECT_DATA_REQUEST_COMMAND = 0x1A; -this.PDU_IEI_RFC822_EMAIL_HEADER = 0x20; -this.PDU_IEI_HYPERLINK_FORMAT_ELEMENT = 0x21; -this.PDU_IEI_REPLY_ADDRESS_ELEMENT = 0x22; -this.PDU_IEI_ENHANCED_VOICE_MAIL_INFORMATION = 0x23; -this.PDU_IEI_NATIONAL_LANGUAGE_SINGLE_SHIFT = 0x24; -this.PDU_IEI_NATIONAL_LANGUAGE_LOCKING_SHIFT = 0x25; - -// Application Port Addressing, see 3GPP TS 23.040 9.2.3.24.3 -this.PDU_APA_RESERVED_8BIT_PORTS = 240; -this.PDU_APA_VALID_16BIT_PORTS = 49152; - -// 7bit alphabet escape character. The encoded value of this code point is left -// undefined in official spec. Its code value is internally assigned to \uffff, -// <noncharacter-FFFF> in Unicode basic multilingual plane. -this.PDU_NL_EXTENDED_ESCAPE = 0x1B; - -// <SP>, <LF>, <CR> are only defined in locking shift tables. -this.PDU_NL_SPACE = 0x20; -this.PDU_NL_LINE_FEED = 0x0A; -this.PDU_NL_CARRIAGE_RETURN = 0x0D; - -// 7bit alphabet page break character, only defined in single shift tables. -// The encoded value of this code point is left undefined in official spec, but -// the code point itself maybe be used for example in compressed CBS messages. -// Its code value is internally assigned to \u000c, ASCII form feed, or new page. -this.PDU_NL_PAGE_BREAK = 0x0A; -// 7bit alphabet reserved control character, only defined in single shift -// tables. The encoded value of this code point is left undefined in official -// spec. Its code value is internally assigned to \ufffe, <noncharacter-FFFE> -// in Unicode basic multilingual plane. -this.PDU_NL_RESERVED_CONTROL = 0x0D; - -this.PDU_NL_IDENTIFIER_DEFAULT = 0; -this.PDU_NL_IDENTIFIER_TURKISH = 1; -this.PDU_NL_IDENTIFIER_SPANISH = 2; -this.PDU_NL_IDENTIFIER_PORTUGUESE = 3; -this.PDU_NL_IDENTIFIER_BENGALI = 4; -this.PDU_NL_IDENTIFIER_GUJARATI = 5; -this.PDU_NL_IDENTIFIER_HINDI = 6; -this.PDU_NL_IDENTIFIER_KANNADA = 7; -this.PDU_NL_IDENTIFIER_MALAYALAM = 8; -this.PDU_NL_IDENTIFIER_ORIYA = 9; -this.PDU_NL_IDENTIFIER_PUNJABI = 10; -this.PDU_NL_IDENTIFIER_TAMIL = 11; -this.PDU_NL_IDENTIFIER_TELUGU = 12; -this.PDU_NL_IDENTIFIER_URDU = 13; - -// The mapping of mcc and their extra GSM national language locking / single -// shift table tuples to enable. The default GSM alphabet and extension table -// are always enabled and need not to be list here. -// -// The content should be updated when a relevant national regulatory body -// requests. See 'NOTE 2' of 6.2.1.2.5 in 3GPP TS 23.038: -// " -// Encoding of a message using the national locking shift mechanism is not -// intended to be implemented until a formal request is issued by the -// relevant national regulatory body. This is because a receiving entity -// not supporting the relevant locking-shift decoding will present different -// characters from the ones intended by the sending entity. -// " -this.PDU_MCC_NL_TABLE_TUPLES_MAPPING = { - // Configuration for Turkey. - // - // The Turkish single shift table contains 7 extra characters - // (Ğ, İ, Ş, ç, ğ, ı, ş) than the GSM default alphabet extension table. Since - // all the 7 characters are also included in Turkish locking shift table, it's - // not necessary to enable Turkish single shift table. Using GSM default - // alphabet extension table instead saves 3 octets when these extension table - // characters present in a message. - 286: [[PDU_NL_IDENTIFIER_TURKISH, PDU_NL_IDENTIFIER_DEFAULT]] -}; - -/* - * 3GPP TS 23.038 - 6.2.1 GSM 7 bit Default Alphabet - */ -this.PDU_NL_GSM_DEFAULT_ALPHABET = - // 01.....23.....4.....5.....6.....7.....8.....9.....A.B.....C.....D.E.....F..... - "@\u00a3$\u00a5\u00e8\u00e9\u00f9\u00ec\u00f2\u00c7\n\u00d8\u00f8\r\u00c5\u00e5" - // 0.....12.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u0394_\u03a6\u0393\u039b\u03a9\u03a0\u03a8\u03a3\u0398\u039e\uffff\u00c6\u00e6\u00df\u00c9" - // 012.34.....56789ABCDEF - + " !\"#\u00a4%&'()*+,-./" - // 0123456789ABCDEF - + "0123456789:;<=>?" - // 0.....123456789ABCDEF - + "\u00a1ABCDEFGHIJKLMNO" - // 0123456789AB.....C.....D.....E.....F..... - + "PQRSTUVWXYZ\u00c4\u00d6\u00d1\u00dc\u00a7" - // 0.....123456789ABCDEF - + "\u00bfabcdefghijklmno" - // 0123456789AB.....C.....D.....E.....F..... - + "pqrstuvwxyz\u00e4\u00f6\u00f1\u00fc\u00e0"; - -// National Language Locking Shift Tables, see 3GPP TS 23.038 -this.PDU_NL_LOCKING_SHIFT_TABLES = [ - /** - * National Language Identifier: 0x00 - * 6.2.1 GSM 7 bit Default Alphabet - */ - PDU_NL_GSM_DEFAULT_ALPHABET, - - /** - * National Language Identifier: 0x01 - * A.3.1 Turkish National Language Locking Shift Table - */ - // 01.....23.....4.....5.....6.....7.....8.....9.....A.B.....C.....D.E.....F..... - "@\u00a3$\u00a5\u20ac\u00e9\u00f9\u0131\u00f2\u00c7\n\u011e\u011f\r\u00c5\u00e5" - // 0.....12.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u0394_\u03a6\u0393\u039b\u03a9\u03a0\u03a8\u03a3\u0398\u039e\uffff\u015e\u015f\u00df\u00c9" - // 012.34.....56789ABCDEF - + " !\"#\u00a4%&'()*+,-./" - // 0123456789ABCDEF - + "0123456789:;<=>?" - // 0.....123456789ABCDEF - + "\u0130ABCDEFGHIJKLMNO" - // 0123456789AB.....C.....D.....E.....F..... - + "PQRSTUVWXYZ\u00c4\u00d6\u00d1\u00dc\u00a7" - // 0.....123456789ABCDEF - + "\u00e7abcdefghijklmno" - // 0123456789AB.....C.....D.....E.....F..... - + "pqrstuvwxyz\u00e4\u00f6\u00f1\u00fc\u00e0", - - /** - * National Language Identifier: 0x02 - * A.3.2 Void - * Fallback to GSM Default Alphabet - */ - PDU_NL_GSM_DEFAULT_ALPHABET, - - /** - * National Language Identifier: 0x03 - * A.3.3 Portuguese National Language Locking Shift Table - */ - // 01.....23.....4.....5.....6.....7.....8.....9.....A.B.....C.....D.E.....F..... - "@\u00a3$\u00a5\u00ea\u00e9\u00fa\u00ed\u00f3\u00e7\n\u00d4\u00f4\r\u00c1\u00e1" - // 0.....12.....3.....4.....5.....67.8.....9.....AB.....C.....D.....E.....F..... - + "\u0394_\u00aa\u00c7\u00c0\u221e^\\\u20ac\u00d3|\uffff\u00c2\u00e2\u00ca\u00c9" - // 012.34.....56789ABCDEF - + " !\"#\u00ba%&'()*+,-./" - // 0123456789ABCDEF - + "0123456789:;<=>?" - // 0.....123456789ABCDEF - + "\u00cdABCDEFGHIJKLMNO" - // 0123456789AB.....C.....D.....E.....F..... - + "PQRSTUVWXYZ\u00c3\u00d5\u00da\u00dc\u00a7" - // 0123456789ABCDEF - + "~abcdefghijklmno" - // 0123456789AB.....C.....DE.....F..... - + "pqrstuvwxyz\u00e3\u00f5`\u00fc\u00e0", - - /** - * National Language Identifier: 0x04 - * A.3.4 Bengali National Language Locking Shift Table - */ - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.B.....CD.EF..... - "\u0981\u0982\u0983\u0985\u0986\u0987\u0988\u0989\u098a\u098b\n\u098c \r \u098f" - // 0.....123.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u0990 \u0993\u0994\u0995\u0996\u0997\u0998\u0999\u099a\uffff\u099b\u099c\u099d\u099e" - // 012.....3.....4.....5.....6.....7.....89A.....B.....CD.....EF..... - + " !\u099f\u09a0\u09a1\u09a2\u09a3\u09a4)(\u09a5\u09a6,\u09a7.\u09a8" - // 0123456789ABCD.....E.....F - + "0123456789:; \u09aa\u09ab?" - // 0.....1.....2.....3.....4.....56.....789A.....B.....C.....D.....E.....F..... - + "\u09ac\u09ad\u09ae\u09af\u09b0 \u09b2 \u09b6\u09b7\u09b8\u09b9\u09bc\u09bd" - // 0.....1.....2.....3.....4.....5.....6.....789.....A.....BCD.....E.....F..... - + "\u09be\u09bf\u09c0\u09c1\u09c2\u09c3\u09c4 \u09c7\u09c8 \u09cb\u09cc\u09cd" - // 0.....123456789ABCDEF - + "\u09ceabcdefghijklmno" - // 0123456789AB.....C.....D.....E.....F..... - + "pqrstuvwxyz\u09d7\u09dc\u09dd\u09f0\u09f1", - - /** - * National Language Identifier: 0x05 - * A.3.5 Gujarati National Language Locking Shift Table - */ - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.B.....C.....D.EF..... - "\u0a81\u0a82\u0a83\u0a85\u0a86\u0a87\u0a88\u0a89\u0a8a\u0a8b\n\u0a8c\u0a8d\r \u0a8f" - // 0.....1.....23.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u0a90\u0a91 \u0a93\u0a94\u0a95\u0a96\u0a97\u0a98\u0a99\u0a9a\uffff\u0a9b\u0a9c\u0a9d\u0a9e" - // 012.....3.....4.....5.....6.....7.....89A.....B.....CD.....EF..... - + " !\u0a9f\u0aa0\u0aa1\u0aa2\u0aa3\u0aa4)(\u0aa5\u0aa6,\u0aa7.\u0aa8" - // 0123456789ABCD.....E.....F - + "0123456789:; \u0aaa\u0aab?" - // 0.....1.....2.....3.....4.....56.....7.....89.....A.....B.....C.....D.....E.....F..... - + "\u0aac\u0aad\u0aae\u0aaf\u0ab0 \u0ab2\u0ab3 \u0ab5\u0ab6\u0ab7\u0ab8\u0ab9\u0abc\u0abd" - // 0.....1.....2.....3.....4.....5.....6.....7.....89.....A.....B.....CD.....E.....F..... - + "\u0abe\u0abf\u0ac0\u0ac1\u0ac2\u0ac3\u0ac4\u0ac5 \u0ac7\u0ac8\u0ac9 \u0acb\u0acc\u0acd" - // 0.....123456789ABCDEF - + "\u0ad0abcdefghijklmno" - // 0123456789AB.....C.....D.....E.....F..... - + "pqrstuvwxyz\u0ae0\u0ae1\u0ae2\u0ae3\u0af1", - - /** - * National Language Identifier: 0x06 - * A.3.6 Hindi National Language Locking Shift Table - */ - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.B.....C.....D.E.....F..... - "\u0901\u0902\u0903\u0905\u0906\u0907\u0908\u0909\u090a\u090b\n\u090c\u090d\r\u090e\u090f" - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u0910\u0911\u0912\u0913\u0914\u0915\u0916\u0917\u0918\u0919\u091a\uffff\u091b\u091c\u091d\u091e" - // 012.....3.....4.....5.....6.....7.....89A.....B.....CD.....EF..... - + " !\u091f\u0920\u0921\u0922\u0923\u0924)(\u0925\u0926,\u0927.\u0928" - // 0123456789ABC.....D.....E.....F - + "0123456789:;\u0929\u092a\u092b?" - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u092c\u092d\u092e\u092f\u0930\u0931\u0932\u0933\u0934\u0935\u0936\u0937\u0938\u0939\u093c\u093d" - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u093e\u093f\u0940\u0941\u0942\u0943\u0944\u0945\u0946\u0947\u0948\u0949\u094a\u094b\u094c\u094d" - // 0.....123456789ABCDEF - + "\u0950abcdefghijklmno" - // 0123456789AB.....C.....D.....E.....F..... - + "pqrstuvwxyz\u0972\u097b\u097c\u097e\u097f", - - /** - * National Language Identifier: 0x07 - * A.3.7 Kannada National Language Locking Shift Table - */ - // 01.....2.....3.....4.....5.....6.....7.....8.....9.....A.B.....CD.E.....F..... - " \u0c82\u0c83\u0c85\u0c86\u0c87\u0c88\u0c89\u0c8a\u0c8b\n\u0c8c \r\u0c8e\u0c8f" - // 0.....12.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u0c90 \u0c92\u0c93\u0c94\u0c95\u0c96\u0c97\u0c98\u0c99\u0c9a\uffff\u0c9b\u0c9c\u0c9d\u0c9e" - // 012.....3.....4.....5.....6.....7.....89A.....B.....CD.....EF..... - + " !\u0c9f\u0ca0\u0ca1\u0ca2\u0ca3\u0ca4)(\u0ca5\u0ca6,\u0ca7.\u0ca8" - // 0123456789ABCD.....E.....F - + "0123456789:; \u0caa\u0cab?" - // 0.....1.....2.....3.....4.....5.....6.....7.....89.....A.....B.....C.....D.....E.....F..... - + "\u0cac\u0cad\u0cae\u0caf\u0cb0\u0cb1\u0cb2\u0cb3 \u0cb5\u0cb6\u0cb7\u0cb8\u0cb9\u0cbc\u0cbd" - // 0.....1.....2.....3.....4.....5.....6.....78.....9.....A.....BC.....D.....E.....F..... - + "\u0cbe\u0cbf\u0cc0\u0cc1\u0cc2\u0cc3\u0cc4 \u0cc6\u0cc7\u0cc8 \u0cca\u0ccb\u0ccc\u0ccd" - // 0.....123456789ABCDEF - + "\u0cd5abcdefghijklmno" - // 0123456789AB.....C.....D.....E.....F..... - + "pqrstuvwxyz\u0cd6\u0ce0\u0ce1\u0ce2\u0ce3", - - /** - * National Language Identifier: 0x08 - * A.3.8 Malayalam National Language Locking Shift Table - */ - // 01.....2.....3.....4.....5.....6.....7.....8.....9.....A.B.....CD.E.....F..... - " \u0d02\u0d03\u0d05\u0d06\u0d07\u0d08\u0d09\u0d0a\u0d0b\n\u0d0c \r\u0d0e\u0d0f" - // 0.....12.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u0d10 \u0d12\u0d13\u0d14\u0d15\u0d16\u0d17\u0d18\u0d19\u0d1a\uffff\u0d1b\u0d1c\u0d1d\u0d1e" - // 012.....3.....4.....5.....6.....7.....89A.....B.....CD.....EF..... - + " !\u0d1f\u0d20\u0d21\u0d22\u0d23\u0d24)(\u0d25\u0d26,\u0d27.\u0d28" - // 0123456789ABCD.....E.....F - + "0123456789:; \u0d2a\u0d2b?" - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....EF..... - + "\u0d2c\u0d2d\u0d2e\u0d2f\u0d30\u0d31\u0d32\u0d33\u0d34\u0d35\u0d36\u0d37\u0d38\u0d39 \u0d3d" - // 0.....1.....2.....3.....4.....5.....6.....78.....9.....A.....BC.....D.....E.....F..... - + "\u0d3e\u0d3f\u0d40\u0d41\u0d42\u0d43\u0d44 \u0d46\u0d47\u0d48 \u0d4a\u0d4b\u0d4c\u0d4d" - // 0.....123456789ABCDEF - + "\u0d57abcdefghijklmno" - // 0123456789AB.....C.....D.....E.....F..... - + "pqrstuvwxyz\u0d60\u0d61\u0d62\u0d63\u0d79", - - /** - * National Language Identifier: 0x09 - * A.3.9 Oriya National Language Locking Shift Table - */ - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.B.....CD.EF..... - "\u0b01\u0b02\u0b03\u0b05\u0b06\u0b07\u0b08\u0b09\u0b0a\u0b0b\n\u0b0c \r \u0b0f" - // 0.....123.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u0b10 \u0b13\u0b14\u0b15\u0b16\u0b17\u0b18\u0b19\u0b1a\uffff\u0b1b\u0b1c\u0b1d\u0b1e" - // 012.....3.....4.....5.....6.....7.....89A.....B.....CD.....EF..... - + " !\u0b1f\u0b20\u0b21\u0b22\u0b23\u0b24)(\u0b25\u0b26,\u0b27.\u0b28" - // 0123456789ABCD.....E.....F - + "0123456789:; \u0b2a\u0b2b?" - // 0.....1.....2.....3.....4.....56.....7.....89.....A.....B.....C.....D.....E.....F..... - + "\u0b2c\u0b2d\u0b2e\u0b2f\u0b30 \u0b32\u0b33 \u0b35\u0b36\u0b37\u0b38\u0b39\u0b3c\u0b3d" - // 0.....1.....2.....3.....4.....5.....6.....789.....A.....BCD.....E.....F..... - + "\u0b3e\u0b3f\u0b40\u0b41\u0b42\u0b43\u0b44 \u0b47\u0b48 \u0b4b\u0b4c\u0b4d" - // 0.....123456789ABCDEF - + "\u0b56abcdefghijklmno" - // 0123456789AB.....C.....D.....E.....F..... - + "pqrstuvwxyz\u0b57\u0b60\u0b61\u0b62\u0b63", - - /** - * National Language Identifier: 0x0A - * A.3.10 Punjabi National Language Locking Shift Table - */ - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9A.BCD.EF..... - "\u0a01\u0a02\u0a03\u0a05\u0a06\u0a07\u0a08\u0a09\u0a0a \n \r \u0a0f" - // 0.....123.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u0a10 \u0a13\u0a14\u0a15\u0a16\u0a17\u0a18\u0a19\u0a1a\uffff\u0a1b\u0a1c\u0a1d\u0a1e" - // 012.....3.....4.....5.....6.....7.....89A.....B.....CD.....EF..... - + " !\u0a1f\u0a20\u0a21\u0a22\u0a23\u0a24)(\u0a25\u0a26,\u0a27.\u0a28" - // 0123456789ABCD.....E.....F - + "0123456789:; \u0a2a\u0a2b?" - // 0.....1.....2.....3.....4.....56.....7.....89.....A.....BC.....D.....E.....F - + "\u0a2c\u0a2d\u0a2e\u0a2f\u0a30 \u0a32\u0a33 \u0a35\u0a36 \u0a38\u0a39\u0a3c " - // 0.....1.....2.....3.....4.....56789.....A.....BCD.....E.....F..... - + "\u0a3e\u0a3f\u0a40\u0a41\u0a42 \u0a47\u0a48 \u0a4b\u0a4c\u0a4d" - // 0.....123456789ABCDEF - + "\u0a51abcdefghijklmno" - // 0123456789AB.....C.....D.....E.....F..... - + "pqrstuvwxyz\u0a70\u0a71\u0a72\u0a73\u0a74", - - /** - * National Language Identifier: 0x0B - * A.3.11 Tamil National Language Locking Shift Table - */ - // 01.....2.....3.....4.....5.....6.....7.....8.....9A.BCD.E.....F..... - " \u0b82\u0b83\u0b85\u0b86\u0b87\u0b88\u0b89\u0b8a \n \r\u0b8e\u0b8f" - // 0.....12.....3.....4.....5.....6789.....A.....B.....CD.....EF..... - + "\u0b90 \u0b92\u0b93\u0b94\u0b95 \u0b99\u0b9a\uffff \u0b9c \u0b9e" - // 012.....3456.....7.....89ABCDEF..... - + " !\u0b9f \u0ba3\u0ba4)( , .\u0ba8" - // 0123456789ABC.....D.....EF - + "0123456789:;\u0ba9\u0baa ?" - // 012.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....EF - + " \u0bae\u0baf\u0bb0\u0bb1\u0bb2\u0bb3\u0bb4\u0bb5\u0bb6\u0bb7\u0bb8\u0bb9 " - // 0.....1.....2.....3.....4.....5678.....9.....A.....BC.....D.....E.....F..... - + "\u0bbe\u0bbf\u0bc0\u0bc1\u0bc2 \u0bc6\u0bc7\u0bc8 \u0bca\u0bcb\u0bcc\u0bcd" - // 0.....123456789ABCDEF - + "\u0bd0abcdefghijklmno" - // 0123456789AB.....C.....D.....E.....F..... - + "pqrstuvwxyz\u0bd7\u0bf0\u0bf1\u0bf2\u0bf9", - - /** - * National Language Identifier: 0x0C - * A.3.12 Telugu National Language Locking Shift Table - */ - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.B.....CD.E.....F..... - "\u0c01\u0c02\u0c03\u0c05\u0c06\u0c07\u0c08\u0c09\u0c0a\u0c0b\n\u0c0c \r\u0c0e\u0c0f" - // 0.....12.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u0c10 \u0c12\u0c13\u0c14\u0c15\u0c16\u0c17\u0c18\u0c19\u0c1a\uffff\u0c1b\u0c1c\u0c1d\u0c1e" - // 012.....3.....4.....5.....6.....7.....89A.....B.....CD.....EF..... - + " !\u0c1f\u0c20\u0c21\u0c22\u0c23\u0c24)(\u0c25\u0c26,\u0c27.\u0c28" - // 0123456789ABCD.....E.....F - + "0123456789:; \u0c2a\u0c2b?" - // 0.....1.....2.....3.....4.....5.....6.....7.....89.....A.....B.....C.....D.....EF..... - + "\u0c2c\u0c2d\u0c2e\u0c2f\u0c30\u0c31\u0c32\u0c33 \u0c35\u0c36\u0c37\u0c38\u0c39 \u0c3d" - // 0.....1.....2.....3.....4.....5.....6.....78.....9.....A.....BC.....D.....E.....F..... - + "\u0c3e\u0c3f\u0c40\u0c41\u0c42\u0c43\u0c44 \u0c46\u0c47\u0c48 \u0c4a\u0c4b\u0c4c\u0c4d" - // 0.....123456789ABCDEF - + "\u0c55abcdefghijklmno" - // 0123456789AB.....C.....D.....E.....F..... - + "pqrstuvwxyz\u0c56\u0c60\u0c61\u0c62\u0c63", - - /** - * National Language Identifier: 0x0D - * A.3.13 Urdu National Language Locking Shift Table - */ - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.B.....C.....D.E.....F..... - "\u0627\u0622\u0628\u067b\u0680\u067e\u06a6\u062a\u06c2\u067f\n\u0679\u067d\r\u067a\u067c" - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u062b\u062c\u0681\u0684\u0683\u0685\u0686\u0687\u062d\u062e\u062f\uffff\u068c\u0688\u0689\u068a" - // 012.....3.....4.....5.....6.....7.....89A.....B.....CD.....EF..... - + " !\u068f\u068d\u0630\u0631\u0691\u0693)(\u0699\u0632,\u0696.\u0698" - // 0123456789ABC.....D.....E.....F - + "0123456789:;\u069a\u0633\u0634?" - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u0635\u0636\u0637\u0638\u0639\u0641\u0642\u06a9\u06aa\u06ab\u06af\u06b3\u06b1\u0644\u0645\u0646" - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u06ba\u06bb\u06bc\u0648\u06c4\u06d5\u06c1\u06be\u0621\u06cc\u06d0\u06d2\u064d\u0650\u064f\u0657" - // 0.....123456789ABCDEF - + "\u0654abcdefghijklmno" - // 0123456789AB.....C.....D.....E.....F..... - + "pqrstuvwxyz\u0655\u0651\u0653\u0656\u0670" -]; - -// National Language Single Shift Tables, see 3GPP TS 23.038 -this.PDU_NL_SINGLE_SHIFT_TABLES = [ - /** - * National Language Identifier: 0x00 - * 6.2.1.1 GSM 7 bit default alphabet extension table - */ - // 0123456789A.....BCD.....EF - " \u000c \ufffe " - // 0123456789AB.....CDEF - + " ^ \uffff " - // 0123456789ABCDEF. - + " {} \\" - // 0123456789ABCDEF - + " [~] " - // 0123456789ABCDEF - + "| " - // 0123456789ABCDEF - + " " - // 012345.....6789ABCDEF - + " \u20ac " - // 0123456789ABCDEF - + " ", - - /** - * National Language Identifier: 0x01 - * A.2.1 Turkish National Language Single Shift Table - */ - // 0123456789A.....BCD.....EF - " \u000c \ufffe " - // 0123456789AB.....CDEF - + " ^ \uffff " - // 0123456789ABCDEF. - + " {} \\" - // 0123456789ABCDEF - + " [~] " - // 01234567.....89.....ABCDEF - + "| \u011e \u0130 " - // 0123.....456789ABCDEF - + " \u015e " - // 0123.....45.....67.....89.....ABCDEF - + " \u00e7 \u20ac \u011f \u0131 " - // 0123.....456789ABCDEF - + " \u015f ", - - /** - * National Language Identifier: 0x02 - * A.2.2 Spanish National Language Single Shift Table - */ - // 0123456789.....A.....BCD.....EF - " \u00e7\u000c \ufffe " - // 0123456789AB.....CDEF - + " ^ \uffff " - // 0123456789ABCDEF. - + " {} \\" - // 0123456789ABCDEF - + " [~] " - // 01.....23456789.....ABCDEF..... - + "|\u00c1 \u00cd \u00d3" - // 012345.....6789ABCDEF - + " \u00da " - // 01.....2345.....6789.....ABCDEF..... - + " \u00e1 \u20ac \u00ed \u00f3" - // 012345.....6789ABCDEF - + " \u00fa ", - - /** - * National Language Identifier: 0x03 - * A.2.3 Portuguese National Language Single Shift Table - */ - // 012345.....6789.....A.....B.....C.....D.....E.....F..... - " \u00ea \u00e7\u000c\u00d4\u00f4\ufffe\u00c1\u00e1" - // 012.....3.....45.....6.....7.....8.....9.....AB.....CDEF..... - + " \u03a6\u0393^\u03a9\u03a0\u03a8\u03a3\u0398 \uffff \u00ca" - // 0123456789ABCDEF. - + " {} \\" - // 0123456789ABCDEF - + " [~] " - // 01.....23456789.....ABCDEF..... - + "|\u00c0 \u00cd \u00d3" - // 012345.....6789AB.....C.....DEF - + " \u00da \u00c3\u00d5 " - // 01.....2345.....6789.....ABCDEF..... - + " \u00c2 \u20ac \u00ed \u00f3" - // 012345.....6789AB.....C.....DEF..... - + " \u00fa \u00e3\u00f5 \u00e2", - - /** - * National Language Identifier: 0x04 - * A.2.4 Bengali National Language Single Shift Table - */ - // 01.....23.....4.....5.6.....789A.....BCD.....EF - "@\u00a3$\u00a5\u00bf\"\u00a4%&'\u000c*+\ufffe-/" - // 0123.....45.....6789.....A.....B.....C.....D.....E.....F..... - + "<=>\u00a1^\u00a1_#*\u09e6\u09e7\uffff\u09e8\u09e9\u09ea\u09eb" - // 0.....1.....2.....3.....4.....5.....6.....7.....89A.....B.....C.....D.....E.....F. - + "\u09ec\u09ed\u09ee\u09ef\u09df\u09e0\u09e1\u09e2{}\u09e3\u09f2\u09f3\u09f4\u09f5\\" - // 0.....1.....2.....3.....4.....56789ABCDEF - + "\u09f6\u09f7\u09f8\u09f9\u09fa [~] " - // 0123456789ABCDEF - + "|ABCDEFGHIJKLMNO" - // 0123456789ABCDEF - + "PQRSTUVWXYZ " - // 012345.....6789ABCDEF - + " \u20ac " - // 0123456789ABCDEF - + " ", - - /** - * National Language Identifier: 0x05 - * A.2.5 Gujarati National Language Single Shift Table - */ - // 01.....23.....4.....5.6.....789A.....BCD.....EF - "@\u00a3$\u00a5\u00bf\"\u00a4%&'\u000c*+\ufffe-/" - // 0123.....45.....6789.....A.....B.....C.....D.....E.....F..... - + "<=>\u00a1^\u00a1_#*\u0964\u0965\uffff\u0ae6\u0ae7\u0ae8\u0ae9" - // 0.....1.....2.....3.....4.....5.....6789ABCDEF. - + "\u0aea\u0aeb\u0aec\u0aed\u0aee\u0aef {} \\" - // 0123456789ABCDEF - + " [~] " - // 0123456789ABCDEF - + "|ABCDEFGHIJKLMNO" - // 0123456789ABCDEF - + "PQRSTUVWXYZ " - // 012345.....6789ABCDEF - + " \u20ac " - // 0123456789ABCDEF - + " ", - - /** - * National Language Identifier: 0x06 - * A.2.6 Hindi National Language Single Shift Table - */ - // 01.....23.....4.....5.6.....789A.....BCD.....EF - "@\u00a3$\u00a5\u00bf\"\u00a4%&'\u000c*+\ufffe-/" - // 0123.....45.....6789.....A.....B.....C.....D.....E.....F..... - + "<=>\u00a1^\u00a1_#*\u0964\u0965\uffff\u0966\u0967\u0968\u0969" - // 0.....1.....2.....3.....4.....5.....6.....7.....89A.....B.....C.....D.....E.....F. - + "\u096a\u096b\u096c\u096d\u096e\u096f\u0951\u0952{}\u0953\u0954\u0958\u0959\u095a\\" - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.....BCDEF - + "\u095b\u095c\u095d\u095e\u095f\u0960\u0961\u0962\u0963\u0970\u0971 [~] " - // 0123456789ABCDEF - + "|ABCDEFGHIJKLMNO" - // 0123456789ABCDEF - + "PQRSTUVWXYZ " - // 012345.....6789ABCDEF - + " \u20ac " - // 0123456789ABCDEF - + " ", - - /** - * National Language Identifier: 0x07 - * A.2.7 Kannada National Language Single Shift Table - */ - // 01.....23.....4.....5.6.....789A.....BCD.....EF - "@\u00a3$\u00a5\u00bf\"\u00a4%&'\u000c*+\ufffe-/" - // 0123.....45.....6789.....A.....B.....C.....D.....E.....F..... - + "<=>\u00a1^\u00a1_#*\u0964\u0965\uffff\u0ce6\u0ce7\u0ce8\u0ce9" - // 0.....1.....2.....3.....4.....5.....6.....7.....89A.....BCDEF. - + "\u0cea\u0ceb\u0cec\u0ced\u0cee\u0cef\u0cde\u0cf1{}\u0cf2 \\" - // 0123456789ABCDEF - + " [~] " - // 0123456789ABCDEF - + "|ABCDEFGHIJKLMNO" - // 0123456789ABCDEF - + "PQRSTUVWXYZ " - // 012345.....6789ABCDEF - + " \u20ac " - // 0123456789ABCDEF - + " ", - - /** - * National Language Identifier: 0x08 - * A.2.8 Malayalam National Language Single Shift Table - */ - // 01.....23.....4.....5.6.....789A.....BCD.....EF - "@\u00a3$\u00a5\u00bf\"\u00a4%&'\u000c*+\ufffe-/" - // 0123.....45.....6789.....A.....B.....C.....D.....E.....F..... - + "<=>\u00a1^\u00a1_#*\u0964\u0965\uffff\u0d66\u0d67\u0d68\u0d69" - // 0.....1.....2.....3.....4.....5.....6.....7.....89A.....B.....C.....D.....E.....F. - + "\u0d6a\u0d6b\u0d6c\u0d6d\u0d6e\u0d6f\u0d70\u0d71{}\u0d72\u0d73\u0d74\u0d75\u0d7a\\" - // 0.....1.....2.....3.....4.....56789ABCDEF - + "\u0d7b\u0d7c\u0d7d\u0d7e\u0d7f [~] " - // 0123456789ABCDEF - + "|ABCDEFGHIJKLMNO" - // 0123456789ABCDEF - + "PQRSTUVWXYZ " - // 012345.....6789ABCDEF - + " \u20ac " - // 0123456789ABCDEF - + " ", - - /** - * National Language Identifier: 0x09 - * A.2.9 Oriya National Language Single Shift Table - */ - // 01.....23.....4.....5.6.....789A.....BCD.....EF - "@\u00a3$\u00a5\u00bf\"\u00a4%&'\u000c*+\ufffe-/" - // 0123.....45.....6789.....A.....B.....C.....D.....E.....F..... - + "<=>\u00a1^\u00a1_#*\u0964\u0965\uffff\u0b66\u0b67\u0b68\u0b69" - // 0.....1.....2.....3.....4.....5.....6.....7.....89A.....B.....C.....DEF. - + "\u0b6a\u0b6b\u0b6c\u0b6d\u0b6e\u0b6f\u0b5c\u0b5d{}\u0b5f\u0b70\u0b71 \\" - // 0123456789ABCDEF - + " [~] " - // 0123456789ABCDEF - + "|ABCDEFGHIJKLMNO" - // 0123456789ABCDEF - + "PQRSTUVWXYZ " - // 012345.....6789ABCDEF - + " \u20ac " - // 0123456789ABCDEF - + " ", - - /** - * National Language Identifier: 0x0A - * A.2.10 Punjabi National Language Single Shift Table - */ - // 01.....23.....4.....5.6.....789A.....BCD.....EF - "@\u00a3$\u00a5\u00bf\"\u00a4%&'\u000c*+\ufffe-/" - // 0123.....45.....6789.....A.....B.....C.....D.....E.....F..... - + "<=>\u00a1^\u00a1_#*\u0964\u0965\uffff\u0a66\u0a67\u0a68\u0a69" - // 0.....1.....2.....3.....4.....5.....6.....7.....89A.....B.....C.....D.....EF. - + "\u0a6a\u0a6b\u0a6c\u0a6d\u0a6e\u0a6f\u0a59\u0a5a{}\u0a5b\u0a5c\u0a5e\u0a75 \\" - // 0123456789ABCDEF - + " [~] " - // 0123456789ABCDEF - + "|ABCDEFGHIJKLMNO" - // 0123456789ABCDEF - + "PQRSTUVWXYZ " - // 012345.....6789ABCDEF - + " \u20ac " - // 0123456789ABCDEF - + " ", - - /** - * National Language Identifier: 0x0B - * A.2.11 Tamil National Language Single Shift Table - */ - // 01.....23.....4.....5.6.....789A.....BCD.....EF - "@\u00a3$\u00a5\u00bf\"\u00a4%&'\u000c*+\ufffe-/" - // 0123.....45.....6789.....A.....B.....C.....D.....E.....F..... - + "<=>\u00a1^\u00a1_#*\u0964\u0965\uffff\u0be6\u0be7\u0be8\u0be9" - // 0.....1.....2.....3.....4.....5.....6.....7.....89A.....B.....C.....D.....E.....F. - + "\u0bea\u0beb\u0bec\u0bed\u0bee\u0bef\u0bf3\u0bf4{}\u0bf5\u0bf6\u0bf7\u0bf8\u0bfa\\" - // 0123456789ABCDEF - + " [~] " - // 0123456789ABCDEF - + "|ABCDEFGHIJKLMNO" - // 0123456789ABCDEF - + "PQRSTUVWXYZ " - // 012345.....6789ABCDEF - + " \u20ac " - // 0123456789ABCDEF - + " ", - - /** - * National Language Identifier: 0x0C - * A.2.12 Telugu National Language Single Shift Table - */ - // 01.....23.....4.....5.6.....789A.....BCD.....EF - "@\u00a3$\u00a5\u00bf\"\u00a4%&'\u000c*+\ufffe-/" - // 0123.....45.....6789AB.....C.....D.....E.....F..... - + "<=>\u00a1^\u00a1_#* \uffff\u0c66\u0c67\u0c68\u0c69" - // 0.....1.....2.....3.....4.....5.....6.....7.....89A.....B.....C.....D.....E.....F. - + "\u0c6a\u0c6b\u0c6c\u0c6d\u0c6e\u0c6f\u0c58\u0c59{}\u0c78\u0c79\u0c7a\u0c7b\u0c7c\\" - // 0.....1.....2.....3456789ABCDEF - + "\u0c7d\u0c7e\u0c7f [~] " - // 0123456789ABCDEF - + "|ABCDEFGHIJKLMNO" - // 0123456789ABCDEF - + "PQRSTUVWXYZ " - // 012345.....6789ABCDEF - + " \u20ac " - // 0123456789ABCDEF - + " ", - - /** - * National Language Identifier: 0x0D - * A.2.13 Urdu National Language Single Shift Table - */ - // 01.....23.....4.....5.6.....789A.....BCD.....EF - "@\u00a3$\u00a5\u00bf\"\u00a4%&'\u000c*+\ufffe-/" - // 0123.....45.....6789.....A.....B.....C.....D.....E.....F..... - + "<=>\u00a1^\u00a1_#*\u0600\u0601\uffff\u06f0\u06f1\u06f2\u06f3" - // 0.....1.....2.....3.....4.....5.....6.....7.....89A.....B.....C.....D.....E.....F. - + "\u06f4\u06f5\u06f6\u06f7\u06f8\u06f9\u060c\u060d{}\u060e\u060f\u0610\u0611\u0612\\" - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.....B.....CDEF..... - + "\u0613\u0614\u061b\u061f\u0640\u0652\u0658\u066b\u066c\u0672\u0673\u06cd[~]\u06d4" - // 0123456789ABCDEF - + "|ABCDEFGHIJKLMNO" - // 0123456789ABCDEF - + "PQRSTUVWXYZ " - // 012345.....6789ABCDEF - + " \u20ac " - // 0123456789ABCDEF - + " " -]; - -// Special SMS Message Indication constants -this.PDU_MWI_STORE_TYPE_BIT = 0x80; -this.PDU_MWI_STORE_TYPE_DISCARD = 0x00; -this.PDU_MWI_STORE_TYPE_STORE = 0x80; - -this.GSM_SMS_STRICT_7BIT_CHARMAP = { -//"\u0024": "\u0024", // "$" => "$", already in default alphabet -//"\u00a5": "\u00a5", // "¥" => "¥", already in default alphabet - "\u00c0": "\u0041", // "À" => "A" - "\u00c1": "\u0041", // "Á" => "A" - "\u00c2": "\u0041", // "Â" => "A" - "\u00c3": "\u0041", // "Ã" => "A" -//"\u00c4": "\u00c4", // "Ä" => "Ä", already in default alphabet -//"\u00c5": "\u00c5", // "Å" => "Å", already in default alphabet -//"\u00c6": "\u00c6", // "Æ" => "Æ", already in default alphabet -//"\u00c7": "\u00c7", // "Ç" => "Ç", already in default alphabet - "\u00c8": "\u0045", // "È" => "E" -//"\u00c9": "\u00c9", // "É" => "É", already in default alphabet - "\u00ca": "\u0045", // "Ê" => "E" - "\u00cb": "\u0045", // "Ë" => "E" - "\u00cc": "\u0049", // "Ì" => "I" - "\u00cd": "\u0049", // "Í" => "I" - "\u00ce": "\u0049", // "Î" => "I" - "\u00cf": "\u0049", // "Ï" => "I" -//"\u00d1": "\u00d1", // "Ñ" => "Ñ", already in default alphabet - "\u00d2": "\u004f", // "Ò" => "O" - "\u00d3": "\u004f", // "Ó" => "O" - "\u00d4": "\u004f", // "Ô" => "O" - "\u00d5": "\u004f", // "Õ" => "O" -//"\u00d6": "\u00d6", // "Ö" => "Ö", already in default alphabet - "\u00d9": "\u0055", // "Ù" => "U" - "\u00da": "\u0055", // "Ú" => "U" - "\u00db": "\u0055", // "Û" => "U" -//"\u00dc": "\u00dc", // "Ü" => "Ü", already in default alphabet -//"\u00df": "\u00df", // "ß" => "ß", already in default alphabet -//"\u00e0": "\u00e0", // "à" => "à", already in default alphabet - "\u00e1": "\u0061", // "á" => "a" - "\u00e2": "\u0061", // "â" => "a" - "\u00e3": "\u0061", // "ã" => "a" -//"\u00e4": "\u00e4", // "ä" => "ä", already in default alphabet -//"\u00e5": "\u00e5", // "å" => "å", already in default alphabet -//"\u00e6": "\u00e6", // "æ" => "æ", already in default alphabet - "\u00e7": "\u00c7", // "ç" => "Ç" -//"\u00e8": "\u00e8", // "è" => "è", already in default alphabet -//"\u00e9": "\u00e9", // "é" => "é", already in default alphabet - "\u00ea": "\u0065", // "ê" => "e" - "\u00eb": "\u0065", // "ë" => "e" -//"\u00ec": "\u00ec", // "ì" => "ì", already in default alphabet - "\u00ed": "\u0069", // "í" => "i" - "\u00ee": "\u0069", // "î" => "i" - "\u00ef": "\u0069", // "ï" => "i" -//"\u00f1": "\u00f1", // "ñ" => "ñ", already in default alphabet -//"\u00f2": "\u00f2", // "ò" => "ò", already in default alphabet - "\u00f3": "\u006f", // "ó" => "o" - "\u00f4": "\u006f", // "ô" => "o" - "\u00f5": "\u006f", // "õ" => "o" -//"\u00f6": "\u00f6", // "ö" => "ö", already in default alphabet -//"\u00f8": "\u00f8", // "ø" => "ø", already in default alphabet -//"\u00f9": "\u00f9", // "ù" => "ù", already in default alphabet - "\u00fa": "\u0075", // "ú" => "u" - "\u00fb": "\u0075", // "û" => "u" -//"\u00fc": "\u00fc", // "ü" => "ü", already in default alphabet - "\u00fe": "\u0074", // "þ" => "t" - "\u0100": "\u0041", // "Ā" => "A" - "\u0101": "\u0061", // "ā" => "a" - "\u0106": "\u0043", // "Ć" => "C" - "\u0107": "\u0063", // "ć" => "c" - "\u010c": "\u0043", // "Č" => "C" - "\u010d": "\u0063", // "č" => "c" - "\u010f": "\u0064", // "ď" => "d" - "\u0110": "\u0044", // "Đ" => "D" - "\u0111": "\u0064", // "đ" => "d" - "\u0112": "\u0045", // "Ē" => "E" - "\u0113": "\u0065", // "ē" => "e" - "\u0118": "\u0045", // "Ę" => "E" - "\u0119": "\u0065", // "ę" => "e" - "\u0128": "\u0049", // "Ĩ" => "I" - "\u0129": "\u0069", // "ĩ" => "i" - "\u012a": "\u0049", // "Ī" => "I" - "\u012b": "\u0069", // "ī" => "i" - "\u012e": "\u0049", // "Į" => "I" - "\u012f": "\u0069", // "į" => "i" - "\u0141": "\u004c", // "Ł" => "L" - "\u0142": "\u006c", // "ł" => "l" - "\u0143": "\u004e", // "Ń" => "N" - "\u0144": "\u006e", // "ń" => "n" - "\u0147": "\u004e", // "Ň" => "N" - "\u0148": "\u006e", // "ň" => "n" - "\u014c": "\u004f", // "Ō" => "O" - "\u014d": "\u006f", // "ō" => "o" - "\u0152": "\u004f", // "Œ" => "O" - "\u0153": "\u006f", // "œ" => "o" - "\u0158": "\u0052", // "Ř" => "R" - "\u0159": "\u0072", // "ř" => "r" - "\u0160": "\u0053", // "Š" => "S" - "\u0161": "\u0073", // "š" => "s" - "\u0165": "\u0074", // "ť" => "t" - "\u0168": "\u0055", // "Ū" => "U" - "\u0169": "\u0075", // "ū" => "u" - "\u016a": "\u0055", // "Ū" => "U" - "\u016b": "\u0075", // "ū" => "u" - "\u0178": "\u0059", // "Ÿ" => "Y" - "\u0179": "\u005a", // "Ź" => "Z" - "\u017a": "\u007a", // "ź" => "z" - "\u017b": "\u005a", // "Ż" => "Z" - "\u017c": "\u007a", // "ż" => "z" - "\u017d": "\u005a", // "Ž" => "Z" - "\u017e": "\u007a", // "ž" => "z" - "\u025b": "\u0045", // "ɛ" => "E" -//"\u0398": "\u0398", // "Θ" => "Θ", already in default alphabet - "\u1e7c": "\u0056", // "Ṽ" => "V" - "\u1e7d": "\u0076", // "ṽ" => "v" - "\u1ebc": "\u0045", // "Ẽ" => "E" - "\u1ebd": "\u0065", // "ẽ" => "e" - "\u1ef8": "\u0059", // "Ỹ" => "Y" - "\u1ef9": "\u0079", // "ỹ" => "y" - "\u20a4": "\u00a3", // "₤" => "£" -//"\u20ac": "\u20ac", // "€" => "€", already in default alphabet -}; - -this.RADIOTECH_FAMILY_3GPP = 1; // GSM, WCDMA, LTE -this.RADIOTECH_FAMILY_3GPP2 = 2; // CDMA, EVDO - -this.DATACALL_RADIOTECHNOLOGY_CDMA = 0; -this.DATACALL_RADIOTECHNOLOGY_GSM = 1; - -this.DATACALL_AUTH_NONE = 0; -this.DATACALL_AUTH_PAP = 1; -this.DATACALL_AUTH_CHAP = 2; -this.DATACALL_AUTH_PAP_OR_CHAP = 3; - -this.GECKO_DATACALL_AUTH_NONE = "none"; -this.GECKO_DATACALL_AUTH_PAP = "pap"; -this.GECKO_DATACALL_AUTH_CHAP = "chap"; -this.GECKO_DATACALL_AUTH_PAP_OR_CHAP = "papOrChap"; -this.GECKO_DATACALL_AUTH_DEFAULT = GECKO_DATACALL_AUTH_PAP_OR_CHAP; -this.RIL_DATACALL_AUTH_TO_GECKO = [ - GECKO_DATACALL_AUTH_NONE, // DATACALL_AUTH_NONE - GECKO_DATACALL_AUTH_PAP, // DATACALL_AUTH_PAP - GECKO_DATACALL_AUTH_CHAP, // DATACALL_AUTH_CHAP - GECKO_DATACALL_AUTH_PAP_OR_CHAP // DATACALL_AUTH_PAP_OR_CHAP -]; - -this.GECKO_DATACALL_PDP_TYPE_IP = "IP"; -this.GECKO_DATACALL_PDP_TYPE_IPV4V6 = "IPV4V6"; -this.GECKO_DATACALL_PDP_TYPE_IPV6 = "IPV6"; -this.GECKO_DATACALL_PDP_TYPE_DEFAULT = GECKO_DATACALL_PDP_TYPE_IP; -this.RIL_DATACALL_PDP_TYPES = [ - GECKO_DATACALL_PDP_TYPE_IP, - GECKO_DATACALL_PDP_TYPE_IPV4V6, - GECKO_DATACALL_PDP_TYPE_IPV6, -]; - -this.DATACALL_PROFILE_DEFAULT = 0; -this.DATACALL_PROFILE_TETHERED = 1; -this.DATACALL_PROFILE_OEM_BASE = 1000; - -this.DATACALL_DEACTIVATE_NO_REASON = 0; -this.DATACALL_DEACTIVATE_RADIO_SHUTDOWN = 1; - -this.DATACALL_ACTIVE_UNKNOWN = -1; -this.DATACALL_INACTIVE = 0; -this.DATACALL_ACTIVE_DOWN = 1; -this.DATACALL_ACTIVE_UP = 2; - -this.DATACALL_FAIL_NONE = 0; -this.DATACALL_FAIL_OPERATOR_BARRED = 0x08; -this.DATACALL_FAIL_INSUFFICIENT_RESOURCES = 0x1A; -this.DATACALL_FAIL_MISSING_UKNOWN_APN = 0x1B; -this.DATACALL_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C; -this.DATACALL_FAIL_USER_AUTHENTICATION = 0x1D; -this.DATACALL_FAIL_ACTIVATION_REJECT_GGSN = 0x1E; -this.DATACALL_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F; -this.DATACALL_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20; -this.DATACALL_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21; -this.DATACALL_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22; -this.DATACALL_FAIL_NSAPI_IN_USE = 0x23; -this.DATACALL_FAIL_ONLY_IPV4_ALLOWED = 0x32; -this.DATACALL_FAIL_ONLY_IPV6_ALLOWED = 0x33; -this.DATACALL_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34; -this.DATACALL_FAIL_PROTOCOL_ERRORS = 0x6F; -this.DATACALL_FAIL_VOICE_REGISTRATION_FAIL = -1; -this.DATACALL_FAIL_DATA_REGISTRATION_FAIL = -2; -this.DATACALL_FAIL_SIGNAL_LOST = -3; -this.DATACALL_FAIL_PREF_RADIO_TECH_CHANGED = -4; -this.DATACALL_FAIL_RADIO_POWER_OFF = -5; -this.DATACALL_FAIL_TETHERED_CALL_ACTIVE = -6; -this.DATACALL_FAIL_ERROR_UNSPECIFIED = 0xffff; - -// Keep consistent with nsINetworkManager.NETWORK_STATE_*. -this.GECKO_NETWORK_STATE_UNKNOWN = -1; -this.GECKO_NETWORK_STATE_CONNECTING = 0; -this.GECKO_NETWORK_STATE_CONNECTED = 1; -this.GECKO_NETWORK_STATE_DISCONNECTING = 2; -this.GECKO_NETWORK_STATE_DISCONNECTED = 3; - -// 3GPP 24.008 Annex H. -this.CALL_FAIL_UNOBTAINABLE_NUMBER = 1; -this.CALL_FAIL_NO_ROUTE_TO_DESTINATION = 3; -this.CALL_FAIL_CHANNEL_UNACCEPTABLE = 6; -this.CALL_FAIL_OPERATOR_DETERMINED_BARRING = 8; -this.CALL_FAIL_NORMAL = 16; -this.CALL_FAIL_BUSY = 17; -this.CALL_FAIL_NO_USER_RESPONDING = 18; -this.CALL_FAIL_USER_ALERTING = 19; -this.CALL_FAIL_CALL_REJECTED = 21; -this.CALL_FAIL_NUMBER_CHANGED = 22; -this.CALL_FAIL_CALL_REJECTED_DESTINATION_FEATURE = 24; -this.CALL_FAIL_CALL_PRE_EMPTION = 25; -this.CALL_FAIL_DEST_OUT_OF_ORDER = 27; -this.CALL_FAIL_INVALID_FORMAT = 28; -this.CALL_FAIL_FACILITY_REJECTED = 29; -this.CALL_FAIL_RESPONSE_TO_STATUS_ENQUIRY = 30; -this.CALL_FAIL_NORMAL_UNSPECIFIED = 31; -this.CALL_FAIL_CONGESTION = 34; -this.CALL_FAIL_NETWORK_OUT_OF_ORDER = 38; -this.CALL_FAIL_NETWORK_TEMP_FAILURE = 41; -this.CALL_FAIL_SWITCHING_EQUIP_CONGESTION = 42; -this.CALL_FAIL_ACCESS_INFO_DISCARDED = 43; -this.CALL_FAIL_REQUESTED_CHANNEL_NOT_AVAILABLE = 44; -this.CALL_FAIL_RESOURCE_UNAVAILABLE = 47; -this.CALL_FAIL_QOS_UNAVAILABLE = 49; -this.CALL_FAIL_REQUESTED_FACILITY_NOT_SUBSCRIBED = 50; -this.CALL_FAIL_INCOMING_CALLS_BARRED_WITHIN_CUG = 55; -this.CALL_FAIL_BEARER_CAPABILITY_NOT_AUTHORIZED = 57; -this.CALL_FAIL_BEARER_CAPABILITY_NOT_AVAILABLE = 58; -this.CALL_FAIL_SERVICE_NOT_AVAILABLE = 63; -this.CALL_FAIL_BEARER_NOT_IMPLEMENTED = 65; -this.CALL_FAIL_ACM_LIMIT_EXCEEDED = 68; -this.CALL_FAIL_REQUESTED_FACILITY_NOT_IMPLEMENTED = 69; -this.CALL_FAIL_UNRESTRICTED_BEARER_NOT_AVAILABLE = 70; -this.CALL_FAIL_SERVICE_NOT_IMPLEMENTED = 79; -this.CALL_FAIL_INVALID_TRANSACTION_ID = 81; -this.CALL_FAIL_USER_NOT_CUG_MEMBER = 87; -this.CALL_FAIL_INCOMPATIBLE_DESTINATION = 88; -this.CALL_FAIL_INVALID_TRANSIT_NETWORK_SELECTION = 91; -this.CALL_FAIL_SEMANTICALLY_INCORRECT_MESSAGE = 95; -this.CALL_FAIL_INVALID_MANDATORY_INFO = 96; -this.CALL_FAIL_MESSAGE_TYPE_NOT_IMPLEMENTED = 97; -this.CALL_FAIL_MESSAGE_TYPE_INCOMPATIBLE_PROTOCOL_STATE = 98; -this.CALL_FAIL_INFO_ELEMENT_NOT_IMPLEMENTED = 99; -this.CALL_FAIL_CONDITIONAL_IE_ERROR = 100; -this.CALL_FAIL_MESSAGE_INCOMPABITLE_PROTOCOL_STATE = 101; -this.CALL_FAIL_RECOVERY_ON_TIMER_EXPIRY = 102; -this.CALL_FAIL_PROTOCOL_ERROR = 111; -this.CALL_FAIL_INTERWORKING = 127; -// AOSP ril.h -this.CALL_FAIL_CALL_BARRED = 240; -this.CALL_FAIL_FDN_BLOCKED = 241; -this.CALL_FAIL_IMSI_UNKNOWN_IN_VLR = 242; -this.CALL_FAIL_IMEI_NOT_ACCEPTED = 243; -this.CALL_FAIL_DIAL_MODIFIED_TO_USSD = 244; // STK Call Control -this.CALL_FAIL_DIAL_MODIFIED_TO_SS = 245; -this.CALL_FAIL_DIAL_MODIFIED_TO_DIAL = 246; -this.CALL_FAIL_CDMA_LOCKED_UNTIL_POWER_CYCLE = 1000; -this.CALL_FAIL_CDMA_DROP = 1001; -this.CALL_FAIL_CDMA_INTERCEPT = 1002; -this.CALL_FAIL_CDMA_REORDER = 1003; -this.CALL_FAIL_CDMA_SO_REJECT = 1004; -this.CALL_FAIL_CDMA_RETRY_ORDER = 1005; -this.CALL_FAIL_CDMA_ACCESS_FAILURE = 1006; -this.CALL_FAIL_CDMA_PREEMPTED = 1007; -this.CALL_FAIL_CDMA_NOT_EMERGENCY = 1008; // For non-emergency number dialed - // during emergency callback mode -this.CALL_FAIL_CDMA_ACCESS_BLOCKED = 1009; -this.CALL_FAIL_ERROR_UNSPECIFIED = 0xffff; - -// See nsIMobileConnection::MOBILE_RADIO_STATE_* -this.GECKO_RADIOSTATE_UNKNOWN = -1; -this.GECKO_RADIOSTATE_ENABLED = 0; -this.GECKO_RADIOSTATE_DISABLED = 1; - -// Only used in ril_worker.js -this.GECKO_CARDSTATE_UNINITIALIZED = 4294967294; // UINT32_MAX - 1 -// See nsIIcc::CARD_STATE_* -this.GECKO_CARDSTATE_UNDETECTED = 4294967295; // UINT32_MAX -this.GECKO_CARDSTATE_UNKNOWN = 0; -this.GECKO_CARDSTATE_READY = 1; -this.GECKO_CARDSTATE_PIN_REQUIRED = 2; -this.GECKO_CARDSTATE_PUK_REQUIRED = 3; -this.GECKO_CARDSTATE_PERMANENT_BLOCKED = 4; -this.GECKO_CARDSTATE_PERSONALIZATION_IN_PROGRESS = 5; -this.GECKO_CARDSTATE_PERSONALIZATION_READY = 6; -this.GECKO_CARDSTATE_NETWORK_LOCKED = 7; -this.GECKO_CARDSTATE_NETWORK_SUBSET_LOCKED = 8; -this.GECKO_CARDSTATE_CORPORATE_LOCKED = 9; -this.GECKO_CARDSTATE_SERVICE_PROVIDER_LOCKED = 10; -this.GECKO_CARDSTATE_SIM_LOCKED = 11; -this.GECKO_CARDSTATE_NETWORK_PUK_REQUIRED = 12; -this.GECKO_CARDSTATE_NETWORK_SUBSET_PUK_REQUIRED = 13; -this.GECKO_CARDSTATE_CORPORATE_PUK_REQUIRED = 14; -this.GECKO_CARDSTATE_SERVICE_PROVIDER_PUK_REQUIRED = 15; -this.GECKO_CARDSTATE_SIM_PUK_REQUIRED = 16; -this.GECKO_CARDSTATE_NETWORK1_LOCKED = 17; -this.GECKO_CARDSTATE_NETWORK2_LOCKED = 18; -this.GECKO_CARDSTATE_HRPD_NETWORK_LOCKED = 19; -this.GECKO_CARDSTATE_RUIM_CORPORATE_LOCKED = 20; -this.GECKO_CARDSTATE_RUIM_SERVICE_PROVIDER_LOCKED = 21; -this.GECKO_CARDSTATE_RUIM_LOCKED = 22; -this.GECKO_CARDSTATE_NETWORK1_PUK_REQUIRED = 23; -this.GECKO_CARDSTATE_NETWORK2_PUK_REQUIRED = 24; -this.GECKO_CARDSTATE_HRPD_NETWORK_PUK_REQUIRED = 25; -this.GECKO_CARDSTATE_RUIM_CORPORATE_PUK_REQUIRED = 26; -this.GECKO_CARDSTATE_RUIM_SERVICE_PROVIDER_PUK_REQUIRED = 27; -this.GECKO_CARDSTATE_RUIM_PUK_REQUIRED = 28; -this.GECKO_CARDSTATE_ILLEGAL = 29; - -// See nsIIcc::CARD_LOCK_TYPE_* -this.GECKO_CARDLOCK_PIN = 0; -this.GECKO_CARDLOCK_PIN2 = 1; -this.GECKO_CARDLOCK_PUK = 2; -this.GECKO_CARDLOCK_PUK2 = 3; -this.GECKO_CARDLOCK_NCK = 4; -this.GECKO_CARDLOCK_NSCK = 5; -this.GECKO_CARDLOCK_NCK1 = 6; -this.GECKO_CARDLOCK_NCK2 = 7; -this.GECKO_CARDLOCK_HNCK = 8; -this.GECKO_CARDLOCK_CCK = 9; -this.GECKO_CARDLOCK_SPCK = 10; -this.GECKO_CARDLOCK_PCK = 11; -this.GECKO_CARDLOCK_RCCK = 12; -this.GECKO_CARDLOCK_RSPCK = 13; -this.GECKO_CARDLOCK_NCK_PUK = 14; -this.GECKO_CARDLOCK_NSCK_PUK = 15; -this.GECKO_CARDLOCK_NCK1_PUK = 16; -this.GECKO_CARDLOCK_NCK2_PUK = 17; -this.GECKO_CARDLOCK_HNCK_PUK = 18; -this.GECKO_CARDLOCK_CCK_PUK = 19; -this.GECKO_CARDLOCK_SPCK_PUK = 20; -this.GECKO_CARDLOCK_PCK_PUK = 21; -this.GECKO_CARDLOCK_RCCK_PUK = 22; -this.GECKO_CARDLOCK_RSPCK_PUK = 23; -this.GECKO_CARDLOCK_FDN = 24; - -this.GECKO_CARDLOCK_TO_FACILITY = {}; -GECKO_CARDLOCK_TO_FACILITY[GECKO_CARDLOCK_PIN] = ICC_CB_FACILITY_SIM; -GECKO_CARDLOCK_TO_FACILITY[GECKO_CARDLOCK_FDN] = ICC_CB_FACILITY_FDN; - -this.GECKO_CARDLOCK_TO_SEL_CODE = {}; -GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOCK_PIN] = ICC_SEL_CODE_SIM_PIN; -GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOCK_PIN2] = ICC_SEL_CODE_SIM_PIN2; -GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOCK_PUK] = ICC_SEL_CODE_SIM_PUK; -GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOCK_PUK2] = ICC_SEL_CODE_SIM_PUK2; -GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOCK_NCK] = ICC_SEL_CODE_PH_NET_PIN; -GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOCK_NSCK] = ICC_SEL_CODE_PH_NETSUB_PIN; -GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOCK_CCK] = ICC_SEL_CODE_PH_CORP_PIN; -GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOCK_SPCK] = ICC_SEL_CODE_PH_SP_PIN; -// TODO: Bug 1116072: identify the mapping between RIL_PERSOSUBSTATE_SIM_SIM @ -// ril.h and TS 27.007, clause 8.65 for GECKO_CARDLOCK_PCK. - -// See nsIIcc::CARD_CONTACT_TYPE_* -this.GECKO_CARDCONTACT_TYPE_ADN = 0; -this.GECKO_CARDCONTACT_TYPE_FDN = 1; -this.GECKO_CARDCONTACT_TYPE_SDN = 2; - -// See nsIIcc::CARD_MVNO_TYPE_* -this.GECKO_CARDMVNO_TYPE_IMSI = 0; -this.GECKO_CARDMVNO_TYPE_SPN = 1; -this.GECKO_CARDMVNO_TYPE_GID = 2; - -// See nsIIcc::CARD_SERVICE_* -this.GECKO_CARDSERVICE_FDN = 0; - -// See ril.h RIL_PersoSubstate -this.PERSONSUBSTATE = {}; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_UNKNOWN] = GECKO_CARDSTATE_UNKNOWN; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_IN_PROGRESS] = GECKO_CARDSTATE_PERSONALIZATION_IN_PROGRESS; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_READY] = GECKO_CARDSTATE_PERSONALIZATION_READY; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_NETWORK] = GECKO_CARDSTATE_NETWORK_LOCKED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_NETWORK_SUBSET] = GECKO_CARDSTATE_NETWORK_SUBSET_LOCKED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_CORPORATE] = GECKO_CARDSTATE_CORPORATE_LOCKED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_SERVICE_PROVIDER] = GECKO_CARDSTATE_SERVICE_PROVIDER_LOCKED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_SIM] = GECKO_CARDSTATE_SIM_LOCKED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_NETWORK_PUK] = GECKO_CARDSTATE_NETWORK_PUK_REQUIRED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK] = GECKO_CARDSTATE_NETWORK_SUBSET_PUK_REQUIRED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_CORPORATE_PUK] = GECKO_CARDSTATE_CORPORATE_PUK_REQUIRED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK] = GECKO_CARDSTATE_SERVICE_PROVIDER_PUK_REQUIRED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_SIM_PUK] = GECKO_CARDSTATE_SIM_PUK_REQUIRED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_NETWORK1] = GECKO_CARDSTATE_NETWORK1_LOCKED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_NETWORK2] = GECKO_CARDSTATE_NETWORK2_LOCKED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_HRPD] = GECKO_CARDSTATE_HRPD_NETWORK_LOCKED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_CORPORATE] = GECKO_CARDSTATE_RUIM_CORPORATE_LOCKED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER] = GECKO_CARDSTATE_RUIM_SERVICE_PROVIDER_LOCKED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_RUIM] = GECKO_CARDSTATE_RUIM_LOCKED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_NETWORK1_PUK] = GECKO_CARDSTATE_NETWORK1_PUK_REQUIRED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_NETWORK2_PUK] = GECKO_CARDSTATE_NETWORK2_PUK_REQUIRED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_HRPD_PUK] = GECKO_CARDSTATE_HRPD_NETWORK_PUK_REQUIRED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_CORPORATE_PUK] = GECKO_CARDSTATE_RUIM_CORPORATE_PUK_REQUIRED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK] = GECKO_CARDSTATE_RUIM_SERVICE_PROVIDER_PUK_REQUIRED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_RUIM_PUK] = GECKO_CARDSTATE_RUIM_PUK_REQUIRED; - -// See nsIMobileConnection::NETWORK_SELECTION_MODE_* -this.GECKO_NETWORK_SELECTION_UNKNOWN = -1; -this.GECKO_NETWORK_SELECTION_AUTOMATIC = 0; -this.GECKO_NETWORK_SELECTION_MANUAL = 1; - -this.GECKO_MOBILE_CONNECTION_STATE_UNKNOWN = null; -this.GECKO_MOBILE_CONNECTION_STATE_NOTSEARCHING = "notSearching"; -this.GECKO_MOBILE_CONNECTION_STATE_SEARCHING = "searching"; -this.GECKO_MOBILE_CONNECTION_STATE_REGISTERED = "registered"; -this.GECKO_MOBILE_CONNECTION_STATE_DENIED = "denied"; - -this.NETWORK_CREG_TO_GECKO_MOBILE_CONNECTION_STATE = {}; -NETWORK_CREG_TO_GECKO_MOBILE_CONNECTION_STATE[NETWORK_CREG_STATE_NOT_SEARCHING] = GECKO_MOBILE_CONNECTION_STATE_NOTSEARCHING; -NETWORK_CREG_TO_GECKO_MOBILE_CONNECTION_STATE[NETWORK_CREG_STATE_REGISTERED_HOME] = GECKO_MOBILE_CONNECTION_STATE_REGISTERED; -NETWORK_CREG_TO_GECKO_MOBILE_CONNECTION_STATE[NETWORK_CREG_STATE_SEARCHING] = GECKO_MOBILE_CONNECTION_STATE_SEARCHING; -NETWORK_CREG_TO_GECKO_MOBILE_CONNECTION_STATE[NETWORK_CREG_STATE_DENIED] = GECKO_MOBILE_CONNECTION_STATE_DENIED; -NETWORK_CREG_TO_GECKO_MOBILE_CONNECTION_STATE[NETWORK_CREG_STATE_UNKNOWN] = GECKO_MOBILE_CONNECTION_STATE_UNKNOWN; -NETWORK_CREG_TO_GECKO_MOBILE_CONNECTION_STATE[NETWORK_CREG_STATE_REGISTERED_ROAMING] = GECKO_MOBILE_CONNECTION_STATE_REGISTERED; -NETWORK_CREG_TO_GECKO_MOBILE_CONNECTION_STATE[NETWORK_CREG_STATE_NOT_SEARCHING_EMERGENCY_CALLS] = GECKO_MOBILE_CONNECTION_STATE_NOTSEARCHING; -NETWORK_CREG_TO_GECKO_MOBILE_CONNECTION_STATE[NETWORK_CREG_STATE_SEARCHING_EMERGENCY_CALLS] = GECKO_MOBILE_CONNECTION_STATE_SEARCHING; -NETWORK_CREG_TO_GECKO_MOBILE_CONNECTION_STATE[NETWORK_CREG_STATE_DENIED_EMERGENCY_CALLS] = GECKO_MOBILE_CONNECTION_STATE_DENIED; -NETWORK_CREG_TO_GECKO_MOBILE_CONNECTION_STATE[NETWORK_CREG_STATE_UNKNOWN_EMERGENCY_CALLS] = GECKO_MOBILE_CONNECTION_STATE_UNKNOWN; - - -// Should match enum TelephonyCallDisconnectedReason defined in TelephonyCall.webidl -this.GECKO_CALL_ERROR_BAD_NUMBER = "BadNumberError"; -this.GECKO_CALL_ERROR_NO_ROUTE_TO_DESTINATION = "NoRouteToDestinationError"; -this.GECKO_CALL_ERROR_CHANNEL_UNACCEPTABLE = "ChannelUnacceptableError"; -this.GECKO_CALL_ERROR_OPERATOR_DETERMINED_BARRING = "OperatorDeterminedBarringError"; -this.GECKO_CALL_ERROR_NORMAL_CALL_CLEARING = "NormalCallClearingError"; -this.GECKO_CALL_ERROR_BUSY = "BusyError"; -this.GECKO_CALL_ERROR_NO_USER_RESPONDING = "NoUserRespondingError"; -this.GECKO_CALL_ERROR_USER_ALERTING = "UserAlertingNoAnswerError"; -this.GECKO_CALL_ERROR_REJECTED = "CallRejectedError"; -this.GECKO_CALL_ERROR_NUMBER_CHANGED = "NumberChangedError"; -this.GECKO_CALL_ERROR_REJECTED_DETINATION_FEATURE = "CallRejectedDestinationFeatureError"; -this.GECKO_CALL_ERROR_PRE_EMPTION = "PreEmptionError"; -this.GECKO_CALL_ERROR_DEST_OUT_OF_ORDER = "DestinationOutOfOrderError"; -this.GECKO_CALL_ERROR_INVALID_NUMBER_FORMAT = "InvalidNumberFormatError"; -this.GECKO_CALL_ERROR_FACILITY_REJECTED = "FacilityRejectedError"; -this.GECKO_CALL_ERROR_RESPONSE_TO_STATUS_ENQUIRY = "ResponseToStatusEnquiryError"; -this.GECKO_CALL_ERROR_CONGESTION = "CongestionError"; -this.GECKO_CALL_ERROR_NETWORK_OUT_OF_ORDER = "NetworkOutOfOrderError"; -this.GECKO_CALL_ERROR_NETWORK_TEMP_FAILURE = "NetworkTempFailureError"; -this.GECKO_CALL_ERROR_SWITCHING_EQUIP_CONGESTION = "SwitchingEquipCongestionError"; -this.GECKO_CALL_ERROR_ACCESS_INFO_DISCARDED = "AccessInfoDiscardedError"; -this.GECKO_CALL_ERROR_REQUESTED_CHANNEL_NOT_AVAILABLE = "RequestedChannelNotAvailableError"; -this.GECKO_CALL_ERROR_RESOURCE_UNAVAILABLE = "ResourceUnavailableError"; -this.GECKO_CALL_ERROR_QOS_UNAVAILABLE = "QosUnavailableError"; -this.GECKO_CALL_ERROR_REQUESTED_FACILITY_NOT_SUBSCRIBED = "RequestedFacilityNotSubscribedError"; -this.GECKO_CALL_ERROR_INCOMING_CALLS_BARRED_WITHIN_CUG = "IncomingCallsBarredWithinCugError"; -this.GECKO_CALL_ERROR_BEARER_CAPABILITY_NOT_AUTHORIZED = "BearerCapabilityNotAuthorizedError"; -this.GECKO_CALL_ERROR_BEARER_CAPABILITY_NOT_AVAILABLE = "BearerCapabilityNotAvailableError"; -this.GECKO_CALL_ERROR_BEARER_NOT_IMPLEMENTED = "BearerNotImplementedError"; -this.GECKO_CALL_ERROR_SERVICE_NOT_AVAILABLE = "ServiceNotAvailableError"; -this.GECKO_CALL_ERROR_INCOMING_CALL_EXCEEDED = "IncomingCallExceededError"; -this.GECKO_CALL_ERROR_REQUESTED_FACILITY_NOT_IMPLEMENTED = "RequestedFacilityNotImplementedError"; -this.GECKO_CALL_ERROR_UNRESTRICTED_BEARER_NOT_AVAILABLE = "UnrestrictedBearerNotAvailableError"; -this.GECKO_CALL_ERROR_SERVICE_NOT_IMPLEMENTED = "ServiceNotImplementedError"; -this.GECKO_CALL_ERROR_INVALID_TRANSACTION_ID = "InvalidTransactionIdError"; -this.GECKO_CALL_ERROR_USER_NOT_CUG_MEMBER = "NotCugMemberError"; -this.GECKO_CALL_ERROR_INCOMPATIBLE_DESTINATION = "IncompatibleDestinationError"; -this.GECKO_CALL_ERROR_INVALID_TRANSIT_NETWORK_SELECTION = "InvalidTransitNetworkSelectionError"; -this.GECKO_CALL_ERROR_SEMANTICALLY_INCORRECT_MESSAGE = "SemanticallyIncorrectMessageError"; -this.GECKO_CALL_ERROR_INVALID_MANDATORY_INFO = "InvalidMandatoryInfoError"; -this.GECKO_CALL_ERROR_MESSAGE_TYPE_NOT_IMPLEMENTED = "MessageTypeNotImplementedError"; -this.GECKO_CALL_ERROR_MESSAGE_TYPE_INCOMPATIBLE_PROTOCOL_STATE = "MessageTypeIncompatibleProtocolStateError"; -this.GECKO_CALL_ERROR_INFO_ELEMENT_NOT_IMPLEMENTED = "InfoElementNotImplementedError"; -this.GECKO_CALL_ERROR_CONDITIONAL_IE = "ConditionalIeError"; -this.GECKO_CALL_ERROR_MESSAGE_INCOMPATIBLE_PROTOCOL_STATE = "MessageIncompatibleProtocolStateError"; -this.GECKO_CALL_ERROR_RECOVERY_ON_TIMER_EXPIRY = "RecoveryOnTimerExpiryError"; -this.GECKO_CALL_ERROR_PROTOCOL = "ProtocolError"; -this.GECKO_CALL_ERROR_INTERWORKING = "InterworkingError"; -this.GECKO_CALL_ERROR_BARRED = "BarredError"; -this.GECKO_CALL_ERROR_FDN_BLOCKED = "FDNBlockedError"; -this.GECKO_CALL_ERROR_SUBSCRIBER_UNKNOWN = "SubscriberUnknownError"; -this.GECKO_CALL_ERROR_DEVICE_NOT_ACCEPTED = "DeviceNotAcceptedError"; -this.GECKO_CALL_ERROR_MODIFIED_TO_DIAL_FAILED = "ModifiedDialError"; -this.GECKO_CALL_ERROR_CDMA_LOCKED_UNTIL_POWER_CYCLE = "CdmaLockedUntilPowerCycleError"; -this.GECKO_CALL_ERROR_CDMA_DROP = "CdmaDropError"; -this.GECKO_CALL_ERROR_CDMA_INTERCEPT = "CdmaInterceptError"; -this.GECKO_CALL_ERROR_CDMA_REORDER = "CdmaReorderError"; -this.GECKO_CALL_ERROR_CDMA_SO_REJECT = "CdmaSoRejectError"; -this.GECKO_CALL_ERROR_CDMA_RETRY_ORDER = "CdmaRetryOrderError"; -this.GECKO_CALL_ERROR_CDMA_ACCESS_FAILURE = "CdmaAcessError"; -this.GECKO_CALL_ERROR_CDMA_PREEMPTED = "CdmaPreemptedError"; -this.GECKO_CALL_ERROR_CDMA_NOT_EMERGENCY = "CdmaNotEmergencyError"; -this.GECKO_CALL_ERROR_CDMA_ACCESS_BLOCKED = "CdmaAccessBlockedError"; -this.GECKO_CALL_ERROR_UNSPECIFIED = "UnspecifiedError"; - -this.RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR = {}; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_UNOBTAINABLE_NUMBER] = GECKO_CALL_ERROR_BAD_NUMBER; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_NO_ROUTE_TO_DESTINATION] = GECKO_CALL_ERROR_NO_ROUTE_TO_DESTINATION; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CHANNEL_UNACCEPTABLE] = GECKO_CALL_ERROR_CHANNEL_UNACCEPTABLE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_OPERATOR_DETERMINED_BARRING] = GECKO_CALL_ERROR_OPERATOR_DETERMINED_BARRING; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_NORMAL] = GECKO_CALL_ERROR_NORMAL_CALL_CLEARING; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_BUSY] = GECKO_CALL_ERROR_BUSY; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_NO_USER_RESPONDING] = GECKO_CALL_ERROR_NO_USER_RESPONDING; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_USER_ALERTING] = GECKO_CALL_ERROR_USER_ALERTING; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CALL_REJECTED] = GECKO_CALL_ERROR_REJECTED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_NUMBER_CHANGED] = GECKO_CALL_ERROR_NUMBER_CHANGED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CALL_REJECTED_DESTINATION_FEATURE] = GECKO_CALL_ERROR_REJECTED_DETINATION_FEATURE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CALL_PRE_EMPTION] = GECKO_CALL_ERROR_PRE_EMPTION; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_DEST_OUT_OF_ORDER] = GECKO_CALL_ERROR_DEST_OUT_OF_ORDER; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_INVALID_FORMAT] = GECKO_CALL_ERROR_INVALID_NUMBER_FORMAT; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_FACILITY_REJECTED] = GECKO_CALL_ERROR_FACILITY_REJECTED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_RESPONSE_TO_STATUS_ENQUIRY] = GECKO_CALL_ERROR_RESPONSE_TO_STATUS_ENQUIRY; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_NORMAL_UNSPECIFIED] = GECKO_CALL_ERROR_NORMAL_CALL_CLEARING; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CONGESTION] = GECKO_CALL_ERROR_CONGESTION; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_NETWORK_OUT_OF_ORDER] = GECKO_CALL_ERROR_NETWORK_OUT_OF_ORDER; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_NETWORK_TEMP_FAILURE] = GECKO_CALL_ERROR_NETWORK_TEMP_FAILURE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_SWITCHING_EQUIP_CONGESTION] = GECKO_CALL_ERROR_SWITCHING_EQUIP_CONGESTION; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_ACCESS_INFO_DISCARDED] = GECKO_CALL_ERROR_ACCESS_INFO_DISCARDED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_REQUESTED_CHANNEL_NOT_AVAILABLE] = GECKO_CALL_ERROR_REQUESTED_CHANNEL_NOT_AVAILABLE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_RESOURCE_UNAVAILABLE] = GECKO_CALL_ERROR_RESOURCE_UNAVAILABLE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_QOS_UNAVAILABLE] = GECKO_CALL_ERROR_QOS_UNAVAILABLE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_REQUESTED_FACILITY_NOT_SUBSCRIBED] = GECKO_CALL_ERROR_REQUESTED_FACILITY_NOT_SUBSCRIBED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_INCOMING_CALLS_BARRED_WITHIN_CUG] = GECKO_CALL_ERROR_INCOMING_CALLS_BARRED_WITHIN_CUG; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_BEARER_CAPABILITY_NOT_AUTHORIZED] = GECKO_CALL_ERROR_BEARER_CAPABILITY_NOT_AUTHORIZED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_BEARER_CAPABILITY_NOT_AVAILABLE] = GECKO_CALL_ERROR_BEARER_CAPABILITY_NOT_AVAILABLE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_SERVICE_NOT_AVAILABLE] = GECKO_CALL_ERROR_SERVICE_NOT_AVAILABLE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_BEARER_NOT_IMPLEMENTED] = GECKO_CALL_ERROR_BEARER_NOT_IMPLEMENTED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_ACM_LIMIT_EXCEEDED] = GECKO_CALL_ERROR_INCOMING_CALL_EXCEEDED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_REQUESTED_FACILITY_NOT_IMPLEMENTED] = GECKO_CALL_ERROR_REQUESTED_FACILITY_NOT_IMPLEMENTED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_UNRESTRICTED_BEARER_NOT_AVAILABLE] = GECKO_CALL_ERROR_UNRESTRICTED_BEARER_NOT_AVAILABLE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_SERVICE_NOT_IMPLEMENTED] = GECKO_CALL_ERROR_SERVICE_NOT_IMPLEMENTED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_INVALID_TRANSACTION_ID] = GECKO_CALL_ERROR_INVALID_TRANSACTION_ID; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_USER_NOT_CUG_MEMBER] = GECKO_CALL_ERROR_USER_NOT_CUG_MEMBER; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_INCOMPATIBLE_DESTINATION] = GECKO_CALL_ERROR_INCOMPATIBLE_DESTINATION; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_INVALID_TRANSIT_NETWORK_SELECTION] = GECKO_CALL_ERROR_INVALID_TRANSIT_NETWORK_SELECTION; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_SEMANTICALLY_INCORRECT_MESSAGE] = GECKO_CALL_ERROR_SEMANTICALLY_INCORRECT_MESSAGE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_INVALID_MANDATORY_INFO] = GECKO_CALL_ERROR_INVALID_MANDATORY_INFO; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_MESSAGE_TYPE_NOT_IMPLEMENTED] = GECKO_CALL_ERROR_MESSAGE_TYPE_NOT_IMPLEMENTED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_MESSAGE_TYPE_INCOMPATIBLE_PROTOCOL_STATE] = GECKO_CALL_ERROR_MESSAGE_TYPE_INCOMPATIBLE_PROTOCOL_STATE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_INFO_ELEMENT_NOT_IMPLEMENTED] = GECKO_CALL_ERROR_INFO_ELEMENT_NOT_IMPLEMENTED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CONDITIONAL_IE_ERROR] = GECKO_CALL_ERROR_CONDITIONAL_IE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_MESSAGE_INCOMPABITLE_PROTOCOL_STATE] = GECKO_CALL_ERROR_MESSAGE_INCOMPATIBLE_PROTOCOL_STATE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_RECOVERY_ON_TIMER_EXPIRY] = GECKO_CALL_ERROR_RECOVERY_ON_TIMER_EXPIRY; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_PROTOCOL_ERROR] = GECKO_CALL_ERROR_PROTOCOL; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_INTERWORKING] = GECKO_CALL_ERROR_INTERWORKING; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CALL_BARRED] = GECKO_CALL_ERROR_BARRED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_FDN_BLOCKED] = GECKO_CALL_ERROR_FDN_BLOCKED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_IMSI_UNKNOWN_IN_VLR] = GECKO_CALL_ERROR_SUBSCRIBER_UNKNOWN; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_IMEI_NOT_ACCEPTED] = GECKO_CALL_ERROR_DEVICE_NOT_ACCEPTED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_DIAL_MODIFIED_TO_USSD] = GECKO_CALL_ERROR_MODIFIED_TO_DIAL_FAILED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_DIAL_MODIFIED_TO_SS] = GECKO_CALL_ERROR_MODIFIED_TO_DIAL_FAILED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_DIAL_MODIFIED_TO_DIAL] = GECKO_CALL_ERROR_MODIFIED_TO_DIAL_FAILED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CDMA_LOCKED_UNTIL_POWER_CYCLE] = GECKO_CALL_ERROR_CDMA_LOCKED_UNTIL_POWER_CYCLE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CDMA_DROP] = GECKO_CALL_ERROR_CDMA_DROP; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CDMA_INTERCEPT] = GECKO_CALL_ERROR_CDMA_INTERCEPT; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CDMA_REORDER] = GECKO_CALL_ERROR_CDMA_REORDER; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CDMA_SO_REJECT] = GECKO_CALL_ERROR_CDMA_SO_REJECT; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CDMA_RETRY_ORDER] = GECKO_CALL_ERROR_CDMA_RETRY_ORDER; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CDMA_ACCESS_FAILURE] = GECKO_CALL_ERROR_CDMA_ACCESS_FAILURE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CDMA_PREEMPTED] = GECKO_CALL_ERROR_CDMA_PREEMPTED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CDMA_NOT_EMERGENCY] = GECKO_CALL_ERROR_CDMA_NOT_EMERGENCY; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CDMA_ACCESS_BLOCKED] = GECKO_CALL_ERROR_CDMA_ACCESS_BLOCKED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_ERROR_UNSPECIFIED] = GECKO_CALL_ERROR_UNSPECIFIED; - -this.GECKO_DATACALL_ERROR_OPERATOR_BARRED = "OperatorBarredError"; -this.GECKO_DATACALL_ERROR_INSUFFICIENT_RESOURCES = "InsufficientResourcesError"; -this.GECKO_DATACALL_ERROR_MISSING_UKNOWN_APN = "MissingUnknownAPNError"; -this.GECKO_DATACALL_ERROR_UNKNOWN_PDP_ADDRESS_TYPE = "UnknownPDPAddressTypeError"; -this.GECKO_DATACALL_ERROR_USER_AUTHENTICATION = "UserAuthenticationError"; -this.GECKO_DATACALL_ERROR_ACTIVATION_REJECT_GGSN = "ActivationRejectGGSNError"; -this.GECKO_DATACALL_ERROR_ACTIVATION_REJECT_UNSPECIFIED = "ActivationRejectUnspecifiedError"; -this.GECKO_DATACALL_ERROR_SERVICE_OPTION_NOT_SUPPORTED = "ServiceOptionNotSupportedError"; -this.GECKO_DATACALL_ERROR_SERVICE_OPTION_NOT_SUBSCRIBED = "ServiceOptionNotSubscribedError"; -this.GECKO_DATACALL_ERROR_SERVICE_OPTION_OUT_OF_ORDER = "ServiceOptionOutOfOrderError"; -this.GECKO_DATACALL_ERROR_NSAPI_IN_USE = "NSAPIInUseError"; -this.GECKO_DATACALL_ERROR_ONLY_IPV4_ALLOWED = "OnlyIPv4Error"; -this.GECKO_DATACALL_ERROR_ONLY_IPV6_ALLOWED = "OnlyIPv6Error"; -this.GECKO_DATACALL_ERROR_ONLY_SINGLE_BEARER_ALLOWED = "OnlySingleBearerAllowedError"; -this.GECKO_DATACALL_ERROR_PROTOCOL_ERRORS = "ProtocolErrorsError"; -this.GECKO_DATACALL_ERROR_VOICE_REGISTRATION_FAIL = "VoiceRegistrationFailError"; -this.GECKO_DATACALL_ERROR_DATA_REGISTRATION_FAIL = "DataRegistrationFailError"; -this.GECKO_DATACALL_ERROR_SIGNAL_LOST = "SignalLostError"; -this.GECKO_DATACALL_ERROR_PREF_RADIO_TECH_CHANGED = "PrefRadioTechChangedError"; -this.GECKO_DATACALL_ERROR_RADIO_POWER_OFF = "RadioPowerOffError"; -this.GECKO_DATACALL_ERROR_TETHERED_CALL_ACTIVE = "TetheredCallActiveError"; -this.GECKO_DATACALL_ERROR_UNSPECIFIED = "UnspecifiedError"; - -this.RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR = {}; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_OPERATOR_BARRED] = GECKO_DATACALL_ERROR_OPERATOR_BARRED; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_INSUFFICIENT_RESOURCES] = GECKO_DATACALL_ERROR_INSUFFICIENT_RESOURCES; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_MISSING_UKNOWN_APN] = GECKO_DATACALL_ERROR_MISSING_UKNOWN_APN; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_UNKNOWN_PDP_ADDRESS_TYPE] = GECKO_DATACALL_ERROR_UNKNOWN_PDP_ADDRESS_TYPE; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_USER_AUTHENTICATION] = GECKO_DATACALL_ERROR_USER_AUTHENTICATION; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_ACTIVATION_REJECT_GGSN] = GECKO_DATACALL_ERROR_ACTIVATION_REJECT_GGSN; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_ACTIVATION_REJECT_UNSPECIFIED] = GECKO_DATACALL_ERROR_ACTIVATION_REJECT_UNSPECIFIED; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_SERVICE_OPTION_NOT_SUPPORTED] = GECKO_DATACALL_ERROR_SERVICE_OPTION_NOT_SUPPORTED; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED] = GECKO_DATACALL_ERROR_SERVICE_OPTION_NOT_SUBSCRIBED; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_SERVICE_OPTION_OUT_OF_ORDER] = GECKO_DATACALL_ERROR_SERVICE_OPTION_OUT_OF_ORDER; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_NSAPI_IN_USE] = GECKO_DATACALL_ERROR_NSAPI_IN_USE; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_ONLY_IPV4_ALLOWED] = GECKO_DATACALL_ERROR_ONLY_IPV4_ALLOWED; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_ONLY_IPV6_ALLOWED] = GECKO_DATACALL_ERROR_ONLY_IPV6_ALLOWED; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_ONLY_SINGLE_BEARER_ALLOWED] = GECKO_DATACALL_ERROR_ONLY_SINGLE_BEARER_ALLOWED; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_PROTOCOL_ERRORS] = GECKO_DATACALL_ERROR_PROTOCOL_ERRORS; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_VOICE_REGISTRATION_FAIL] = GECKO_DATACALL_ERROR_VOICE_REGISTRATION_FAIL; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_DATA_REGISTRATION_FAIL] = GECKO_DATACALL_ERROR_DATA_REGISTRATION_FAIL; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_SIGNAL_LOST] = GECKO_DATACALL_ERROR_SIGNAL_LOST; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_PREF_RADIO_TECH_CHANGED] = GECKO_DATACALL_ERROR_PREF_RADIO_TECH_CHANGED; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_RADIO_POWER_OFF] = GECKO_DATACALL_ERROR_RADIO_POWER_OFF; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_TETHERED_CALL_ACTIVE] = GECKO_DATACALL_ERROR_TETHERED_CALL_ACTIVE; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_ERROR_UNSPECIFIED] = GECKO_DATACALL_ERROR_UNSPECIFIED; - -this.GECKO_RADIO_TECH = [ - null, - "gprs", - "edge", - "umts", - "is95a", - "is95b", - "1xrtt", - "evdo0", - "evdoa", - "hsdpa", - "hsupa", - "hspa", - "evdob", - "ehrpd", - "lte", - "hspa+", - "gsm", - null, - "hspa+", // DC-HSPA+ - "hspa+" -]; - -this.GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN = -1; - -// Call forwarding action. Must be in sync with nsIMobileConnectionService interface -this.CALL_FORWARD_ACTION_DISABLE = 0; -this.CALL_FORWARD_ACTION_ENABLE = 1; -this.CALL_FORWARD_ACTION_QUERY_STATUS = 2; -this.CALL_FORWARD_ACTION_REGISTRATION = 3; -this.CALL_FORWARD_ACTION_ERASURE = 4; - -// Call forwarding reason. Must be in sync with nsIMobileConnectionService interface -this.CALL_FORWARD_REASON_UNCONDITIONAL = 0; -this.CALL_FORWARD_REASON_MOBILE_BUSY = 1; -this.CALL_FORWARD_REASON_NO_REPLY = 2; -this.CALL_FORWARD_REASON_NOT_REACHABLE = 3; -this.CALL_FORWARD_REASON_ALL_CALL_FORWARDING = 4; -this.CALL_FORWARD_REASON_ALL_CONDITIONAL_CALL_FORWARDING = 5; - -// Call barring program. Must be in sync with nsIMobileConnectionService interface -this.CALL_BARRING_PROGRAM_ALL_OUTGOING = 0; -this.CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL = 1; -this.CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL_EXCEPT_HOME = 2; -this.CALL_BARRING_PROGRAM_ALL_INCOMING = 3; -this.CALL_BARRING_PROGRAM_INCOMING_ROAMING = 4; -this.CALL_BARRING_PROGRAM_ALL_SERVICE = 5; -this.CALL_BARRING_PROGRAM_OUTGOING_SERVICE = 6; -this.CALL_BARRING_PROGRAM_INCOMING_SERVICE = 7; - -this.CALL_BARRING_PROGRAM_TO_FACILITY = {}; -CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_ALL_OUTGOING] = ICC_CB_FACILITY_BAOC; -CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL] = ICC_CB_FACILITY_BAOIC; -CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL_EXCEPT_HOME] = ICC_CB_FACILITY_BAOICxH; -CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_ALL_INCOMING] = ICC_CB_FACILITY_BAIC; -CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_INCOMING_ROAMING] = ICC_CB_FACILITY_BAICr; -CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_ALL_SERVICE] = ICC_CB_FACILITY_BA_ALL; -CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_OUTGOING_SERVICE] = ICC_CB_FACILITY_BA_MO; -CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_INCOMING_SERVICE] = ICC_CB_FACILITY_BA_MT; - -/** - * CDMA PDU constants - */ - -// SMS Message Type, as defined in 3GPP2 C.S0015-A v2.0, Table 3.4-1 -this.PDU_CDMA_MSG_TYPE_P2P = 0x00; // Point-to-Point -this.PDU_CDMA_MSG_TYPE_BROADCAST = 0x01; // Broadcast -this.PDU_CDMA_MSG_TYPE_ACK = 0x02; // Acknowledge - -// SMS Teleservice Identitifier, as defined in 3GPP2 N.S0005, Table 175 -this.PDU_CDMA_MSG_TELESERIVCIE_ID_SMS = 0x1002; // SMS -this.PDU_CDMA_MSG_TELESERIVCIE_ID_WAP = 0x1004; // WAP -this.PDU_CDMA_MSG_TELESERIVCIE_ID_WEMT = 0x1005; // Wireless Enhanced Messaging Teleservice - // required for fragmented SMS - -// SMS Service Category, as defined in 3GPP2 C.R1001-D, Table 9.3.1-1 -this.PDU_CDMA_MSG_CATEGORY_UNSPEC = 0x00; // Unknown/Unspecified - -// Address Information, Digit Mode, as defined in 3GPP2 C.S0015-A v2.0, sec 3.4.3.3 -this.PDU_CDMA_MSG_ADDR_DIGIT_MODE_DTMF = 0x00; // Digit Mode : DTMF -this.PDU_CDMA_MSG_ADDR_DIGIT_MODE_ASCII = 0x01; // Digit Mode : 8-bit ASCII with MSB = 0 - -// Address Information, Number Mode, as defined in 3GPP2 C.S0015-A v2.0, sec 3.4.3.3 -this.PDU_CDMA_MSG_ADDR_NUMBER_MODE_ANSI = 0x00; // Number Mode : ANSI T1.607-2000(R2004) -this.PDU_CDMA_MSG_ADDR_NUMBER_MODE_ASCII = 0x01; // Number Mode : Data network address format - -// Address Information, Number Type, as defined in 3GPP2 C.S0015-A v2.0, Table 3.4.3.3-1 -this.PDU_CDMA_MSG_ADDR_NUMBER_TYPE_UNKNOWN = 0x00; // Number Type : Unknown -this.PDU_CDMA_MSG_ADDR_NUMBER_TYPE_INTERNATIONAL = 0x01; // Number Type : Internaltional number(+XXXXX) -this.PDU_CDMA_MSG_ADDR_NUMBER_TYPE_NATIONAL = 0x02; // Number Type : National number - -// Address Information, Number Plan, as defined in 3GPP2 C.S0005-D v2.0, Table 2.7.1.3.2.4-3 -this.PDU_CDMA_MSG_ADDR_NUMBER_PLAN_UNKNOWN = 0x00; // Number Plan : Unknown -this.PDU_CDMA_MSG_ADDR_NUMBER_PLAN_ISDN = 0x01; // Number Plan : ISDN/Telephony numbering plan - -// SMS Encoding, as defined in 3GPP2 C.R1001-D, Table 9.1-1 -this.PDU_CDMA_MSG_CODING_OCTET = 0x00; // octet(8-bit), Not tested -this.PDU_CDMA_MSG_CODING_IS_91 = 0x01; // IS-91 Extended Protocol Message(variable), Not tested -this.PDU_CDMA_MSG_CODING_7BITS_ASCII = 0x02; // 7-bit ASCII(7-bit) -this.PDU_CDMA_MSG_CODING_IA5 = 0x03; // IA5(7-bit), Not tested -this.PDU_CDMA_MSG_CODING_UNICODE = 0x04; // Unicode(16-bit) -this.PDU_CDMA_MSG_CODING_SHIFT_JIS = 0x05; // Shift-6 JIS(8/16-bit variable), Not supported -this.PDU_CDMA_MSG_CODING_KOREAN = 0x06; // Korean(8/16-bit variable), Not supported -this.PDU_CDMA_MSG_CODING_LATIN_HEBREW = 0x07; // Latin/ Hebrew(8-bit), ISO/IEC 8859-8, Not supported -this.PDU_CDMA_MSG_CODING_LATIN = 0x08; // Latin(8-bit), ISO/IEC 8859-1, Not tested -this.PDU_CDMA_MSG_CODING_7BITS_GSM = 0x09; // GSM 7-bit default alphabet(7-bit), Not tested -this.PDU_CDMA_MSG_CODING_GSM_DCS = 0x0A; // GSM Data-Coding-Scheme, Not supported - -// SMS Message Type, as defined in 3GPP2 C.S0015-A v2.0, Table 4.5.1-1 -this.PDU_CDMA_MSG_TYPE_DELIVER = 0x01; // Deliver -this.PDU_CDMA_MSG_TYPE_SUBMIT = 0x02; // Submit -this.PDU_CDMA_MSG_TYPE_DELIVER_ACK = 0x04; // Delivery Acknowledgment - -// SMS User Data Subparameters, as defined in 3GPP2 C.S0015-A v2.0, Table 4.5-1 -this.PDU_CDMA_MSG_USERDATA_MSG_ID = 0x00; // Message Identifier -this.PDU_CDMA_MSG_USERDATA_BODY = 0x01; // User Data Body -this.PDU_CDMA_MSG_USERDATA_TIMESTAMP = 0x03; // Message Center Time Stamp -this.PDU_CDMA_MSG_USERDATA_REPLY_OPTION = 0x0A; // Reply Option -this.PDU_CDMA_LANGUAGE_INDICATOR = 0x0D; // Language Indicator -this.PDU_CDMA_MSG_USERDATA_CALLBACK_NUMBER = 0x0E; // Callback Number -this.PDU_CDMA_MSG_USER_DATA_MSG_STATUS = 0x14; // Message Status - -// CDMA Language Indicator: Language groups -// see 3GPP2 C.R1001-F table 9.2-1 -this.CB_CDMA_LANG_GROUP = [ - null, "en", "fr", "es", "ja", "ko", "zh", "he" -]; - -// IS-91 Message Type, as defined in TIA/EIA/IS-91-A, Table 9 -this.PDU_CDMA_MSG_CODING_IS_91_TYPE_VOICEMAIL_STATUS = 0x82; -this.PDU_CDMA_MSG_CODING_IS_91_TYPE_SMS_FULL = 0x83; -this.PDU_CDMA_MSG_CODING_IS_91_TYPE_CLI = 0x84; -this.PDU_CDMA_MSG_CODING_IS_91_TYPE_SMS = 0x85; - -// Information Record Type, reference from ril.h -this.PDU_CDMA_INFO_REC_TYPE_DISPLAY = 0; -this.PDU_CDMA_INFO_REC_TYPE_CALLED_PARTY_NUMBER = 1; -this.PDU_CDMA_INFO_REC_TYPE_CALLING_PARTY_NUMBER = 2; -this.PDU_CDMA_INFO_REC_TYPE_CONNECTED_NUMBER =3; -this.PDU_CDMA_INFO_REC_TYPE_SIGNAL = 4; -this.PDU_CDMA_INFO_REC_TYPE_REDIRECTING_NUMBER = 5; -this.PDU_CDMA_INFO_REC_TYPE_LINE_CONTROL = 6; -this.PDU_CDMA_INFO_REC_TYPE_EXTENDED_DISPLAY = 7; -this.PDU_CDMA_INFO_REC_TYPE_T53_CLIR = 8; -this.PDU_CDMA_INFO_REC_TYPE_T53_RELEASE = 9; -this.PDU_CDMA_INFO_REC_TYPE_T53_AUDIO_CONTROL = 10; - -// Display type of extended display of information record, -// as defined in C.S0005-F v1.0, Table 3.7.5.16-2 -this.INFO_REC_EXTENDED_DISPLAY_BLANK = 0x80; -this.INFO_REC_EXTENDED_DISPLAY_SKIP = 0x81; -this.INFO_REC_EXTENDED_DISPLAY_CONTINATION = 0x82; -this.INFO_REC_EXTENDED_DISPLAY_CALLED_ADDRESS = 0x83; -this.INFO_REC_EXTENDED_DISPLAY_CAUSE = 0x84; -this.INFO_REC_EXTENDED_DISPLAY_PROGRESS_INDICATOR = 0x85; -this.INFO_REC_EXTENDED_DISPLAY_NOTIFICATION_INDICATOR = 0x86; -this.INFO_REC_EXTENDED_DISPLAY_PROMPT = 0x87; -this.INFO_REC_EXTENDED_DISPLAY_ACCUMULATED_DIGITS = 0x88; -this.INFO_REC_EXTENDED_DISPLAY_STATUS = 0x89; -this.INFO_REC_EXTENDED_DISPLAY_INBAND = 0x8A; -this.INFO_REC_EXTENDED_DISPLAY_CALLING_ADDRESS = 0x8B; -this.INFO_REC_EXTENDED_DISPLAY_REASON = 0x8C; -this.INFO_REC_EXTENDED_DISPLAY_CALLING_PARTY_NAME = 0x8D; -this.INFO_REC_EXTENDED_DISPLAY_CALLED_PARTY_NAME = 0x8E; -this.INFO_REC_EXTENDED_DISPLAY_ORIGINAL_CALLED_NAME = 0x8F; -this.INFO_REC_EXTENDED_DISPLAY_REDIRECT_NAME = 0x90; -this.INFO_REC_EXTENDED_DISPLAY_CONNECTED_NAME = 0x91; -this.INFO_REC_EXTENDED_DISPLAY_ORIGINATING_RESTRICTIONS = 0x92; -this.INFO_REC_EXTENDED_DISPLAY_DATE_TIME_OF_DAY = 0x93; -this.INFO_REC_EXTENDED_DISPLAY_CALL_APPEARANCE_ID = 0x94; -this.INFO_REC_EXTENDED_DISPLAY_FEATURE_ADDRESS = 0x95; -this.INFO_REC_EXTENDED_DISPLAY_REDIRECTION_NAME = 0x96; -this.INFO_REC_EXTENDED_DISPLAY_REDIRECTION_NUMBER = 0x97; -this.INFO_REC_EXTENDED_DISPLAY_REDIRECTING_NUMBER = 0x98; -this.INFO_REC_EXTENDED_DISPLAY_ORIGINAL_CALLED_NUMBER = 0x99; -this.INFO_REC_EXTENDED_DISPLAY_CONNECTED_NUMBER = 0x9A; -this.INFO_REC_EXTENDED_DISPLAY_TEXT = 0x9B; - -/** - * The table for MCC/MNC which the length of MNC is 3. - * - * This table is built from below links. - * - http://www.itu.int/pub/T-SP-E.212B-2013 - * - http://en.wikipedia.org/wiki/Mobile_Network_Code - */ -this.PLMN_HAVING_3DIGITS_MNC = { - // Puerto Rico. - "330": - ["110", // América Móvil - "120" // PR Wireless - ], - // Trinidad and Tobago. - "374": - ["130", // Digicel Trinidad and Tobago Ltd. - "140" // LaqTel Ltd. - ], - // India. - "405": - ["000", // Shyam Telelink Ltd. - "005", // Reliance, Delhi - "006", // Reliance, Gujarat - "007", // Reliance, Haryana - "009", // Reliance, J&K - "010", // Reliance, Karnataka - "011", // Reliance, Kerala - "012", // Reliance, Andhra Pradesh - "013", // Reliance, Maharashtr - "014", // Reliance, Madhya Pradesh - "018", // Reliance, Punjab - "020", // Reliance, Tamilnadu - "021", // Reliance, UP (East) - "022", // Reliance, UP (West) - "025", // TATA DOCOMO, Andhra Pradesh - "026", // TATA DOCOMO, Assam - "027", // TATA DOCOMO, Bihar - "028", // TATA DOCOMO, Chennai - "029", // TATA DOCOMO, Delhi - "030", // TATA DOCOMO, Gujarat - "031", // TATA DOCOMO, Haryana - "032", // TATA DOCOMO, Himachal Pradesh - "033", // Reliance, Bihar - "034", // TATA DOCOMO, Kamataka - "035", // TATA DOCOMO, Kerala - "036", // TATA DOCOMO, Kolkata - "037", // TATA DOCOMO, Maharashtra - "038", // TATA DOCOMO, Madhya Pradesh - "039", // TATA DOCOMO, Mumbai - "040", // Reliance, Chennai - "041", // TATA DOCOMO, Orissa - "042", // TATA DOCOMO, Punjab - "043", // TATA DOCOMO, Rajasthan - "044", // TATA DOCOMO, Tamilnadu - "045", // TATA DOCOMO, UP (East) - "046", // TATA DOCOMO, UP (West) - "047", // TATA DOCOMO, West Bengal - "750", // Vodafone IN, J&K - "751", // Vodafone IN, Assam - "752", // Vodafone IN, Bihar - "753", // Vodafone IN, Orissa - "754", // Vodafone IN, Himachal Pradesh - "755", // Vodafone IN, North East - "756", // Vodafone IN, Madhya Pradesh & Chhattisgarh - "799", // Idea, MUMBAI - "800", // Aircell, Delhi - "801", // Aircell, Andhra Pradesh - "802", // Aircell, Gujarat - "803", // Aircell, Kamataka - "804", // Aircell, Maharashtra - "805", // Aircell, Mumbai - "806", // Aircell, Rajasthan - "807", // Aircell, Haryana - "808", // Aircell, Madhya Pradesh - "809", // Aircell, Kerala - "810", // Aircell, Uttar Pradesh (East) - "811", // Aircell, Uttar Pradesh (West) - "812", // Aircell, Punjab - "818", // Uninor, Uttar Pradesh (West) - "819", // Uninor, Andhra Pradesh - "820", // Uninor, Karnataka - "821", // Uninor, Kerala - "822", // Uninor, Kolkata - "824", // Videocon, Assam - "827", // Videocon, Gujarat - "834", // Videocon, Madhya Pradesh - "840", // Jio, West Bengal - "844", // Uninor, Delhi & NCR - "845", // IDEA, Assam - "846", // IDEA, Jammu & Kashmir - "847", // IDEA, Karnataka - "848", // IDEA, Kolkata - "849", // IDEA, North East - "850", // IDEA, Orissa - "851", // IDEA, Punjab - "852", // IDEA, Tamil Nadu - "853", // IDEA, West Bengal - "854", // Jio, Andra Pradesh - "855", // Jio, Assam - "856", // Jio, Bihar - "857", // Jio, Gujarat - "858", // Jio, Haryana - "859", // Jio, Himachal Pradesh - "860", // Jio, Jammu Kashmir - "861", // Jio, Karnataka - "862", // Jio, Kerala - "863", // Jio, Madhyya Pradesh - "864", // Jio, Maharashtra - "865", // Jio, North East - "866", // Jio, Orissa - "867", // Jio, Punjab - "868", // Jio, Rajasthan - "869", // Jio, Tamil Nadu Chennai - "870", // Jio, Uttar Pradesh West - "871", // Jio, Uttar Pradesh East - "872", // Jio, Delhi - "873", // Jio, Kolkatta - "874", // Jio, Mumbai - "875", // Uninor, Assam - "880", // Uninor, West Bengal - "881", // S Tel, Assam - "908", // IDEA, Andhra Pradesh - "909", // IDEA, Delhi - "910", // IDEA, Haryana - "911", // Etisalat, Maharashtra - "912", // Etisalat, Andhra Pradesh - "913", // Etisalat, Delhi & NCR - "914", // Etisalat, Gujarat - "917", // Etisalat, Kerala - "927", // Uninor, Gujarat - "929" // Uninor, Maharashtra - ], - // Malaysia. - "502": - ["150", // Tune Talk Sdn Bhd - "151", // Baraka Telecom Sdn Bhd (MVNE) - "152", // YTL Communications Sdn Bhd - "156" // Altel Communications Sdn Bhd - ], - // Brazil. - "724": - ["055" // Sercomtel - ] -}; - -/** - * The table for MCC which the length of MNC is 3 - * - * This table is built from below links. - * - http://www.itu.int/pub/T-SP-E.212B-2013 - * - http://en.wikipedia.org/wiki/Mobile_Network_Code - */ -this.MCC_TABLE_FOR_MNC_LENGTH_IS_3 = [ - "302", // Canada - "310", // United States of America - "311", // United States of America - "312", // United States of America - "313", // United States of America - "316", // United States of America - "330", // Puerto Rico - "334", // Mexico - "338", // Jamaica - "342", // Barbados - "344", // Antigua and Barbuda - "346", // Cayman Islands - "348", // British Virgin Islands - "350", // Bermuda - "352", // Grenada - "354", // Montserrat - "356", // Saint Kitts and Nevis - "358", // Saint Lucia - "360", // Saint Vincent and the Grenadines - "365", // Anguilla - "366", // Dominica - "376", // Turks and Caicos Islands - "708", // Honduras - "722", // Argentina - "732", // Colombia - "750" // Falkland Islands (Malvinas) -]; - -// Supplementary service notifications, code2, as defined in 3GPP 27.007 7.17 -this.SUPP_SVC_NOTIFICATION_CODE2_PUT_ON_HOLD = 2; -this.SUPP_SVC_NOTIFICATION_CODE2_RETRIEVED = 3; - -this.GECKO_SUPP_SVC_NOTIFICATION_REMOTE_HELD = "RemoteHeld"; -this.GECKO_SUPP_SVC_NOTIFICATION_REMOTE_RESUMED = "RemoteResumed"; - -this.GECKO_SUPP_SVC_NOTIFICATION_FROM_CODE2 = {}; -GECKO_SUPP_SVC_NOTIFICATION_FROM_CODE2[SUPP_SVC_NOTIFICATION_CODE2_PUT_ON_HOLD] = GECKO_SUPP_SVC_NOTIFICATION_REMOTE_HELD; -GECKO_SUPP_SVC_NOTIFICATION_FROM_CODE2[SUPP_SVC_NOTIFICATION_CODE2_RETRIEVED] = GECKO_SUPP_SVC_NOTIFICATION_REMOTE_RESUMED; - -/** - * The status for an Over-the-Air Service Provisioning / Over-the-Air - * Parameter Administration (OTASP/OTAPA) session. - * - * @see 3GPP2 C.S0016 - */ -this.GECKO_OTA_STATUS_SPL_UNLOCKED = "spl_unlocked"; -this.GECKO_OTA_STATUS_SPC_RETRIES_EXCEEDED = "spc_retries_exceeded"; -this.GECKO_OTA_STATUS_A_KEY_EXCHANGED = "a_key_exchanged"; -this.GECKO_OTA_STATUS_SSD_UPDATED = "ssd_updated"; -this.GECKO_OTA_STATUS_NAM_DOWNLOADED = "nam_downloaded"; -this.GECKO_OTA_STATUS_MDN_DOWNLOADED = "mdn_downloaded"; -this.GECKO_OTA_STATUS_IMSI_DOWNLOADED = "imsi_downloaded"; -this.GECKO_OTA_STATUS_PRL_DOWNLOADED = "prl_downloaded"; -this.GECKO_OTA_STATUS_COMMITTED = "committed"; -this.GECKO_OTA_STATUS_OTAPA_STARTED = "otapa_started"; -this.GECKO_OTA_STATUS_OTAPA_STOPPED = "otapa_stopped"; -this.GECKO_OTA_STATUS_OTAPA_ABORTED = "otapa_aborted"; -this.CDMA_OTA_PROVISION_STATUS_TO_GECKO = [ - GECKO_OTA_STATUS_SPL_UNLOCKED, - GECKO_OTA_STATUS_SPC_RETRIES_EXCEEDED, - GECKO_OTA_STATUS_A_KEY_EXCHANGED, - GECKO_OTA_STATUS_SSD_UPDATED, - GECKO_OTA_STATUS_NAM_DOWNLOADED, - GECKO_OTA_STATUS_MDN_DOWNLOADED, - GECKO_OTA_STATUS_IMSI_DOWNLOADED, - GECKO_OTA_STATUS_PRL_DOWNLOADED, - GECKO_OTA_STATUS_COMMITTED, - GECKO_OTA_STATUS_OTAPA_STARTED, - GECKO_OTA_STATUS_OTAPA_STOPPED, - GECKO_OTA_STATUS_OTAPA_ABORTED -]; - -// Allow this file to be imported via Components.utils.import(). -this.EXPORTED_SYMBOLS = Object.keys(this); diff --git a/dom/system/gonk/ril_worker.js b/dom/system/gonk/ril_worker.js deleted file mode 100644 index 0608a5be3..000000000 --- a/dom/system/gonk/ril_worker.js +++ /dev/null @@ -1,15206 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -/** - * This file implements the RIL worker thread. It communicates with - * the main thread to provide a high-level API to the phone's RIL - * stack, and with the RIL IPC thread to communicate with the RIL - * device itself. These communication channels use message events as - * known from Web Workers: - * - * - postMessage()/"message" events for main thread communication - * - * - postRILMessage()/"RILMessageEvent" events for RIL IPC thread - * communication. - * - * The two main objects in this file represent individual parts of this - * communication chain: - * - * - RILMessageEvent -> Buf -> RIL -> postMessage() -> nsIRadioInterfaceLayer - * - nsIRadioInterfaceLayer -> postMessage() -> RIL -> Buf -> postRILMessage() - * - * Note: The code below is purposely lean on abstractions to be as lean in - * terms of object allocations. As a result, it may look more like C than - * JavaScript, and that's intended. - */ - -/* global BufObject */ -/* global TelephonyRequestQueue */ - -"use strict"; - -importScripts("ril_consts.js"); -importScripts("resource://gre/modules/workers/require.js"); -importScripts("ril_worker_buf_object.js"); -importScripts("ril_worker_telephony_request_queue.js"); - -// set to true in ril_consts.js to see debug messages -var DEBUG = DEBUG_WORKER; -var GLOBAL = this; - -if (!this.debug) { - // Debugging stub that goes nowhere. - this.debug = function debug(message) { - dump("RIL Worker: " + message + "\n"); - }; -} - -// Timeout value for emergency callback mode. -const EMERGENCY_CB_MODE_TIMEOUT_MS = 300000; // 5 mins = 300000 ms. - -const ICC_MAX_LINEAR_FIXED_RECORDS = 0xfe; - -const GET_CURRENT_CALLS_RETRY_MAX = 3; - -var RILQUIRKS_CALLSTATE_EXTRA_UINT32; -var RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL; -var RILQUIRKS_SIM_APP_STATE_EXTRA_FIELDS; -var RILQUIRKS_SIGNAL_EXTRA_INT32; -var RILQUIRKS_AVAILABLE_NETWORKS_EXTRA_STRING; -// Needed for call-waiting on Peak device -var RILQUIRKS_EXTRA_UINT32_2ND_CALL; -// On the emulator we support querying the number of lock retries -var RILQUIRKS_HAVE_QUERY_ICC_LOCK_RETRY_COUNT; -// Ril quirk to Send STK Profile Download -var RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD; -// Ril quirk to attach data registration on demand. -var RILQUIRKS_DATA_REGISTRATION_ON_DEMAND; -// Ril quirk to control the uicc/data subscription. -var RILQUIRKS_SUBSCRIPTION_CONTROL; -// Ril quirk to describe the SMSC address format. -var RILQUIRKS_SMSC_ADDRESS_FORMAT; - -/** - * The RIL state machine. - * - * This object communicates with rild via parcels and with the main thread - * via post messages. It maintains state about the radio, ICC, calls, etc. - * and acts upon state changes accordingly. - */ -function RilObject(aContext) { - this.context = aContext; - - this.telephonyRequestQueue = new TelephonyRequestQueue(this); - this.currentConferenceState = CALL_STATE_UNKNOWN; - this._pendingSentSmsMap = {}; - this.pendingNetworkType = {}; - this._receivedSmsCbPagesMap = {}; - this._getCurrentCallsRetryCount = 0; -} -RilObject.prototype = { - context: null, - - /** - * RIL version. - */ - version: null, - - /** - * Call state of current conference group. - */ - currentConferenceState: null, - - /** - * Outgoing messages waiting for SMS-STATUS-REPORT. - */ - _pendingSentSmsMap: null, - - /** - * Marker object. - */ - pendingNetworkType: null, - - /** - * Global Cell Broadcast switch. - */ - cellBroadcastDisabled: false, - - /** - * Parsed Cell Broadcast search lists. - * cellBroadcastConfigs.MMI should be preserved over rild reset. - */ - cellBroadcastConfigs: null, - mergedCellBroadcastConfig: null, - - _receivedSmsCbPagesMap: null, - - initRILState: function() { - /** - * One of the RADIO_STATE_* constants. - */ - this.radioState = GECKO_RADIOSTATE_UNKNOWN; - - /** - * True if we are on a CDMA phone. - */ - this._isCdma = false; - - /** - * True if we are in emergency callback mode. - */ - this._isInEmergencyCbMode = false; - - /** - * Set when radio is ready but radio tech is unknown. That is, we are - * waiting for REQUEST_VOICE_RADIO_TECH - */ - this._waitingRadioTech = false; - - /** - * Card state - */ - this.cardState = GECKO_CARDSTATE_UNINITIALIZED; - - /** - * Device Identities including IMEI, IMEISV, ESN and MEID. - */ - this.deviceIdentities = null; - - /** - * ICC information that is not exposed to Gaia. - */ - this.iccInfoPrivate = {}; - - /** - * ICC information, such as MSISDN, MCC, MNC, SPN...etc. - */ - this.iccInfo = {}; - - /** - * CDMA specific information. ex. CDMA Network ID, CDMA System ID... etc. - */ - this.cdmaHome = null; - - /** - * Application identification for apps in ICC. - */ - this.aid = null; - - /** - * Application type for apps in ICC. - */ - this.appType = null; - - this.networkSelectionMode = GECKO_NETWORK_SELECTION_UNKNOWN; - - this.voiceRegistrationState = {}; - this.dataRegistrationState = {}; - - /** - * List of strings identifying the network operator. - */ - this.operator = null; - - /** - * String containing the baseband version. - */ - this.basebandVersion = null; - - // Clean up currentCalls: rild might have restarted. - this.sendChromeMessage({ - rilMessageType: "currentCalls", - calls: {} - }); - - // Don't clean up this._pendingSentSmsMap - // because on rild restart: we may continue with the pending segments. - - /** - * Whether or not the multiple requests in requestNetworkInfo() are currently - * being processed - */ - this._processingNetworkInfo = false; - - /** - * Multiple requestNetworkInfo() in a row before finishing the first - * request, hence we need to fire requestNetworkInfo() again after - * gathering all necessary stuffs. This is to make sure that ril_worker - * gets precise network information. - */ - this._needRepollNetworkInfo = false; - - /** - * Pending messages to be send in batch from requestNetworkInfo() - */ - this._pendingNetworkInfo = {rilMessageType: "networkinfochanged"}; - - /** - * Cell Broadcast Search Lists. - */ - let cbmmi = this.cellBroadcastConfigs && this.cellBroadcastConfigs.MMI; - this.cellBroadcastConfigs = { - MMI: cbmmi || null - }; - this.mergedCellBroadcastConfig = null; - - /** - * True when the request to report SMS Memory Status is pending. - */ - this.pendingToReportSmsMemoryStatus = false; - this.smsStorageAvailable = true; - }, - - /** - * Parse an integer from a string, falling back to a default value - * if the the provided value is not a string or does not contain a valid - * number. - * - * @param string - * String to be parsed. - * @param defaultValue [optional] - * Default value to be used. - * @param radix [optional] - * A number that represents the numeral system to be used. Default 10. - */ - parseInt: function(string, defaultValue, radix) { - let number = parseInt(string, radix || 10); - if (!isNaN(number)) { - return number; - } - if (defaultValue === undefined) { - defaultValue = null; - } - return defaultValue; - }, - - - /** - * Outgoing requests to the RIL. These can be triggered from the - * main thread via messages that look like this: - * - * {rilMessageType: "methodName", - * extra: "parameters", - * go: "here"} - * - * So if one of the following methods takes arguments, it takes only one, - * an object, which then contains all of the parameters as attributes. - * The "@param" documentation is to be interpreted accordingly. - */ - - /** - * Retrieve the ICC's status. - */ - getICCStatus: function() { - this.context.Buf.simpleRequest(REQUEST_GET_SIM_STATUS); - }, - - /** - * Helper function for unlocking ICC locks. - */ - iccUnlockCardLock: function(options) { - switch (options.lockType) { - case GECKO_CARDLOCK_PIN: - this.enterICCPIN(options); - break; - case GECKO_CARDLOCK_PIN2: - this.enterICCPIN2(options); - break; - case GECKO_CARDLOCK_PUK: - this.enterICCPUK(options); - break; - case GECKO_CARDLOCK_PUK2: - this.enterICCPUK2(options); - break; - case GECKO_CARDLOCK_NCK: - case GECKO_CARDLOCK_NSCK: - case GECKO_CARDLOCK_NCK1: - case GECKO_CARDLOCK_NCK2: - case GECKO_CARDLOCK_HNCK: - case GECKO_CARDLOCK_CCK: - case GECKO_CARDLOCK_SPCK: - case GECKO_CARDLOCK_PCK: - case GECKO_CARDLOCK_RCCK: - case GECKO_CARDLOCK_RSPCK: - case GECKO_CARDLOCK_NCK_PUK: - case GECKO_CARDLOCK_NSCK_PUK: - case GECKO_CARDLOCK_NCK1_PUK: - case GECKO_CARDLOCK_NCK2_PUK: - case GECKO_CARDLOCK_HNCK_PUK: - case GECKO_CARDLOCK_CCK_PUK: - case GECKO_CARDLOCK_SPCK_PUK: - case GECKO_CARDLOCK_PCK_PUK: - case GECKO_CARDLOCK_RCCK_PUK: // Fall through. - case GECKO_CARDLOCK_RSPCK_PUK: - this.enterDepersonalization(options); - break; - default: - options.errorMsg = GECKO_ERROR_REQUEST_NOT_SUPPORTED; - this.sendChromeMessage(options); - } - }, - - /** - * Enter a PIN to unlock the ICC. - * - * @param password - * String containing the PIN. - * @param [optional] aid - * AID value. - */ - enterICCPIN: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_ENTER_SIM_PIN, options); - Buf.writeInt32(2); - Buf.writeString(options.password); - Buf.writeString(options.aid || this.aid); - Buf.sendParcel(); - }, - - /** - * Enter a PIN2 to unlock the ICC. - * - * @param password - * String containing the PIN2. - * @param [optional] aid - * AID value. - */ - enterICCPIN2: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_ENTER_SIM_PIN2, options); - Buf.writeInt32(2); - Buf.writeString(options.password); - Buf.writeString(options.aid || this.aid); - Buf.sendParcel(); - }, - - /** - * Requests a network personalization be deactivated. - * - * @param personlization - * One of CARD_PERSOSUBSTATE_* - * @param password - * String containing the password. - */ - enterDepersonalization: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_ENTER_NETWORK_DEPERSONALIZATION_CODE, options); - Buf.writeInt32(1); - Buf.writeString(options.password); - Buf.sendParcel(); - }, - - /** - * Change the current ICC PIN number. - * - * @param password - * String containing the old PIN value - * @param newPassword - * String containing the new PIN value - * @param [optional] aid - * AID value. - */ - changeICCPIN: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_CHANGE_SIM_PIN, options); - Buf.writeInt32(3); - Buf.writeString(options.password); - Buf.writeString(options.newPassword); - Buf.writeString(options.aid || this.aid); - Buf.sendParcel(); - }, - - /** - * Change the current ICC PIN2 number. - * - * @param password - * String containing the old PIN2 value - * @param newPassword - * String containing the new PIN2 value - * @param [optional] aid - * AID value. - */ - changeICCPIN2: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_CHANGE_SIM_PIN2, options); - Buf.writeInt32(3); - Buf.writeString(options.password); - Buf.writeString(options.newPassword); - Buf.writeString(options.aid || this.aid); - Buf.sendParcel(); - }, - - /** - * Supplies ICC PUK and a new PIN to unlock the ICC. - * - * @param password - * String containing the PUK value. - * @param newPassword - * String containing the new PIN value. - * @param [optional] aid - * AID value. - */ - enterICCPUK: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_ENTER_SIM_PUK, options); - Buf.writeInt32(3); - Buf.writeString(options.password); - Buf.writeString(options.newPin); - Buf.writeString(options.aid || this.aid); - Buf.sendParcel(); - }, - - /** - * Supplies ICC PUK2 and a new PIN2 to unlock the ICC. - * - * @param password - * String containing the PUK2 value. - * @param newPassword - * String containing the new PIN2 value. - * @param [optional] aid - * AID value. - */ - enterICCPUK2: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_ENTER_SIM_PUK2, options); - Buf.writeInt32(3); - Buf.writeString(options.password); - Buf.writeString(options.newPin); - Buf.writeString(options.aid || this.aid); - Buf.sendParcel(); - }, - - /** - * Helper function for changing ICC locks. - */ - iccChangeCardLockPassword: function(options) { - switch (options.lockType) { - case GECKO_CARDLOCK_PIN: - this.changeICCPIN(options); - break; - case GECKO_CARDLOCK_PIN2: - this.changeICCPIN2(options); - break; - default: - options.errorMsg = GECKO_ERROR_REQUEST_NOT_SUPPORTED; - this.sendChromeMessage(options); - } - }, - - /** - * Helper function for setting the state of ICC locks. - */ - iccSetCardLockEnabled: function(options) { - switch (options.lockType) { - case GECKO_CARDLOCK_PIN: // Fall through. - case GECKO_CARDLOCK_FDN: - options.facility = GECKO_CARDLOCK_TO_FACILITY[options.lockType]; - break; - default: - options.errorMsg = GECKO_ERROR_REQUEST_NOT_SUPPORTED; - this.sendChromeMessage(options); - return; - } - - options.serviceClass = ICC_SERVICE_CLASS_VOICE | - ICC_SERVICE_CLASS_DATA | - ICC_SERVICE_CLASS_FAX; - this.setICCFacilityLock(options); - }, - - /** - * Helper function for fetching the state of ICC locks. - */ - iccGetCardLockEnabled: function(options) { - switch (options.lockType) { - case GECKO_CARDLOCK_PIN: // Fall through. - case GECKO_CARDLOCK_FDN: - options.facility = GECKO_CARDLOCK_TO_FACILITY[options.lockType]; - break; - default: - options.errorMsg = GECKO_ERROR_REQUEST_NOT_SUPPORTED; - this.sendChromeMessage(options); - return; - } - - options.password = ""; // For query no need to provide pin. - options.serviceClass = ICC_SERVICE_CLASS_VOICE | - ICC_SERVICE_CLASS_DATA | - ICC_SERVICE_CLASS_FAX; - this.queryICCFacilityLock(options); - }, - - /** - * Helper function for fetching the number of unlock retries of ICC locks. - * - * We only query the retry count when we're on the emulator. The phones do - * not support the request id and their rild doesn't return an error. - */ - iccGetCardLockRetryCount: function(options) { - if (!RILQUIRKS_HAVE_QUERY_ICC_LOCK_RETRY_COUNT) { - // Only the emulator supports this request. - options.errorMsg = GECKO_ERROR_REQUEST_NOT_SUPPORTED; - this.sendChromeMessage(options); - return; - } - - switch (options.lockType) { - case GECKO_CARDLOCK_PIN: - case GECKO_CARDLOCK_PIN2: - case GECKO_CARDLOCK_PUK: - case GECKO_CARDLOCK_PUK2: - case GECKO_CARDLOCK_NCK: - case GECKO_CARDLOCK_NSCK: - case GECKO_CARDLOCK_CCK: // Fall through. - case GECKO_CARDLOCK_SPCK: - // TODO: Bug 1116072: identify the mapping between RIL_PERSOSUBSTATE_SIM_SIM - // @ ril.h and TS 27.007, clause 8.65 for GECKO_CARDLOCK_SPCK. - options.selCode = GECKO_CARDLOCK_TO_SEL_CODE[options.lockType]; - break; - default: - options.errorMsg = GECKO_ERROR_REQUEST_NOT_SUPPORTED; - this.sendChromeMessage(options); - return; - } - - this.queryICCLockRetryCount(options); - }, - - /** - * Query ICC lock retry count. - * - * @param selCode - * One of ICC_SEL_CODE_*. - * @param serviceClass - * One of ICC_SERVICE_CLASS_*. - */ - queryICCLockRetryCount: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_GET_UNLOCK_RETRY_COUNT, options); - Buf.writeInt32(1); - Buf.writeString(options.selCode); - Buf.sendParcel(); - }, - - /** - * Query ICC facility lock. - * - * @param facility - * One of ICC_CB_FACILITY_*. - * @param password - * Password for the facility, or "" if not required. - * @param serviceClass - * One of ICC_SERVICE_CLASS_*. - * @param [optional] aid - * AID value. - */ - queryICCFacilityLock: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_QUERY_FACILITY_LOCK, options); - Buf.writeInt32(4); - Buf.writeString(options.facility); - Buf.writeString(options.password); - Buf.writeString(options.serviceClass.toString()); - Buf.writeString(options.aid || this.aid); - Buf.sendParcel(); - }, - - /** - * Set ICC facility lock. - * - * @param facility - * One of ICC_CB_FACILITY_*. - * @param enabled - * true to enable, false to disable. - * @param password - * Password for the facility, or "" if not required. - * @param serviceClass - * One of ICC_SERVICE_CLASS_*. - * @param [optional] aid - * AID value. - */ - setICCFacilityLock: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SET_FACILITY_LOCK, options); - Buf.writeInt32(5); - Buf.writeString(options.facility); - Buf.writeString(options.enabled ? "1" : "0"); - Buf.writeString(options.password); - Buf.writeString(options.serviceClass.toString()); - Buf.writeString(options.aid || this.aid); - Buf.sendParcel(); - }, - - /** - * Request an ICC I/O operation. - * - * See TS 27.007 "restricted SIM" operation, "AT Command +CRSM". - * The sequence is in the same order as how libril reads this parcel, - * see the struct RIL_SIM_IO_v5 or RIL_SIM_IO_v6 defined in ril.h - * - * @param command - * The I/O command, one of the ICC_COMMAND_* constants. - * @param fileId - * The file to operate on, one of the ICC_EF_* constants. - * @param pathId - * String type, check the 'pathid' parameter from TS 27.007 +CRSM. - * @param p1, p2, p3 - * Arbitrary integer parameters for the command. - * @param [optional] dataWriter - * The function for writing string parameter for the ICC_COMMAND_UPDATE_RECORD. - * @param [optional] pin2 - * String containing the PIN2. - * @param [optional] aid - * AID value. - */ - iccIO: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SIM_IO, options); - Buf.writeInt32(options.command); - Buf.writeInt32(options.fileId); - Buf.writeString(options.pathId); - Buf.writeInt32(options.p1); - Buf.writeInt32(options.p2); - Buf.writeInt32(options.p3); - - // Write data. - if (options.command == ICC_COMMAND_UPDATE_RECORD && - options.dataWriter) { - options.dataWriter(options.p3); - } else { - Buf.writeString(null); - } - - // Write pin2. - if (options.command == ICC_COMMAND_UPDATE_RECORD && - options.pin2) { - Buf.writeString(options.pin2); - } else { - Buf.writeString(null); - } - - Buf.writeString(options.aid || this.aid); - Buf.sendParcel(); - }, - - /** - * Get IMSI. - * - * @param [optional] aid - * AID value. - */ - getIMSI: function(aid) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_GET_IMSI); - Buf.writeInt32(1); - Buf.writeString(aid || this.aid); - Buf.sendParcel(); - }, - - /** - * Retrieve ICC's GID1 field. - */ - getGID1: function(options) { - options.gid1 = this.iccInfoPrivate.gid1; - this.sendChromeMessage(options); - }, - - /** - * Read UICC Phonebook contacts. - * - * @param contactType - * One of GECKO_CARDCONTACT_TYPE_*. - * @param requestId - * Request id from RadioInterfaceLayer. - */ - readICCContacts: function(options) { - if (!this.appType) { - options.errorMsg = CONTACT_ERR_REQUEST_NOT_SUPPORTED; - this.sendChromeMessage(options); - return; - } - - this.context.ICCContactHelper.readICCContacts( - this.appType, - options.contactType, - function onsuccess(contacts) { - for (let i = 0; i < contacts.length; i++) { - let contact = contacts[i]; - let pbrIndex = contact.pbrIndex || 0; - let recordIndex = pbrIndex * ICC_MAX_LINEAR_FIXED_RECORDS + contact.recordId; - contact.contactId = this.iccInfo.iccid + recordIndex; - } - // Reuse 'options' to get 'requestId' and 'contactType'. - options.contacts = contacts; - this.sendChromeMessage(options); - }.bind(this), - function onerror(errorMsg) { - options.errorMsg = errorMsg; - this.sendChromeMessage(options); - }.bind(this)); - }, - - /** - * Update UICC Phonebook. - * - * @param contactType One of GECKO_CARDCONTACT_TYPE_*. - * @param contact The contact will be updated. - * @param pin2 PIN2 is required for updating FDN. - * @param requestId Request id from RadioInterfaceLayer. - */ - updateICCContact: function(options) { - let onsuccess = function onsuccess(updatedContact) { - let recordIndex = - updatedContact.pbrIndex * ICC_MAX_LINEAR_FIXED_RECORDS + updatedContact.recordId; - updatedContact.contactId = this.iccInfo.iccid + recordIndex; - options.contact = updatedContact; - // Reuse 'options' to get 'requestId' and 'contactType'. - this.sendChromeMessage(options); - }.bind(this); - - let onerror = function onerror(errorMsg) { - options.errorMsg = errorMsg; - this.sendChromeMessage(options); - }.bind(this); - - if (!this.appType || !options.contact) { - onerror(CONTACT_ERR_REQUEST_NOT_SUPPORTED ); - return; - } - - let contact = options.contact; - let iccid = this.iccInfo.iccid; - let isValidRecordId = false; - if (typeof contact.contactId === "string" && - contact.contactId.startsWith(iccid)) { - let recordIndex = contact.contactId.substring(iccid.length); - contact.pbrIndex = Math.floor(recordIndex / ICC_MAX_LINEAR_FIXED_RECORDS); - contact.recordId = recordIndex % ICC_MAX_LINEAR_FIXED_RECORDS; - isValidRecordId = contact.recordId > 0 && contact.recordId < 0xff; - } - - if (DEBUG) { - this.context.debug("Update ICC Contact " + JSON.stringify(contact)); - } - - let ICCContactHelper = this.context.ICCContactHelper; - // If contact has 'recordId' property, updates corresponding record. - // If not, inserts the contact into a free record. - if (isValidRecordId) { - ICCContactHelper.updateICCContact( - this.appType, options.contactType, contact, options.pin2, onsuccess, onerror); - } else { - ICCContactHelper.addICCContact( - this.appType, options.contactType, contact, options.pin2, onsuccess, onerror); - } - }, - - /** - * Check if operator name needs to be overriden by current voiceRegistrationState - * , EFOPL and EFPNN. See 3GPP TS 31.102 clause 4.2.58 EFPNN and 4.2.59 EFOPL - * for detail. - * - * @return true if operator name is overridden, false otherwise. - */ - overrideICCNetworkName: function() { - if (!this.operator) { - return false; - } - - // We won't get network name using PNN and OPL if voice registration isn't - // ready. - if (!this.voiceRegistrationState.cell || - this.voiceRegistrationState.cell.gsmLocationAreaCode == -1) { - return false; - } - - let ICCUtilsHelper = this.context.ICCUtilsHelper; - let networkName = ICCUtilsHelper.getNetworkNameFromICC( - this.operator.mcc, - this.operator.mnc, - this.voiceRegistrationState.cell.gsmLocationAreaCode); - - if (!networkName) { - return false; - } - - if (DEBUG) { - this.context.debug("Operator names will be overriden: " + - "longName = " + networkName.fullName + ", " + - "shortName = " + networkName.shortName); - } - - this.operator.longName = networkName.fullName; - this.operator.shortName = networkName.shortName; - - this._sendNetworkInfoMessage(NETWORK_INFO_OPERATOR, this.operator); - return true; - }, - - /** - * Request the phone's radio to be enabled or disabled. - * - * @param enabled - * Boolean indicating the desired state. - */ - setRadioEnabled: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_RADIO_POWER, options); - Buf.writeInt32(1); - Buf.writeInt32(options.enabled ? 1 : 0); - Buf.sendParcel(); - }, - - /** - * Query call waiting status. - * - */ - queryCallWaiting: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_QUERY_CALL_WAITING, options); - Buf.writeInt32(1); - // As per 3GPP TS 24.083, section 1.6 UE doesn't need to send service - // class parameter in call waiting interrogation to network. - Buf.writeInt32(ICC_SERVICE_CLASS_NONE); - Buf.sendParcel(); - }, - - /** - * Set call waiting status. - * - * @param enabled - * Boolean indicating the desired waiting status. - * @param serviceClass - * One of ICC_SERVICE_CLASS_* constants. - */ - setCallWaiting: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SET_CALL_WAITING, options); - Buf.writeInt32(2); - Buf.writeInt32(options.enabled ? 1 : 0); - Buf.writeInt32(options.serviceClass); - Buf.sendParcel(); - }, - - /** - * Queries current CLIP status. - */ - queryCLIP: function(options) { - this.context.Buf.simpleRequest(REQUEST_QUERY_CLIP, options); - }, - - /** - * Queries current CLIR status. - * - */ - getCLIR: function(options) { - this.context.Buf.simpleRequest(REQUEST_GET_CLIR, options); - }, - - /** - * Enables or disables the presentation of the calling line identity (CLI) to - * the called party when originating a call. - * - * @param options.clirMode - * One of the CLIR_* constants. - */ - setCLIR: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SET_CLIR, options); - Buf.writeInt32(1); - Buf.writeInt32(options.clirMode); - Buf.sendParcel(); - }, - - /** - * Set screen state. - * - * @param on - * Boolean indicating whether the screen should be on or off. - */ - setScreenState: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SCREEN_STATE); - Buf.writeInt32(1); - Buf.writeInt32(options.on ? 1 : 0); - Buf.sendParcel(); - }, - - getVoiceRegistrationState: function() { - this.context.Buf.simpleRequest(REQUEST_VOICE_REGISTRATION_STATE); - }, - - getVoiceRadioTechnology: function() { - this.context.Buf.simpleRequest(REQUEST_VOICE_RADIO_TECH); - }, - - getDataRegistrationState: function() { - this.context.Buf.simpleRequest(REQUEST_DATA_REGISTRATION_STATE); - }, - - getOperator: function() { - this.context.Buf.simpleRequest(REQUEST_OPERATOR); - }, - - /** - * Set the preferred network type. - * - * @param options An object contains a valid value of - * RIL_PREFERRED_NETWORK_TYPE_TO_GECKO as its `type` attribute. - */ - setPreferredNetworkType: function(options) { - let networkType = options.type; - if (networkType < 0 || networkType >= RIL_PREFERRED_NETWORK_TYPE_TO_GECKO.length) { - options.errorMsg = GECKO_ERROR_INVALID_PARAMETER; - this.sendChromeMessage(options); - return; - } - - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SET_PREFERRED_NETWORK_TYPE, options); - Buf.writeInt32(1); - Buf.writeInt32(networkType); - Buf.sendParcel(); - }, - - /** - * Get the preferred network type. - */ - getPreferredNetworkType: function(options) { - this.context.Buf.simpleRequest(REQUEST_GET_PREFERRED_NETWORK_TYPE, options); - }, - - /** - * Request neighboring cell ids in GSM network. - */ - getNeighboringCellIds: function(options) { - this.context.Buf.simpleRequest(REQUEST_GET_NEIGHBORING_CELL_IDS, options); - }, - - /** - * Request all of the current cell information known to the radio. - */ - getCellInfoList: function(options) { - this.context.Buf.simpleRequest(REQUEST_GET_CELL_INFO_LIST, options); - }, - - /** - * Request various states about the network. - */ - requestNetworkInfo: function() { - if (this._processingNetworkInfo) { - if (DEBUG) { - this.context.debug("Network info requested, but we're already " + - "requesting network info."); - } - this._needRepollNetworkInfo = true; - return; - } - - if (DEBUG) this.context.debug("Requesting network info"); - - this._processingNetworkInfo = true; - this.getVoiceRegistrationState(); - this.getDataRegistrationState(); //TODO only GSM - this.getOperator(); - this.getNetworkSelectionMode(); - this.getSignalStrength(); - }, - - /** - * Get the available networks - */ - getAvailableNetworks: function(options) { - if (DEBUG) this.context.debug("Getting available networks"); - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_QUERY_AVAILABLE_NETWORKS, options); - Buf.sendParcel(); - }, - - /** - * Request the radio's network selection mode - */ - getNetworkSelectionMode: function() { - if (DEBUG) this.context.debug("Getting network selection mode"); - this.context.Buf.simpleRequest(REQUEST_QUERY_NETWORK_SELECTION_MODE); - }, - - /** - * Tell the radio to automatically choose a voice/data network - */ - selectNetworkAuto: function(options) { - if (DEBUG) this.context.debug("Setting automatic network selection"); - this.context.Buf.simpleRequest(REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, options); - }, - - /** - * Set the roaming preference mode - */ - setRoamingPreference: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_CDMA_SET_ROAMING_PREFERENCE, options); - Buf.writeInt32(1); - Buf.writeInt32(options.mode); - Buf.sendParcel(); - }, - - /** - * Get the roaming preference mode - */ - queryRoamingPreference: function(options) { - this.context.Buf.simpleRequest(REQUEST_CDMA_QUERY_ROAMING_PREFERENCE, options); - }, - - /** - * Set the voice privacy mode - */ - setVoicePrivacyMode: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE, options); - Buf.writeInt32(1); - Buf.writeInt32(options.enabled ? 1 : 0); - Buf.sendParcel(); - }, - - /** - * Get the voice privacy mode - */ - queryVoicePrivacyMode: function(options) { - this.context.Buf.simpleRequest(REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE, options); - }, - - /** - * Open Logical UICC channel (aid) for Secure Element access - */ - iccOpenChannel: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SIM_OPEN_CHANNEL, options); - Buf.writeString(options.aid); - Buf.sendParcel(); - }, - - /** - * Exchange APDU data on an open Logical UICC channel - */ - iccExchangeAPDU: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SIM_TRANSMIT_APDU_CHANNEL, options); - Buf.writeInt32(options.channel); - Buf.writeInt32(options.apdu.cla); - Buf.writeInt32(options.apdu.command); - Buf.writeInt32(options.apdu.p1); - Buf.writeInt32(options.apdu.p2); - Buf.writeInt32(options.apdu.p3); - Buf.writeString(options.apdu.data); - Buf.sendParcel(); - }, - - /** - * Close Logical UICC channel - */ - iccCloseChannel: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SIM_CLOSE_CHANNEL, options); - Buf.writeInt32(1); - Buf.writeInt32(options.channel); - Buf.sendParcel(); - }, - - /** - * Get UICC service state - */ - getIccServiceState: function(options) { - switch (options.service) { - case GECKO_CARDSERVICE_FDN: - let ICCUtilsHelper = this.context.ICCUtilsHelper; - options.result = ICCUtilsHelper.isICCServiceAvailable("FDN"); - break; - default: - options.errorMsg = GECKO_ERROR_REQUEST_NOT_SUPPORTED; - break; - } - this.sendChromeMessage(options); - }, - - /** - * Enable/Disable UICC subscription - */ - setUiccSubscription: function(options) { - if (DEBUG) { - this.context.debug("setUiccSubscription: " + JSON.stringify(options)); - } - - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SET_UICC_SUBSCRIPTION, options); - Buf.writeInt32(this.context.clientId); - Buf.writeInt32(options.appIndex); - Buf.writeInt32(this.context.clientId); - Buf.writeInt32(options.enabled ? 1 : 0); - Buf.sendParcel(); - }, - - /** - * Tell the radio to choose a specific voice/data network - */ - selectNetwork: function(options) { - if (DEBUG) { - this.context.debug("Setting manual network selection: " + - options.mcc + ", " + options.mnc); - } - - let numeric = (options.mcc && options.mnc) ? options.mcc + options.mnc : null; - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SET_NETWORK_SELECTION_MANUAL, options); - Buf.writeString(numeric); - Buf.sendParcel(); - }, - - /** - * Get the signal strength. - */ - getSignalStrength: function() { - this.context.Buf.simpleRequest(REQUEST_SIGNAL_STRENGTH); - }, - - getDeviceIdentity: function() { - this.deviceIdentities || this.context.Buf.simpleRequest(REQUEST_DEVICE_IDENTITY); - }, - - getBasebandVersion: function() { - this.context.Buf.simpleRequest(REQUEST_BASEBAND_VERSION); - }, - - sendExitEmergencyCbModeRequest: function(options) { - this.context.Buf.simpleRequest(REQUEST_EXIT_EMERGENCY_CALLBACK_MODE, options); - }, - - getCdmaSubscription: function() { - this.context.Buf.simpleRequest(REQUEST_CDMA_SUBSCRIPTION); - }, - - exitEmergencyCbMode: function(options) { - // The function could be called by an API from RadioInterfaceLayer or by - // ril_worker itself. From ril_worker, we won't pass the parameter - // 'options'. In this case, it is marked as internal. - if (!options) { - options = {internal: true}; - } - this._cancelEmergencyCbModeTimeout(); - this.sendExitEmergencyCbModeRequest(options); - }, - - /** - * Dial a non-emergency number. - * - * @param isEmergency - * Whether the number is an emergency number. - * @param number - * String containing the number to dial. - * @param clirMode - * Integer for showing/hidding the caller Id to the called party. - * @param uusInfo - * Integer doing something XXX TODO - */ - dial: function(options) { - if (options.isEmergency) { - options.request = RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL ? - REQUEST_DIAL_EMERGENCY_CALL : REQUEST_DIAL; - - } else { - options.request = REQUEST_DIAL; - - // Exit emergency callback mode when user dial a non-emergency call. - if (this._isInEmergencyCbMode) { - this.exitEmergencyCbMode(); - } - } - - this.telephonyRequestQueue.push(options.request, () => { - let Buf = this.context.Buf; - Buf.newParcel(options.request, options); - Buf.writeString(options.number); - Buf.writeInt32(options.clirMode || 0); - Buf.writeInt32(options.uusInfo || 0); - // TODO Why do we need this extra 0? It was put it in to make this - // match the format of the binary message. - Buf.writeInt32(0); - Buf.sendParcel(); - }); - }, - - /** - * CDMA flash. - * - * @param featureStr (optional) - * Dialing number when the command is used for three-way-calling - */ - cdmaFlash: function(options) { - let Buf = this.context.Buf; - options.request = REQUEST_CDMA_FLASH; - Buf.newParcel(options.request, options); - Buf.writeString(options.featureStr || ""); - Buf.sendParcel(); - }, - - /** - * Hang up the phone. - * - * @param callIndex - * Call index (1-based) as reported by REQUEST_GET_CURRENT_CALLS. - */ - hangUpCall: function(options) { - this.telephonyRequestQueue.push(REQUEST_HANGUP, () => { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_HANGUP, options); - Buf.writeInt32(1); - Buf.writeInt32(options.callIndex); - Buf.sendParcel(); - }); - }, - - hangUpForeground: function(options) { - this.telephonyRequestQueue.push(REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, () => { - this.context.Buf.simpleRequest(REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, - options); - }); - }, - - hangUpBackground: function(options) { - this.telephonyRequestQueue.push(REQUEST_HANGUP_WAITING_OR_BACKGROUND, () => { - this.context.Buf.simpleRequest(REQUEST_HANGUP_WAITING_OR_BACKGROUND, - options); - }); - }, - - switchActiveCall: function(options) { - this.telephonyRequestQueue.push(REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, () => { - this.context.Buf.simpleRequest(REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, - options); - }); - }, - - udub: function(options) { - this.telephonyRequestQueue.push(REQUEST_UDUB, () => { - this.context.Buf.simpleRequest(REQUEST_UDUB, options); - }); - }, - - answerCall: function(options) { - this.telephonyRequestQueue.push(REQUEST_ANSWER, () => { - this.context.Buf.simpleRequest(REQUEST_ANSWER, options); - }); - }, - - conferenceCall: function(options) { - this.telephonyRequestQueue.push(REQUEST_CONFERENCE, () => { - this.context.Buf.simpleRequest(REQUEST_CONFERENCE, options); - }); - }, - - separateCall: function(options) { - this.telephonyRequestQueue.push(REQUEST_SEPARATE_CONNECTION, () => { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SEPARATE_CONNECTION, options); - Buf.writeInt32(1); - Buf.writeInt32(options.callIndex); - Buf.sendParcel(); - }); - }, - - /** - * Get current calls. - */ - getCurrentCalls: function(options) { - this.telephonyRequestQueue.push(REQUEST_GET_CURRENT_CALLS, () => { - this.context.Buf.simpleRequest(REQUEST_GET_CURRENT_CALLS, options); - }); - }, - - /** - * Mute or unmute the radio. - * - * @param mute - * Boolean to indicate whether to mute or unmute the radio. - */ - setMute: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SET_MUTE); - Buf.writeInt32(1); - Buf.writeInt32(options.muted ? 1 : 0); - Buf.sendParcel(); - }, - - /** - * Send an SMS. - * - * The `options` parameter object should contain the following attributes: - * - * @param number - * String containing the recipient number. - * @param body - * String containing the message text. - * @param envelopeId - * Numeric value identifying the sms request. - */ - sendSMS: function(options) { - options.langIndex = options.langIndex || PDU_NL_IDENTIFIER_DEFAULT; - options.langShiftIndex = options.langShiftIndex || PDU_NL_IDENTIFIER_DEFAULT; - - if (!options.segmentSeq) { - // Fist segment to send - options.segmentSeq = 1; - options.body = options.segments[0].body; - options.encodedBodyLength = options.segments[0].encodedBodyLength; - } - - let Buf = this.context.Buf; - if (this._isCdma) { - Buf.newParcel(REQUEST_CDMA_SEND_SMS, options); - this.context.CdmaPDUHelper.writeMessage(options); - } else { - Buf.newParcel(REQUEST_SEND_SMS, options); - Buf.writeInt32(2); - Buf.writeString(options.SMSC); - this.context.GsmPDUHelper.writeMessage(options); - } - Buf.sendParcel(); - }, - - /** - * Acknowledge the receipt and handling of an SMS. - * - * @param success - * Boolean indicating whether the message was successfuly handled. - * @param cause - * SMS_* constant indicating the reason for unsuccessful handling. - */ - acknowledgeGsmSms: function(success, cause) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SMS_ACKNOWLEDGE); - Buf.writeInt32(2); - Buf.writeInt32(success ? 1 : 0); - Buf.writeInt32(cause); - Buf.sendParcel(); - }, - - /** - * Acknowledge the receipt and handling of an SMS. - * - * @param success - * Boolean indicating whether the message was successfuly handled. - */ - ackSMS: function(options) { - if (options.result == PDU_FCS_RESERVED) { - return; - } - if (this._isCdma) { - this.acknowledgeCdmaSms(options.result == PDU_FCS_OK, options.result); - } else { - this.acknowledgeGsmSms(options.result == PDU_FCS_OK, options.result); - } - }, - - /** - * Acknowledge the receipt and handling of a CDMA SMS. - * - * @param success - * Boolean indicating whether the message was successfuly handled. - * @param cause - * SMS_* constant indicating the reason for unsuccessful handling. - */ - acknowledgeCdmaSms: function(success, cause) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_CDMA_SMS_ACKNOWLEDGE); - Buf.writeInt32(success ? 0 : 1); - Buf.writeInt32(cause); - Buf.sendParcel(); - }, - - /** - * Update received MWI into EF_MWIS. - */ - updateMwis: function(options) { - if (this.context.ICCUtilsHelper.isICCServiceAvailable("MWIS")) { - this.context.SimRecordHelper.updateMWIS(options.mwi); - } - }, - - /** - * Report SMS storage status to modem. - */ - _updateSmsMemoryStatus: function() { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_REPORT_SMS_MEMORY_STATUS); - Buf.writeInt32(1); - Buf.writeInt32(this.smsStorageAvailable ? 1 : 0); - Buf.sendParcel(); - }, - - reportSmsMemoryStatus: function(options) { - this.pendingToReportSmsMemoryStatus = true; - this.smsStorageAvailable = options.isAvailable; - this._updateSmsMemoryStatus(); - }, - - setCellBroadcastDisabled: function(options) { - this.cellBroadcastDisabled = options.disabled; - - // If |this.mergedCellBroadcastConfig| is null, either we haven't finished - // reading required SIM files, or no any channel is ever configured. In - // the former case, we'll call |this.updateCellBroadcastConfig()| later - // with correct configs; in the latter case, we don't bother resetting CB - // to disabled again. - if (this.mergedCellBroadcastConfig) { - this.updateCellBroadcastConfig(); - } - }, - - setCellBroadcastSearchList: function(options) { - let getSearchListStr = function(aSearchList) { - if (typeof aSearchList === "string" || aSearchList instanceof String) { - return aSearchList; - } - - // TODO: Set search list for CDMA/GSM individually. Bug 990926 - let prop = this._isCdma ? "cdma" : "gsm"; - - return aSearchList && aSearchList[prop]; - }.bind(this); - - try { - let str = getSearchListStr(options.searchList); - this.cellBroadcastConfigs.MMI = this._convertCellBroadcastSearchList(str); - } catch (e) { - if (DEBUG) { - this.context.debug("Invalid Cell Broadcast search list: " + e); - } - options.errorMsg = GECKO_ERROR_UNSPECIFIED_ERROR; - } - - this.sendChromeMessage(options); - if (options.errorMsg) { - return; - } - - this._mergeAllCellBroadcastConfigs(); - }, - - updateCellBroadcastConfig: function() { - let activate = !this.cellBroadcastDisabled && - (this.mergedCellBroadcastConfig != null) && - (this.mergedCellBroadcastConfig.length > 0); - if (activate) { - this.setSmsBroadcastConfig(this.mergedCellBroadcastConfig); - } else { - // It's unnecessary to set config first if we're deactivating. - this.setSmsBroadcastActivation(false); - } - }, - - setGsmSmsBroadcastConfig: function(config) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_GSM_SET_BROADCAST_SMS_CONFIG); - - let numConfigs = config ? config.length / 2 : 0; - Buf.writeInt32(numConfigs); - for (let i = 0; i < config.length;) { - // convert [from, to) to [from, to - 1] - Buf.writeInt32(config[i++]); - Buf.writeInt32(config[i++] - 1); - Buf.writeInt32(0x00); - Buf.writeInt32(0xFF); - Buf.writeInt32(1); - } - - Buf.sendParcel(); - }, - - /** - * Send CDMA SMS broadcast config. - * - * @see 3GPP2 C.R1001 Sec. 9.2 and 9.3 - */ - setCdmaSmsBroadcastConfig: function(config) { - let Buf = this.context.Buf; - // |config| is an array of half-closed range: [[from, to), [from, to), ...]. - // It will be further decomposed, ex: [1, 4) => 1, 2, 3. - Buf.newParcel(REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG); - - let numConfigs = 0; - for (let i = 0; i < config.length; i += 2) { - numConfigs += (config[i+1] - config[i]); - } - - Buf.writeInt32(numConfigs); - for (let i = 0; i < config.length;) { - let begin = config[i++]; - let end = config[i++]; - - for (let j = begin; j < end; ++j) { - Buf.writeInt32(j); - Buf.writeInt32(0); // Language Indicator: Unknown or unspecified. - Buf.writeInt32(1); - } - } - - Buf.sendParcel(); - }, - - setSmsBroadcastConfig: function(config) { - if (this._isCdma) { - this.setCdmaSmsBroadcastConfig(config); - } else { - this.setGsmSmsBroadcastConfig(config); - } - }, - - setSmsBroadcastActivation: function(activate) { - let parcelType = this._isCdma ? REQUEST_CDMA_SMS_BROADCAST_ACTIVATION : - REQUEST_GSM_SMS_BROADCAST_ACTIVATION; - let Buf = this.context.Buf; - Buf.newParcel(parcelType); - Buf.writeInt32(1); - // See hardware/ril/include/telephony/ril.h, 0 - Activate, 1 - Turn off. - Buf.writeInt32(activate ? 0 : 1); - Buf.sendParcel(); - }, - - /** - * Start a DTMF Tone. - * - * @param dtmfChar - * DTMF signal to send, 0-9, *, + - */ - startTone: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_DTMF_START, options); - Buf.writeString(options.dtmfChar); - Buf.sendParcel(); - }, - - stopTone: function() { - this.context.Buf.simpleRequest(REQUEST_DTMF_STOP); - }, - - /** - * Send a DTMF tone. - * - * @param dtmfChar - * DTMF signal to send, 0-9, *, + - */ - sendTone: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_DTMF); - Buf.writeString(options.dtmfChar); - Buf.sendParcel(); - }, - - /** - * Get the Short Message Service Center address. - */ - getSmscAddress: function(options) { - this.context.Buf.simpleRequest(REQUEST_GET_SMSC_ADDRESS, options); - }, - - /** - * Set the Short Message Service Center address. - * - * @param smscAddress - * Number part of the SMSC address. - * @param typeOfNumber - * Type of number in integer, as defined in - * |Table 10.5.118: Called party BCD number| of 3GPP TS 24.008. - * @param numberPlanIdentification - * The index of number plan identification value in - * CALLED_PARTY_BCD_NPI array. - */ - setSmscAddress: function(options) { - let ton = options.typeOfNumber; - let npi = CALLED_PARTY_BCD_NPI[options.numberPlanIdentification]; - - // If any of the mandatory arguments is not available, return an error - // immediately. - if (ton === undefined || npi === undefined || !options.smscAddress) { - options.errorMsg = GECKO_ERROR_INVALID_PARAMETER; - this.sendChromeMessage(options); - return; - } - - // Remove all illegal characters in the number string for user-input fault - // tolerance. - let numStart = options.smscAddress[0] === "+" ? 1 : 0; - let number = options.smscAddress.substring(0, numStart) + - options.smscAddress.substring(numStart) - .replace(/[^0-9*#abc]/ig, ""); - - // If the filtered number is an empty string, return an error immediately. - if (number.length === 0) { - options.errorMsg = GECKO_ERROR_INVALID_PARAMETER; - this.sendChromeMessage(options); - return; - } - - // Init parcel. - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SET_SMSC_ADDRESS, options); - - // +---+-----------+---------------+ - // | 1 | TON | NPI | - // +---+-----------+---------------+ - let tosca = (0x1 << 7) + (ton << 4) + npi; - if (RILQUIRKS_SMSC_ADDRESS_FORMAT === "pdu") { - let pduHelper = this.context.GsmPDUHelper; - - // Remove the preceding '+', and covert the special BCD digits defined in - // |Called party BCD number| of 3GPP TS 24.008 to corresponding - // hexadecimal values (refer the following table). - // - // +=========+=======+=====+ - // | value | digit | hex | - // +======================== - // | 1 0 1 0 | * | 0xA | - // | 1 0 1 1 | # | 0xB | - // | 1 1 0 0 | a | 0xC | - // | 1 1 0 1 | b | 0xD | - // | 1 1 1 0 | c | 0xE | - // +=========+=======+=====+ - // - // The replace order is reversed intentionally, because if the digits are - // replaced in ascending order, "#" will be converted to "b" and then be - // converted again to "d", which generates incorrect result. - let pureNumber = number.substring(numStart) - .replace(/c/ig, "e") - .replace(/b/ig, "d") - .replace(/a/ig, "c") - .replace(/\#/g, "b") - .replace(/\*/g, "a"); - - // address length and string length - let length = Math.ceil(pureNumber.length / 2) + 1; // +1 octet for TOA - let strlen = length * 2 + 2; // +2 semi-octets for length octet - - Buf.writeInt32(strlen); - pduHelper.writeHexOctet(length); - pduHelper.writeHexOctet(tosca); - pduHelper.writeSwappedNibbleBCD(pureNumber); - Buf.writeStringDelimiter(strlen); - } else /* RILQUIRKS_SMSC_ADDRESS_FORMAT === "text" */ { - let sca; - sca = '"' + number + '"' + ',' + tosca; - Buf.writeString(sca); - } - - Buf.sendParcel(); - }, - - /** - * Setup a data call. - * - * @param radioTech - * Integer to indicate radio technology. - * DATACALL_RADIOTECHNOLOGY_CDMA => CDMA. - * DATACALL_RADIOTECHNOLOGY_GSM => GSM. - * @param apn - * String containing the name of the APN to connect to. - * @param user - * String containing the username for the APN. - * @param passwd - * String containing the password for the APN. - * @param chappap - * Integer containing CHAP/PAP auth type. - * DATACALL_AUTH_NONE => PAP and CHAP is never performed. - * DATACALL_AUTH_PAP => PAP may be performed. - * DATACALL_AUTH_CHAP => CHAP may be performed. - * DATACALL_AUTH_PAP_OR_CHAP => PAP / CHAP may be performed. - * @param pdptype - * String containing PDP type to request. ("IP", "IPV6", ...) - */ - setupDataCall: function(options) { - // From ./hardware/ril/include/telephony/ril.h: - // ((const char **)data)[0] Radio technology to use: 0-CDMA, 1-GSM/UMTS, 2... - // for values above 2 this is RIL_RadioTechnology + 2. - // - // From frameworks/base/telephony/java/com/android/internal/telephony/DataConnection.java: - // if the mRilVersion < 6, radio technology must be GSM/UMTS or CDMA. - // Otherwise, it must be + 2 - // - // See also bug 901232 and 867873 - let radioTech = options.radioTech + 2; - let Buf = this.context.Buf; - let token = Buf.newParcel(REQUEST_SETUP_DATA_CALL, options); - Buf.writeInt32(7); - Buf.writeString(radioTech.toString()); - Buf.writeString(DATACALL_PROFILE_DEFAULT.toString()); - Buf.writeString(options.apn); - Buf.writeString(options.user); - Buf.writeString(options.passwd); - Buf.writeString(options.chappap.toString()); - Buf.writeString(options.pdptype); - Buf.sendParcel(); - return token; - }, - - /** - * Deactivate a data call. - * - * @param cid - * String containing CID. - * @param reason - * One of DATACALL_DEACTIVATE_* constants. - */ - deactivateDataCall: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_DEACTIVATE_DATA_CALL, options); - Buf.writeInt32(2); - Buf.writeString(options.cid.toString()); - Buf.writeString(options.reason !== undefined ? - options.reason.toString() : - DATACALL_DEACTIVATE_NO_REASON.toString()); - Buf.sendParcel(); - }, - - /** - * Get a list of data calls. - */ - getDataCallList: function(options) { - this.context.Buf.simpleRequest(REQUEST_DATA_CALL_LIST, options); - }, - - _attachDataRegistration: false, - /** - * Manually attach/detach data registration. - * - * @param attach - * Boolean value indicating attach or detach. - */ - setDataRegistration: function(options) { - this._attachDataRegistration = options.attach; - - if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND) { - let request = options.attach ? RIL_REQUEST_GPRS_ATTACH : - RIL_REQUEST_GPRS_DETACH; - this.context.Buf.simpleRequest(request, options); - return; - } else if (RILQUIRKS_SUBSCRIPTION_CONTROL && options.attach) { - this.context.Buf.simpleRequest(REQUEST_SET_DATA_SUBSCRIPTION, options); - return; - } - - // We don't really send a request to rild, so instantly reply success to - // RadioInterfaceLayer. - this.sendChromeMessage(options); - }, - - /** - * Get failure casue code for the most recently failed PDP context. - */ - getFailCause: function(options) { - this.context.Buf.simpleRequest(REQUEST_LAST_CALL_FAIL_CAUSE, options); - }, - - /** - * Send USSD. - * - * @param ussd - * String containing the USSD code. - */ - sendUSSD: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SEND_USSD, options); - Buf.writeString(options.ussd); - Buf.sendParcel(); - }, - - /** - * Cancel pending USSD. - */ - cancelUSSD: function(options) { - this.context.Buf.simpleRequest(REQUEST_CANCEL_USSD, options); - }, - - /** - * Queries current call forward rules. - * - * @param reason - * One of CALL_FORWARD_REASON_* constants. - * @param serviceClass - * One of ICC_SERVICE_CLASS_* constants. - * @param number - * Phone number of forwarding address. - */ - queryCallForwardStatus: function(options) { - let Buf = this.context.Buf; - let number = options.number || ""; - Buf.newParcel(REQUEST_QUERY_CALL_FORWARD_STATUS, options); - Buf.writeInt32(CALL_FORWARD_ACTION_QUERY_STATUS); - Buf.writeInt32(options.reason); - Buf.writeInt32(options.serviceClass || ICC_SERVICE_CLASS_NONE); - Buf.writeInt32(this._toaFromString(number)); - Buf.writeString(number); - Buf.writeInt32(0); - Buf.sendParcel(); - }, - - /** - * Configures call forward rule. - * - * @param action - * One of CALL_FORWARD_ACTION_* constants. - * @param reason - * One of CALL_FORWARD_REASON_* constants. - * @param serviceClass - * One of ICC_SERVICE_CLASS_* constants. - * @param number - * Phone number of forwarding address. - * @param timeSeconds - * Time in seconds to wait beforec all is forwarded. - */ - setCallForward: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SET_CALL_FORWARD, options); - Buf.writeInt32(options.action); - Buf.writeInt32(options.reason); - Buf.writeInt32(options.serviceClass); - Buf.writeInt32(this._toaFromString(options.number)); - Buf.writeString(options.number); - Buf.writeInt32(options.timeSeconds); - Buf.sendParcel(); - }, - - /** - * Queries current call barring rules. - * - * @param program - * One of CALL_BARRING_PROGRAM_* constants. - * @param serviceClass - * One of ICC_SERVICE_CLASS_* constants. - */ - queryCallBarringStatus: function(options) { - options.facility = CALL_BARRING_PROGRAM_TO_FACILITY[options.program]; - options.password = ""; // For query no need to provide it. - - // For some operators, querying specific serviceClass doesn't work. We use - // serviceClass 0 instead, and then process the response to extract the - // answer for queryServiceClass. - options.queryServiceClass = options.serviceClass; - options.serviceClass = 0; - - this.queryICCFacilityLock(options); - }, - - /** - * Configures call barring rule. - * - * @param program - * One of CALL_BARRING_PROGRAM_* constants. - * @param enabled - * Enable or disable the call barring. - * @param password - * Barring password. - * @param serviceClass - * One of ICC_SERVICE_CLASS_* constants. - */ - setCallBarring: function(options) { - options.facility = CALL_BARRING_PROGRAM_TO_FACILITY[options.program]; - this.setICCFacilityLock(options); - }, - - /** - * Change call barring facility password. - * - * @param pin - * Old password. - * @param newPin - * New password. - */ - changeCallBarringPassword: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_CHANGE_BARRING_PASSWORD, options); - Buf.writeInt32(3); - // Set facility to ICC_CB_FACILITY_BA_ALL by following TS.22.030 clause - // 6.5.4 and Table B.1. - Buf.writeString(ICC_CB_FACILITY_BA_ALL); - Buf.writeString(options.pin); - Buf.writeString(options.newPin); - Buf.sendParcel(); - }, - - /** - * Handle STK CALL_SET_UP request. - * - * @param hasConfirmed - * Does use have confirmed the call requested from ICC? - */ - stkHandleCallSetup: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM); - Buf.writeInt32(1); - Buf.writeInt32(options.hasConfirmed ? 1 : 0); - Buf.sendParcel(); - }, - - /** - * Send STK Profile Download. - * - * @param profile Profile supported by ME. - */ - sendStkTerminalProfile: function(profile) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - - Buf.newParcel(REQUEST_STK_SET_PROFILE); - Buf.writeInt32(profile.length * 2); - for (let i = 0; i < profile.length; i++) { - GsmPDUHelper.writeHexOctet(profile[i]); - } - Buf.writeInt32(0); - Buf.sendParcel(); - }, - - /** - * Send STK terminal response. - * - * @param command - * @param deviceIdentities - * @param resultCode - * @param [optional] additionalInformation - * @param [optional] itemIdentifier - * @param [optional] input - * @param [optional] isYesNo - * @param [optional] hasConfirmed - * @param [optional] localInfo - * @param [optional] timer - */ - sendStkTerminalResponse: function(response) { - if (response.hasConfirmed !== undefined) { - this.stkHandleCallSetup(response); - return; - } - - let Buf = this.context.Buf; - let ComprehensionTlvHelper = this.context.ComprehensionTlvHelper; - let GsmPDUHelper = this.context.GsmPDUHelper; - - let command = response.command; - Buf.newParcel(REQUEST_STK_SEND_TERMINAL_RESPONSE); - - // 1st mark for Parcel size - Buf.startCalOutgoingSize(function(size) { - // Parcel size is in string length, which costs 2 uint8 per char. - Buf.writeInt32(size / 2); - }); - - // Command Details - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_COMMAND_DETAILS | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(3); - if (command) { - GsmPDUHelper.writeHexOctet(command.commandNumber); - GsmPDUHelper.writeHexOctet(command.typeOfCommand); - GsmPDUHelper.writeHexOctet(command.commandQualifier); - } else { - GsmPDUHelper.writeHexOctet(0x00); - GsmPDUHelper.writeHexOctet(0x00); - GsmPDUHelper.writeHexOctet(0x00); - } - - // Device Identifier - // According to TS102.223/TS31.111 section 6.8 Structure of - // TERMINAL RESPONSE, "For all SIMPLE-TLV objects with Min=N, - // the ME should set the CR(comprehension required) flag to - // comprehension not required.(CR=0)" - // Since DEVICE_IDENTITIES and DURATION TLVs have Min=N, - // the CR flag is not set. - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_DEVICE_ID); - GsmPDUHelper.writeHexOctet(2); - GsmPDUHelper.writeHexOctet(STK_DEVICE_ID_ME); - GsmPDUHelper.writeHexOctet(STK_DEVICE_ID_SIM); - - // Result - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_RESULT | - COMPREHENSIONTLV_FLAG_CR); - if ("additionalInformation" in response) { - // In |12.12 Result| TS 11.14, the length of additional information is - // varied and all possible values are addressed in 12.12.1-11 of TS 11.14 - // and 8.12.1-13 in TS 31.111. - // However, - // 1. Only SEND SS requires info with more than 1 octet. - // 2. In rild design, SEND SS is expected to be handled by modem and - // UNSOLICITED_STK_EVENT_NOTIFY will be sent to application layer to - // indicate appropriate messages to users. TR is not required in this - // case. - // Hence, we simplify the structure of |additionalInformation| to a - // numeric value instead of a octet array. - GsmPDUHelper.writeHexOctet(2); - GsmPDUHelper.writeHexOctet(response.resultCode); - GsmPDUHelper.writeHexOctet(response.additionalInformation); - } else { - GsmPDUHelper.writeHexOctet(1); - GsmPDUHelper.writeHexOctet(response.resultCode); - } - - // Item Identifier - if (response.itemIdentifier != null) { - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_ITEM_ID | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(1); - GsmPDUHelper.writeHexOctet(response.itemIdentifier); - } - - // No need to process Text data if user requests help information. - if (response.resultCode != STK_RESULT_HELP_INFO_REQUIRED) { - let text; - let coding = command.options.isUCS2 ? - STK_TEXT_CODING_UCS2 : - (command.options.isPacked ? - STK_TEXT_CODING_GSM_7BIT_PACKED : - STK_TEXT_CODING_GSM_8BIT); - if (response.isYesNo !== undefined) { - // Tag: GET_INKEY - // When the ME issues a successful TERMINAL RESPONSE for a GET INKEY - // ("Yes/No") command with command qualifier set to "Yes/No", it shall - // supply the value '01' when the answer is "positive" and the value - // '00' when the answer is "negative" in the Text string data object. - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_TEXT_STRING | - COMPREHENSIONTLV_FLAG_CR); - // Length: 2 - GsmPDUHelper.writeHexOctet(2); - // Value: Coding, Yes/No. - GsmPDUHelper.writeHexOctet(coding); - GsmPDUHelper.writeHexOctet(response.isYesNo ? 0x01 : 0x00); - } else { - if (response.input !== undefined) { - ComprehensionTlvHelper.writeTextStringTlv(response.input, coding); - } - } - } - - // Duration - if (response.resultCode === STK_RESULT_NO_RESPONSE_FROM_USER) { - // In TS102 223, 6.4.2 GET INKEY, "if the UICC requests a variable timeout, - // the terminal shall wait until either the user enters a single character - // or the timeout expires. The timer starts when the text is displayed on - // the screen and stops when the TERMINAL RESPONSE is sent. The terminal - // shall pass the total display text duration (command execution duration) - // to the UICC using the TERMINAL RESPONSE. The time unit of the response - // is identical to the time unit of the requested variable timeout." - let duration = command && command.options && command.options.duration; - if (duration) { - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_DURATION); - GsmPDUHelper.writeHexOctet(2); - GsmPDUHelper.writeHexOctet(duration.timeUnit); - GsmPDUHelper.writeHexOctet(duration.timeInterval); - } - } - - // Local Information - if (response.localInfo) { - let localInfo = response.localInfo; - - // Location Infomation - if (localInfo.locationInfo) { - ComprehensionTlvHelper.writeLocationInfoTlv(localInfo.locationInfo); - } - - // IMEI - if (localInfo.imei != null) { - let imei = localInfo.imei; - if (imei.length == 15) { - imei = imei + "0"; - } - - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_IMEI); - GsmPDUHelper.writeHexOctet(8); - for (let i = 0; i < imei.length / 2; i++) { - GsmPDUHelper.writeHexOctet(parseInt(imei.substr(i * 2, 2), 16)); - } - } - - // Date and Time Zone - if (localInfo.date != null) { - ComprehensionTlvHelper.writeDateTimeZoneTlv(localInfo.date); - } - - // Language - if (localInfo.language) { - ComprehensionTlvHelper.writeLanguageTlv(localInfo.language); - } - } - - // Timer - if (response.timer) { - let timer = response.timer; - - if (timer.timerId) { - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_TIMER_IDENTIFIER); - GsmPDUHelper.writeHexOctet(1); - GsmPDUHelper.writeHexOctet(timer.timerId); - } - - if (timer.timerValue) { - ComprehensionTlvHelper.writeTimerValueTlv(timer.timerValue, false); - } - } - - // Calculate and write Parcel size to 1st mark - Buf.stopCalOutgoingSize(); - - Buf.writeInt32(0); - Buf.sendParcel(); - }, - - /** - * Send STK Envelope(Menu Selection) command. - * - * @param itemIdentifier - * @param helpRequested - */ - sendStkMenuSelection: function(command) { - command.tag = BER_MENU_SELECTION_TAG; - command.deviceId = { - sourceId :STK_DEVICE_ID_KEYPAD, - destinationId: STK_DEVICE_ID_SIM - }; - this.sendICCEnvelopeCommand(command); - }, - - /** - * Send STK Envelope(Timer Expiration) command. - * - * @param timer - */ - sendStkTimerExpiration: function(command) { - command.tag = BER_TIMER_EXPIRATION_TAG; - command.deviceId = { - sourceId: STK_DEVICE_ID_ME, - destinationId: STK_DEVICE_ID_SIM - }; - command.timerId = command.timer.timerId; - command.timerValue = command.timer.timerValue; - this.sendICCEnvelopeCommand(command); - }, - - /** - * Send STK Envelope(Event Download) command. - * @param event - */ - sendStkEventDownload: function(command) { - command.tag = BER_EVENT_DOWNLOAD_TAG; - command.eventList = command.event.eventType; - switch (command.eventList) { - case STK_EVENT_TYPE_LOCATION_STATUS: - command.deviceId = { - sourceId :STK_DEVICE_ID_ME, - destinationId: STK_DEVICE_ID_SIM - }; - command.locationStatus = command.event.locationStatus; - // Location info should only be provided when locationStatus is normal. - if (command.locationStatus == STK_SERVICE_STATE_NORMAL) { - command.locationInfo = command.event.locationInfo; - } - break; - case STK_EVENT_TYPE_MT_CALL: - command.deviceId = { - sourceId: STK_DEVICE_ID_NETWORK, - destinationId: STK_DEVICE_ID_SIM - }; - command.transactionId = 0; - command.address = command.event.number; - break; - case STK_EVENT_TYPE_CALL_DISCONNECTED: - command.cause = command.event.error; - // Fall through. - case STK_EVENT_TYPE_CALL_CONNECTED: - command.deviceId = { - sourceId: (command.event.isIssuedByRemote ? - STK_DEVICE_ID_NETWORK : STK_DEVICE_ID_ME), - destinationId: STK_DEVICE_ID_SIM - }; - command.transactionId = 0; - break; - case STK_EVENT_TYPE_USER_ACTIVITY: - command.deviceId = { - sourceId: STK_DEVICE_ID_ME, - destinationId: STK_DEVICE_ID_SIM - }; - break; - case STK_EVENT_TYPE_IDLE_SCREEN_AVAILABLE: - command.deviceId = { - sourceId: STK_DEVICE_ID_DISPLAY, - destinationId: STK_DEVICE_ID_SIM - }; - break; - case STK_EVENT_TYPE_LANGUAGE_SELECTION: - command.deviceId = { - sourceId: STK_DEVICE_ID_ME, - destinationId: STK_DEVICE_ID_SIM - }; - command.language = command.event.language; - break; - case STK_EVENT_TYPE_BROWSER_TERMINATION: - command.deviceId = { - sourceId: STK_DEVICE_ID_ME, - destinationId: STK_DEVICE_ID_SIM - }; - command.terminationCause = command.event.terminationCause; - break; - } - this.sendICCEnvelopeCommand(command); - }, - - /** - * Send REQUEST_STK_SEND_ENVELOPE_COMMAND to ICC. - * - * @param tag - * @patam deviceId - * @param [optioanl] itemIdentifier - * @param [optional] helpRequested - * @param [optional] eventList - * @param [optional] locationStatus - * @param [optional] locationInfo - * @param [optional] address - * @param [optional] transactionId - * @param [optional] cause - * @param [optional] timerId - * @param [optional] timerValue - * @param [optional] terminationCause - */ - sendICCEnvelopeCommand: function(options) { - if (DEBUG) { - this.context.debug("Stk Envelope " + JSON.stringify(options)); - } - - let Buf = this.context.Buf; - let ComprehensionTlvHelper = this.context.ComprehensionTlvHelper; - let GsmPDUHelper = this.context.GsmPDUHelper; - - Buf.newParcel(REQUEST_STK_SEND_ENVELOPE_COMMAND); - - // 1st mark for Parcel size - Buf.startCalOutgoingSize(function(size) { - // Parcel size is in string length, which costs 2 uint8 per char. - Buf.writeInt32(size / 2); - }); - - // Write a BER-TLV - GsmPDUHelper.writeHexOctet(options.tag); - // 2nd mark for BER length - Buf.startCalOutgoingSize(function(size) { - // BER length is in number of hexOctets, which costs 4 uint8 per hexOctet. - GsmPDUHelper.writeHexOctet(size / 4); - }); - - // Event List - if (options.eventList != null) { - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_EVENT_LIST | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(1); - GsmPDUHelper.writeHexOctet(options.eventList); - } - - // Device Identifies - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_DEVICE_ID | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(2); - GsmPDUHelper.writeHexOctet(options.deviceId.sourceId); - GsmPDUHelper.writeHexOctet(options.deviceId.destinationId); - - // Item Identifier - if (options.itemIdentifier != null) { - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_ITEM_ID | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(1); - GsmPDUHelper.writeHexOctet(options.itemIdentifier); - } - - // Help Request - if (options.helpRequested) { - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_HELP_REQUEST | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(0); - // Help Request doesn't have value - } - - // Location Status - if (options.locationStatus != null) { - let len = options.locationStatus.length; - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_LOCATION_STATUS | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(1); - GsmPDUHelper.writeHexOctet(options.locationStatus); - } - - // Location Info - if (options.locationInfo) { - ComprehensionTlvHelper.writeLocationInfoTlv(options.locationInfo); - } - - // Transaction Id - if (options.transactionId != null) { - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_TRANSACTION_ID | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(1); - GsmPDUHelper.writeHexOctet(options.transactionId); - } - - // Address - if (options.address) { - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_ADDRESS | - COMPREHENSIONTLV_FLAG_CR); - let addressLength = options.address[0] == '+' ? options.address.length - 1 - : options.address.length; - ComprehensionTlvHelper.writeLength( - Math.ceil(addressLength / 2) + 1 // address BCD + TON - ); - this.context.ICCPDUHelper.writeDiallingNumber(options.address); - } - - // Cause of disconnection. - if (options.cause != null) { - ComprehensionTlvHelper.writeCauseTlv(options.cause); - } - - // Timer Identifier - if (options.timerId != null) { - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_TIMER_IDENTIFIER | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(1); - GsmPDUHelper.writeHexOctet(options.timerId); - } - - // Timer Value - if (options.timerValue != null) { - ComprehensionTlvHelper.writeTimerValueTlv(options.timerValue, true); - } - - // Language - if (options.language) { - ComprehensionTlvHelper.writeLanguageTlv(options.language); - } - - // Browser Termination - if (options.terminationCause != null) { - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_BROWSER_TERMINATION_CAUSE | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(1); - GsmPDUHelper.writeHexOctet(options.terminationCause); - } - - // Calculate and write BER length to 2nd mark - Buf.stopCalOutgoingSize(); - - // Calculate and write Parcel size to 1st mark - Buf.stopCalOutgoingSize(); - - Buf.writeInt32(0); - Buf.sendParcel(); - }, - - /** - * Report STK Service is running. - */ - reportStkServiceIsRunning: function() { - this.context.Buf.simpleRequest(REQUEST_REPORT_STK_SERVICE_IS_RUNNING); - }, - - /** - * Process ICC status. - */ - _processICCStatus: function(iccStatus) { - // If |_waitingRadioTech| is true, we should not get app information because - // the |_isCdma| flag is not ready yet. Otherwise we may use wrong index to - // get app information, especially for the case that icc card has both cdma - // and gsm subscription. - if (this._waitingRadioTech) { - return; - } - - // When |iccStatus.cardState| is not CARD_STATE_PRESENT, set cardState to - // undetected. - if (iccStatus.cardState !== CARD_STATE_PRESENT) { - if (this.cardState !== GECKO_CARDSTATE_UNDETECTED) { - this.operator = null; - // We should send |cardstatechange| before |iccinfochange|, otherwise we - // may lost cardstatechange event when icc card becomes undetected. - this.cardState = GECKO_CARDSTATE_UNDETECTED; - this.sendChromeMessage({rilMessageType: "cardstatechange", - cardState: this.cardState}); - - this.iccInfo = {iccType: null}; - this.context.ICCUtilsHelper.handleICCInfoChange(); - } - return; - } - - if (RILQUIRKS_SUBSCRIPTION_CONTROL) { - // All appIndex is -1 means the subscription is not activated yet. - // Note that we don't support "ims" for now, so we don't take it into - // account. - let neetToActivate = iccStatus.cdmaSubscriptionAppIndex === -1 && - iccStatus.gsmUmtsSubscriptionAppIndex === -1; - if (neetToActivate && - // Note: setUiccSubscription works abnormally when RADIO is OFF, - // which causes SMS function broken in Flame. - // See bug 1008557 for detailed info. - this.radioState === GECKO_RADIOSTATE_ENABLED) { - for (let i = 0; i < iccStatus.apps.length; i++) { - this.setUiccSubscription({appIndex: i, enabled: true}); - } - } - } - - let newCardState; - let index = this._isCdma ? iccStatus.cdmaSubscriptionAppIndex - : iccStatus.gsmUmtsSubscriptionAppIndex; - let app = iccStatus.apps[index]; - if (app) { - // fetchICCRecords will need to read aid, so read aid here. - this.aid = app.aid; - this.appType = app.app_type; - this.iccInfo.iccType = GECKO_CARD_TYPE[this.appType]; - - switch (app.app_state) { - case CARD_APPSTATE_ILLEGAL: - newCardState = GECKO_CARDSTATE_ILLEGAL; - break; - case CARD_APPSTATE_PIN: - newCardState = GECKO_CARDSTATE_PIN_REQUIRED; - break; - case CARD_APPSTATE_PUK: - newCardState = GECKO_CARDSTATE_PUK_REQUIRED; - break; - case CARD_APPSTATE_SUBSCRIPTION_PERSO: - newCardState = PERSONSUBSTATE[app.perso_substate]; - break; - case CARD_APPSTATE_READY: - newCardState = GECKO_CARDSTATE_READY; - break; - case CARD_APPSTATE_UNKNOWN: - case CARD_APPSTATE_DETECTED: - // Fall through. - default: - newCardState = GECKO_CARDSTATE_UNKNOWN; - } - - let pin1State = app.pin1_replaced ? iccStatus.universalPINState : - app.pin1; - if (pin1State === CARD_PINSTATE_ENABLED_PERM_BLOCKED) { - newCardState = GECKO_CARDSTATE_PERMANENT_BLOCKED; - } - } else { - // Having incorrect app information, set card state to unknown. - newCardState = GECKO_CARDSTATE_UNKNOWN; - } - - let ICCRecordHelper = this.context.ICCRecordHelper; - // Try to get iccId only when cardState left GECKO_CARDSTATE_UNDETECTED. - if (iccStatus.cardState === CARD_STATE_PRESENT && - (this.cardState === GECKO_CARDSTATE_UNINITIALIZED || - this.cardState === GECKO_CARDSTATE_UNDETECTED)) { - ICCRecordHelper.readICCID(); - } - - if (this.cardState == newCardState) { - return; - } - - // This was moved down from CARD_APPSTATE_READY - this.requestNetworkInfo(); - if (newCardState == GECKO_CARDSTATE_READY) { - // For type SIM, we need to check EF_phase first. - // Other types of ICC we can send Terminal_Profile immediately. - if (this.appType == CARD_APPTYPE_SIM) { - this.context.SimRecordHelper.readSimPhase(); - } else if (RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD) { - this.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE); - } - - ICCRecordHelper.fetchICCRecords(); - } - - this.cardState = newCardState; - this.sendChromeMessage({rilMessageType: "cardstatechange", - cardState: this.cardState}); - }, - - /** - * Helper for processing responses of functions such as enterICC* and changeICC*. - */ - _processEnterAndChangeICCResponses: function(length, options) { - options.retryCount = length ? this.context.Buf.readInt32List()[0] : -1; - this.sendChromeMessage(options); - }, - - // We combine all of the NETWORK_INFO_MESSAGE_TYPES into one "networkinfochange" - // message to the RadioInterfaceLayer, so we can avoid sending multiple - // VoiceInfoChanged events for both operator / voice_data_registration - // - // State management here is a little tricky. We need to know both: - // 1. Whether or not a response was received for each of the - // NETWORK_INFO_MESSAGE_TYPES - // 2. The outbound message that corresponds with that response -- but this - // only happens when internal state changes (i.e. it isn't guaranteed) - // - // To collect this state, each message response function first calls - // _receivedNetworkInfo, to mark the response as received. When the - // final response is received, a call to _sendPendingNetworkInfo is placed - // on the next tick of the worker thread. - // - // Since the original call to _receivedNetworkInfo happens at the top - // of the response handler, this gives the final handler a chance to - // queue up it's "changed" message by calling _sendNetworkInfoMessage if/when - // the internal state has actually changed. - _sendNetworkInfoMessage: function(type, message) { - if (!this._processingNetworkInfo) { - // We only combine these messages in the case of the combined request - // in requestNetworkInfo() - this.sendChromeMessage(message); - return; - } - - if (DEBUG) { - this.context.debug("Queuing " + type + " network info message: " + - JSON.stringify(message)); - } - this._pendingNetworkInfo[type] = message; - }, - - _receivedNetworkInfo: function(type) { - if (DEBUG) this.context.debug("Received " + type + " network info."); - if (!this._processingNetworkInfo) { - return; - } - - let pending = this._pendingNetworkInfo; - - // We still need to track states for events that aren't fired. - if (!(type in pending)) { - pending[type] = this.pendingNetworkType; - } - - // Pending network info is ready to be sent when no more messages - // are waiting for responses, but the combined payload hasn't been sent. - for (let i = 0; i < NETWORK_INFO_MESSAGE_TYPES.length; i++) { - let msgType = NETWORK_INFO_MESSAGE_TYPES[i]; - if (!(msgType in pending)) { - if (DEBUG) { - this.context.debug("Still missing some more network info, not " + - "notifying main thread."); - } - return; - } - } - - // Do a pass to clean up the processed messages that didn't create - // a response message, so we don't have unused keys in the outbound - // networkinfochanged message. - for (let key in pending) { - if (pending[key] == this.pendingNetworkType) { - delete pending[key]; - } - } - - if (DEBUG) { - this.context.debug("All pending network info has been received: " + - JSON.stringify(pending)); - } - - // Send the message on the next tick of the worker's loop, so we give the - // last message a chance to call _sendNetworkInfoMessage first. - setTimeout(this._sendPendingNetworkInfo.bind(this), 0); - }, - - _sendPendingNetworkInfo: function() { - this.sendChromeMessage(this._pendingNetworkInfo); - - this._processingNetworkInfo = false; - for (let i = 0; i < NETWORK_INFO_MESSAGE_TYPES.length; i++) { - delete this._pendingNetworkInfo[NETWORK_INFO_MESSAGE_TYPES[i]]; - } - - if (this._needRepollNetworkInfo) { - this._needRepollNetworkInfo = false; - this.requestNetworkInfo(); - } - }, - - /** - * Normalize the signal strength in dBm to the signal level from 0 to 100. - * - * @param signal - * The signal strength in dBm to normalize. - * @param min - * The signal strength in dBm maps to level 0. - * @param max - * The signal strength in dBm maps to level 100. - * - * @return level - * The signal level from 0 to 100. - */ - _processSignalLevel: function(signal, min, max) { - if (signal <= min) { - return 0; - } - - if (signal >= max) { - return 100; - } - - return Math.floor((signal - min) * 100 / (max - min)); - }, - - /** - * Process LTE signal strength to the signal info object. - * - * @param signal - * The signal object reported from RIL/modem. - * - * @return The object of signal strength info. - * Or null if invalid signal input. - * - * TODO: Bug 982013: reconsider the format of signal strength APIs for - * GSM/CDMA/LTE to expose details, such as rsrp and rsnnr, - * individually. - */ - _processLteSignal: function(signal) { - let info = { - voice: { - signalStrength: null, - relSignalStrength: null - }, - data: { - signalStrength: null, - relSignalStrength: null - } - }; - - // Referring to AOSP, use lteRSRP for signalStrength in dBm. - let signalStrength = (signal.lteRSRP === undefined || signal.lteRSRP === 0x7FFFFFFF) ? - null : signal.lteRSRP; - info.voice.signalStrength = info.data.signalStrength = signalStrength; - - // Referring to AOSP, first determine signalLevel based on RSRP and RSSNR, - // then on lteSignalStrength if RSRP and RSSNR are invalid. - let rsrpLevel = -1; - let rssnrLevel = -1; - if (signal.lteRSRP !== undefined && - signal.lteRSRP !== 0x7FFFFFFF && - signal.lteRSRP >= 44 && - signal.lteRSRP <= 140) { - rsrpLevel = this._processSignalLevel(signal.lteRSRP * -1, -115, -85); - } - - if (signal.lteRSSNR !== undefined && - signal.lteRSSNR !== 0x7FFFFFFF && - signal.lteRSSNR >= -200 && - signal.lteRSSNR <= 300) { - rssnrLevel = this._processSignalLevel(signal.lteRSSNR, -30, 130); - } - - if (rsrpLevel !== -1 && rssnrLevel !== -1) { - info.voice.relSignalStrength = info.data.relSignalStrength = - Math.min(rsrpLevel, rssnrLevel); - return info; - } - - let level = Math.max(rsrpLevel, rssnrLevel); - if (level !== -1) { - info.voice.relSignalStrength = info.data.relSignalStrength = level; - return info; - } - - // Valid values are 0-63 as defined in TS 27.007 clause 8.69. - if (signal.lteSignalStrength !== undefined && - signal.lteSignalStrength >= 0 && - signal.lteSignalStrength <= 63) { - level = this._processSignalLevel(signal.lteSignalStrength, 0, 12); - info.voice.relSignalStrength = info.data.relSignalStrength = level; - return info; - } - - return null; - }, - - _processSignalStrength: function(signal) { - let info = { - voice: { - signalStrength: null, - relSignalStrength: null - }, - data: { - signalStrength: null, - relSignalStrength: null - } - }; - - // During startup, |radioTech| is not yet defined, so we need to - // check it separately. - if (("radioTech" in this.voiceRegistrationState) && - !this._isGsmTechGroup(this.voiceRegistrationState.radioTech)) { - // CDMA RSSI. - // Valid values are positive integers. This value is the actual RSSI value - // multiplied by -1. Example: If the actual RSSI is -75, then this - // response value will be 75. - if (signal.cdmaDBM && signal.cdmaDBM > 0) { - let signalStrength = -1 * signal.cdmaDBM; - info.voice.signalStrength = signalStrength; - - // -105 and -70 are referred to AOSP's implementation. These values are - // not constants and can be customized based on different requirement. - let signalLevel = this._processSignalLevel(signalStrength, -105, -70); - info.voice.relSignalStrength = signalLevel; - } - - // EVDO RSSI. - // Valid values are positive integers. This value is the actual RSSI value - // multiplied by -1. Example: If the actual RSSI is -75, then this - // response value will be 75. - if (signal.evdoDBM && signal.evdoDBM > 0) { - let signalStrength = -1 * signal.evdoDBM; - info.data.signalStrength = signalStrength; - - // -105 and -70 are referred to AOSP's implementation. These values are - // not constants and can be customized based on different requirement. - let signalLevel = this._processSignalLevel(signalStrength, -105, -70); - info.data.relSignalStrength = signalLevel; - } - } else { - // Check LTE level first, and check GSM/UMTS level next if LTE one is not - // valid. - let lteInfo = this._processLteSignal(signal); - if (lteInfo) { - info = lteInfo; - } else { - // GSM signal strength. - // Valid values are 0-31 as defined in TS 27.007 8.5. - // 0 : -113 dBm or less - // 1 : -111 dBm - // 2...30: -109...-53 dBm - // 31 : -51 dBm - if (signal.gsmSignalStrength && - signal.gsmSignalStrength >= 0 && - signal.gsmSignalStrength <= 31) { - let signalStrength = -113 + 2 * signal.gsmSignalStrength; - info.voice.signalStrength = info.data.signalStrength = signalStrength; - - // -115 and -85 are referred to AOSP's implementation. These values are - // not constants and can be customized based on different requirement. - let signalLevel = this._processSignalLevel(signalStrength, -110, -85); - info.voice.relSignalStrength = info.data.relSignalStrength = signalLevel; - } - } - } - - info.rilMessageType = "signalstrengthchange"; - this._sendNetworkInfoMessage(NETWORK_INFO_SIGNAL, info); - }, - - /** - * Process the network registration flags. - * - * @return true if the state changed, false otherwise. - */ - _processCREG: function(curState, newState) { - let changed = false; - - let regState = this.parseInt(newState[0], NETWORK_CREG_STATE_UNKNOWN); - if (curState.regState === undefined || curState.regState !== regState) { - changed = true; - curState.regState = regState; - - curState.state = NETWORK_CREG_TO_GECKO_MOBILE_CONNECTION_STATE[regState]; - curState.connected = regState == NETWORK_CREG_STATE_REGISTERED_HOME || - regState == NETWORK_CREG_STATE_REGISTERED_ROAMING; - curState.roaming = regState == NETWORK_CREG_STATE_REGISTERED_ROAMING; - curState.emergencyCallsOnly = !curState.connected; - } - - if (!curState.cell) { - curState.cell = {}; - } - - // From TS 23.003, 0000 and 0xfffe are indicated that no valid LAI exists - // in MS. So we still need to report the '0000' as well. - let lac = this.parseInt(newState[1], -1, 16); - if (curState.cell.gsmLocationAreaCode === undefined || - curState.cell.gsmLocationAreaCode !== lac) { - curState.cell.gsmLocationAreaCode = lac; - changed = true; - } - - let cid = this.parseInt(newState[2], -1, 16); - if (curState.cell.gsmCellId === undefined || - curState.cell.gsmCellId !== cid) { - curState.cell.gsmCellId = cid; - changed = true; - } - - let radioTech = (newState[3] === undefined ? - NETWORK_CREG_TECH_UNKNOWN : - this.parseInt(newState[3], NETWORK_CREG_TECH_UNKNOWN)); - if (curState.radioTech === undefined || curState.radioTech !== radioTech) { - changed = true; - curState.radioTech = radioTech; - curState.type = GECKO_RADIO_TECH[radioTech] || null; - } - return changed; - }, - - _processVoiceRegistrationState: function(state) { - let rs = this.voiceRegistrationState; - let stateChanged = this._processCREG(rs, state); - if (stateChanged && rs.connected) { - this.getSmscAddress(); - } - - let cell = rs.cell; - if (this._isCdma) { - // Some variables below are not used. Comment them instead of removing to - // keep the information about state[x]. - let cdmaBaseStationId = this.parseInt(state[4], -1); - let cdmaBaseStationLatitude = this.parseInt(state[5], -2147483648); - let cdmaBaseStationLongitude = this.parseInt(state[6], -2147483648); - // let cssIndicator = this.parseInt(state[7]); - let cdmaSystemId = this.parseInt(state[8], -1); - let cdmaNetworkId = this.parseInt(state[9], -1); - // let roamingIndicator = this.parseInt(state[10]); - // let systemIsInPRL = this.parseInt(state[11]); - // let defaultRoamingIndicator = this.parseInt(state[12]); - // let reasonForDenial = this.parseInt(state[13]); - - if (cell.cdmaBaseStationId !== cdmaBaseStationId || - cell.cdmaBaseStationLatitude !== cdmaBaseStationLatitude || - cell.cdmaBaseStationLongitude !== cdmaBaseStationLongitude || - cell.cdmaSystemId !== cdmaSystemId || - cell.cdmaNetworkId !== cdmaNetworkId) { - stateChanged = true; - cell.cdmaBaseStationId = cdmaBaseStationId; - cell.cdmaBaseStationLatitude = cdmaBaseStationLatitude; - cell.cdmaBaseStationLongitude = cdmaBaseStationLongitude; - cell.cdmaSystemId = cdmaSystemId; - cell.cdmaNetworkId = cdmaNetworkId; - } - } - - if (stateChanged) { - rs.rilMessageType = "voiceregistrationstatechange"; - this._sendNetworkInfoMessage(NETWORK_INFO_VOICE_REGISTRATION_STATE, rs); - } - }, - - _processDataRegistrationState: function(state) { - let rs = this.dataRegistrationState; - let stateChanged = this._processCREG(rs, state); - if (stateChanged) { - rs.rilMessageType = "dataregistrationstatechange"; - this._sendNetworkInfoMessage(NETWORK_INFO_DATA_REGISTRATION_STATE, rs); - } - }, - - _processOperator: function(operatorData) { - if (operatorData.length < 3) { - if (DEBUG) { - this.context.debug("Expected at least 3 strings for operator."); - } - } - - if (!this.operator) { - this.operator = { - rilMessageType: "operatorchange", - longName: null, - shortName: null - }; - } - - let [longName, shortName, networkTuple] = operatorData; - let thisTuple = (this.operator.mcc || "") + (this.operator.mnc || ""); - - if (this.operator.longName !== longName || - this.operator.shortName !== shortName || - thisTuple !== networkTuple) { - - this.operator.mcc = null; - this.operator.mnc = null; - - if (networkTuple) { - try { - this._processNetworkTuple(networkTuple, this.operator); - } catch (e) { - if (DEBUG) this.context.debug("Error processing operator tuple: " + e); - } - } else { - // According to ril.h, the operator fields will be NULL when the operator - // is not currently registered. We can avoid trying to parse the numeric - // tuple in that case. - if (DEBUG) { - this.context.debug("Operator is currently unregistered"); - } - } - - this.operator.longName = longName; - this.operator.shortName = shortName; - - let ICCUtilsHelper = this.context.ICCUtilsHelper; - if (ICCUtilsHelper.updateDisplayCondition()) { - ICCUtilsHelper.handleICCInfoChange(); - } - - // NETWORK_INFO_OPERATOR message will be sent out by overrideICCNetworkName - // itself if operator name is overridden after checking, or we have to - // do it by ourself. - if (!this.overrideICCNetworkName()) { - this._sendNetworkInfoMessage(NETWORK_INFO_OPERATOR, this.operator); - } - } - }, - - _processSuppSvcNotification: function(info) { - if (DEBUG) { - this.context.debug("handle supp svc notification: " + JSON.stringify(info)); - } - - if (info.notificationType !== 1) { - // We haven't supported MO intermediate result code, i.e. - // info.notificationType === 0, which refers to code1 defined in 3GPP - // 27.007 7.17. We only support partial MT unsolicited result code, - // referring to code2, for now. - return; - } - - let notification = null; - - switch (info.code) { - case SUPP_SVC_NOTIFICATION_CODE2_PUT_ON_HOLD: - case SUPP_SVC_NOTIFICATION_CODE2_RETRIEVED: - notification = GECKO_SUPP_SVC_NOTIFICATION_FROM_CODE2[info.code]; - break; - default: - // Notification type not supported. - return; - } - - let message = {rilMessageType: "suppSvcNotification", - number: info.number, // could be empty. - notification: notification}; - this.sendChromeMessage(message); - }, - - _cancelEmergencyCbModeTimeout: function() { - if (this._exitEmergencyCbModeTimeoutID) { - clearTimeout(this._exitEmergencyCbModeTimeoutID); - this._exitEmergencyCbModeTimeoutID = null; - } - }, - - _handleChangedEmergencyCbMode: function(active) { - this._isInEmergencyCbMode = active; - - // Clear the existed timeout event. - this._cancelEmergencyCbModeTimeout(); - - // Start a new timeout event when entering the mode. - if (active) { - this._exitEmergencyCbModeTimeoutID = setTimeout( - this.exitEmergencyCbMode.bind(this), EMERGENCY_CB_MODE_TIMEOUT_MS); - } - - let message = {rilMessageType: "emergencyCbModeChange", - active: active, - timeoutMs: EMERGENCY_CB_MODE_TIMEOUT_MS}; - this.sendChromeMessage(message); - }, - - _updateNetworkSelectionMode: function(mode) { - if (this.networkSelectionMode === mode) { - return; - } - - let options = { - rilMessageType: "networkselectionmodechange", - mode: mode - }; - this.networkSelectionMode = mode; - this._sendNetworkInfoMessage(NETWORK_INFO_NETWORK_SELECTION_MODE, options); - }, - - _processNetworks: function() { - let strings = this.context.Buf.readStringList(); - let networks = []; - - for (let i = 0; i < strings.length; - i += RILQUIRKS_AVAILABLE_NETWORKS_EXTRA_STRING ? 5 : 4) { - let network = { - longName: strings[i], - shortName: strings[i + 1], - mcc: null, - mnc: null, - state: null - }; - - let networkTuple = strings[i + 2]; - try { - this._processNetworkTuple(networkTuple, network); - } catch (e) { - if (DEBUG) this.context.debug("Error processing operator tuple: " + e); - } - - let state = strings[i + 3]; - network.state = RIL_QAN_STATE_TO_GECKO_STATE[state]; - - networks.push(network); - } - return networks; - }, - - /** - * The "numeric" portion of the operator info is a tuple - * containing MCC (country code) and MNC (network code). - * AFAICT, MCC should always be 3 digits, making the remaining - * portion the MNC. - */ - _processNetworkTuple: function(networkTuple, network) { - let tupleLen = networkTuple.length; - - if (tupleLen == 5 || tupleLen == 6) { - network.mcc = networkTuple.substr(0, 3); - network.mnc = networkTuple.substr(3); - } else { - network.mcc = null; - network.mnc = null; - - throw new Error("Invalid network tuple (should be 5 or 6 digits): " + networkTuple); - } - }, - - /** - * Check if GSM radio access technology group. - */ - _isGsmTechGroup: function(radioTech) { - if (!radioTech) { - return true; - } - - switch(radioTech) { - case NETWORK_CREG_TECH_GPRS: - case NETWORK_CREG_TECH_EDGE: - case NETWORK_CREG_TECH_UMTS: - case NETWORK_CREG_TECH_HSDPA: - case NETWORK_CREG_TECH_HSUPA: - case NETWORK_CREG_TECH_HSPA: - case NETWORK_CREG_TECH_LTE: - case NETWORK_CREG_TECH_HSPAP: - case NETWORK_CREG_TECH_GSM: - case NETWORK_CREG_TECH_DCHSPAP_1: - case NETWORK_CREG_TECH_DCHSPAP_2: - return true; - } - - return false; - }, - - /** - * Process radio technology change. - */ - _processRadioTech: function(radioTech) { - let isCdma = !this._isGsmTechGroup(radioTech); - this.radioTech = radioTech; - - if (DEBUG) { - this.context.debug("Radio tech is set to: " + GECKO_RADIO_TECH[radioTech] + - ", it is a " + (isCdma?"cdma":"gsm") + " technology"); - } - - // We should request SIM information when - // 1. Radio state has been changed, so we are waiting for radioTech or - // 2. isCdma is different from this._isCdma. - if (this._waitingRadioTech || isCdma != this._isCdma) { - this._isCdma = isCdma; - this._waitingRadioTech = false; - this.getICCStatus(); - } - }, - - /** - * Helper for returning the TOA for the given dial string. - */ - _toaFromString: function(number) { - let toa = TOA_UNKNOWN; - if (number && number.length > 0 && number[0] == '+') { - toa = TOA_INTERNATIONAL; - } - return toa; - }, - - /** - * @param message A decoded SMS-DELIVER message. - * - * @see 3GPP TS 31.111 section 7.1.1 - */ - dataDownloadViaSMSPP: function(message) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - - let options = { - pid: message.pid, - dcs: message.dcs, - encoding: message.encoding, - }; - Buf.newParcel(REQUEST_STK_SEND_ENVELOPE_WITH_STATUS, options); - - Buf.seekIncoming(-1 * (Buf.getCurrentParcelSize() - Buf.getReadAvailable() - - 2 * Buf.UINT32_SIZE)); // Skip response_type & request_type. - let messageStringLength = Buf.readInt32(); // In semi-octets - let smscLength = GsmPDUHelper.readHexOctet(); // In octets, inclusive of TOA - let tpduLength = (messageStringLength / 2) - (smscLength + 1); // In octets - - // Device identities: 4 bytes - // Address: 0 or (2 + smscLength) - // SMS TPDU: (2 or 3) + tpduLength - let berLen = 4 + - (smscLength ? (2 + smscLength) : 0) + - (tpduLength <= 127 ? 2 : 3) + tpduLength; // In octets - - let parcelLength = (berLen <= 127 ? 2 : 3) + berLen; // In octets - Buf.writeInt32(parcelLength * 2); // In semi-octets - - // Write a BER-TLV - GsmPDUHelper.writeHexOctet(BER_SMS_PP_DOWNLOAD_TAG); - if (berLen > 127) { - GsmPDUHelper.writeHexOctet(0x81); - } - GsmPDUHelper.writeHexOctet(berLen); - - // Device Identifies-TLV - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_DEVICE_ID | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(0x02); - GsmPDUHelper.writeHexOctet(STK_DEVICE_ID_NETWORK); - GsmPDUHelper.writeHexOctet(STK_DEVICE_ID_SIM); - - // Address-TLV - if (smscLength) { - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_ADDRESS); - GsmPDUHelper.writeHexOctet(smscLength); - Buf.copyIncomingToOutgoing(Buf.PDU_HEX_OCTET_SIZE * smscLength); - } - - // SMS TPDU-TLV - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_SMS_TPDU | - COMPREHENSIONTLV_FLAG_CR); - if (tpduLength > 127) { - GsmPDUHelper.writeHexOctet(0x81); - } - GsmPDUHelper.writeHexOctet(tpduLength); - Buf.copyIncomingToOutgoing(Buf.PDU_HEX_OCTET_SIZE * tpduLength); - - // Write 2 string delimitors for the total string length must be even. - Buf.writeStringDelimiter(0); - - Buf.sendParcel(); - }, - - /** - * @param success A boolean value indicating the result of previous - * SMS-DELIVER message handling. - * @param responsePduLen ICC IO response PDU length in octets. - * @param options An object that contains four attributes: `pid`, `dcs`, - * `encoding` and `responsePduLen`. - * - * @see 3GPP TS 23.040 section 9.2.2.1a - */ - acknowledgeIncomingGsmSmsWithPDU: function(success, responsePduLen, options) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - - Buf.newParcel(REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU); - - // Two strings. - Buf.writeInt32(2); - - // String 1: Success - Buf.writeString(success ? "1" : "0"); - - // String 2: RP-ACK/RP-ERROR PDU - Buf.writeInt32(2 * (responsePduLen + (success ? 5 : 6))); // In semi-octet - // 1. TP-MTI & TP-UDHI - GsmPDUHelper.writeHexOctet(PDU_MTI_SMS_DELIVER); - if (!success) { - // 2. TP-FCS - GsmPDUHelper.writeHexOctet(PDU_FCS_USIM_DATA_DOWNLOAD_ERROR); - } - // 3. TP-PI - GsmPDUHelper.writeHexOctet(PDU_PI_USER_DATA_LENGTH | - PDU_PI_DATA_CODING_SCHEME | - PDU_PI_PROTOCOL_IDENTIFIER); - // 4. TP-PID - GsmPDUHelper.writeHexOctet(options.pid); - // 5. TP-DCS - GsmPDUHelper.writeHexOctet(options.dcs); - // 6. TP-UDL - if (options.encoding == PDU_DCS_MSG_CODING_7BITS_ALPHABET) { - GsmPDUHelper.writeHexOctet(Math.floor(responsePduLen * 8 / 7)); - } else { - GsmPDUHelper.writeHexOctet(responsePduLen); - } - // TP-UD - Buf.copyIncomingToOutgoing(Buf.PDU_HEX_OCTET_SIZE * responsePduLen); - // Write 2 string delimitors for the total string length must be even. - Buf.writeStringDelimiter(0); - - Buf.sendParcel(); - }, - - /** - * @param message A decoded SMS-DELIVER message. - */ - writeSmsToSIM: function(message) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - - Buf.newParcel(REQUEST_WRITE_SMS_TO_SIM); - - // Write EFsms Status - Buf.writeInt32(EFSMS_STATUS_FREE); - - Buf.seekIncoming(-1 * (Buf.getCurrentParcelSize() - Buf.getReadAvailable() - - 2 * Buf.UINT32_SIZE)); // Skip response_type & request_type. - let messageStringLength = Buf.readInt32(); // In semi-octets - let smscLength = GsmPDUHelper.readHexOctet(); // In octets, inclusive of TOA - let pduLength = (messageStringLength / 2) - (smscLength + 1); // In octets - - // 1. Write PDU first. - if (smscLength > 0) { - Buf.seekIncoming(smscLength * Buf.PDU_HEX_OCTET_SIZE); - } - // Write EFsms PDU string length - Buf.writeInt32(2 * pduLength); // In semi-octets - if (pduLength) { - Buf.copyIncomingToOutgoing(Buf.PDU_HEX_OCTET_SIZE * pduLength); - } - // Write 2 string delimitors for the total string length must be even. - Buf.writeStringDelimiter(0); - - // 2. Write SMSC - // Write EFsms SMSC string length - Buf.writeInt32(2 * (smscLength + 1)); // Plus smscLength itself, in semi-octets - // Write smscLength - GsmPDUHelper.writeHexOctet(smscLength); - // Write TOA & SMSC Address - if (smscLength) { - Buf.seekIncoming(-1 * (Buf.getCurrentParcelSize() - Buf.getReadAvailable() - - 2 * Buf.UINT32_SIZE // Skip response_type, request_type. - - 2 * Buf.PDU_HEX_OCTET_SIZE)); // Skip messageStringLength & smscLength. - Buf.copyIncomingToOutgoing(Buf.PDU_HEX_OCTET_SIZE * smscLength); - } - // Write 2 string delimitors for the total string length must be even. - Buf.writeStringDelimiter(0); - - Buf.sendParcel(); - }, - - /** - * Helper to delegate the received sms segment to RadioInterface to process. - * - * @param message - * Received sms message. - * - * @return MOZ_FCS_WAIT_FOR_EXPLICIT_ACK - */ - _processSmsMultipart: function(message) { - message.rilMessageType = "sms-received"; - - this.sendChromeMessage(message); - - return MOZ_FCS_WAIT_FOR_EXPLICIT_ACK; - }, - - /** - * Helper for processing SMS-STATUS-REPORT PDUs. - * - * @param length - * Length of SMS string in the incoming parcel. - * - * @return A failure cause defined in 3GPP 23.040 clause 9.2.3.22. - */ - _processSmsStatusReport: function(length) { - let [message, result] = this.context.GsmPDUHelper.processReceivedSms(length); - if (!message) { - if (DEBUG) this.context.debug("invalid SMS-STATUS-REPORT"); - return PDU_FCS_UNSPECIFIED; - } - - let options = this._pendingSentSmsMap[message.messageRef]; - if (!options) { - if (DEBUG) this.context.debug("no pending SMS-SUBMIT message"); - return PDU_FCS_OK; - } - - let status = message.status; - - // 3GPP TS 23.040 9.2.3.15 `The MS shall interpret any reserved values as - // "Service Rejected"(01100011) but shall store them exactly as received.` - if ((status >= 0x80) - || ((status >= PDU_ST_0_RESERVED_BEGIN) - && (status < PDU_ST_0_SC_SPECIFIC_BEGIN)) - || ((status >= PDU_ST_1_RESERVED_BEGIN) - && (status < PDU_ST_1_SC_SPECIFIC_BEGIN)) - || ((status >= PDU_ST_2_RESERVED_BEGIN) - && (status < PDU_ST_2_SC_SPECIFIC_BEGIN)) - || ((status >= PDU_ST_3_RESERVED_BEGIN) - && (status < PDU_ST_3_SC_SPECIFIC_BEGIN)) - ) { - status = PDU_ST_3_SERVICE_REJECTED; - } - - // Pending. Waiting for next status report. - if ((status >>> 5) == 0x01) { - if (DEBUG) this.context.debug("SMS-STATUS-REPORT: delivery still pending"); - return PDU_FCS_OK; - } - - delete this._pendingSentSmsMap[message.messageRef]; - - let deliveryStatus = ((status >>> 5) === 0x00) - ? GECKO_SMS_DELIVERY_STATUS_SUCCESS - : GECKO_SMS_DELIVERY_STATUS_ERROR; - this.sendChromeMessage({ - rilMessageType: options.rilMessageType, - rilMessageToken: options.rilMessageToken, - deliveryStatus: deliveryStatus - }); - - return PDU_FCS_OK; - }, - - /** - * Helper for processing CDMA SMS Delivery Acknowledgment Message - * - * @param message - * decoded SMS Delivery ACK message from CdmaPDUHelper. - * - * @return A failure cause defined in 3GPP 23.040 clause 9.2.3.22. - */ - _processCdmaSmsStatusReport: function(message) { - let options = this._pendingSentSmsMap[message.msgId]; - if (!options) { - if (DEBUG) this.context.debug("no pending SMS-SUBMIT message"); - return PDU_FCS_OK; - } - - if (message.errorClass === 2) { - if (DEBUG) { - this.context.debug("SMS-STATUS-REPORT: delivery still pending, " + - "msgStatus: " + message.msgStatus); - } - return PDU_FCS_OK; - } - - delete this._pendingSentSmsMap[message.msgId]; - - if (message.errorClass === -1 && message.body) { - // Process as normal incoming SMS, if errorClass is invalid - // but message body is available. - return this._processSmsMultipart(message); - } - - let deliveryStatus = (message.errorClass === 0) - ? GECKO_SMS_DELIVERY_STATUS_SUCCESS - : GECKO_SMS_DELIVERY_STATUS_ERROR; - this.sendChromeMessage({ - rilMessageType: options.rilMessageType, - rilMessageToken: options.rilMessageToken, - deliveryStatus: deliveryStatus - }); - - return PDU_FCS_OK; - }, - - /** - * Helper for processing CDMA SMS WAP Push Message - * - * @param message - * decoded WAP message from CdmaPDUHelper. - * - * @return A failure cause defined in 3GPP 23.040 clause 9.2.3.22. - */ - _processCdmaSmsWapPush: function(message) { - if (!message.data) { - if (DEBUG) this.context.debug("no data inside WAP Push message."); - return PDU_FCS_OK; - } - - // See 6.5. MAPPING OF WDP TO CDMA SMS in WAP-295-WDP. - // - // Field | Length (bits) - // ----------------------------------------- - // MSG_TYPE | 8 - // TOTAL_SEGMENTS | 8 - // SEGMENT_NUMBER | 8 - // DATAGRAM | (NUM_FIELDS - 3) * 8 - let index = 0; - if (message.data[index++] !== 0) { - if (DEBUG) this.context.debug("Ignore a WAP Message which is not WDP."); - return PDU_FCS_OK; - } - - // 1. Originator Address in SMS-TL + Message_Id in SMS-TS are used to identify a unique WDP datagram. - // 2. TOTAL_SEGMENTS, SEGMENT_NUMBER are used to verify that a complete - // datagram has been received and is ready to be passed to a higher layer. - message.header = { - segmentRef: message.msgId, - segmentMaxSeq: message.data[index++], - segmentSeq: message.data[index++] + 1 // It's zero-based in CDMA WAP Push. - }; - - if (message.header.segmentSeq > message.header.segmentMaxSeq) { - if (DEBUG) this.context.debug("Wrong WDP segment info."); - return PDU_FCS_OK; - } - - // Ports are only specified in 1st segment. - if (message.header.segmentSeq == 1) { - message.header.originatorPort = message.data[index++] << 8; - message.header.originatorPort |= message.data[index++]; - message.header.destinationPort = message.data[index++] << 8; - message.header.destinationPort |= message.data[index++]; - } - - message.data = message.data.subarray(index); - - return this._processSmsMultipart(message); - }, - - /** - * Helper for processing sent multipart SMS. - */ - _processSentSmsSegment: function(options) { - // Setup attributes for sending next segment - let next = options.segmentSeq; - options.body = options.segments[next].body; - options.encodedBodyLength = options.segments[next].encodedBodyLength; - options.segmentSeq = next + 1; - - this.sendSMS(options); - }, - - /** - * Helper for processing result of send SMS. - * - * @param length - * Length of SMS string in the incoming parcel. - * @param options - * Sms information. - */ - _processSmsSendResult: function(length, options) { - if (options.errorMsg) { - if (DEBUG) { - this.context.debug("_processSmsSendResult: errorMsg = " + - options.errorMsg); - } - - this.sendChromeMessage({ - rilMessageType: options.rilMessageType, - rilMessageToken: options.rilMessageToken, - errorMsg: options.errorMsg, - }); - return; - } - - let Buf = this.context.Buf; - options.messageRef = Buf.readInt32(); - options.ackPDU = Buf.readString(); - options.errorCode = Buf.readInt32(); - - if ((options.segmentMaxSeq > 1) - && (options.segmentSeq < options.segmentMaxSeq)) { - // Not last segment - this._processSentSmsSegment(options); - } else { - // Last segment sent with success. - if (options.requestStatusReport) { - if (DEBUG) { - this.context.debug("waiting SMS-STATUS-REPORT for messageRef " + - options.messageRef); - } - this._pendingSentSmsMap[options.messageRef] = options; - } - - this.sendChromeMessage({ - rilMessageType: options.rilMessageType, - rilMessageToken: options.rilMessageToken, - }); - } - }, - - _processReceivedSmsCbPage: function(original) { - if (original.numPages <= 1) { - if (original.body) { - original.fullBody = original.body; - delete original.body; - } else if (original.data) { - original.fullData = original.data; - delete original.data; - } - return original; - } - - // Hash = <serial>:<mcc>:<mnc>:<lac>:<cid> - let hash = original.serial + ":" + this.iccInfo.mcc + ":" - + this.iccInfo.mnc + ":"; - switch (original.geographicalScope) { - case CB_GSM_GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE: - case CB_GSM_GEOGRAPHICAL_SCOPE_CELL_WIDE: - hash += this.voiceRegistrationState.cell.gsmLocationAreaCode + ":" - + this.voiceRegistrationState.cell.gsmCellId; - break; - case CB_GSM_GEOGRAPHICAL_SCOPE_LOCATION_AREA_WIDE: - hash += this.voiceRegistrationState.cell.gsmLocationAreaCode + ":"; - break; - default: - hash += ":"; - break; - } - - let index = original.pageIndex; - - let options = this._receivedSmsCbPagesMap[hash]; - if (!options) { - options = original; - this._receivedSmsCbPagesMap[hash] = options; - - options.receivedPages = 0; - options.pages = []; - } else if (options.pages[index]) { - // Duplicated page? - if (DEBUG) { - this.context.debug("Got duplicated page no." + index + - " of a multipage SMSCB: " + JSON.stringify(original)); - } - return null; - } - - if (options.encoding == PDU_DCS_MSG_CODING_8BITS_ALPHABET) { - options.pages[index] = original.data; - delete original.data; - } else { - options.pages[index] = original.body; - delete original.body; - } - options.receivedPages++; - if (options.receivedPages < options.numPages) { - if (DEBUG) { - this.context.debug("Got page no." + index + " of a multipage SMSCB: " + - JSON.stringify(options)); - } - return null; - } - - // Remove from map - delete this._receivedSmsCbPagesMap[hash]; - - // Rebuild full body - if (options.encoding == PDU_DCS_MSG_CODING_8BITS_ALPHABET) { - // Uint8Array doesn't have `concat`, so we have to merge all pages by hand. - let fullDataLen = 0; - for (let i = 1; i <= options.numPages; i++) { - fullDataLen += options.pages[i].length; - } - - options.fullData = new Uint8Array(fullDataLen); - for (let d= 0, i = 1; i <= options.numPages; i++) { - let data = options.pages[i]; - for (let j = 0; j < data.length; j++) { - options.fullData[d++] = data[j]; - } - } - } else { - options.fullBody = options.pages.join(""); - } - - if (DEBUG) { - this.context.debug("Got full multipage SMSCB: " + JSON.stringify(options)); - } - - return options; - }, - - _mergeCellBroadcastConfigs: function(list, from, to) { - if (!list) { - return [from, to]; - } - - for (let i = 0, f1, t1; i < list.length;) { - f1 = list[i++]; - t1 = list[i++]; - if (to == f1) { - // ...[from]...[to|f1]...(t1) - list[i - 2] = from; - return list; - } - - if (to < f1) { - // ...[from]...(to)...[f1] or ...[from]...(to)[f1] - if (i > 2) { - // Not the first range pair, merge three arrays. - return list.slice(0, i - 2).concat([from, to]).concat(list.slice(i - 2)); - } else { - return [from, to].concat(list); - } - } - - if (from > t1) { - // ...[f1]...(t1)[from] or ...[f1]...(t1)...[from] - continue; - } - - // Have overlap or merge-able adjacency with [f1]...(t1). Replace it - // with [min(from, f1)]...(max(to, t1)). - - let changed = false; - if (from < f1) { - // [from]...[f1]...(t1) or [from][f1]...(t1) - // Save minimum from value. - list[i - 2] = from; - changed = true; - } - - if (to <= t1) { - // [from]...[to](t1) or [from]...(to|t1) - // Can't have further merge-able adjacency. Return. - return list; - } - - // Try merging possible next adjacent range. - let j = i; - for (let f2, t2; j < list.length;) { - f2 = list[j++]; - t2 = list[j++]; - if (to > t2) { - // [from]...[f2]...[t2]...(to) or [from]...[f2]...[t2](to) - // Merge next adjacent range again. - continue; - } - - if (to < t2) { - if (to < f2) { - // [from]...(to)[f2] or [from]...(to)...[f2] - // Roll back and give up. - j -= 2; - } else if (to < t2) { - // [from]...[to|f2]...(t2), or [from]...[f2]...[to](t2) - // Merge to [from]...(t2) and give up. - to = t2; - } - } - - break; - } - - // Save maximum to value. - list[i - 1] = to; - - if (j != i) { - // Remove merged adjacent ranges. - let ret = list.slice(0, i); - if (j < list.length) { - ret = ret.concat(list.slice(j)); - } - return ret; - } - - return list; - } - - // Append to the end. - list.push(from); - list.push(to); - - return list; - }, - - _isCellBroadcastConfigReady: function() { - if (!("MMI" in this.cellBroadcastConfigs)) { - return false; - } - - // CBMI should be ready in GSM. - if (!this._isCdma && - (!("CBMI" in this.cellBroadcastConfigs) || - !("CBMID" in this.cellBroadcastConfigs) || - !("CBMIR" in this.cellBroadcastConfigs))) { - return false; - } - - return true; - }, - - /** - * Merge all members of cellBroadcastConfigs into mergedCellBroadcastConfig. - */ - _mergeAllCellBroadcastConfigs: function() { - if (!this._isCellBroadcastConfigReady()) { - if (DEBUG) { - this.context.debug("cell broadcast configs not ready, waiting ..."); - } - return; - } - - // Prepare cell broadcast config. CBMI* are only used in GSM. - let usedCellBroadcastConfigs = {MMI: this.cellBroadcastConfigs.MMI}; - if (!this._isCdma) { - usedCellBroadcastConfigs.CBMI = this.cellBroadcastConfigs.CBMI; - usedCellBroadcastConfigs.CBMID = this.cellBroadcastConfigs.CBMID; - usedCellBroadcastConfigs.CBMIR = this.cellBroadcastConfigs.CBMIR; - } - - if (DEBUG) { - this.context.debug("Cell Broadcast search lists: " + - JSON.stringify(usedCellBroadcastConfigs)); - } - - let list = null; - for (let key in usedCellBroadcastConfigs) { - let ll = usedCellBroadcastConfigs[key]; - if (ll == null) { - continue; - } - - for (let i = 0; i < ll.length; i += 2) { - list = this._mergeCellBroadcastConfigs(list, ll[i], ll[i + 1]); - } - } - - if (DEBUG) { - this.context.debug("Cell Broadcast search lists(merged): " + - JSON.stringify(list)); - } - this.mergedCellBroadcastConfig = list; - this.updateCellBroadcastConfig(); - }, - - /** - * Check whether search list from settings is settable by MMI, that is, - * whether the range is bounded in any entries of CB_NON_MMI_SETTABLE_RANGES. - */ - _checkCellBroadcastMMISettable: function(from, to) { - if ((to <= from) || (from >= 65536) || (from < 0)) { - return false; - } - - if (!this._isCdma) { - // GSM not settable ranges. - for (let i = 0, f, t; i < CB_NON_MMI_SETTABLE_RANGES.length;) { - f = CB_NON_MMI_SETTABLE_RANGES[i++]; - t = CB_NON_MMI_SETTABLE_RANGES[i++]; - if ((from < t) && (to > f)) { - // Have overlap. - return false; - } - } - } - - return true; - }, - - /** - * Convert Cell Broadcast settings string into search list. - */ - _convertCellBroadcastSearchList: function(searchListStr) { - let parts = searchListStr && searchListStr.split(","); - if (!parts) { - return null; - } - - let list = null; - let result, from, to; - for (let range of parts) { - // Match "12" or "12-34". The result will be ["12", "12", null] or - // ["12-34", "12", "34"]. - result = range.match(/^(\d+)(?:-(\d+))?$/); - if (!result) { - throw "Invalid format"; - } - - from = parseInt(result[1], 10); - to = (result[2]) ? parseInt(result[2], 10) + 1 : from + 1; - if (!this._checkCellBroadcastMMISettable(from, to)) { - throw "Invalid range"; - } - - if (list == null) { - list = []; - } - list.push(from); - list.push(to); - } - - return list; - }, - - /** - * Handle incoming messages from the main UI thread. - * - * @param message - * Object containing the message. Messages are supposed - */ - handleChromeMessage: function(message) { - if (DEBUG) { - this.context.debug("Received chrome message " + JSON.stringify(message)); - } - let method = this[message.rilMessageType]; - if (typeof method != "function") { - if (DEBUG) { - this.context.debug("Don't know what to do with message " + - JSON.stringify(message)); - } - return; - } - method.call(this, message); - }, - - /** - * Process STK Proactive Command. - */ - processStkProactiveCommand: function() { - let Buf = this.context.Buf; - let length = Buf.readInt32(); - let berTlv; - try { - berTlv = this.context.BerTlvHelper.decode(length / 2); - } catch (e) { - if (DEBUG) this.context.debug("processStkProactiveCommand : " + e); - this.sendStkTerminalResponse({ - resultCode: STK_RESULT_CMD_DATA_NOT_UNDERSTOOD}); - return; - } - - Buf.readStringDelimiter(length); - - let ctlvs = berTlv.value; - let ctlv = this.context.StkProactiveCmdHelper.searchForTag( - COMPREHENSIONTLV_TAG_COMMAND_DETAILS, ctlvs); - if (!ctlv) { - this.sendStkTerminalResponse({ - resultCode: STK_RESULT_CMD_DATA_NOT_UNDERSTOOD}); - throw new Error("Can't find COMMAND_DETAILS ComprehensionTlv"); - } - - let cmdDetails = ctlv.value; - if (DEBUG) { - this.context.debug("commandNumber = " + cmdDetails.commandNumber + - " typeOfCommand = " + cmdDetails.typeOfCommand.toString(16) + - " commandQualifier = " + cmdDetails.commandQualifier); - } - - // STK_CMD_MORE_TIME need not to propagate event to chrome. - if (cmdDetails.typeOfCommand == STK_CMD_MORE_TIME) { - this.sendStkTerminalResponse({ - command: cmdDetails, - resultCode: STK_RESULT_OK}); - return; - } - - this.context.StkCommandParamsFactory.createParam(cmdDetails, - ctlvs, - (aResult) => { - cmdDetails.options = aResult; - cmdDetails.rilMessageType = "stkcommand"; - this.sendChromeMessage(cmdDetails); - }); - }, - - sendDefaultResponse: function(options) { - if (!options.rilMessageType) { - return; - } - - this.sendChromeMessage(options); - }, - - /** - * Send messages to the main thread. - */ - sendChromeMessage: function(message) { - message.rilMessageClientId = this.context.clientId; - postMessage(message); - }, - - /** - * Handle incoming requests from the RIL. We find the method that - * corresponds to the request type. Incidentally, the request type - * _is_ the method name, so that's easy. - */ - - handleParcel: function(request_type, length, options) { - let method = this[request_type]; - if (typeof method == "function") { - if (DEBUG) this.context.debug("Handling parcel as " + method.name); - method.call(this, length, options); - } - - if (this.telephonyRequestQueue.isValidRequest(request_type)) { - this.telephonyRequestQueue.pop(request_type); - } - } -}; - -RilObject.prototype[REQUEST_GET_SIM_STATUS] = function REQUEST_GET_SIM_STATUS(length, options) { - if (options.errorMsg) { - return; - } - - let iccStatus = {}; - let Buf = this.context.Buf; - iccStatus.cardState = Buf.readInt32(); // CARD_STATE_* - iccStatus.universalPINState = Buf.readInt32(); // CARD_PINSTATE_* - iccStatus.gsmUmtsSubscriptionAppIndex = Buf.readInt32(); - iccStatus.cdmaSubscriptionAppIndex = Buf.readInt32(); - iccStatus.imsSubscriptionAppIndex = Buf.readInt32(); - - let apps_length = Buf.readInt32(); - if (apps_length > CARD_MAX_APPS) { - apps_length = CARD_MAX_APPS; - } - - iccStatus.apps = []; - for (let i = 0 ; i < apps_length ; i++) { - iccStatus.apps.push({ - app_type: Buf.readInt32(), // CARD_APPTYPE_* - app_state: Buf.readInt32(), // CARD_APPSTATE_* - perso_substate: Buf.readInt32(), // CARD_PERSOSUBSTATE_* - aid: Buf.readString(), - app_label: Buf.readString(), - pin1_replaced: Buf.readInt32(), - pin1: Buf.readInt32(), - pin2: Buf.readInt32() - }); - if (RILQUIRKS_SIM_APP_STATE_EXTRA_FIELDS) { - Buf.readInt32(); - Buf.readInt32(); - Buf.readInt32(); - Buf.readInt32(); - } - } - - if (DEBUG) this.context.debug("iccStatus: " + JSON.stringify(iccStatus)); - this._processICCStatus(iccStatus); -}; -RilObject.prototype[REQUEST_ENTER_SIM_PIN] = function REQUEST_ENTER_SIM_PIN(length, options) { - this._processEnterAndChangeICCResponses(length, options); -}; -RilObject.prototype[REQUEST_ENTER_SIM_PUK] = function REQUEST_ENTER_SIM_PUK(length, options) { - this._processEnterAndChangeICCResponses(length, options); -}; -RilObject.prototype[REQUEST_ENTER_SIM_PIN2] = function REQUEST_ENTER_SIM_PIN2(length, options) { - this._processEnterAndChangeICCResponses(length, options); -}; -RilObject.prototype[REQUEST_ENTER_SIM_PUK2] = function REQUEST_ENTER_SIM_PUK(length, options) { - this._processEnterAndChangeICCResponses(length, options); -}; -RilObject.prototype[REQUEST_CHANGE_SIM_PIN] = function REQUEST_CHANGE_SIM_PIN(length, options) { - this._processEnterAndChangeICCResponses(length, options); -}; -RilObject.prototype[REQUEST_CHANGE_SIM_PIN2] = function REQUEST_CHANGE_SIM_PIN2(length, options) { - this._processEnterAndChangeICCResponses(length, options); -}; -RilObject.prototype[REQUEST_ENTER_NETWORK_DEPERSONALIZATION_CODE] = - function REQUEST_ENTER_NETWORK_DEPERSONALIZATION_CODE(length, options) { - this._processEnterAndChangeICCResponses(length, options); -}; -RilObject.prototype[REQUEST_GET_CURRENT_CALLS] = function REQUEST_GET_CURRENT_CALLS(length, options) { - // Retry getCurrentCalls several times when error occurs. - if (options.errorMsg) { - if (this._getCurrentCallsRetryCount < GET_CURRENT_CALLS_RETRY_MAX) { - this._getCurrentCallsRetryCount++; - this.getCurrentCalls(options); - } else { - this.sendDefaultResponse(options); - } - return; - } - - this._getCurrentCallsRetryCount = 0; - - let Buf = this.context.Buf; - let calls_length = 0; - // The RIL won't even send us the length integer if there are no active calls. - // So only read this integer if the parcel actually has it. - if (length) { - calls_length = Buf.readInt32(); - } - - let calls = {}; - for (let i = 0; i < calls_length; i++) { - let call = {}; - - // Extra uint32 field to get correct callIndex and rest of call data for - // call waiting feature. - if (RILQUIRKS_EXTRA_UINT32_2ND_CALL && i > 0) { - Buf.readInt32(); - } - - call.state = Buf.readInt32(); // CALL_STATE_* - call.callIndex = Buf.readInt32(); // GSM index (1-based) - call.toa = Buf.readInt32(); - call.isMpty = Boolean(Buf.readInt32()); - call.isMT = Boolean(Buf.readInt32()); - call.als = Buf.readInt32(); - call.isVoice = Boolean(Buf.readInt32()); - call.isVoicePrivacy = Boolean(Buf.readInt32()); - if (RILQUIRKS_CALLSTATE_EXTRA_UINT32) { - Buf.readInt32(); - } - call.number = Buf.readString(); - call.numberPresentation = Buf.readInt32(); // CALL_PRESENTATION_* - call.name = Buf.readString(); - call.namePresentation = Buf.readInt32(); - - call.uusInfo = null; - let uusInfoPresent = Buf.readInt32(); - if (uusInfoPresent == 1) { - call.uusInfo = { - type: Buf.readInt32(), - dcs: Buf.readInt32(), - userData: null //XXX TODO byte array?!? - }; - } - - if (call.isVoice) { - calls[call.callIndex] = call; - } - } - - options.calls = calls; - options.rilMessageType = options.rilMessageType || "currentCalls"; - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_DIAL] = function REQUEST_DIAL(length, options) { - this.sendDefaultResponse(options); -}; -RilObject.prototype[REQUEST_DIAL_EMERGENCY_CALL] = function REQUEST_DIAL_EMERGENCY_CALL(length, options) { - RilObject.prototype[REQUEST_DIAL].call(this, length, options); -}; -RilObject.prototype[REQUEST_GET_IMSI] = function REQUEST_GET_IMSI(length, options) { - if (options.errorMsg) { - return; - } - - this.iccInfoPrivate.imsi = this.context.Buf.readString(); - if (DEBUG) { - this.context.debug("IMSI: " + this.iccInfoPrivate.imsi); - } - - options.rilMessageType = "iccimsi"; - options.imsi = this.iccInfoPrivate.imsi; - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_HANGUP] = function REQUEST_HANGUP(length, options) { - this.sendDefaultResponse(options); -}; -RilObject.prototype[REQUEST_HANGUP_WAITING_OR_BACKGROUND] = function REQUEST_HANGUP_WAITING_OR_BACKGROUND(length, options) { - this.sendDefaultResponse(options); -}; -RilObject.prototype[REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND] = function REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND(length, options) { - this.sendDefaultResponse(options); -}; -RilObject.prototype[REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE] = function REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE(length, options) { - this.sendDefaultResponse(options); -}; -RilObject.prototype[REQUEST_CONFERENCE] = function REQUEST_CONFERENCE(length, options) { - this.sendDefaultResponse(options); -}; -RilObject.prototype[REQUEST_UDUB] = function REQUEST_UDUB(length, options) { - this.sendDefaultResponse(options); -}; -RilObject.prototype[REQUEST_LAST_CALL_FAIL_CAUSE] = function REQUEST_LAST_CALL_FAIL_CAUSE(length, options) { - // Treat it as CALL_FAIL_ERROR_UNSPECIFIED if the request failed. - let failCause = CALL_FAIL_ERROR_UNSPECIFIED; - - if (!options.errorMsg) { - let Buf = this.context.Buf; - let num = length ? Buf.readInt32() : 0; - - if (num) { - let causeNum = Buf.readInt32(); - failCause = RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[causeNum] || failCause; - } - if (DEBUG) this.context.debug("Last call fail cause: " + failCause); - } - - options.failCause = failCause; - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_SIGNAL_STRENGTH] = function REQUEST_SIGNAL_STRENGTH(length, options) { - this._receivedNetworkInfo(NETWORK_INFO_SIGNAL); - - if (options.errorMsg) { - return; - } - - let Buf = this.context.Buf; - let signal = {}; - - signal.gsmSignalStrength = Buf.readInt32(); - signal.gsmBitErrorRate = Buf.readInt32(); - if (RILQUIRKS_SIGNAL_EXTRA_INT32) { - Buf.readInt32(); - } - signal.cdmaDBM = Buf.readInt32(); - signal.cdmaECIO = Buf.readInt32(); - signal.evdoDBM = Buf.readInt32(); - signal.evdoECIO = Buf.readInt32(); - signal.evdoSNR = Buf.readInt32(); - - signal.lteSignalStrength = Buf.readInt32(); - signal.lteRSRP = Buf.readInt32(); - signal.lteRSRQ = Buf.readInt32(); - signal.lteRSSNR = Buf.readInt32(); - signal.lteCQI = Buf.readInt32(); - - if (DEBUG) this.context.debug("signal strength: " + JSON.stringify(signal)); - - this._processSignalStrength(signal); -}; -RilObject.prototype[REQUEST_VOICE_REGISTRATION_STATE] = function REQUEST_VOICE_REGISTRATION_STATE(length, options) { - this._receivedNetworkInfo(NETWORK_INFO_VOICE_REGISTRATION_STATE); - - if (options.errorMsg) { - return; - } - - let state = this.context.Buf.readStringList(); - if (DEBUG) this.context.debug("voice registration state: " + state); - - this._processVoiceRegistrationState(state); -}; -RilObject.prototype[REQUEST_DATA_REGISTRATION_STATE] = function REQUEST_DATA_REGISTRATION_STATE(length, options) { - this._receivedNetworkInfo(NETWORK_INFO_DATA_REGISTRATION_STATE); - - if (options.errorMsg) { - return; - } - - let state = this.context.Buf.readStringList(); - this._processDataRegistrationState(state); -}; -RilObject.prototype[REQUEST_OPERATOR] = function REQUEST_OPERATOR(length, options) { - this._receivedNetworkInfo(NETWORK_INFO_OPERATOR); - - if (options.errorMsg) { - return; - } - - let operatorData = this.context.Buf.readStringList(); - if (DEBUG) this.context.debug("Operator: " + operatorData); - this._processOperator(operatorData); -}; -RilObject.prototype[REQUEST_RADIO_POWER] = function REQUEST_RADIO_POWER(length, options) { - this.sendDefaultResponse(options); -}; -RilObject.prototype[REQUEST_DTMF] = null; -RilObject.prototype[REQUEST_SEND_SMS] = function REQUEST_SEND_SMS(length, options) { - this._processSmsSendResult(length, options); -}; -RilObject.prototype[REQUEST_SEND_SMS_EXPECT_MORE] = null; - -RilObject.prototype[REQUEST_SETUP_DATA_CALL] = function REQUEST_SETUP_DATA_CALL(length, options) { - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - let Buf = this.context.Buf; - let version = Buf.readInt32(); - // Skip number of data calls. - Buf.readInt32(); - - this.readDataCall(options, version); - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_SIM_IO] = function REQUEST_SIM_IO(length, options) { - if (options.errorMsg) { - if (options.onerror) { - options.onerror(options.errorMsg); - } - return; - } - - let Buf = this.context.Buf; - options.sw1 = Buf.readInt32(); - options.sw2 = Buf.readInt32(); - - // See 3GPP TS 11.11, clause 9.4.1 for operation success results. - if (options.sw1 !== ICC_STATUS_NORMAL_ENDING && - options.sw1 !== ICC_STATUS_NORMAL_ENDING_WITH_EXTRA && - options.sw1 !== ICC_STATUS_WITH_SIM_DATA && - options.sw1 !== ICC_STATUS_WITH_RESPONSE_DATA) { - if (DEBUG) { - this.context.debug("ICC I/O Error EF id = 0x" + options.fileId.toString(16) + - ", command = 0x" + options.command.toString(16) + - ", sw1 = 0x" + options.sw1.toString(16) + - ", sw2 = 0x" + options.sw2.toString(16)); - } - if (options.onerror) { - // We can get fail cause from sw1/sw2 (See TS 11.11 clause 9.4.1 and - // ISO 7816-4 clause 6). But currently no one needs this information, - // so simply reports "GenericFailure" for now. - options.onerror(GECKO_ERROR_GENERIC_FAILURE); - } - return; - } - this.context.ICCIOHelper.processICCIO(options); -}; -RilObject.prototype[REQUEST_SEND_USSD] = function REQUEST_SEND_USSD(length, options) { - if (DEBUG) { - this.context.debug("REQUEST_SEND_USSD " + JSON.stringify(options)); - } - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_CANCEL_USSD] = function REQUEST_CANCEL_USSD(length, options) { - if (DEBUG) { - this.context.debug("REQUEST_CANCEL_USSD" + JSON.stringify(options)); - } - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_GET_CLIR] = function REQUEST_GET_CLIR(length, options) { - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - let Buf = this.context.Buf; - let bufLength = Buf.readInt32(); - if (!bufLength || bufLength < 2) { - options.errorMsg = GECKO_ERROR_GENERIC_FAILURE; - this.sendChromeMessage(options); - return; - } - - options.n = Buf.readInt32(); // Will be TS 27.007 +CLIR parameter 'n'. - options.m = Buf.readInt32(); // Will be TS 27.007 +CLIR parameter 'm'. - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_SET_CLIR] = function REQUEST_SET_CLIR(length, options) { - if (options.rilMessageType == null) { - // The request was made by ril_worker itself automatically. Don't report. - return; - } - - this.sendChromeMessage(options); -}; - -RilObject.prototype[REQUEST_QUERY_CALL_FORWARD_STATUS] = - function REQUEST_QUERY_CALL_FORWARD_STATUS(length, options) { - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - let Buf = this.context.Buf; - let rulesLength = 0; - if (length) { - rulesLength = Buf.readInt32(); - } - if (!rulesLength) { - options.errorMsg = GECKO_ERROR_GENERIC_FAILURE; - this.sendChromeMessage(options); - return; - } - let rules = new Array(rulesLength); - for (let i = 0; i < rulesLength; i++) { - let rule = {}; - rule.active = Buf.readInt32() == 1; // CALL_FORWARD_STATUS_* - rule.reason = Buf.readInt32(); // CALL_FORWARD_REASON_* - rule.serviceClass = Buf.readInt32(); - rule.toa = Buf.readInt32(); - rule.number = Buf.readString(); - rule.timeSeconds = Buf.readInt32(); - rules[i] = rule; - } - options.rules = rules; - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_SET_CALL_FORWARD] = - function REQUEST_SET_CALL_FORWARD(length, options) { - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_QUERY_CALL_WAITING] = - function REQUEST_QUERY_CALL_WAITING(length, options) { - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - let Buf = this.context.Buf; - let results = Buf.readInt32List(); - let enabled = (results[0] === 1); - options.serviceClass = enabled ? results[1] : ICC_SERVICE_CLASS_NONE; - this.sendChromeMessage(options); -}; - -RilObject.prototype[REQUEST_SET_CALL_WAITING] = function REQUEST_SET_CALL_WAITING(length, options) { - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_SMS_ACKNOWLEDGE] = null; -RilObject.prototype[REQUEST_GET_IMEI] = null; -RilObject.prototype[REQUEST_GET_IMEISV] = null; -RilObject.prototype[REQUEST_ANSWER] = function REQUEST_ANSWER(length, options) { - this.sendDefaultResponse(options); -}; -RilObject.prototype[REQUEST_DEACTIVATE_DATA_CALL] = function REQUEST_DEACTIVATE_DATA_CALL(length, options) { - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_QUERY_FACILITY_LOCK] = function REQUEST_QUERY_FACILITY_LOCK(length, options) { - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - if (!length) { - options.errorMsg = GECKO_ERROR_GENERIC_FAILURE; - this.sendChromeMessage(options); - return; - } - - // Buf.readInt32List()[0] for Call Barring is a bit vector of services. - options.serviceClass = this.context.Buf.readInt32List()[0]; - if (options.queryServiceClass) { - options.enabled = (options.serviceClass & options.queryServiceClass) ? true : false; - options.serviceClass = options.queryServiceClass; - } else { - options.enabled = options.serviceClass ? true : false; - } - - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_SET_FACILITY_LOCK] = function REQUEST_SET_FACILITY_LOCK(length, options) { - options.retryCount = length ? this.context.Buf.readInt32List()[0] : -1; - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_CHANGE_BARRING_PASSWORD] = - function REQUEST_CHANGE_BARRING_PASSWORD(length, options) { - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_QUERY_NETWORK_SELECTION_MODE] = function REQUEST_QUERY_NETWORK_SELECTION_MODE(length, options) { - this._receivedNetworkInfo(NETWORK_INFO_NETWORK_SELECTION_MODE); - - if (options.errorMsg) { - return; - } - - let mode = this.context.Buf.readInt32List(); - let selectionMode; - - switch (mode[0]) { - case NETWORK_SELECTION_MODE_AUTOMATIC: - selectionMode = GECKO_NETWORK_SELECTION_AUTOMATIC; - break; - case NETWORK_SELECTION_MODE_MANUAL: - selectionMode = GECKO_NETWORK_SELECTION_MANUAL; - break; - default: - selectionMode = GECKO_NETWORK_SELECTION_UNKNOWN; - break; - } - - this._updateNetworkSelectionMode(selectionMode); -}; -RilObject.prototype[REQUEST_SET_NETWORK_SELECTION_AUTOMATIC] = function REQUEST_SET_NETWORK_SELECTION_AUTOMATIC(length, options) { - if (!options.errorMsg) { - this._updateNetworkSelectionMode(GECKO_NETWORK_SELECTION_AUTOMATIC); - } - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_SET_NETWORK_SELECTION_MANUAL] = function REQUEST_SET_NETWORK_SELECTION_MANUAL(length, options) { - if (!options.errorMsg) { - this._updateNetworkSelectionMode(GECKO_NETWORK_SELECTION_MANUAL); - } - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_QUERY_AVAILABLE_NETWORKS] = function REQUEST_QUERY_AVAILABLE_NETWORKS(length, options) { - if (!options.errorMsg) { - options.networks = this._processNetworks(); - } - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_DTMF_START] = function REQUEST_DTMF_START(length, options) { - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_DTMF_STOP] = null; -RilObject.prototype[REQUEST_BASEBAND_VERSION] = function REQUEST_BASEBAND_VERSION(length, options) { - if (options.errorMsg) { - return; - } - - this.basebandVersion = this.context.Buf.readString(); - if (DEBUG) this.context.debug("Baseband version: " + this.basebandVersion); -}; -RilObject.prototype[REQUEST_SEPARATE_CONNECTION] = function REQUEST_SEPARATE_CONNECTION(length, options) { - this.sendDefaultResponse(options); -}; -RilObject.prototype[REQUEST_SET_MUTE] = null; -RilObject.prototype[REQUEST_GET_MUTE] = null; -RilObject.prototype[REQUEST_QUERY_CLIP] = function REQUEST_QUERY_CLIP(length, options) { - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - let Buf = this.context.Buf; - let bufLength = Buf.readInt32(); - if (!bufLength) { - options.errorMsg = GECKO_ERROR_GENERIC_FAILURE; - this.sendChromeMessage(options); - return; - } - - options.provisioned = Buf.readInt32(); - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_LAST_DATA_CALL_FAIL_CAUSE] = null; - -/** - * V6: - * # addresses - A space-delimited list of addresses with optional "/" prefix - * length. - * # dnses - A space-delimited list of DNS server addresses. - * # gateways - A space-delimited list of default gateway addresses. - * - * V10: - * # pcscf - A space-delimited list of Proxy Call State Control Function - * addresses. - */ - -RilObject.prototype.readDataCall = function(options, version) { - if (!options) { - options = {}; - } - let Buf = this.context.Buf; - options.failCause = Buf.readInt32(); // DATACALL_FAIL_* - options.suggestedRetryTime = Buf.readInt32(); - options.cid = Buf.readInt32().toString(); - options.active = Buf.readInt32(); // DATACALL_ACTIVE_* - options.type = Buf.readString(); - options.ifname = Buf.readString(); - options.addresses = Buf.readString(); - options.dnses = Buf.readString(); - options.gateways = Buf.readString(); - - if (version >= 10) { - options.pcscf = Buf.readString(); - } - - if (version >= 11) { - let mtu = Buf.readInt32(); - options.mtu = (mtu > 0) ? mtu : -1 ; - } - - return options; -}; - -RilObject.prototype[REQUEST_DATA_CALL_LIST] = function REQUEST_DATA_CALL_LIST(length, options) { - if (options.errorMsg) { - if (options.rilMessageType) { - this.sendChromeMessage(options); - } - return; - } - - if (!options.rilMessageType) { - // This is an unsolicited data call list changed. - options.rilMessageType = "datacalllistchanged"; - } - - if (!length) { - options.datacalls = []; - this.sendChromeMessage(options); - return; - } - - let Buf = this.context.Buf; - let version = Buf.readInt32(); - let num = Buf.readInt32(); - let datacalls = []; - for (let i = 0; i < num; i++) { - let datacall; - datacall = this.readDataCall({}, version); - datacalls.push(datacall); - } - - options.datacalls = datacalls; - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_RESET_RADIO] = null; -RilObject.prototype[REQUEST_OEM_HOOK_RAW] = null; -RilObject.prototype[REQUEST_OEM_HOOK_STRINGS] = null; -RilObject.prototype[REQUEST_SCREEN_STATE] = null; -RilObject.prototype[REQUEST_SET_SUPP_SVC_NOTIFICATION] = null; -RilObject.prototype[REQUEST_WRITE_SMS_TO_SIM] = function REQUEST_WRITE_SMS_TO_SIM(length, options) { - if (options.errorMsg) { - // `The MS shall return a "protocol error, unspecified" error message if - // the short message cannot be stored in the (U)SIM, and there is other - // message storage available at the MS` ~ 3GPP TS 23.038 section 4. Here - // we assume we always have indexed db as another storage. - this.acknowledgeGsmSms(false, PDU_FCS_PROTOCOL_ERROR); - } else { - this.acknowledgeGsmSms(true, PDU_FCS_OK); - } -}; -RilObject.prototype[REQUEST_DELETE_SMS_ON_SIM] = null; -RilObject.prototype[REQUEST_SET_BAND_MODE] = null; -RilObject.prototype[REQUEST_QUERY_AVAILABLE_BAND_MODE] = null; -RilObject.prototype[REQUEST_STK_GET_PROFILE] = null; -RilObject.prototype[REQUEST_STK_SET_PROFILE] = null; -RilObject.prototype[REQUEST_STK_SEND_ENVELOPE_COMMAND] = null; -RilObject.prototype[REQUEST_STK_SEND_TERMINAL_RESPONSE] = null; -RilObject.prototype[REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM] = null; -RilObject.prototype[REQUEST_EXPLICIT_CALL_TRANSFER] = null; -RilObject.prototype[REQUEST_SET_PREFERRED_NETWORK_TYPE] = function REQUEST_SET_PREFERRED_NETWORK_TYPE(length, options) { - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_GET_PREFERRED_NETWORK_TYPE] = function REQUEST_GET_PREFERRED_NETWORK_TYPE(length, options) { - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - options.type = this.context.Buf.readInt32List()[0]; - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_GET_NEIGHBORING_CELL_IDS] = function REQUEST_GET_NEIGHBORING_CELL_IDS(length, options) { - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - let radioTech = this.voiceRegistrationState.radioTech; - if (radioTech == undefined || radioTech == NETWORK_CREG_TECH_UNKNOWN) { - options.errorMsg = "RadioTechUnavailable"; - this.sendChromeMessage(options); - return; - } - if (!this._isGsmTechGroup(radioTech) || radioTech == NETWORK_CREG_TECH_LTE) { - options.errorMsg = "UnsupportedRadioTech"; - this.sendChromeMessage(options); - return; - } - - let Buf = this.context.Buf; - let neighboringCellIds = []; - let num = Buf.readInt32(); - - for (let i = 0; i < num; i++) { - let cellId = {}; - cellId.networkType = GECKO_RADIO_TECH[radioTech]; - cellId.signalStrength = Buf.readInt32(); - - let cid = Buf.readString(); - // pad cid string with leading "0" - let length = cid.length; - if (length > 8) { - continue; - } - if (length < 8) { - for (let j = 0; j < (8-length); j++) { - cid = "0" + cid; - } - } - - switch (radioTech) { - case NETWORK_CREG_TECH_GPRS: - case NETWORK_CREG_TECH_EDGE: - case NETWORK_CREG_TECH_GSM: - cellId.gsmCellId = this.parseInt(cid.substring(4), -1, 16); - cellId.gsmLocationAreaCode = this.parseInt(cid.substring(0, 4), -1, 16); - break; - case NETWORK_CREG_TECH_UMTS: - case NETWORK_CREG_TECH_HSDPA: - case NETWORK_CREG_TECH_HSUPA: - case NETWORK_CREG_TECH_HSPA: - case NETWORK_CREG_TECH_HSPAP: - case NETWORK_CREG_TECH_DCHSPAP_1: - case NETWORK_CREG_TECH_DCHSPAP_2: - cellId.wcdmaPsc = this.parseInt(cid, -1, 16); - break; - } - - neighboringCellIds.push(cellId); - } - - options.result = neighboringCellIds; - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_GET_CELL_INFO_LIST] = function REQUEST_GET_CELL_INFO_LIST(length, options) { - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - let Buf = this.context.Buf; - let cellInfoList = []; - let num = Buf.readInt32(); - for (let i = 0; i < num; i++) { - let cellInfo = {}; - cellInfo.type = Buf.readInt32(); - cellInfo.registered = Buf.readInt32() ? true : false; - cellInfo.timestampType = Buf.readInt32(); - cellInfo.timestamp = Buf.readInt64(); - - switch(cellInfo.type) { - case CELL_INFO_TYPE_GSM: - case CELL_INFO_TYPE_WCDMA: - cellInfo.mcc = Buf.readInt32(); - cellInfo.mnc = Buf.readInt32(); - cellInfo.lac = Buf.readInt32(); - cellInfo.cid = Buf.readInt32(); - if (cellInfo.type == CELL_INFO_TYPE_WCDMA) { - cellInfo.psc = Buf.readInt32(); - } - cellInfo.signalStrength = Buf.readInt32(); - cellInfo.bitErrorRate = Buf.readInt32(); - break; - case CELL_INFO_TYPE_CDMA: - cellInfo.networkId = Buf.readInt32(); - cellInfo.systemId = Buf.readInt32(); - cellInfo.basestationId = Buf.readInt32(); - cellInfo.longitude = Buf.readInt32(); - cellInfo.latitude = Buf.readInt32(); - cellInfo.cdmaDbm = Buf.readInt32(); - cellInfo.cdmaEcio = Buf.readInt32(); - cellInfo.evdoDbm = Buf.readInt32(); - cellInfo.evdoEcio = Buf.readInt32(); - cellInfo.evdoSnr = Buf.readInt32(); - break; - case CELL_INFO_TYPE_LTE: - cellInfo.mcc = Buf.readInt32(); - cellInfo.mnc = Buf.readInt32(); - cellInfo.cid = Buf.readInt32(); - cellInfo.pcid = Buf.readInt32(); - cellInfo.tac = Buf.readInt32(); - cellInfo.signalStrength = Buf.readInt32(); - cellInfo.rsrp = Buf.readInt32(); - cellInfo.rsrq = Buf.readInt32(); - cellInfo.rssnr = Buf.readInt32(); - cellInfo.cqi = Buf.readInt32(); - break; - } - cellInfoList.push(cellInfo); - } - options.result = cellInfoList; - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_SET_LOCATION_UPDATES] = null; -RilObject.prototype[REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE] = null; -RilObject.prototype[REQUEST_CDMA_SET_ROAMING_PREFERENCE] = function REQUEST_CDMA_SET_ROAMING_PREFERENCE(length, options) { - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_CDMA_QUERY_ROAMING_PREFERENCE] = function REQUEST_CDMA_QUERY_ROAMING_PREFERENCE(length, options) { - if (!options.errorMsg) { - options.mode = this.context.Buf.readInt32List()[0]; - } - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_SET_TTY_MODE] = null; -RilObject.prototype[REQUEST_QUERY_TTY_MODE] = null; -RilObject.prototype[REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE] = function REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE(length, options) { - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE] = function REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE(length, options) { - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - let enabled = this.context.Buf.readInt32List(); - options.enabled = enabled[0] ? true : false; - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_CDMA_FLASH] = function REQUEST_CDMA_FLASH(length, options) { - this.sendDefaultResponse(options); -}; -RilObject.prototype[REQUEST_CDMA_BURST_DTMF] = null; -RilObject.prototype[REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY] = null; -RilObject.prototype[REQUEST_CDMA_SEND_SMS] = function REQUEST_CDMA_SEND_SMS(length, options) { - this._processSmsSendResult(length, options); -}; -RilObject.prototype[REQUEST_CDMA_SMS_ACKNOWLEDGE] = null; -RilObject.prototype[REQUEST_GSM_GET_BROADCAST_SMS_CONFIG] = null; -RilObject.prototype[REQUEST_GSM_SET_BROADCAST_SMS_CONFIG] = function REQUEST_GSM_SET_BROADCAST_SMS_CONFIG(length, options) { - if (options.errorMsg) { - return; - } - this.setSmsBroadcastActivation(true); -}; -RilObject.prototype[REQUEST_GSM_SMS_BROADCAST_ACTIVATION] = null; -RilObject.prototype[REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG] = null; -RilObject.prototype[REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG] = function REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG(length, options) { - if (options.errorMsg) { - return; - } - this.setSmsBroadcastActivation(true); -}; -RilObject.prototype[REQUEST_CDMA_SMS_BROADCAST_ACTIVATION] = null; -RilObject.prototype[REQUEST_CDMA_SUBSCRIPTION] = function REQUEST_CDMA_SUBSCRIPTION(length, options) { - if (options.errorMsg) { - return; - } - - let result = this.context.Buf.readStringList(); - - this.iccInfo.mdn = result[0]; - // The result[1] is Home SID. (Already be handled in readCDMAHome()) - // The result[2] is Home NID. (Already be handled in readCDMAHome()) - // The result[3] is MIN. - this.iccInfo.prlVersion = parseInt(result[4], 10); - - this.context.ICCUtilsHelper.handleICCInfoChange(); -}; -RilObject.prototype[REQUEST_CDMA_WRITE_SMS_TO_RUIM] = null; -RilObject.prototype[REQUEST_CDMA_DELETE_SMS_ON_RUIM] = null; -RilObject.prototype[REQUEST_DEVICE_IDENTITY] = function REQUEST_DEVICE_IDENTITY(length, options) { - if (options.errorMsg) { - this.context.debug("Failed to get device identities:" + options.errorMsg); - return; - } - - let result = this.context.Buf.readStringList(); - this.deviceIdentities = { - imei: result[0] || null, - imeisv: result[1] || null, - esn: result[2] || null, - meid: result[3] || null, - }; - - this.sendChromeMessage({ - rilMessageType: "deviceidentitieschange", - deviceIdentities: this.deviceIdentities - }); -}; -RilObject.prototype[REQUEST_EXIT_EMERGENCY_CALLBACK_MODE] = function REQUEST_EXIT_EMERGENCY_CALLBACK_MODE(length, options) { - if (options.internal) { - return; - } - - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_GET_SMSC_ADDRESS] = function REQUEST_GET_SMSC_ADDRESS(length, options) { - if (!options.rilMessageType || options.rilMessageType !== "getSmscAddress") { - return; - } - - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - let tosca = TOA_UNKNOWN; - let smsc = ""; - let Buf = this.context.Buf; - if (RILQUIRKS_SMSC_ADDRESS_FORMAT === "pdu") { - let pduHelper = this.context.GsmPDUHelper; - let strlen = Buf.readInt32(); - let length = pduHelper.readHexOctet(); - - // As defined in |8.2.5.2 Destination address element| of 3GPP TS 24.011, - // the value of length field can not exceed 11. Since the content might be - // filled with 12 'F' when SMSC is cleared, we don't parse the TOA and - // address fields if reported length exceeds 11 here. Instead, keep the - // default value (TOA_UNKNOWN with an empty address) in this case. - const MAX_LENGTH = 11 - if (length <= MAX_LENGTH) { - tosca = pduHelper.readHexOctet(); - - // Read and covert the decimal values back to special BCD digits defined in - // |Called party BCD number| of 3GPP TS 24.008 (refer the following table). - // - // +=========+=======+=====+ - // | value | digit | hex | - // +======================== - // | 1 0 1 0 | * | 0xA | - // | 1 0 1 1 | # | 0xB | - // | 1 1 0 0 | a | 0xC | - // | 1 1 0 1 | b | 0xD | - // | 1 1 1 0 | c | 0xE | - // +=========+=======+=====+ - smsc = pduHelper.readSwappedNibbleBcdString(length - 1, true) - .replace(/a/ig, "*") - .replace(/b/ig, "#") - .replace(/c/ig, "a") - .replace(/d/ig, "b") - .replace(/e/ig, "c"); - - Buf.readStringDelimiter(strlen); - } - } else /* RILQUIRKS_SMSC_ADDRESS_FORMAT === "text" */ { - let text = Buf.readString(); - let segments = text.split(",", 2); - // Parse TOA only if it presents since some devices might omit the TOA - // segment in the reported SMSC address. If TOA does not present, keep the - // default value TOA_UNKNOWN. - if (segments.length === 2) { - tosca = this.parseInt(segments[1], TOA_UNKNOWN, 10); - } - - smsc = segments[0].replace(/\"/g, ""); - } - - // Convert the NPI value to the corresponding index of CALLED_PARTY_BCD_NPI - // array. If the value does not present in the array, use - // CALLED_PARTY_BCD_NPI_ISDN. - let npi = CALLED_PARTY_BCD_NPI.indexOf(tosca & 0xf); - if (npi === -1) { - npi = CALLED_PARTY_BCD_NPI.indexOf(CALLED_PARTY_BCD_NPI_ISDN); - } - - // Extract TON. - let ton = (tosca & 0x70) >> 4; - - // Ensure + sign if TON is international, and vice versa. - const TON_INTERNATIONAL = (TOA_INTERNATIONAL & 0x70) >> 4; - if (ton === TON_INTERNATIONAL && smsc.charAt(0) !== "+") { - smsc = "+" + smsc; - } else if (smsc.charAt(0) === "+" && ton !== TON_INTERNATIONAL) { - if (DEBUG) { - this.context.debug("SMSC address number begins with '+' while the TON is not international. Change TON to international."); - } - ton = TON_INTERNATIONAL; - } - - options.smscAddress = smsc; - options.typeOfNumber = ton; - options.numberPlanIdentification = npi; - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_SET_SMSC_ADDRESS] = function REQUEST_SET_SMSC_ADDRESS(length, options) { - if (!options.rilMessageType || options.rilMessageType !== "setSmscAddress") { - return; - } - - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_REPORT_SMS_MEMORY_STATUS] = function REQUEST_REPORT_SMS_MEMORY_STATUS(length, options) { - this.pendingToReportSmsMemoryStatus = !!options.errorMsg; -}; -RilObject.prototype[REQUEST_REPORT_STK_SERVICE_IS_RUNNING] = null; -RilObject.prototype[REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE] = null; -RilObject.prototype[REQUEST_ISIM_AUTHENTICATION] = null; -RilObject.prototype[REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU] = null; -RilObject.prototype[REQUEST_STK_SEND_ENVELOPE_WITH_STATUS] = function REQUEST_STK_SEND_ENVELOPE_WITH_STATUS(length, options) { - if (options.errorMsg) { - this.acknowledgeGsmSms(false, PDU_FCS_UNSPECIFIED); - return; - } - - let Buf = this.context.Buf; - let sw1 = Buf.readInt32(); - let sw2 = Buf.readInt32(); - if ((sw1 == ICC_STATUS_SAT_BUSY) && (sw2 === 0x00)) { - this.acknowledgeGsmSms(false, PDU_FCS_USAT_BUSY); - return; - } - - let success = ((sw1 == ICC_STATUS_NORMAL_ENDING) && (sw2 === 0x00)) - || (sw1 == ICC_STATUS_NORMAL_ENDING_WITH_EXTRA); - - let messageStringLength = Buf.readInt32(); // In semi-octets - let responsePduLen = messageStringLength / 2; // In octets - if (!responsePduLen) { - this.acknowledgeGsmSms(success, success ? PDU_FCS_OK - : PDU_FCS_USIM_DATA_DOWNLOAD_ERROR); - return; - } - - this.acknowledgeIncomingGsmSmsWithPDU(success, responsePduLen, options); -}; -RilObject.prototype[REQUEST_VOICE_RADIO_TECH] = function REQUEST_VOICE_RADIO_TECH(length, options) { - if (options.errorMsg) { - if (DEBUG) { - this.context.debug("Error when getting voice radio tech: " + - options.errorMsg); - } - return; - } - let radioTech = this.context.Buf.readInt32List(); - this._processRadioTech(radioTech[0]); -}; -RilObject.prototype[REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE] = null; -RilObject.prototype[REQUEST_SET_INITIAL_ATTACH_APN] = null; -RilObject.prototype[REQUEST_IMS_REGISTRATION_STATE] = null; -RilObject.prototype[REQUEST_IMS_SEND_SMS] = null; -RilObject.prototype[REQUEST_SIM_TRANSMIT_APDU_BASIC] = null; -RilObject.prototype[REQUEST_SIM_OPEN_CHANNEL] = function REQUEST_SIM_OPEN_CHANNEL(length, options) { - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - options.channel = this.context.Buf.readInt32List()[0]; - // onwards may optionally contain the select response for the open channel - // command with one byte per integer. - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_SIM_CLOSE_CHANNEL] = function REQUEST_SIM_CLOSE_CHANNEL(length, options) { - this.sendDefaultResponse(options); -}; -RilObject.prototype[REQUEST_SIM_TRANSMIT_APDU_CHANNEL] = function REQUEST_SIM_TRANSMIT_APDU_CHANNEL(length, options) { - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - let Buf = this.context.Buf; - options.sw1 = Buf.readInt32(); - options.sw2 = Buf.readInt32(); - options.simResponse = Buf.readString(); - if (DEBUG) { - this.context.debug("Setting return values for RIL[REQUEST_SIM_TRANSMIT_APDU_CHANNEL]: [" + - options.sw1 + "," + - options.sw2 + ", " + - options.simResponse + "]"); - } - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_NV_READ_ITEM] = null; -RilObject.prototype[REQUEST_NV_WRITE_ITEM] = null; -RilObject.prototype[REQUEST_NV_WRITE_CDMA_PRL] = null; -RilObject.prototype[REQUEST_NV_RESET_CONFIG] = null; -RilObject.prototype[REQUEST_SET_UICC_SUBSCRIPTION] = function REQUEST_SET_UICC_SUBSCRIPTION(length, options) { - // Resend data subscription after uicc subscription. - if (this._attachDataRegistration) { - this.setDataRegistration({attach: true}); - } -}; -RilObject.prototype[REQUEST_ALLOW_DATA] = null; -RilObject.prototype[REQUEST_GET_HARDWARE_CONFIG] = null; -RilObject.prototype[REQUEST_SIM_AUTHENTICATION] = null; -RilObject.prototype[REQUEST_GET_DC_RT_INFO] = null; -RilObject.prototype[REQUEST_SET_DC_RT_INFO_RATE] = null; -RilObject.prototype[REQUEST_SET_DATA_PROFILE] = null; -RilObject.prototype[REQUEST_SHUTDOWN] = null; -RilObject.prototype[REQUEST_SET_DATA_SUBSCRIPTION] = function REQUEST_SET_DATA_SUBSCRIPTION(length, options) { - if (!options.rilMessageType) { - // The request was made by ril_worker itself. Don't report. - return; - } - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_GET_UNLOCK_RETRY_COUNT] = function REQUEST_GET_UNLOCK_RETRY_COUNT(length, options) { - options.retryCount = length ? this.context.Buf.readInt32List()[0] : -1; - this.sendChromeMessage(options); -}; -RilObject.prototype[RIL_REQUEST_GPRS_ATTACH] = function RIL_REQUEST_GPRS_ATTACH(length, options) { - if (!options.rilMessageType) { - // The request was made by ril_worker itself. Don't report. - return; - } - this.sendChromeMessage(options); -}; -RilObject.prototype[RIL_REQUEST_GPRS_DETACH] = function RIL_REQUEST_GPRS_DETACH(length, options) { - this.sendChromeMessage(options); -}; -RilObject.prototype[UNSOLICITED_RESPONSE_RADIO_STATE_CHANGED] = function UNSOLICITED_RESPONSE_RADIO_STATE_CHANGED() { - let radioState = this.context.Buf.readInt32(); - let newState; - switch (radioState) { - case RADIO_STATE_UNAVAILABLE: - newState = GECKO_RADIOSTATE_UNKNOWN; - break; - case RADIO_STATE_OFF: - newState = GECKO_RADIOSTATE_DISABLED; - break; - default: - newState = GECKO_RADIOSTATE_ENABLED; - } - - if (DEBUG) { - this.context.debug("Radio state changed from '" + this.radioState + - "' to '" + newState + "'"); - } - if (this.radioState == newState) { - return; - } - - if (radioState !== RADIO_STATE_UNAVAILABLE) { - // Retrieve device identities once radio is available. - this.getDeviceIdentity(); - } - - if (radioState == RADIO_STATE_ON) { - // This value is defined in RIL v7, we will retrieve radio tech by another - // request. We leave _isCdma untouched, and it will be set once we get the - // radio technology. - this._waitingRadioTech = true; - this.getVoiceRadioTechnology(); - } - - if ((this.radioState == GECKO_RADIOSTATE_UNKNOWN || - this.radioState == GECKO_RADIOSTATE_DISABLED) && - newState == GECKO_RADIOSTATE_ENABLED) { - // The radio became available, let's get its info. - this.getBasebandVersion(); - this.updateCellBroadcastConfig(); - if ((RILQUIRKS_DATA_REGISTRATION_ON_DEMAND || - RILQUIRKS_SUBSCRIPTION_CONTROL) && - this._attachDataRegistration) { - this.setDataRegistration({attach: true}); - } - - if (this.pendingToReportSmsMemoryStatus) { - this._updateSmsMemoryStatus(); - } - } - - this.radioState = newState; - this.sendChromeMessage({ - rilMessageType: "radiostatechange", - radioState: newState - }); - - // If the radio is up and on, so let's query the card state. - // On older RILs only if the card is actually ready, though. - // If _waitingRadioTech is set, we don't need to get icc status now. - if (radioState == RADIO_STATE_UNAVAILABLE || - radioState == RADIO_STATE_OFF || - this._waitingRadioTech) { - return; - } - this.getICCStatus(); -}; -RilObject.prototype[UNSOLICITED_RESPONSE_CALL_STATE_CHANGED] = function UNSOLICITED_RESPONSE_CALL_STATE_CHANGED() { - this.getCurrentCalls(); -}; -RilObject.prototype[UNSOLICITED_RESPONSE_VOICE_NETWORK_STATE_CHANGED] = function UNSOLICITED_RESPONSE_VOICE_NETWORK_STATE_CHANGED() { - if (DEBUG) { - this.context.debug("Network state changed, re-requesting phone state and " + - "ICC status"); - } - this.getICCStatus(); - this.requestNetworkInfo(); -}; -RilObject.prototype[UNSOLICITED_RESPONSE_NEW_SMS] = function UNSOLICITED_RESPONSE_NEW_SMS(length) { - let [message, result] = this.context.GsmPDUHelper.processReceivedSms(length); - - if (message) { - result = this._processSmsMultipart(message); - } - - if (result == PDU_FCS_RESERVED || result == MOZ_FCS_WAIT_FOR_EXPLICIT_ACK) { - return; - } - - // Not reserved FCS values, send ACK now. - this.acknowledgeGsmSms(result == PDU_FCS_OK, result); -}; -RilObject.prototype[UNSOLICITED_RESPONSE_NEW_SMS_STATUS_REPORT] = function UNSOLICITED_RESPONSE_NEW_SMS_STATUS_REPORT(length) { - let result = this._processSmsStatusReport(length); - this.acknowledgeGsmSms(result == PDU_FCS_OK, result); -}; -RilObject.prototype[UNSOLICITED_RESPONSE_NEW_SMS_ON_SIM] = function UNSOLICITED_RESPONSE_NEW_SMS_ON_SIM(length) { - let recordNumber = this.context.Buf.readInt32List()[0]; - - this.context.SimRecordHelper.readSMS( - recordNumber, - function onsuccess(message) { - if (message && message.simStatus === 3) { //New Unread SMS - this._processSmsMultipart(message); - } - }.bind(this), - function onerror(errorMsg) { - if (DEBUG) { - this.context.debug("Failed to Read NEW SMS on SIM #" + recordNumber + - ", errorMsg: " + errorMsg); - } - }); -}; -RilObject.prototype[UNSOLICITED_ON_USSD] = function UNSOLICITED_ON_USSD() { - let [typeCode, message] = this.context.Buf.readStringList(); - if (DEBUG) { - this.context.debug("On USSD. Type Code: " + typeCode + " Message: " + message); - } - - this.sendChromeMessage({rilMessageType: "ussdreceived", - message: message, - // Per ril.h the USSD session is assumed to persist if - // the type code is "1", otherwise the current session - // (if any) is assumed to have terminated. - sessionEnded: typeCode !== "1"}); -}; -RilObject.prototype[UNSOLICITED_ON_USSD_REQUEST] = null; -RilObject.prototype[UNSOLICITED_NITZ_TIME_RECEIVED] = function UNSOLICITED_NITZ_TIME_RECEIVED() { - let dateString = this.context.Buf.readString(); - - // The data contained in the NITZ message is - // in the form "yy/mm/dd,hh:mm:ss(+/-)tz,dt" - // for example: 12/02/16,03:36:08-20,00,310410 - // See also bug 714352 - Listen for NITZ updates from rild. - - if (DEBUG) this.context.debug("DateTimeZone string " + dateString); - - let now = Date.now(); - - let year = parseInt(dateString.substr(0, 2), 10); - let month = parseInt(dateString.substr(3, 2), 10); - let day = parseInt(dateString.substr(6, 2), 10); - let hours = parseInt(dateString.substr(9, 2), 10); - let minutes = parseInt(dateString.substr(12, 2), 10); - let seconds = parseInt(dateString.substr(15, 2), 10); - // Note that |tz| is in 15-min units. - let tz = parseInt(dateString.substr(17, 3), 10); - // Note that |dst| is in 1-hour units and is already applied in |tz|. - let dst = parseInt(dateString.substr(21, 2), 10); - - let timeInMS = Date.UTC(year + PDU_TIMESTAMP_YEAR_OFFSET, month - 1, day, - hours, minutes, seconds); - - if (isNaN(timeInMS)) { - if (DEBUG) this.context.debug("NITZ failed to convert date"); - return; - } - - this.sendChromeMessage({rilMessageType: "nitzTime", - networkTimeInMS: timeInMS, - networkTimeZoneInMinutes: -(tz * 15), - networkDSTInMinutes: -(dst * 60), - receiveTimeInMS: now}); -}; - -RilObject.prototype[UNSOLICITED_SIGNAL_STRENGTH] = function UNSOLICITED_SIGNAL_STRENGTH(length) { - this[REQUEST_SIGNAL_STRENGTH](length, {}); -}; -RilObject.prototype[UNSOLICITED_DATA_CALL_LIST_CHANGED] = function UNSOLICITED_DATA_CALL_LIST_CHANGED(length) { - this[REQUEST_DATA_CALL_LIST](length, {}); -}; -RilObject.prototype[UNSOLICITED_SUPP_SVC_NOTIFICATION] = function UNSOLICITED_SUPP_SVC_NOTIFICATION(length) { - let Buf = this.context.Buf; - let info = {}; - info.notificationType = Buf.readInt32(); - info.code = Buf.readInt32(); - info.index = Buf.readInt32(); - info.type = Buf.readInt32(); - info.number = Buf.readString(); - - this._processSuppSvcNotification(info); -}; - -RilObject.prototype[UNSOLICITED_STK_SESSION_END] = function UNSOLICITED_STK_SESSION_END() { - this.sendChromeMessage({rilMessageType: "stksessionend"}); -}; -RilObject.prototype[UNSOLICITED_STK_PROACTIVE_COMMAND] = function UNSOLICITED_STK_PROACTIVE_COMMAND() { - this.processStkProactiveCommand(); -}; -RilObject.prototype[UNSOLICITED_STK_EVENT_NOTIFY] = function UNSOLICITED_STK_EVENT_NOTIFY() { - this.processStkProactiveCommand(); -}; -RilObject.prototype[UNSOLICITED_STK_CALL_SETUP] = null; -RilObject.prototype[UNSOLICITED_SIM_SMS_STORAGE_FULL] = null; -RilObject.prototype[UNSOLICITED_SIM_REFRESH] = null; -RilObject.prototype[UNSOLICITED_CALL_RING] = function UNSOLICITED_CALL_RING() { - let Buf = this.context.Buf; - let info = {rilMessageType: "callRing"}; - let isCDMA = false; //XXX TODO hard-code this for now - if (isCDMA) { - info.isPresent = Buf.readInt32(); - info.signalType = Buf.readInt32(); - info.alertPitch = Buf.readInt32(); - info.signal = Buf.readInt32(); - } - // At this point we don't know much other than the fact there's an incoming - // call, but that's enough to bring up the Phone app already. We'll know - // details once we get a call state changed notification and can then - // dispatch DOM events etc. - this.sendChromeMessage(info); -}; -RilObject.prototype[UNSOLICITED_RESPONSE_SIM_STATUS_CHANGED] = function UNSOLICITED_RESPONSE_SIM_STATUS_CHANGED() { - this.getICCStatus(); -}; -RilObject.prototype[UNSOLICITED_RESPONSE_CDMA_NEW_SMS] = function UNSOLICITED_RESPONSE_CDMA_NEW_SMS(length) { - let [message, result] = this.context.CdmaPDUHelper.processReceivedSms(length); - - if (message) { - if (message.teleservice === PDU_CDMA_MSG_TELESERIVCIE_ID_WAP) { - result = this._processCdmaSmsWapPush(message); - } else if (message.subMsgType === PDU_CDMA_MSG_TYPE_DELIVER_ACK) { - result = this._processCdmaSmsStatusReport(message); - } else { - result = this._processSmsMultipart(message); - } - } - - if (result == PDU_FCS_RESERVED || result == MOZ_FCS_WAIT_FOR_EXPLICIT_ACK) { - return; - } - - // Not reserved FCS values, send ACK now. - this.acknowledgeCdmaSms(result == PDU_FCS_OK, result); -}; -RilObject.prototype[UNSOLICITED_RESPONSE_NEW_BROADCAST_SMS] = function UNSOLICITED_RESPONSE_NEW_BROADCAST_SMS(length) { - let message; - try { - message = - this.context.GsmPDUHelper.readCbMessage(this.context.Buf.readInt32()); - - // "Data-Download" message is expected to be handled by the modem. - // Ignore it here to prevent any garbage messages to be displayed. - // See 9.4.1.2.2 Message Identifier of TS 32.041 for the range of - // Message-identifier of the Data-Download CB messages. - if (message.messageId >= 0x1000 && message.messageId <= 0x10FF) { - if (DEBUG) { - this.context.debug("Ignore a Data-Download message, messageId: " + - message.messageId); - } - return; - } - } catch (e) { - if (DEBUG) { - this.context.debug("Failed to parse Cell Broadcast message: " + e); - } - return; - } - - message = this._processReceivedSmsCbPage(message); - if (!message) { - return; - } - - // Bug 1235697, failed to deactivate CBS in some modem. - // Workaround it according to the settings. - // Note: ETWS/CMAS/PWS can be received even disabled. - // It will be displayed according to the setting in application layer. - if (this.cellBroadcastDisabled && ( - !(message.messageId >= 0x1100 && message.messageId <= 0x1107) && // ETWS - !(message.messageId >= 0x1112 && message.messageId <= 0x112F) && // CMAS - !(message.messageId >= 0x1130 && message.messageId <= 0x18FF) // PWS - )) { - if (DEBUG) { - this.context.debug("Ignore a CB message when disabled, messageId: " + - message.messageId); - } - return; - } - - message.rilMessageType = "cellbroadcast-received"; - this.sendChromeMessage(message); -}; -RilObject.prototype[UNSOLICITED_CDMA_RUIM_SMS_STORAGE_FULL] = null; -RilObject.prototype[UNSOLICITED_RESTRICTED_STATE_CHANGED] = null; -RilObject.prototype[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE] = function UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE() { - this._handleChangedEmergencyCbMode(true); -}; -RilObject.prototype[UNSOLICITED_CDMA_CALL_WAITING] = function UNSOLICITED_CDMA_CALL_WAITING(length) { - let Buf = this.context.Buf; - let call = {}; - call.number = Buf.readString(); - call.numberPresentation = Buf.readInt32(); - call.name = Buf.readString(); - call.namePresentation = Buf.readInt32(); - call.isPresent = Buf.readInt32(); - call.signalType = Buf.readInt32(); - call.alertPitch = Buf.readInt32(); - call.signal = Buf.readInt32(); - this.sendChromeMessage({rilMessageType: "cdmaCallWaiting", - waitingCall: call}); -}; -RilObject.prototype[UNSOLICITED_CDMA_OTA_PROVISION_STATUS] = function UNSOLICITED_CDMA_OTA_PROVISION_STATUS() { - let status = - CDMA_OTA_PROVISION_STATUS_TO_GECKO[this.context.Buf.readInt32List()[0]]; - if (!status) { - return; - } - this.sendChromeMessage({rilMessageType: "otastatuschange", - status: status}); -}; -RilObject.prototype[UNSOLICITED_CDMA_INFO_REC] = function UNSOLICITED_CDMA_INFO_REC(length) { - this.sendChromeMessage({ - rilMessageType: "cdma-info-rec-received", - records: this.context.CdmaPDUHelper.decodeInformationRecord() - }); -}; -RilObject.prototype[UNSOLICITED_OEM_HOOK_RAW] = null; -RilObject.prototype[UNSOLICITED_RINGBACK_TONE] = null; -RilObject.prototype[UNSOLICITED_RESEND_INCALL_MUTE] = null; -RilObject.prototype[UNSOLICITED_CDMA_SUBSCRIPTION_SOURCE_CHANGED] = null; -RilObject.prototype[UNSOLICITED_CDMA_PRL_CHANGED] = function UNSOLICITED_CDMA_PRL_CHANGED(length) { - let version = this.context.Buf.readInt32List()[0]; - if (version !== this.iccInfo.prlVersion) { - this.iccInfo.prlVersion = version; - this.context.ICCUtilsHelper.handleICCInfoChange(); - } -}; -RilObject.prototype[UNSOLICITED_EXIT_EMERGENCY_CALLBACK_MODE] = function UNSOLICITED_EXIT_EMERGENCY_CALLBACK_MODE() { - this._handleChangedEmergencyCbMode(false); -}; -RilObject.prototype[UNSOLICITED_RIL_CONNECTED] = function UNSOLICITED_RIL_CONNECTED(length) { - // Prevent response id collision between UNSOLICITED_RIL_CONNECTED and - // UNSOLICITED_VOICE_RADIO_TECH_CHANGED for Akami on gingerbread branch. - if (!length) { - return; - } - - this.version = this.context.Buf.readInt32List()[0]; - if (DEBUG) { - this.context.debug("Detected RIL version " + this.version); - } - - this.initRILState(); - // rild might have restarted, ensure data call list. - this.getDataCallList(); - // Always ensure that we are not in emergency callback mode when init. - this.exitEmergencyCbMode(); - // Reset radio in the case that b2g restart (or crash). - this.setRadioEnabled({enabled: false}); -}; -RilObject.prototype[UNSOLICITED_VOICE_RADIO_TECH_CHANGED] = function UNSOLICITED_VOICE_RADIO_TECH_CHANGED(length) { - // This unsolicited response will be sent when the technology of a multi-tech - // modem is changed, ex. switch between gsm and cdma. - // TODO: We may need to do more on updating data when switching between gsm - // and cdma mode, e.g. IMEI, ESN, iccInfo, iccType ... etc. - // See Bug 866038. - this._processRadioTech(this.context.Buf.readInt32List()[0]); -}; -RilObject.prototype[UNSOLICITED_CELL_INFO_LIST] = null; -RilObject.prototype[UNSOLICITED_RESPONSE_IMS_NETWORK_STATE_CHANGED] = null; -RilObject.prototype[UNSOLICITED_UICC_SUBSCRIPTION_STATUS_CHANGED] = null; -RilObject.prototype[UNSOLICITED_SRVCC_STATE_NOTIFY] = null; -RilObject.prototype[UNSOLICITED_HARDWARE_CONFIG_CHANGED] = null; -RilObject.prototype[UNSOLICITED_DC_RT_INFO_CHANGED] = null; - -/** - * This object exposes the functionality to parse and serialize PDU strings - * - * A PDU is a string containing a series of hexadecimally encoded octets - * or nibble-swapped binary-coded decimals (BCDs). It contains not only the - * message text but information about the sender, the SMS service center, - * timestamp, etc. - */ -function GsmPDUHelperObject(aContext) { - this.context = aContext; -} -GsmPDUHelperObject.prototype = { - context: null, - - /** - * Read one character (2 bytes) from a RIL string and decode as hex. - * - * @return the nibble as a number. - */ - readHexNibble: function() { - let nibble = this.context.Buf.readUint16(); - if (nibble >= 48 && nibble <= 57) { - nibble -= 48; // ASCII '0'..'9' - } else if (nibble >= 65 && nibble <= 70) { - nibble -= 55; // ASCII 'A'..'F' - } else if (nibble >= 97 && nibble <= 102) { - nibble -= 87; // ASCII 'a'..'f' - } else { - throw "Found invalid nibble during PDU parsing: " + - String.fromCharCode(nibble); - } - return nibble; - }, - - /** - * Encode a nibble as one hex character in a RIL string (2 bytes). - * - * @param nibble - * The nibble to encode (represented as a number) - */ - writeHexNibble: function(nibble) { - nibble &= 0x0f; - if (nibble < 10) { - nibble += 48; // ASCII '0' - } else { - nibble += 55; // ASCII 'A' - } - this.context.Buf.writeUint16(nibble); - }, - - /** - * Read a hex-encoded octet (two nibbles). - * - * @return the octet as a number. - */ - readHexOctet: function() { - return (this.readHexNibble() << 4) | this.readHexNibble(); - }, - - /** - * Write an octet as two hex-encoded nibbles. - * - * @param octet - * The octet (represented as a number) to encode. - */ - writeHexOctet: function(octet) { - this.writeHexNibble(octet >> 4); - this.writeHexNibble(octet); - }, - - /** - * Read an array of hex-encoded octets. - */ - readHexOctetArray: function(length) { - let array = new Uint8Array(length); - for (let i = 0; i < length; i++) { - array[i] = this.readHexOctet(); - } - return array; - }, - - /** - * Helper to write data into a temporary buffer for easier length encoding when - * the number of octets for the length encoding is varied. - * - * @param writeFunction - * Function of how the data to be written into temporary buffer. - * - * @return array of written octets. - **/ - writeWithBuffer: function(writeFunction) { - let buf = []; - let writeHexOctet = this.writeHexOctet; - this.writeHexOctet = function(octet) { - buf.push(octet); - } - - try { - writeFunction(); - } catch (e) { - if (DEBUG) { - debug("Error when writeWithBuffer: " + e); - } - buf = []; - } finally { - this.writeHexOctet = writeHexOctet; - } - - return buf; - }, - - /** - * Convert an octet (number) to a BCD number. - * - * Any nibbles that are not in the BCD range count as 0. - * - * @param octet - * The octet (a number, as returned by getOctet()) - * - * @return the corresponding BCD number. - */ - octetToBCD: function(octet) { - return ((octet & 0xf0) <= 0x90) * ((octet >> 4) & 0x0f) + - ((octet & 0x0f) <= 0x09) * (octet & 0x0f) * 10; - }, - - /** - * Convert a BCD number to an octet (number) - * - * Only take two digits with absolute value. - * - * @param bcd - * - * @return the corresponding octet. - */ - BCDToOctet: function(bcd) { - bcd = Math.abs(bcd); - return ((bcd % 10) << 4) + (Math.floor(bcd / 10) % 10); - }, - - /** - * Convert a semi-octet (number) to a GSM BCD char, or return empty - * string if invalid semiOctet and suppressException is set to true. - * - * @param semiOctet - * Nibble to be converted to. - * @param suppressException [optional] - * Suppress exception if invalid semiOctet and suppressException is set - * to true. - * - * @return GSM BCD char, or empty string. - */ - bcdChars: "0123456789", - semiOctetToBcdChar: function(semiOctet, suppressException) { - if (semiOctet >= this.bcdChars.length) { - if (suppressException) { - return ""; - } else { - throw new RangeError(); - } - } - - return this.bcdChars.charAt(semiOctet); - }, - - /** - * Convert a semi-octet (number) to a GSM extended BCD char, or return empty - * string if invalid semiOctet and suppressException is set to true. - * - * @param semiOctet - * Nibble to be converted to. - * @param suppressException [optional] - * Suppress exception if invalid semiOctet and suppressException is set - * to true. - * - * @return GSM extended BCD char, or empty string. - */ - extendedBcdChars: "0123456789*#,;", - semiOctetToExtendedBcdChar: function(semiOctet, suppressException) { - if (semiOctet >= this.extendedBcdChars.length) { - if (suppressException) { - return ""; - } else { - throw new RangeError(); - } - } - - return this.extendedBcdChars.charAt(semiOctet); - }, - - /** - * Convert string to a GSM extended BCD string - */ - stringToExtendedBcd: function(string) { - return string.replace(/[^0-9*#,]/g, "") - .replace(/\*/g, "a") - .replace(/\#/g, "b") - .replace(/\,/g, "c"); - }, - - /** - * Read a *swapped nibble* binary coded decimal (BCD) - * - * @param pairs - * Number of nibble *pairs* to read. - * - * @return the decimal as a number. - */ - readSwappedNibbleBcdNum: function(pairs) { - let number = 0; - for (let i = 0; i < pairs; i++) { - let octet = this.readHexOctet(); - // Ignore 'ff' octets as they're often used as filler. - if (octet == 0xff) { - continue; - } - // If the first nibble is an "F" , only the second nibble is to be taken - // into account. - if ((octet & 0xf0) == 0xf0) { - number *= 10; - number += octet & 0x0f; - continue; - } - number *= 100; - number += this.octetToBCD(octet); - } - return number; - }, - - /** - * Read a *swapped nibble* binary coded decimal (BCD) string - * - * @param pairs - * Number of nibble *pairs* to read. - * @param suppressException [optional] - * Suppress exception if invalid semiOctet and suppressException is set - * to true. - * - * @return The BCD string. - */ - readSwappedNibbleBcdString: function(pairs, suppressException) { - let str = ""; - for (let i = 0; i < pairs; i++) { - let nibbleH = this.readHexNibble(); - let nibbleL = this.readHexNibble(); - if (nibbleL == 0x0F) { - break; - } - - str += this.semiOctetToBcdChar(nibbleL, suppressException); - if (nibbleH != 0x0F) { - str += this.semiOctetToBcdChar(nibbleH, suppressException); - } - } - - return str; - }, - - /** - * Read a *swapped nibble* extended binary coded decimal (BCD) string - * - * @param pairs - * Number of nibble *pairs* to read. - * @param suppressException [optional] - * Suppress exception if invalid semiOctet and suppressException is set - * to true. - * - * @return The BCD string. - */ - readSwappedNibbleExtendedBcdString: function(pairs, suppressException) { - let str = ""; - for (let i = 0; i < pairs; i++) { - let nibbleH = this.readHexNibble(); - let nibbleL = this.readHexNibble(); - if (nibbleL == 0x0F) { - break; - } - - str += this.semiOctetToExtendedBcdChar(nibbleL, suppressException); - if (nibbleH != 0x0F) { - str += this.semiOctetToExtendedBcdChar(nibbleH, suppressException); - } - } - - return str; - }, - - /** - * Write numerical data as swapped nibble BCD. - * - * @param data - * Data to write (as a string or a number) - */ - writeSwappedNibbleBCD: function(data) { - data = data.toString(); - if (data.length % 2) { - data += "F"; - } - let Buf = this.context.Buf; - for (let i = 0; i < data.length; i += 2) { - Buf.writeUint16(data.charCodeAt(i + 1)); - Buf.writeUint16(data.charCodeAt(i)); - } - }, - - /** - * Write numerical data as swapped nibble BCD. - * If the number of digit of data is even, add '0' at the beginning. - * - * @param data - * Data to write (as a string or a number) - */ - writeSwappedNibbleBCDNum: function(data) { - data = data.toString(); - if (data.length % 2) { - data = "0" + data; - } - let Buf = this.context.Buf; - for (let i = 0; i < data.length; i += 2) { - Buf.writeUint16(data.charCodeAt(i + 1)); - Buf.writeUint16(data.charCodeAt(i)); - } - }, - - /** - * Read user data, convert to septets, look up relevant characters in a - * 7-bit alphabet, and construct string. - * - * @param length - * Number of septets to read (*not* octets) - * @param paddingBits - * Number of padding bits in the first byte of user data. - * @param langIndex - * Table index used for normal 7-bit encoded character lookup. - * @param langShiftIndex - * Table index used for escaped 7-bit encoded character lookup. - * - * @return a string. - */ - readSeptetsToString: function(length, paddingBits, langIndex, langShiftIndex) { - let ret = ""; - let byteLength = Math.ceil((length * 7 + paddingBits) / 8); - - /** - * |<- last byte in header ->| - * |<- incompleteBits ->|<- last header septet->| - * +===7===|===6===|===5===|===4===|===3===|===2===|===1===|===0===| - * - * |<- 1st byte in user data ->| - * |<- data septet 1 ->|<-paddingBits->| - * +===7===|===6===|===5===|===4===|===3===|===2===|===1===|===0===| - * - * |<- 2nd byte in user data ->| - * |<- data spetet 2 ->|<-ds1->| - * +===7===|===6===|===5===|===4===|===3===|===2===|===1===|===0===| - */ - let data = 0; - let dataBits = 0; - if (paddingBits) { - data = this.readHexOctet() >> paddingBits; - dataBits = 8 - paddingBits; - --byteLength; - } - - let escapeFound = false; - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[langIndex]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[langShiftIndex]; - do { - // Read as much as fits in 32bit word - let bytesToRead = Math.min(byteLength, dataBits ? 3 : 4); - for (let i = 0; i < bytesToRead; i++) { - data |= this.readHexOctet() << dataBits; - dataBits += 8; - --byteLength; - } - - // Consume available full septets - for (; dataBits >= 7; dataBits -= 7) { - let septet = data & 0x7F; - data >>>= 7; - - if (escapeFound) { - escapeFound = false; - if (septet == PDU_NL_EXTENDED_ESCAPE) { - // According to 3GPP TS 23.038, section 6.2.1.1, NOTE 1, "On - // receipt of this code, a receiving entity shall display a space - // until another extensiion table is defined." - ret += " "; - } else if (septet == PDU_NL_RESERVED_CONTROL) { - // According to 3GPP TS 23.038 B.2, "This code represents a control - // character and therefore must not be used for language specific - // characters." - ret += " "; - } else { - ret += langShiftTable[septet]; - } - } else if (septet == PDU_NL_EXTENDED_ESCAPE) { - escapeFound = true; - - // <escape> is not an effective character - --length; - } else { - ret += langTable[septet]; - } - } - } while (byteLength); - - if (ret.length != length) { - /** - * If num of effective characters does not equal to the length of read - * string, cut the tail off. This happens when the last octet of user - * data has following layout: - * - * |<- penultimate octet in user data ->| - * |<- data septet N ->|<- dsN-1 ->| - * +===7===|===6===|===5===|===4===|===3===|===2===|===1===|===0===| - * - * |<- last octet in user data ->| - * |<- fill bits ->|<-dsN->| - * +===7===|===6===|===5===|===4===|===3===|===2===|===1===|===0===| - * - * The fill bits in the last octet may happen to form a full septet and - * be appended at the end of result string. - */ - ret = ret.slice(0, length); - } - return ret; - }, - - writeStringAsSeptets: function(message, paddingBits, langIndex, langShiftIndex) { - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[langIndex]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[langShiftIndex]; - - let dataBits = paddingBits; - let data = 0; - for (let i = 0; i < message.length; i++) { - let c = message.charAt(i); - let septet = langTable.indexOf(c); - if (septet == PDU_NL_EXTENDED_ESCAPE) { - continue; - } - - if (septet >= 0) { - data |= septet << dataBits; - dataBits += 7; - } else { - septet = langShiftTable.indexOf(c); - if (septet == -1) { - throw new Error("'" + c + "' is not in 7 bit alphabet " - + langIndex + ":" + langShiftIndex + "!"); - } - - if (septet == PDU_NL_RESERVED_CONTROL) { - continue; - } - - data |= PDU_NL_EXTENDED_ESCAPE << dataBits; - dataBits += 7; - data |= septet << dataBits; - dataBits += 7; - } - - for (; dataBits >= 8; dataBits -= 8) { - this.writeHexOctet(data & 0xFF); - data >>>= 8; - } - } - - if (dataBits !== 0) { - this.writeHexOctet(data & 0xFF); - } - }, - - writeStringAs8BitUnpacked: function(text) { - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - - let len = text ? text.length : 0; - for (let i = 0; i < len; i++) { - let c = text.charAt(i); - let octet = langTable.indexOf(c); - - if (octet == -1) { - octet = langShiftTable.indexOf(c); - if (octet == -1) { - // Fallback to ASCII space. - octet = langTable.indexOf(' '); - } else { - this.writeHexOctet(PDU_NL_EXTENDED_ESCAPE); - } - } - this.writeHexOctet(octet); - } - }, - - /** - * Read user data and decode as a UCS2 string. - * - * @param numOctets - * Number of octets to be read as UCS2 string. - * - * @return a string. - */ - readUCS2String: function(numOctets) { - let str = ""; - let length = numOctets / 2; - for (let i = 0; i < length; ++i) { - let code = (this.readHexOctet() << 8) | this.readHexOctet(); - str += String.fromCharCode(code); - } - - if (DEBUG) this.context.debug("Read UCS2 string: " + str); - - return str; - }, - - /** - * Write user data as a UCS2 string. - * - * @param message - * Message string to encode as UCS2 in hex-encoded octets. - */ - writeUCS2String: function(message) { - for (let i = 0; i < message.length; ++i) { - let code = message.charCodeAt(i); - this.writeHexOctet((code >> 8) & 0xFF); - this.writeHexOctet(code & 0xFF); - } - }, - - /** - * Read 1 + UDHL octets and construct user data header. - * - * @param msg - * message object for output. - * - * @see 3GPP TS 23.040 9.2.3.24 - */ - readUserDataHeader: function(msg) { - /** - * A header object with properties contained in received message. - * The properties set include: - * - * length: totoal length of the header, default 0. - * langIndex: used locking shift table index, default - * PDU_NL_IDENTIFIER_DEFAULT. - * langShiftIndex: used locking shift table index, default - * PDU_NL_IDENTIFIER_DEFAULT. - * - */ - let header = { - length: 0, - langIndex: PDU_NL_IDENTIFIER_DEFAULT, - langShiftIndex: PDU_NL_IDENTIFIER_DEFAULT - }; - - header.length = this.readHexOctet(); - if (DEBUG) this.context.debug("Read UDH length: " + header.length); - - let dataAvailable = header.length; - while (dataAvailable >= 2) { - let id = this.readHexOctet(); - let length = this.readHexOctet(); - if (DEBUG) this.context.debug("Read UDH id: " + id + ", length: " + length); - - dataAvailable -= 2; - - switch (id) { - case PDU_IEI_CONCATENATED_SHORT_MESSAGES_8BIT: { - let ref = this.readHexOctet(); - let max = this.readHexOctet(); - let seq = this.readHexOctet(); - dataAvailable -= 3; - if (max && seq && (seq <= max)) { - header.segmentRef = ref; - header.segmentMaxSeq = max; - header.segmentSeq = seq; - } - break; - } - case PDU_IEI_APPLICATION_PORT_ADDRESSING_SCHEME_8BIT: { - let dstp = this.readHexOctet(); - let orip = this.readHexOctet(); - dataAvailable -= 2; - if ((dstp < PDU_APA_RESERVED_8BIT_PORTS) - || (orip < PDU_APA_RESERVED_8BIT_PORTS)) { - // 3GPP TS 23.040 clause 9.2.3.24.3: "A receiving entity shall - // ignore any information element where the value of the - // Information-Element-Data is Reserved or not supported" - break; - } - header.destinationPort = dstp; - header.originatorPort = orip; - break; - } - case PDU_IEI_APPLICATION_PORT_ADDRESSING_SCHEME_16BIT: { - let dstp = (this.readHexOctet() << 8) | this.readHexOctet(); - let orip = (this.readHexOctet() << 8) | this.readHexOctet(); - dataAvailable -= 4; - if ((dstp >= PDU_APA_VALID_16BIT_PORTS) || - (orip >= PDU_APA_VALID_16BIT_PORTS)) { - // 3GPP TS 23.040 clause 9.2.3.24.4: "A receiving entity shall - // ignore any information element where the value of the - // Information-Element-Data is Reserved or not supported" - // Bug 1130292, some carriers set originatorPort to reserved port - // numbers for wap push. We rise this as a warning in debug message - // instead of ingoring this IEI to allow user to receive Wap Push - // under these carriers. - this.context.debug("Warning: Invalid port numbers [dstp, orip]: " + - JSON.stringify([dstp, orip])); - } - header.destinationPort = dstp; - header.originatorPort = orip; - break; - } - case PDU_IEI_CONCATENATED_SHORT_MESSAGES_16BIT: { - let ref = (this.readHexOctet() << 8) | this.readHexOctet(); - let max = this.readHexOctet(); - let seq = this.readHexOctet(); - dataAvailable -= 4; - if (max && seq && (seq <= max)) { - header.segmentRef = ref; - header.segmentMaxSeq = max; - header.segmentSeq = seq; - } - break; - } - case PDU_IEI_NATIONAL_LANGUAGE_SINGLE_SHIFT: - let langShiftIndex = this.readHexOctet(); - --dataAvailable; - if (langShiftIndex < PDU_NL_SINGLE_SHIFT_TABLES.length) { - header.langShiftIndex = langShiftIndex; - } - break; - case PDU_IEI_NATIONAL_LANGUAGE_LOCKING_SHIFT: - let langIndex = this.readHexOctet(); - --dataAvailable; - if (langIndex < PDU_NL_LOCKING_SHIFT_TABLES.length) { - header.langIndex = langIndex; - } - break; - case PDU_IEI_SPECIAL_SMS_MESSAGE_INDICATION: - let msgInd = this.readHexOctet() & 0xFF; - let msgCount = this.readHexOctet(); - dataAvailable -= 2; - - - /* - * TS 23.040 V6.8.1 Sec 9.2.3.24.2 - * bits 1 0 : basic message indication type - * bits 4 3 2 : extended message indication type - * bits 6 5 : Profile id - * bit 7 : storage type - */ - let storeType = msgInd & PDU_MWI_STORE_TYPE_BIT; - let mwi = msg.mwi; - if (!mwi) { - mwi = msg.mwi = {}; - } - - if (storeType == PDU_MWI_STORE_TYPE_STORE) { - // Store message because TP_UDH indicates so, note this may override - // the setting in DCS, but that is expected - mwi.discard = false; - } else if (mwi.discard === undefined) { - // storeType == PDU_MWI_STORE_TYPE_DISCARD - // only override mwi.discard here if it hasn't already been set - mwi.discard = true; - } - - mwi.msgCount = msgCount & 0xFF; - mwi.active = mwi.msgCount > 0; - - if (DEBUG) { - this.context.debug("MWI in TP_UDH received: " + JSON.stringify(mwi)); - } - - break; - default: - if (DEBUG) { - this.context.debug("readUserDataHeader: unsupported IEI(" + id + - "), " + length + " bytes."); - } - - // Read out unsupported data - if (length) { - let octets; - if (DEBUG) octets = new Uint8Array(length); - - for (let i = 0; i < length; i++) { - let octet = this.readHexOctet(); - if (DEBUG) octets[i] = octet; - } - dataAvailable -= length; - - if (DEBUG) { - this.context.debug("readUserDataHeader: " + Array.slice(octets)); - } - } - break; - } - } - - if (dataAvailable !== 0) { - throw new Error("Illegal user data header found!"); - } - - msg.header = header; - }, - - /** - * Write out user data header. - * - * @param options - * Options containing information for user data header write-out. The - * `userDataHeaderLength` property must be correctly pre-calculated. - */ - writeUserDataHeader: function(options) { - this.writeHexOctet(options.userDataHeaderLength); - - if (options.segmentMaxSeq > 1) { - if (options.segmentRef16Bit) { - this.writeHexOctet(PDU_IEI_CONCATENATED_SHORT_MESSAGES_16BIT); - this.writeHexOctet(4); - this.writeHexOctet((options.segmentRef >> 8) & 0xFF); - } else { - this.writeHexOctet(PDU_IEI_CONCATENATED_SHORT_MESSAGES_8BIT); - this.writeHexOctet(3); - } - this.writeHexOctet(options.segmentRef & 0xFF); - this.writeHexOctet(options.segmentMaxSeq & 0xFF); - this.writeHexOctet(options.segmentSeq & 0xFF); - } - - if (options.dcs == PDU_DCS_MSG_CODING_7BITS_ALPHABET) { - if (options.langIndex != PDU_NL_IDENTIFIER_DEFAULT) { - this.writeHexOctet(PDU_IEI_NATIONAL_LANGUAGE_LOCKING_SHIFT); - this.writeHexOctet(1); - this.writeHexOctet(options.langIndex); - } - - if (options.langShiftIndex != PDU_NL_IDENTIFIER_DEFAULT) { - this.writeHexOctet(PDU_IEI_NATIONAL_LANGUAGE_SINGLE_SHIFT); - this.writeHexOctet(1); - this.writeHexOctet(options.langShiftIndex); - } - } - }, - - /** - * Read SM-TL Address. - * - * @param len - * Length of useful semi-octets within the Address-Value field. For - * example, the lenth of "12345" should be 5, and 4 for "1234". - * - * @see 3GPP TS 23.040 9.1.2.5 - */ - readAddress: function(len) { - // Address Length - if (!len || (len < 0)) { - if (DEBUG) { - this.context.debug("PDU error: invalid sender address length: " + len); - } - return null; - } - if (len % 2 == 1) { - len += 1; - } - if (DEBUG) this.context.debug("PDU: Going to read address: " + len); - - // Type-of-Address - let toa = this.readHexOctet(); - let addr = ""; - - if ((toa & 0xF0) == PDU_TOA_ALPHANUMERIC) { - addr = this.readSeptetsToString(Math.floor(len * 4 / 7), 0, - PDU_NL_IDENTIFIER_DEFAULT , PDU_NL_IDENTIFIER_DEFAULT ); - return addr; - } - addr = this.readSwappedNibbleExtendedBcdString(len / 2); - if (addr.length <= 0) { - if (DEBUG) this.context.debug("PDU error: no number provided"); - return null; - } - if ((toa & 0xF0) == (PDU_TOA_INTERNATIONAL)) { - addr = '+' + addr; - } - - return addr; - }, - - /** - * Read TP-Protocol-Indicator(TP-PID). - * - * @param msg - * message object for output. - * - * @see 3GPP TS 23.040 9.2.3.9 - */ - readProtocolIndicator: function(msg) { - // `The MS shall interpret reserved, obsolete, or unsupported values as the - // value 00000000 but shall store them exactly as received.` - msg.pid = this.readHexOctet(); - - msg.epid = msg.pid; - switch (msg.epid & 0xC0) { - case 0x40: - // Bit 7..0 = 01xxxxxx - switch (msg.epid) { - case PDU_PID_SHORT_MESSAGE_TYPE_0: - case PDU_PID_ANSI_136_R_DATA: - case PDU_PID_USIM_DATA_DOWNLOAD: - return; - } - break; - } - - msg.epid = PDU_PID_DEFAULT; - }, - - /** - * Read TP-Data-Coding-Scheme(TP-DCS) - * - * @param msg - * message object for output. - * - * @see 3GPP TS 23.040 9.2.3.10, 3GPP TS 23.038 4. - */ - readDataCodingScheme: function(msg) { - let dcs = this.readHexOctet(); - if (DEBUG) this.context.debug("PDU: read SMS dcs: " + dcs); - - // No message class by default. - let messageClass = PDU_DCS_MSG_CLASS_NORMAL; - // 7 bit is the default fallback encoding. - let encoding = PDU_DCS_MSG_CODING_7BITS_ALPHABET; - switch (dcs & PDU_DCS_CODING_GROUP_BITS) { - case 0x40: // bits 7..4 = 01xx - case 0x50: - case 0x60: - case 0x70: - // Bit 5..0 are coded exactly the same as Group 00xx - case 0x00: // bits 7..4 = 00xx - case 0x10: - case 0x20: - case 0x30: - if (dcs & 0x10) { - messageClass = dcs & PDU_DCS_MSG_CLASS_BITS; - } - switch (dcs & 0x0C) { - case 0x4: - encoding = PDU_DCS_MSG_CODING_8BITS_ALPHABET; - break; - case 0x8: - encoding = PDU_DCS_MSG_CODING_16BITS_ALPHABET; - break; - } - break; - - case 0xE0: // bits 7..4 = 1110 - encoding = PDU_DCS_MSG_CODING_16BITS_ALPHABET; - // Bit 3..0 are coded exactly the same as Message Waiting Indication - // Group 1101. - // Fall through. - case 0xC0: // bits 7..4 = 1100 - case 0xD0: // bits 7..4 = 1101 - // Indiciates voicemail indicator set or clear - let active = (dcs & PDU_DCS_MWI_ACTIVE_BITS) == PDU_DCS_MWI_ACTIVE_VALUE; - - // If TP-UDH is present, these values will be overwritten - switch (dcs & PDU_DCS_MWI_TYPE_BITS) { - case PDU_DCS_MWI_TYPE_VOICEMAIL: - let mwi = msg.mwi; - if (!mwi) { - mwi = msg.mwi = {}; - } - - mwi.active = active; - mwi.discard = (dcs & PDU_DCS_CODING_GROUP_BITS) == 0xC0; - mwi.msgCount = active ? GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN : 0; - - if (DEBUG) { - this.context.debug("MWI in DCS received for voicemail: " + - JSON.stringify(mwi)); - } - break; - case PDU_DCS_MWI_TYPE_FAX: - if (DEBUG) this.context.debug("MWI in DCS received for fax"); - break; - case PDU_DCS_MWI_TYPE_EMAIL: - if (DEBUG) this.context.debug("MWI in DCS received for email"); - break; - default: - if (DEBUG) this.context.debug("MWI in DCS received for \"other\""); - break; - } - break; - - case 0xF0: // bits 7..4 = 1111 - if (dcs & 0x04) { - encoding = PDU_DCS_MSG_CODING_8BITS_ALPHABET; - } - messageClass = dcs & PDU_DCS_MSG_CLASS_BITS; - break; - - default: - // Falling back to default encoding. - break; - } - - msg.dcs = dcs; - msg.encoding = encoding; - msg.messageClass = GECKO_SMS_MESSAGE_CLASSES[messageClass]; - - if (DEBUG) this.context.debug("PDU: message encoding is " + encoding + " bit."); - }, - - /** - * Read GSM TP-Service-Centre-Time-Stamp(TP-SCTS). - * - * @see 3GPP TS 23.040 9.2.3.11 - */ - readTimestamp: function() { - let year = this.readSwappedNibbleBcdNum(1) + PDU_TIMESTAMP_YEAR_OFFSET; - let month = this.readSwappedNibbleBcdNum(1) - 1; - let day = this.readSwappedNibbleBcdNum(1); - let hour = this.readSwappedNibbleBcdNum(1); - let minute = this.readSwappedNibbleBcdNum(1); - let second = this.readSwappedNibbleBcdNum(1); - let timestamp = Date.UTC(year, month, day, hour, minute, second); - - // If the most significant bit of the least significant nibble is 1, - // the timezone offset is negative (fourth bit from the right => 0x08): - // localtime = UTC + tzOffset - // therefore - // UTC = localtime - tzOffset - let tzOctet = this.readHexOctet(); - let tzOffset = this.octetToBCD(tzOctet & ~0x08) * 15 * 60 * 1000; - tzOffset = (tzOctet & 0x08) ? -tzOffset : tzOffset; - timestamp -= tzOffset; - - return timestamp; - }, - - /** - * Write GSM TP-Service-Centre-Time-Stamp(TP-SCTS). - * - * @see 3GPP TS 23.040 9.2.3.11 - */ - writeTimestamp: function(date) { - this.writeSwappedNibbleBCDNum(date.getFullYear() - PDU_TIMESTAMP_YEAR_OFFSET); - - // The value returned by getMonth() is an integer between 0 and 11. - // 0 is corresponds to January, 1 to February, and so on. - this.writeSwappedNibbleBCDNum(date.getMonth() + 1); - this.writeSwappedNibbleBCDNum(date.getDate()); - this.writeSwappedNibbleBCDNum(date.getHours()); - this.writeSwappedNibbleBCDNum(date.getMinutes()); - this.writeSwappedNibbleBCDNum(date.getSeconds()); - - // the value returned by getTimezoneOffset() is the difference, - // in minutes, between UTC and local time. - // For example, if your time zone is UTC+10 (Australian Eastern Standard Time), - // -600 will be returned. - // In TS 23.040 9.2.3.11, the Time Zone field of TP-SCTS indicates - // the different between the local time and GMT. - // And expressed in quarters of an hours. (so need to divid by 15) - let zone = date.getTimezoneOffset() / 15; - let octet = this.BCDToOctet(zone); - - // the bit3 of the Time Zone field represents the algebraic sign. - // (0: positive, 1: negative). - // For example, if the time zone is -0800 GMT, - // 480 will be returned by getTimezoneOffset(). - // In this case, need to mark sign bit as 1. => 0x08 - if (zone > 0) { - octet = octet | 0x08; - } - this.writeHexOctet(octet); - }, - - /** - * User data can be 7 bit (default alphabet) data, 8 bit data, or 16 bit - * (UCS2) data. - * - * @param msg - * message object for output. - * @param length - * length of user data to read in octets. - */ - readUserData: function(msg, length) { - if (DEBUG) { - this.context.debug("Reading " + length + " bytes of user data."); - } - - let paddingBits = 0; - if (msg.udhi) { - this.readUserDataHeader(msg); - - if (msg.encoding == PDU_DCS_MSG_CODING_7BITS_ALPHABET) { - let headerBits = (msg.header.length + 1) * 8; - let headerSeptets = Math.ceil(headerBits / 7); - - length -= headerSeptets; - paddingBits = headerSeptets * 7 - headerBits; - } else { - length -= (msg.header.length + 1); - } - } - - if (DEBUG) { - this.context.debug("After header, " + length + " septets left of user data"); - } - - msg.body = null; - msg.data = null; - - if (length <= 0) { - // No data to read. - return; - } - - switch (msg.encoding) { - case PDU_DCS_MSG_CODING_7BITS_ALPHABET: - // 7 bit encoding allows 140 octets, which means 160 characters - // ((140x8) / 7 = 160 chars) - if (length > PDU_MAX_USER_DATA_7BIT) { - if (DEBUG) { - this.context.debug("PDU error: user data is too long: " + length); - } - break; - } - - let langIndex = msg.udhi ? msg.header.langIndex : PDU_NL_IDENTIFIER_DEFAULT; - let langShiftIndex = msg.udhi ? msg.header.langShiftIndex : PDU_NL_IDENTIFIER_DEFAULT; - msg.body = this.readSeptetsToString(length, paddingBits, langIndex, - langShiftIndex); - break; - case PDU_DCS_MSG_CODING_8BITS_ALPHABET: - msg.data = this.readHexOctetArray(length); - break; - case PDU_DCS_MSG_CODING_16BITS_ALPHABET: - msg.body = this.readUCS2String(length); - break; - } - }, - - /** - * Read extra parameters if TP-PI is set. - * - * @param msg - * message object for output. - */ - readExtraParams: function(msg) { - // Because each PDU octet is converted to two UCS2 char2, we should always - // get even messageStringLength in this#_processReceivedSms(). So, we'll - // always need two delimitors at the end. - if (this.context.Buf.getReadAvailable() <= 4) { - return; - } - - // TP-Parameter-Indicator - let pi; - do { - // `The most significant bit in octet 1 and any other TP-PI octets which - // may be added later is reserved as an extension bit which when set to a - // 1 shall indicate that another TP-PI octet follows immediately - // afterwards.` ~ 3GPP TS 23.040 9.2.3.27 - pi = this.readHexOctet(); - } while (pi & PDU_PI_EXTENSION); - - // `If the TP-UDL bit is set to "1" but the TP-DCS bit is set to "0" then - // the receiving entity shall for TP-DCS assume a value of 0x00, i.e. the - // 7bit default alphabet.` ~ 3GPP 23.040 9.2.3.27 - msg.dcs = 0; - msg.encoding = PDU_DCS_MSG_CODING_7BITS_ALPHABET; - - // TP-Protocol-Identifier - if (pi & PDU_PI_PROTOCOL_IDENTIFIER) { - this.readProtocolIndicator(msg); - } - // TP-Data-Coding-Scheme - if (pi & PDU_PI_DATA_CODING_SCHEME) { - this.readDataCodingScheme(msg); - } - // TP-User-Data-Length - if (pi & PDU_PI_USER_DATA_LENGTH) { - let userDataLength = this.readHexOctet(); - this.readUserData(msg, userDataLength); - } - }, - - /** - * Read and decode a PDU-encoded message from the stream. - * - * TODO: add some basic sanity checks like: - * - do we have the minimum number of chars available - */ - readMessage: function() { - // An empty message object. This gets filled below and then returned. - let msg = { - // D:DELIVER, DR:DELIVER-REPORT, S:SUBMIT, SR:SUBMIT-REPORT, - // ST:STATUS-REPORT, C:COMMAND - // M:Mandatory, O:Optional, X:Unavailable - // D DR S SR ST C - SMSC: null, // M M M M M M - mti: null, // M M M M M M - udhi: null, // M M O M M M - sender: null, // M X X X X X - recipient: null, // X X M X M M - pid: null, // M O M O O M - epid: null, // M O M O O M - dcs: null, // M O M O O X - mwi: null, // O O O O O O - replace: false, // O O O O O O - header: null, // M M O M M M - body: null, // M O M O O O - data: null, // M O M O O O - sentTimestamp: null, // M X X X X X - status: null, // X X X X M X - scts: null, // X X X M M X - dt: null, // X X X X M X - }; - - // SMSC info - let smscLength = this.readHexOctet(); - if (smscLength > 0) { - let smscTypeOfAddress = this.readHexOctet(); - // Subtract the type-of-address octet we just read from the length. - msg.SMSC = this.readSwappedNibbleExtendedBcdString(smscLength - 1); - if ((smscTypeOfAddress >> 4) == (PDU_TOA_INTERNATIONAL >> 4)) { - msg.SMSC = '+' + msg.SMSC; - } - } - - // First octet of this SMS-DELIVER or SMS-SUBMIT message - let firstOctet = this.readHexOctet(); - // Message Type Indicator - msg.mti = firstOctet & 0x03; - // User data header indicator - msg.udhi = firstOctet & PDU_UDHI; - - switch (msg.mti) { - case PDU_MTI_SMS_RESERVED: - // `If an MS receives a TPDU with a "Reserved" value in the TP-MTI it - // shall process the message as if it were an "SMS-DELIVER" but store - // the message exactly as received.` ~ 3GPP TS 23.040 9.2.3.1 - case PDU_MTI_SMS_DELIVER: - return this.readDeliverMessage(msg); - case PDU_MTI_SMS_STATUS_REPORT: - return this.readStatusReportMessage(msg); - default: - return null; - } - }, - - /** - * Helper for processing received SMS parcel data. - * - * @param length - * Length of SMS string in the incoming parcel. - * - * @return Message parsed or null for invalid message. - */ - processReceivedSms: function(length) { - if (!length) { - if (DEBUG) this.context.debug("Received empty SMS!"); - return [null, PDU_FCS_UNSPECIFIED]; - } - - let Buf = this.context.Buf; - - // An SMS is a string, but we won't read it as such, so let's read the - // string length and then defer to PDU parsing helper. - let messageStringLength = Buf.readInt32(); - if (DEBUG) this.context.debug("Got new SMS, length " + messageStringLength); - let message = this.readMessage(); - if (DEBUG) this.context.debug("Got new SMS: " + JSON.stringify(message)); - - // Read string delimiters. See Buf.readString(). - Buf.readStringDelimiter(length); - - // Determine result - if (!message) { - return [null, PDU_FCS_UNSPECIFIED]; - } - - if (message.epid == PDU_PID_SHORT_MESSAGE_TYPE_0) { - // `A short message type 0 indicates that the ME must acknowledge receipt - // of the short message but shall discard its contents.` ~ 3GPP TS 23.040 - // 9.2.3.9 - return [null, PDU_FCS_OK]; - } - - if (message.messageClass == GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]) { - let RIL = this.context.RIL; - switch (message.epid) { - case PDU_PID_ANSI_136_R_DATA: - case PDU_PID_USIM_DATA_DOWNLOAD: - let ICCUtilsHelper = this.context.ICCUtilsHelper; - if (ICCUtilsHelper.isICCServiceAvailable("DATA_DOWNLOAD_SMS_PP")) { - // `If the service "data download via SMS Point-to-Point" is - // allocated and activated in the (U)SIM Service Table, ... then the - // ME shall pass the message transparently to the UICC using the - // ENVELOPE (SMS-PP DOWNLOAD).` ~ 3GPP TS 31.111 7.1.1.1 - RIL.dataDownloadViaSMSPP(message); - - // `the ME shall not display the message, or alert the user of a - // short message waiting.` ~ 3GPP TS 31.111 7.1.1.1 - return [null, PDU_FCS_RESERVED]; - } - - // If the service "data download via SMS-PP" is not available in the - // (U)SIM Service Table, ..., then the ME shall store the message in - // EFsms in accordance with TS 31.102` ~ 3GPP TS 31.111 7.1.1.1 - - // Fall through. - default: - RIL.writeSmsToSIM(message); - break; - } - } - - // TODO: Bug 739143: B2G SMS: Support SMS Storage Full event - if ((message.messageClass != GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]) && !true) { - // `When a mobile terminated message is class 0..., the MS shall display - // the message immediately and send a ACK to the SC ..., irrespective of - // whether there is memory available in the (U)SIM or ME.` ~ 3GPP 23.038 - // clause 4. - - if (message.messageClass == GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]) { - // `If all the short message storage at the MS is already in use, the - // MS shall return "memory capacity exceeded".` ~ 3GPP 23.038 clause 4. - return [null, PDU_FCS_MEMORY_CAPACITY_EXCEEDED]; - } - - return [null, PDU_FCS_UNSPECIFIED]; - } - - return [message, PDU_FCS_OK]; - }, - - /** - * Read and decode a SMS-DELIVER PDU. - * - * @param msg - * message object for output. - */ - readDeliverMessage: function(msg) { - // - Sender Address info - - let senderAddressLength = this.readHexOctet(); - msg.sender = this.readAddress(senderAddressLength); - // - TP-Protocolo-Identifier - - this.readProtocolIndicator(msg); - // - TP-Data-Coding-Scheme - - this.readDataCodingScheme(msg); - // - TP-Service-Center-Time-Stamp - - msg.sentTimestamp = this.readTimestamp(); - // - TP-User-Data-Length - - let userDataLength = this.readHexOctet(); - - // - TP-User-Data - - if (userDataLength > 0) { - this.readUserData(msg, userDataLength); - } - - return msg; - }, - - /** - * Read and decode a SMS-STATUS-REPORT PDU. - * - * @param msg - * message object for output. - */ - readStatusReportMessage: function(msg) { - // TP-Message-Reference - msg.messageRef = this.readHexOctet(); - // TP-Recipient-Address - let recipientAddressLength = this.readHexOctet(); - msg.recipient = this.readAddress(recipientAddressLength); - // TP-Service-Centre-Time-Stamp - msg.scts = this.readTimestamp(); - // TP-Discharge-Time - msg.dt = this.readTimestamp(); - // TP-Status - msg.status = this.readHexOctet(); - - this.readExtraParams(msg); - - return msg; - }, - - /** - * Serialize a SMS-SUBMIT PDU message and write it to the output stream. - * - * This method expects that a data coding scheme has been chosen already - * and that the length of the user data payload in that encoding is known, - * too. Both go hand in hand together anyway. - * - * @param address - * String containing the address (number) of the SMS receiver - * @param userData - * String containing the message to be sent as user data - * @param dcs - * Data coding scheme. One of the PDU_DCS_MSG_CODING_*BITS_ALPHABET - * constants. - * @param userDataHeaderLength - * Length of embedded user data header, in bytes. The whole header - * size will be userDataHeaderLength + 1; 0 for no header. - * @param encodedBodyLength - * Length of the user data when encoded with the given DCS. For UCS2, - * in bytes; for 7-bit, in septets. - * @param langIndex - * Table index used for normal 7-bit encoded character lookup. - * @param langShiftIndex - * Table index used for escaped 7-bit encoded character lookup. - * @param requestStatusReport - * Request status report. - */ - writeMessage: function(options) { - if (DEBUG) { - this.context.debug("writeMessage: " + JSON.stringify(options)); - } - let Buf = this.context.Buf; - let address = options.number; - let body = options.body; - let dcs = options.dcs; - let userDataHeaderLength = options.userDataHeaderLength; - let encodedBodyLength = options.encodedBodyLength; - let langIndex = options.langIndex; - let langShiftIndex = options.langShiftIndex; - - // SMS-SUBMIT Format: - // - // PDU Type - 1 octet - // Message Reference - 1 octet - // DA - Destination Address - 2 to 12 octets - // PID - Protocol Identifier - 1 octet - // DCS - Data Coding Scheme - 1 octet - // VP - Validity Period - 0, 1 or 7 octets - // UDL - User Data Length - 1 octet - // UD - User Data - 140 octets - - let addressFormat = PDU_TOA_ISDN; // 81 - if (address[0] == '+') { - addressFormat = PDU_TOA_INTERNATIONAL | PDU_TOA_ISDN; // 91 - address = address.substring(1); - } - //TODO validity is unsupported for now - let validity = 0; - - let headerOctets = (userDataHeaderLength ? userDataHeaderLength + 1 : 0); - let paddingBits; - let userDataLengthInSeptets; - let userDataLengthInOctets; - if (dcs == PDU_DCS_MSG_CODING_7BITS_ALPHABET) { - let headerSeptets = Math.ceil(headerOctets * 8 / 7); - userDataLengthInSeptets = headerSeptets + encodedBodyLength; - userDataLengthInOctets = Math.ceil(userDataLengthInSeptets * 7 / 8); - paddingBits = headerSeptets * 7 - headerOctets * 8; - } else { - userDataLengthInOctets = headerOctets + encodedBodyLength; - paddingBits = 0; - } - - let pduOctetLength = 4 + // PDU Type, Message Ref, address length + format - Math.ceil(address.length / 2) + - 3 + // PID, DCS, UDL - userDataLengthInOctets; - if (validity) { - //TODO: add more to pduOctetLength - } - - // Start the string. Since octets are represented in hex, we will need - // twice as many characters as octets. - Buf.writeInt32(pduOctetLength * 2); - - // - PDU-TYPE- - - // +--------+----------+---------+---------+--------+---------+ - // | RP (1) | UDHI (1) | SRR (1) | VPF (2) | RD (1) | MTI (2) | - // +--------+----------+---------+---------+--------+---------+ - // RP: 0 Reply path parameter is not set - // 1 Reply path parameter is set - // UDHI: 0 The UD Field contains only the short message - // 1 The beginning of the UD field contains a header in addition - // of the short message - // SRR: 0 A status report is not requested - // 1 A status report is requested - // VPF: bit4 bit3 - // 0 0 VP field is not present - // 0 1 Reserved - // 1 0 VP field present an integer represented (relative) - // 1 1 VP field present a semi-octet represented (absolute) - // RD: Instruct the SMSC to accept(0) or reject(1) an SMS-SUBMIT - // for a short message still held in the SMSC which has the same - // MR and DA as a previously submitted short message from the - // same OA - // MTI: bit1 bit0 Message Type - // 0 0 SMS-DELIVER (SMSC ==> MS) - // 0 1 SMS-SUBMIT (MS ==> SMSC) - - // PDU type. MTI is set to SMS-SUBMIT - let firstOctet = PDU_MTI_SMS_SUBMIT; - - // Status-Report-Request - if (options.requestStatusReport) { - firstOctet |= PDU_SRI_SRR; - } - - // Validity period - if (validity) { - //TODO: not supported yet, OR with one of PDU_VPF_* - } - // User data header indicator - if (headerOctets) { - firstOctet |= PDU_UDHI; - } - this.writeHexOctet(firstOctet); - - // Message reference 00 - this.writeHexOctet(0x00); - - // - Destination Address - - this.writeHexOctet(address.length); - this.writeHexOctet(addressFormat); - this.writeSwappedNibbleBCD(address); - - // - Protocol Identifier - - this.writeHexOctet(0x00); - - // - Data coding scheme - - // For now it assumes bits 7..4 = 1111 except for the 16 bits use case - this.writeHexOctet(dcs); - - // - Validity Period - - if (validity) { - this.writeHexOctet(validity); - } - - // - User Data - - if (dcs == PDU_DCS_MSG_CODING_7BITS_ALPHABET) { - this.writeHexOctet(userDataLengthInSeptets); - } else { - this.writeHexOctet(userDataLengthInOctets); - } - - if (headerOctets) { - this.writeUserDataHeader(options); - } - - switch (dcs) { - case PDU_DCS_MSG_CODING_7BITS_ALPHABET: - this.writeStringAsSeptets(body, paddingBits, langIndex, langShiftIndex); - break; - case PDU_DCS_MSG_CODING_8BITS_ALPHABET: - // Unsupported. - break; - case PDU_DCS_MSG_CODING_16BITS_ALPHABET: - this.writeUCS2String(body); - break; - } - - // End of the string. The string length is always even by definition, so - // we write two \0 delimiters. - Buf.writeUint16(0); - Buf.writeUint16(0); - }, - - /** - * Read GSM CBS message serial number. - * - * @param msg - * message object for output. - * - * @see 3GPP TS 23.041 section 9.4.1.2.1 - */ - readCbSerialNumber: function(msg) { - let Buf = this.context.Buf; - msg.serial = Buf.readUint8() << 8 | Buf.readUint8(); - msg.geographicalScope = (msg.serial >>> 14) & 0x03; - msg.messageCode = (msg.serial >>> 4) & 0x03FF; - msg.updateNumber = msg.serial & 0x0F; - }, - - /** - * Read GSM CBS message message identifier. - * - * @param msg - * message object for output. - * - * @see 3GPP TS 23.041 section 9.4.1.2.2 - */ - readCbMessageIdentifier: function(msg) { - let Buf = this.context.Buf; - msg.messageId = Buf.readUint8() << 8 | Buf.readUint8(); - }, - - /** - * Read ETWS information from message identifier and serial Number - * @param msg - * message object for output. - * - * @see 3GPP TS 23.041 section 9.4.1.2.1 & 9.4.1.2.2 - */ - readCbEtwsInfo: function(msg) { - if ((msg.format != CB_FORMAT_ETWS) - && (msg.messageId >= CB_GSM_MESSAGEID_ETWS_BEGIN) - && (msg.messageId <= CB_GSM_MESSAGEID_ETWS_END)) { - // `In the case of transmitting CBS message for ETWS, a part of - // Message Code can be used to command mobile terminals to activate - // emergency user alert and message popup in order to alert the users.` - msg.etws = { - emergencyUserAlert: msg.messageCode & 0x0200 ? true : false, - popup: msg.messageCode & 0x0100 ? true : false - }; - - let warningType = msg.messageId - CB_GSM_MESSAGEID_ETWS_BEGIN; - if (warningType < CB_ETWS_WARNING_TYPE_NAMES.length) { - msg.etws.warningType = warningType; - } - } - }, - - /** - * Read CBS Data Coding Scheme. - * - * @param msg - * message object for output. - * - * @see 3GPP TS 23.038 section 5. - */ - readCbDataCodingScheme: function(msg) { - let dcs = this.context.Buf.readUint8(); - if (DEBUG) this.context.debug("PDU: read CBS dcs: " + dcs); - - let language = null, hasLanguageIndicator = false; - // `Any reserved codings shall be assumed to be the GSM 7bit default - // alphabet.` - let encoding = PDU_DCS_MSG_CODING_7BITS_ALPHABET; - let messageClass = PDU_DCS_MSG_CLASS_NORMAL; - - switch (dcs & PDU_DCS_CODING_GROUP_BITS) { - case 0x00: // 0000 - language = CB_DCS_LANG_GROUP_1[dcs & 0x0F]; - break; - - case 0x10: // 0001 - switch (dcs & 0x0F) { - case 0x00: - hasLanguageIndicator = true; - break; - case 0x01: - encoding = PDU_DCS_MSG_CODING_16BITS_ALPHABET; - hasLanguageIndicator = true; - break; - } - break; - - case 0x20: // 0010 - language = CB_DCS_LANG_GROUP_2[dcs & 0x0F]; - break; - - case 0x40: // 01xx - case 0x50: - //case 0x60: Text Compression, not supported - //case 0x70: Text Compression, not supported - case 0x90: // 1001 - encoding = (dcs & 0x0C); - if (encoding == 0x0C) { - encoding = PDU_DCS_MSG_CODING_7BITS_ALPHABET; - } - messageClass = (dcs & PDU_DCS_MSG_CLASS_BITS); - break; - - case 0xF0: - encoding = (dcs & 0x04) ? PDU_DCS_MSG_CODING_8BITS_ALPHABET - : PDU_DCS_MSG_CODING_7BITS_ALPHABET; - switch(dcs & PDU_DCS_MSG_CLASS_BITS) { - case 0x01: messageClass = PDU_DCS_MSG_CLASS_USER_1; break; - case 0x02: messageClass = PDU_DCS_MSG_CLASS_USER_2; break; - case 0x03: messageClass = PDU_DCS_MSG_CLASS_3; break; - } - break; - - case 0x30: // 0011 (Reserved) - case 0x80: // 1000 (Reserved) - case 0xA0: // 1010..1100 (Reserved) - case 0xB0: - case 0xC0: - break; - - default: - throw new Error("Unsupported CBS data coding scheme: " + dcs); - } - - msg.dcs = dcs; - msg.encoding = encoding; - msg.language = language; - msg.messageClass = GECKO_SMS_MESSAGE_CLASSES[messageClass]; - msg.hasLanguageIndicator = hasLanguageIndicator; - }, - - /** - * Read GSM CBS message page parameter. - * - * @param msg - * message object for output. - * - * @see 3GPP TS 23.041 section 9.4.1.2.4 - */ - readCbPageParameter: function(msg) { - let octet = this.context.Buf.readUint8(); - msg.pageIndex = (octet >>> 4) & 0x0F; - msg.numPages = octet & 0x0F; - if (!msg.pageIndex || !msg.numPages) { - // `If a mobile receives the code 0000 in either the first field or the - // second field then it shall treat the CBS message exactly the same as a - // CBS message with page parameter 0001 0001 (i.e. a single page message).` - msg.pageIndex = msg.numPages = 1; - } - }, - - /** - * Read ETWS Primary Notification message warning type. - * - * @param msg - * message object for output. - * - * @see 3GPP TS 23.041 section 9.3.24 - */ - readCbWarningType: function(msg) { - let Buf = this.context.Buf; - let word = Buf.readUint8() << 8 | Buf.readUint8(); - msg.etws = { - warningType: (word >>> 9) & 0x7F, - popup: word & 0x80 ? true : false, - emergencyUserAlert: word & 0x100 ? true : false - }; - }, - - /** - * Read GSM CB Data - * - * This parameter is a copy of the 'CBS-Message-Information-Page' as sent - * from the CBC to the BSC. - * - * @see 3GPP TS 23.041 section 9.4.1.2.5 - */ - readGsmCbData: function(msg, length) { - let Buf = this.context.Buf; - let bufAdapter = { - context: this.context, - readHexOctet: function() { - return Buf.readUint8(); - } - }; - - msg.body = null; - msg.data = null; - switch (msg.encoding) { - case PDU_DCS_MSG_CODING_7BITS_ALPHABET: - msg.body = this.readSeptetsToString.call(bufAdapter, - Math.floor(length * 8 / 7), 0, - PDU_NL_IDENTIFIER_DEFAULT, - PDU_NL_IDENTIFIER_DEFAULT); - if (msg.hasLanguageIndicator) { - msg.language = msg.body.substring(0, 2); - msg.body = msg.body.substring(3); - } - break; - - case PDU_DCS_MSG_CODING_8BITS_ALPHABET: - msg.data = Buf.readUint8Array(length); - break; - - case PDU_DCS_MSG_CODING_16BITS_ALPHABET: - if (msg.hasLanguageIndicator) { - msg.language = this.readSeptetsToString.call(bufAdapter, 2, 0, - PDU_NL_IDENTIFIER_DEFAULT, - PDU_NL_IDENTIFIER_DEFAULT); - length -= 2; - } - msg.body = this.readUCS2String.call(bufAdapter, length); - break; - } - - if (msg.data || !msg.body) { - return; - } - - // According to 9.3.19 CBS-Message-Information-Page in TS 23.041: - // " - // This parameter is of a fixed length of 82 octets and carries up to and - // including 82 octets of user information. Where the user information is - // less than 82 octets, the remaining octets must be filled with padding. - // " - // According to 6.2.1.1 GSM 7 bit Default Alphabet and 6.2.3 UCS2 in - // TS 23.038, the padding character is <CR>. - for (let i = msg.body.length - 1; i >= 0; i--) { - if (msg.body.charAt(i) !== '\r') { - msg.body = msg.body.substring(0, i + 1); - break; - } - } - }, - - /** - * Read UMTS CB Data - * - * Octet Number(s) Parameter - * 1 Number-of-Pages - * 2 - 83 CBS-Message-Information-Page 1 - * 84 CBS-Message-Information-Length 1 - * ... - * CBS-Message-Information-Page n - * CBS-Message-Information-Length n - * - * @see 3GPP TS 23.041 section 9.4.2.2.5 - */ - readUmtsCbData: function(msg) { - let Buf = this.context.Buf; - let numOfPages = Buf.readUint8(); - if (numOfPages < 0 || numOfPages > 15) { - throw new Error("Invalid numOfPages: " + numOfPages); - } - - let bufAdapter = { - context: this.context, - readHexOctet: function() { - return Buf.readUint8(); - } - }; - - let removePaddingCharactors = function (text) { - for (let i = text.length - 1; i >= 0; i--) { - if (text.charAt(i) !== '\r') { - return text.substring(0, i + 1); - } - } - return text; - }; - - let totalLength = 0, length, pageLengths = []; - for (let i = 0; i < numOfPages; i++) { - Buf.seekIncoming(CB_MSG_PAGE_INFO_SIZE); - length = Buf.readUint8(); - totalLength += length; - pageLengths.push(length); - } - - // Seek back to beginning of CB Data. - Buf.seekIncoming(-numOfPages * (CB_MSG_PAGE_INFO_SIZE + 1)); - - switch (msg.encoding) { - case PDU_DCS_MSG_CODING_7BITS_ALPHABET: { - let body; - msg.body = ""; - for (let i = 0; i < numOfPages; i++) { - body = this.readSeptetsToString.call(bufAdapter, - Math.floor(pageLengths[i] * 8 / 7), - 0, - PDU_NL_IDENTIFIER_DEFAULT, - PDU_NL_IDENTIFIER_DEFAULT); - if (msg.hasLanguageIndicator) { - if (!msg.language) { - msg.language = body.substring(0, 2); - } - body = body.substring(3); - } - - msg.body += removePaddingCharactors(body); - - // Skip padding octets - Buf.seekIncoming(CB_MSG_PAGE_INFO_SIZE - pageLengths[i]); - // Read the octet of CBS-Message-Information-Length - Buf.readUint8(); - } - - break; - } - - case PDU_DCS_MSG_CODING_8BITS_ALPHABET: { - msg.data = new Uint8Array(totalLength); - for (let i = 0, j = 0; i < numOfPages; i++) { - for (let pageLength = pageLengths[i]; pageLength > 0; pageLength--) { - msg.data[j++] = Buf.readUint8(); - } - - // Skip padding octets - Buf.seekIncoming(CB_MSG_PAGE_INFO_SIZE - pageLengths[i]); - // Read the octet of CBS-Message-Information-Length - Buf.readUint8(); - } - - break; - } - - case PDU_DCS_MSG_CODING_16BITS_ALPHABET: { - msg.body = ""; - for (let i = 0; i < numOfPages; i++) { - let pageLength = pageLengths[i]; - if (msg.hasLanguageIndicator) { - if (!msg.language) { - msg.language = this.readSeptetsToString.call(bufAdapter, - 2, - 0, - PDU_NL_IDENTIFIER_DEFAULT, - PDU_NL_IDENTIFIER_DEFAULT); - } else { - Buf.readUint16(); - } - - pageLength -= 2; - } - - msg.body += removePaddingCharactors( - this.readUCS2String.call(bufAdapter, pageLength)); - - // Skip padding octets - Buf.seekIncoming(CB_MSG_PAGE_INFO_SIZE - pageLengths[i]); - // Read the octet of CBS-Message-Information-Length - Buf.readUint8(); - } - - break; - } - } - }, - - /** - * Read Cell GSM/ETWS/UMTS Broadcast Message. - * - * @param pduLength - * total length of the incoming PDU in octets. - */ - readCbMessage: function(pduLength) { - // Validity GSM ETWS UMTS - let msg = { - // Internally used in ril_worker: - serial: null, // O O O - updateNumber: null, // O O O - format: null, // O O O - dcs: 0x0F, // O X O - encoding: PDU_DCS_MSG_CODING_7BITS_ALPHABET, // O X O - hasLanguageIndicator: false, // O X O - data: null, // O X O - body: null, // O X O - pageIndex: 1, // O X X - numPages: 1, // O X X - - // DOM attributes: - geographicalScope: null, // O O O - messageCode: null, // O O O - messageId: null, // O O O - language: null, // O X O - fullBody: null, // O X O - fullData: null, // O X O - messageClass: GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], // O x O - etws: null // ? O ? - /*{ - warningType: null, // X O X - popup: false, // X O X - emergencyUserAlert: false, // X O X - }*/ - }; - - if (pduLength <= CB_MESSAGE_SIZE_ETWS) { - msg.format = CB_FORMAT_ETWS; - return this.readEtwsCbMessage(msg); - } - - if (pduLength <= CB_MESSAGE_SIZE_GSM) { - msg.format = CB_FORMAT_GSM; - return this.readGsmCbMessage(msg, pduLength); - } - - if (pduLength >= CB_MESSAGE_SIZE_UMTS_MIN && - pduLength <= CB_MESSAGE_SIZE_UMTS_MAX) { - msg.format = CB_FORMAT_UMTS; - return this.readUmtsCbMessage(msg); - } - - throw new Error("Invalid PDU Length: " + pduLength); - }, - - /** - * Read UMTS CBS Message. - * - * @param msg - * message object for output. - * - * @see 3GPP TS 23.041 section 9.4.2 - * @see 3GPP TS 25.324 section 10.2 - */ - readUmtsCbMessage: function(msg) { - let Buf = this.context.Buf; - let type = Buf.readUint8(); - if (type != CB_UMTS_MESSAGE_TYPE_CBS) { - throw new Error("Unsupported UMTS Cell Broadcast message type: " + type); - } - - this.readCbMessageIdentifier(msg); - this.readCbSerialNumber(msg); - this.readCbEtwsInfo(msg); - this.readCbDataCodingScheme(msg); - this.readUmtsCbData(msg); - - return msg; - }, - - /** - * Read GSM Cell Broadcast Message. - * - * @param msg - * message object for output. - * @param pduLength - * total length of the incomint PDU in octets. - * - * @see 3GPP TS 23.041 clause 9.4.1.2 - */ - readGsmCbMessage: function(msg, pduLength) { - this.readCbSerialNumber(msg); - this.readCbMessageIdentifier(msg); - this.readCbEtwsInfo(msg); - this.readCbDataCodingScheme(msg); - this.readCbPageParameter(msg); - - // GSM CB message header takes 6 octets. - this.readGsmCbData(msg, pduLength - 6); - - return msg; - }, - - /** - * Read ETWS Primary Notification Message. - * - * @param msg - * message object for output. - * - * @see 3GPP TS 23.041 clause 9.4.1.3 - */ - readEtwsCbMessage: function(msg) { - this.readCbSerialNumber(msg); - this.readCbMessageIdentifier(msg); - this.readCbWarningType(msg); - - // Octet 7..56 is Warning Security Information. However, according to - // section 9.4.1.3.6, `The UE shall ignore this parameter.` So we just skip - // processing it here. - - return msg; - }, - - /** - * Read network name. - * - * @param len Length of the information element. - * @return - * { - * networkName: network name. - * shouldIncludeCi: Should Country's initials included in text string. - * } - * @see TS 24.008 clause 10.5.3.5a. - */ - readNetworkName: function(len) { - // According to TS 24.008 Sec. 10.5.3.5a, the first octet is: - // bit 8: must be 1. - // bit 5-7: Text encoding. - // 000 - GSM default alphabet. - // 001 - UCS2 (16 bit). - // else - reserved. - // bit 4: MS should add the letters for Country's Initials and a space - // to the text string if this bit is true. - // bit 1-3: number of spare bits in last octet. - - let codingInfo = this.readHexOctet(); - if (!(codingInfo & 0x80)) { - return null; - } - - let textEncoding = (codingInfo & 0x70) >> 4; - let shouldIncludeCountryInitials = !!(codingInfo & 0x08); - let spareBits = codingInfo & 0x07; - let resultString; - - switch (textEncoding) { - case 0: - // GSM Default alphabet. - resultString = this.readSeptetsToString( - Math.floor(((len - 1) * 8 - spareBits) / 7), 0, - PDU_NL_IDENTIFIER_DEFAULT, - PDU_NL_IDENTIFIER_DEFAULT); - break; - case 1: - // UCS2 encoded. - resultString = this.context.ICCPDUHelper.readAlphaIdentifier(len - 1); - break; - default: - // Not an available text coding. - return null; - } - - // TODO - Bug 820286: According to shouldIncludeCountryInitials, add - // country initials to the resulting string. - return resultString; - } -}; - -/** - * Provide buffer with bitwise read/write function so make encoding/decoding easier. - */ -function BitBufferHelperObject(/* unused */aContext) { - this.readBuffer = []; - this.writeBuffer = []; -} -BitBufferHelperObject.prototype = { - readCache: 0, - readCacheSize: 0, - readBuffer: null, - readIndex: 0, - writeCache: 0, - writeCacheSize: 0, - writeBuffer: null, - - // Max length is 32 because we use integer as read/write cache. - // All read/write functions are implemented based on bitwise operation. - readBits: function(length) { - if (length <= 0 || length > 32) { - return null; - } - - if (length > this.readCacheSize) { - let bytesToRead = Math.ceil((length - this.readCacheSize) / 8); - for(let i = 0; i < bytesToRead; i++) { - this.readCache = (this.readCache << 8) | (this.readBuffer[this.readIndex++] & 0xFF); - this.readCacheSize += 8; - } - } - - let bitOffset = (this.readCacheSize - length), - resultMask = (1 << length) - 1, - result = 0; - - result = (this.readCache >> bitOffset) & resultMask; - this.readCacheSize -= length; - - return result; - }, - - backwardReadPilot: function(length) { - if (length <= 0) { - return; - } - - // Zero-based position. - let bitIndexToRead = this.readIndex * 8 - this.readCacheSize - length; - - if (bitIndexToRead < 0) { - return; - } - - // Update readIndex, readCache, readCacheSize accordingly. - let readBits = bitIndexToRead % 8; - this.readIndex = Math.floor(bitIndexToRead / 8) + ((readBits) ? 1 : 0); - this.readCache = (readBits) ? this.readBuffer[this.readIndex - 1] : 0; - this.readCacheSize = (readBits) ? (8 - readBits) : 0; - }, - - writeBits: function(value, length) { - if (length <= 0 || length > 32) { - return; - } - - let totalLength = length + this.writeCacheSize; - - // 8-byte cache not full - if (totalLength < 8) { - let valueMask = (1 << length) - 1; - this.writeCache = (this.writeCache << length) | (value & valueMask); - this.writeCacheSize += length; - return; - } - - // Deal with unaligned part - if (this.writeCacheSize) { - let mergeLength = 8 - this.writeCacheSize, - valueMask = (1 << mergeLength) - 1; - - this.writeCache = (this.writeCache << mergeLength) | ((value >> (length - mergeLength)) & valueMask); - this.writeBuffer.push(this.writeCache & 0xFF); - length -= mergeLength; - } - - // Aligned part, just copy - while (length >= 8) { - length -= 8; - this.writeBuffer.push((value >> length) & 0xFF); - } - - // Rest part is saved into cache - this.writeCacheSize = length; - this.writeCache = value & ((1 << length) - 1); - - return; - }, - - // Drop what still in read cache and goto next 8-byte alignment. - // There might be a better naming. - nextOctetAlign: function() { - this.readCache = 0; - this.readCacheSize = 0; - }, - - // Flush current write cache to Buf with padding 0s. - // There might be a better naming. - flushWithPadding: function() { - if (this.writeCacheSize) { - this.writeBuffer.push(this.writeCache << (8 - this.writeCacheSize)); - } - this.writeCache = 0; - this.writeCacheSize = 0; - }, - - startWrite: function(dataBuffer) { - this.writeBuffer = dataBuffer; - this.writeCache = 0; - this.writeCacheSize = 0; - }, - - startRead: function(dataBuffer) { - this.readBuffer = dataBuffer; - this.readCache = 0; - this.readCacheSize = 0; - this.readIndex = 0; - }, - - getWriteBufferSize: function() { - return this.writeBuffer.length; - }, - - overwriteWriteBuffer: function(position, data) { - let writeLength = data.length; - if (writeLength + position >= this.writeBuffer.length) { - writeLength = this.writeBuffer.length - position; - } - for (let i = 0; i < writeLength; i++) { - this.writeBuffer[i + position] = data[i]; - } - } -}; - -/** - * Helper for CDMA PDU - * - * Currently, some function are shared with GsmPDUHelper, they should be - * moved from GsmPDUHelper to a common object shared among GsmPDUHelper and - * CdmaPDUHelper. - */ -function CdmaPDUHelperObject(aContext) { - this.context = aContext; -} -CdmaPDUHelperObject.prototype = { - context: null, - - // 1..........C - // Only "1234567890*#" is defined in C.S0005-D v2.0 - dtmfChars: ".1234567890*#...", - - /** - * Entry point for SMS encoding, the options object is made compatible - * with existing writeMessage() of GsmPDUHelper, but less key is used. - * - * Current used key in options: - * @param number - * String containing the address (number) of the SMS receiver - * @param body - * String containing the message to be sent, segmented part - * @param dcs - * Data coding scheme. One of the PDU_DCS_MSG_CODING_*BITS_ALPHABET - * constants. - * @param encodedBodyLength - * Length of the user data when encoded with the given DCS. For UCS2, - * in bytes; for 7-bit, in septets. - * @param requestStatusReport - * Request status report. - * @param segmentRef - * Reference number of concatenated SMS message - * @param segmentMaxSeq - * Total number of concatenated SMS message - * @param segmentSeq - * Sequence number of concatenated SMS message - */ - writeMessage: function(options) { - if (DEBUG) { - this.context.debug("cdma_writeMessage: " + JSON.stringify(options)); - } - - // Get encoding - options.encoding = this.gsmDcsToCdmaEncoding(options.dcs); - - // Common Header - if (options.segmentMaxSeq > 1) { - this.writeInt(PDU_CDMA_MSG_TELESERIVCIE_ID_WEMT); - } else { - this.writeInt(PDU_CDMA_MSG_TELESERIVCIE_ID_SMS); - } - - this.writeInt(0); - this.writeInt(PDU_CDMA_MSG_CATEGORY_UNSPEC); - - // Just fill out address info in byte, rild will encap them for us - let addrInfo = this.encodeAddr(options.number); - this.writeByte(addrInfo.digitMode); - this.writeByte(addrInfo.numberMode); - this.writeByte(addrInfo.numberType); - this.writeByte(addrInfo.numberPlan); - this.writeByte(addrInfo.address.length); - for (let i = 0; i < addrInfo.address.length; i++) { - this.writeByte(addrInfo.address[i]); - } - - // Subaddress, not supported - this.writeByte(0); // Subaddress : Type - this.writeByte(0); // Subaddress : Odd - this.writeByte(0); // Subaddress : length - - // User Data - let encodeResult = this.encodeUserData(options); - this.writeByte(encodeResult.length); - for (let i = 0; i < encodeResult.length; i++) { - this.writeByte(encodeResult[i]); - } - - encodeResult = null; - }, - - /** - * Data writters - */ - writeInt: function(value) { - this.context.Buf.writeInt32(value); - }, - - writeByte: function(value) { - this.context.Buf.writeInt32(value & 0xFF); - }, - - /** - * Transform GSM DCS to CDMA encoding. - */ - gsmDcsToCdmaEncoding: function(encoding) { - switch (encoding) { - case PDU_DCS_MSG_CODING_7BITS_ALPHABET: - return PDU_CDMA_MSG_CODING_7BITS_ASCII; - case PDU_DCS_MSG_CODING_8BITS_ALPHABET: - return PDU_CDMA_MSG_CODING_OCTET; - case PDU_DCS_MSG_CODING_16BITS_ALPHABET: - return PDU_CDMA_MSG_CODING_UNICODE; - } - throw new Error("gsmDcsToCdmaEncoding(): Invalid GSM SMS DCS value: " + encoding); - }, - - /** - * Encode address into CDMA address format, as a byte array. - * - * @see 3GGP2 C.S0015-B 2.0, 3.4.3.3 Address Parameters - * - * @param address - * String of address to be encoded - */ - encodeAddr: function(address) { - let result = {}; - - result.numberType = PDU_CDMA_MSG_ADDR_NUMBER_TYPE_UNKNOWN; - result.numberPlan = PDU_CDMA_MSG_ADDR_NUMBER_TYPE_UNKNOWN; - - if (address[0] === '+') { - address = address.substring(1); - } - - // Try encode with DTMF first - result.digitMode = PDU_CDMA_MSG_ADDR_DIGIT_MODE_DTMF; - result.numberMode = PDU_CDMA_MSG_ADDR_NUMBER_MODE_ANSI; - - result.address = []; - for (let i = 0; i < address.length; i++) { - let addrDigit = this.dtmfChars.indexOf(address.charAt(i)); - if (addrDigit < 0) { - result.digitMode = PDU_CDMA_MSG_ADDR_DIGIT_MODE_ASCII; - result.numberMode = PDU_CDMA_MSG_ADDR_NUMBER_MODE_ASCII; - result.address = []; - break; - } - result.address.push(addrDigit); - } - - // Address can't be encoded with DTMF, then use 7-bit ASCII - if (result.digitMode !== PDU_CDMA_MSG_ADDR_DIGIT_MODE_DTMF) { - if (address.indexOf("@") !== -1) { - result.numberType = PDU_CDMA_MSG_ADDR_NUMBER_TYPE_NATIONAL; - } - - for (let i = 0; i < address.length; i++) { - result.address.push(address.charCodeAt(i) & 0x7F); - } - } - - return result; - }, - - /** - * Encode SMS contents in options into CDMA userData field. - * Corresponding and required subparameters will be added automatically. - * - * @see 3GGP2 C.S0015-B 2.0, 3.4.3.7 Bearer Data - * 4.5 Bearer Data Parameters - * - * Current used key in options: - * @param body - * String containing the message to be sent, segmented part - * @param encoding - * Encoding method of CDMA, can be transformed from GSM DCS by function - * cdmaPduHelp.gsmDcsToCdmaEncoding() - * @param encodedBodyLength - * Length of the user data when encoded with the given DCS. For UCS2, - * in bytes; for 7-bit, in septets. - * @param requestStatusReport - * Request status report. - * @param segmentRef - * Reference number of concatenated SMS message - * @param segmentMaxSeq - * Total number of concatenated SMS message - * @param segmentSeq - * Sequence number of concatenated SMS message - */ - encodeUserData: function(options) { - let userDataBuffer = []; - this.context.BitBufferHelper.startWrite(userDataBuffer); - - // Message Identifier - this.encodeUserDataMsgId(options); - - // User Data - this.encodeUserDataMsg(options); - - // Reply Option - this.encodeUserDataReplyOption(options); - - return userDataBuffer; - }, - - /** - * User data subparameter encoder : Message Identifier - * - * @see 3GGP2 C.S0015-B 2.0, 4.5.1 Message Identifier - */ - encodeUserDataMsgId: function(options) { - let BitBufferHelper = this.context.BitBufferHelper; - BitBufferHelper.writeBits(PDU_CDMA_MSG_USERDATA_MSG_ID, 8); - BitBufferHelper.writeBits(3, 8); - BitBufferHelper.writeBits(PDU_CDMA_MSG_TYPE_SUBMIT, 4); - BitBufferHelper.writeBits(1, 16); // TODO: How to get message ID? - if (options.segmentMaxSeq > 1) { - BitBufferHelper.writeBits(1, 1); - } else { - BitBufferHelper.writeBits(0, 1); - } - - BitBufferHelper.flushWithPadding(); - }, - - /** - * User data subparameter encoder : User Data - * - * @see 3GGP2 C.S0015-B 2.0, 4.5.2 User Data - */ - encodeUserDataMsg: function(options) { - let BitBufferHelper = this.context.BitBufferHelper; - BitBufferHelper.writeBits(PDU_CDMA_MSG_USERDATA_BODY, 8); - // Reserve space for length - BitBufferHelper.writeBits(0, 8); - let lengthPosition = BitBufferHelper.getWriteBufferSize(); - - BitBufferHelper.writeBits(options.encoding, 5); - - // Add user data header for message segement - let msgBody = options.body, - msgBodySize = (options.encoding === PDU_CDMA_MSG_CODING_7BITS_ASCII ? - options.encodedBodyLength : - msgBody.length); - if (options.segmentMaxSeq > 1) { - if (options.encoding === PDU_CDMA_MSG_CODING_7BITS_ASCII) { - BitBufferHelper.writeBits(msgBodySize + 7, 8); // Required length for user data header, in septet(7-bit) - - BitBufferHelper.writeBits(5, 8); // total header length 5 bytes - BitBufferHelper.writeBits(PDU_IEI_CONCATENATED_SHORT_MESSAGES_8BIT, 8); // header id 0 - BitBufferHelper.writeBits(3, 8); // length of element for id 0 is 3 - BitBufferHelper.writeBits(options.segmentRef & 0xFF, 8); // Segement reference - BitBufferHelper.writeBits(options.segmentMaxSeq & 0xFF, 8); // Max segment - BitBufferHelper.writeBits(options.segmentSeq & 0xFF, 8); // Current segment - BitBufferHelper.writeBits(0, 1); // Padding to make header data septet(7-bit) aligned - } else { - if (options.encoding === PDU_CDMA_MSG_CODING_UNICODE) { - BitBufferHelper.writeBits(msgBodySize + 3, 8); // Required length for user data header, in 16-bit - } else { - BitBufferHelper.writeBits(msgBodySize + 6, 8); // Required length for user data header, in octet(8-bit) - } - - BitBufferHelper.writeBits(5, 8); // total header length 5 bytes - BitBufferHelper.writeBits(PDU_IEI_CONCATENATED_SHORT_MESSAGES_8BIT, 8); // header id 0 - BitBufferHelper.writeBits(3, 8); // length of element for id 0 is 3 - BitBufferHelper.writeBits(options.segmentRef & 0xFF, 8); // Segement reference - BitBufferHelper.writeBits(options.segmentMaxSeq & 0xFF, 8); // Max segment - BitBufferHelper.writeBits(options.segmentSeq & 0xFF, 8); // Current segment - } - } else { - BitBufferHelper.writeBits(msgBodySize, 8); - } - - // Encode message based on encoding method - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - for (let i = 0; i < msgBody.length; i++) { - switch (options.encoding) { - case PDU_CDMA_MSG_CODING_OCTET: { - let msgDigit = msgBody.charCodeAt(i); - BitBufferHelper.writeBits(msgDigit, 8); - break; - } - case PDU_CDMA_MSG_CODING_7BITS_ASCII: { - let msgDigit = msgBody.charCodeAt(i), - msgDigitChar = msgBody.charAt(i); - - if (msgDigit >= 32) { - BitBufferHelper.writeBits(msgDigit, 7); - } else { - msgDigit = langTable.indexOf(msgDigitChar); - - if (msgDigit === PDU_NL_EXTENDED_ESCAPE) { - break; - } - if (msgDigit >= 0) { - BitBufferHelper.writeBits(msgDigit, 7); - } else { - msgDigit = langShiftTable.indexOf(msgDigitChar); - if (msgDigit == -1) { - throw new Error("'" + msgDigitChar + "' is not in 7 bit alphabet " - + langIndex + ":" + langShiftIndex + "!"); - } - - if (msgDigit === PDU_NL_RESERVED_CONTROL) { - break; - } - - BitBufferHelper.writeBits(PDU_NL_EXTENDED_ESCAPE, 7); - BitBufferHelper.writeBits(msgDigit, 7); - } - } - break; - } - case PDU_CDMA_MSG_CODING_UNICODE: { - let msgDigit = msgBody.charCodeAt(i); - BitBufferHelper.writeBits(msgDigit, 16); - break; - } - } - } - BitBufferHelper.flushWithPadding(); - - // Fill length - let currentPosition = BitBufferHelper.getWriteBufferSize(); - BitBufferHelper.overwriteWriteBuffer(lengthPosition - 1, [currentPosition - lengthPosition]); - }, - - /** - * User data subparameter encoder : Reply Option - * - * @see 3GGP2 C.S0015-B 2.0, 4.5.11 Reply Option - */ - encodeUserDataReplyOption: function(options) { - if (options.requestStatusReport) { - let BitBufferHelper = this.context.BitBufferHelper; - BitBufferHelper.writeBits(PDU_CDMA_MSG_USERDATA_REPLY_OPTION, 8); - BitBufferHelper.writeBits(1, 8); - BitBufferHelper.writeBits(0, 1); // USER_ACK_REQ - BitBufferHelper.writeBits(1, 1); // DAK_REQ - BitBufferHelper.flushWithPadding(); - } - }, - - /** - * Entry point for SMS decoding, the returned object is made compatible - * with existing readMessage() of GsmPDUHelper - */ - readMessage: function() { - let message = {}; - - // Teleservice Identifier - message.teleservice = this.readInt(); - - // Message Type - let isServicePresent = this.readByte(); - if (isServicePresent) { - message.messageType = PDU_CDMA_MSG_TYPE_BROADCAST; - } else { - if (message.teleservice) { - message.messageType = PDU_CDMA_MSG_TYPE_P2P; - } else { - message.messageType = PDU_CDMA_MSG_TYPE_ACK; - } - } - - // Service Category - message.service = this.readInt(); - - // Originated Address - let addrInfo = {}; - addrInfo.digitMode = (this.readInt() & 0x01); - addrInfo.numberMode = (this.readInt() & 0x01); - addrInfo.numberType = (this.readInt() & 0x01); - addrInfo.numberPlan = (this.readInt() & 0x01); - addrInfo.addrLength = this.readByte(); - addrInfo.address = []; - for (let i = 0; i < addrInfo.addrLength; i++) { - addrInfo.address.push(this.readByte()); - } - message.sender = this.decodeAddr(addrInfo); - - // Originated Subaddress - addrInfo.Type = (this.readInt() & 0x07); - addrInfo.Odd = (this.readByte() & 0x01); - addrInfo.addrLength = this.readByte(); - for (let i = 0; i < addrInfo.addrLength; i++) { - let addrDigit = this.readByte(); - message.sender += String.fromCharCode(addrDigit); - } - - // Bearer Data - this.decodeUserData(message); - - // Bearer Data Sub-Parameter: User Data - let userData = message[PDU_CDMA_MSG_USERDATA_BODY]; - [message.header, message.body, message.encoding, message.data] = - (userData) ? [userData.header, userData.body, userData.encoding, userData.data] - : [null, null, null, null]; - - // Bearer Data Sub-Parameter: Message Status - // Success Delivery (0) if both Message Status and User Data are absent. - // Message Status absent (-1) if only User Data is available. - let msgStatus = message[PDU_CDMA_MSG_USER_DATA_MSG_STATUS]; - [message.errorClass, message.msgStatus] = - (msgStatus) ? [msgStatus.errorClass, msgStatus.msgStatus] - : ((message.body) ? [-1, -1] : [0, 0]); - - // Transform message to GSM msg - let msg = { - SMSC: "", - mti: 0, - udhi: 0, - sender: message.sender, - recipient: null, - pid: PDU_PID_DEFAULT, - epid: PDU_PID_DEFAULT, - dcs: 0, - mwi: null, - replace: false, - header: message.header, - body: message.body, - data: message.data, - sentTimestamp: message[PDU_CDMA_MSG_USERDATA_TIMESTAMP], - language: message[PDU_CDMA_LANGUAGE_INDICATOR], - status: null, - scts: null, - dt: null, - encoding: message.encoding, - messageClass: GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], - messageType: message.messageType, - serviceCategory: message.service, - subMsgType: message[PDU_CDMA_MSG_USERDATA_MSG_ID].msgType, - msgId: message[PDU_CDMA_MSG_USERDATA_MSG_ID].msgId, - errorClass: message.errorClass, - msgStatus: message.msgStatus, - teleservice: message.teleservice - }; - - return msg; - }, - - /** - * Helper for processing received SMS parcel data. - * - * @param length - * Length of SMS string in the incoming parcel. - * - * @return Message parsed or null for invalid message. - */ - processReceivedSms: function(length) { - if (!length) { - if (DEBUG) this.context.debug("Received empty SMS!"); - return [null, PDU_FCS_UNSPECIFIED]; - } - - let message = this.readMessage(); - if (DEBUG) this.context.debug("Got new SMS: " + JSON.stringify(message)); - - // Determine result - if (!message) { - return [null, PDU_FCS_UNSPECIFIED]; - } - - return [message, PDU_FCS_OK]; - }, - - /** - * Data readers - */ - readInt: function() { - return this.context.Buf.readInt32(); - }, - - readByte: function() { - return (this.context.Buf.readInt32() & 0xFF); - }, - - /** - * Decode CDMA address data into address string - * - * @see 3GGP2 C.S0015-B 2.0, 3.4.3.3 Address Parameters - * - * Required key in addrInfo - * @param addrLength - * Length of address - * @param digitMode - * Address encoding method - * @param address - * Array of encoded address data - */ - decodeAddr: function(addrInfo) { - let result = ""; - for (let i = 0; i < addrInfo.addrLength; i++) { - if (addrInfo.digitMode === PDU_CDMA_MSG_ADDR_DIGIT_MODE_DTMF) { - result += this.dtmfChars.charAt(addrInfo.address[i]); - } else { - result += String.fromCharCode(addrInfo.address[i]); - } - } - return result; - }, - - /** - * Read userData in parcel buffer and decode into message object. - * Each subparameter will be stored in corresponding key. - * - * @see 3GGP2 C.S0015-B 2.0, 3.4.3.7 Bearer Data - * 4.5 Bearer Data Parameters - */ - decodeUserData: function(message) { - let userDataLength = this.readInt(); - - while (userDataLength > 0) { - let id = this.readByte(), - length = this.readByte(), - userDataBuffer = []; - - for (let i = 0; i < length; i++) { - userDataBuffer.push(this.readByte()); - } - - this.context.BitBufferHelper.startRead(userDataBuffer); - - switch (id) { - case PDU_CDMA_MSG_USERDATA_MSG_ID: - message[id] = this.decodeUserDataMsgId(); - break; - case PDU_CDMA_MSG_USERDATA_BODY: - message[id] = this.decodeUserDataMsg(message[PDU_CDMA_MSG_USERDATA_MSG_ID].userHeader); - break; - case PDU_CDMA_MSG_USERDATA_TIMESTAMP: - message[id] = this.decodeUserDataTimestamp(); - break; - case PDU_CDMA_MSG_USERDATA_REPLY_OPTION: - message[id] = this.decodeUserDataReplyOption(); - break; - case PDU_CDMA_LANGUAGE_INDICATOR: - message[id] = this.decodeLanguageIndicator(); - break; - case PDU_CDMA_MSG_USERDATA_CALLBACK_NUMBER: - message[id] = this.decodeUserDataCallbackNumber(); - break; - case PDU_CDMA_MSG_USER_DATA_MSG_STATUS: - message[id] = this.decodeUserDataMsgStatus(); - break; - } - - userDataLength -= (length + 2); - userDataBuffer = []; - } - }, - - /** - * User data subparameter decoder: Message Identifier - * - * @see 3GGP2 C.S0015-B 2.0, 4.5.1 Message Identifier - */ - decodeUserDataMsgId: function() { - let result = {}; - let BitBufferHelper = this.context.BitBufferHelper; - result.msgType = BitBufferHelper.readBits(4); - result.msgId = BitBufferHelper.readBits(16); - result.userHeader = BitBufferHelper.readBits(1); - - return result; - }, - - /** - * Decode user data header, we only care about segment information - * on CDMA. - * - * This function is mostly copied from gsmPduHelper.readUserDataHeader() but - * change the read function, because CDMA user header decoding is't byte-wise - * aligned. - */ - decodeUserDataHeader: function(encoding) { - let BitBufferHelper = this.context.BitBufferHelper; - let header = {}, - headerSize = BitBufferHelper.readBits(8), - userDataHeaderSize = headerSize + 1, - headerPaddingBits = 0; - - // Calculate header size - if (encoding === PDU_DCS_MSG_CODING_7BITS_ALPHABET) { - // Length is in 7-bit - header.length = Math.ceil(userDataHeaderSize * 8 / 7); - // Calulate padding length - headerPaddingBits = (header.length * 7) - (userDataHeaderSize * 8); - } else if (encoding === PDU_DCS_MSG_CODING_8BITS_ALPHABET) { - header.length = userDataHeaderSize; - } else { - header.length = userDataHeaderSize / 2; - } - - while (headerSize) { - let identifier = BitBufferHelper.readBits(8), - length = BitBufferHelper.readBits(8); - - headerSize -= (2 + length); - - switch (identifier) { - case PDU_IEI_CONCATENATED_SHORT_MESSAGES_8BIT: { - let ref = BitBufferHelper.readBits(8), - max = BitBufferHelper.readBits(8), - seq = BitBufferHelper.readBits(8); - if (max && seq && (seq <= max)) { - header.segmentRef = ref; - header.segmentMaxSeq = max; - header.segmentSeq = seq; - } - break; - } - case PDU_IEI_APPLICATION_PORT_ADDRESSING_SCHEME_8BIT: { - let dstp = BitBufferHelper.readBits(8), - orip = BitBufferHelper.readBits(8); - if ((dstp < PDU_APA_RESERVED_8BIT_PORTS) - || (orip < PDU_APA_RESERVED_8BIT_PORTS)) { - // 3GPP TS 23.040 clause 9.2.3.24.3: "A receiving entity shall - // ignore any information element where the value of the - // Information-Element-Data is Reserved or not supported" - break; - } - header.destinationPort = dstp; - header.originatorPort = orip; - break; - } - case PDU_IEI_APPLICATION_PORT_ADDRESSING_SCHEME_16BIT: { - let dstp = (BitBufferHelper.readBits(8) << 8) | BitBufferHelper.readBits(8), - orip = (BitBufferHelper.readBits(8) << 8) | BitBufferHelper.readBits(8); - // 3GPP TS 23.040 clause 9.2.3.24.4: "A receiving entity shall - // ignore any information element where the value of the - // Information-Element-Data is Reserved or not supported" - if ((dstp < PDU_APA_VALID_16BIT_PORTS) - && (orip < PDU_APA_VALID_16BIT_PORTS)) { - header.destinationPort = dstp; - header.originatorPort = orip; - } - break; - } - case PDU_IEI_CONCATENATED_SHORT_MESSAGES_16BIT: { - let ref = (BitBufferHelper.readBits(8) << 8) | BitBufferHelper.readBits(8), - max = BitBufferHelper.readBits(8), - seq = BitBufferHelper.readBits(8); - if (max && seq && (seq <= max)) { - header.segmentRef = ref; - header.segmentMaxSeq = max; - header.segmentSeq = seq; - } - break; - } - case PDU_IEI_NATIONAL_LANGUAGE_SINGLE_SHIFT: { - let langShiftIndex = BitBufferHelper.readBits(8); - if (langShiftIndex < PDU_NL_SINGLE_SHIFT_TABLES.length) { - header.langShiftIndex = langShiftIndex; - } - break; - } - case PDU_IEI_NATIONAL_LANGUAGE_LOCKING_SHIFT: { - let langIndex = BitBufferHelper.readBits(8); - if (langIndex < PDU_NL_LOCKING_SHIFT_TABLES.length) { - header.langIndex = langIndex; - } - break; - } - case PDU_IEI_SPECIAL_SMS_MESSAGE_INDICATION: { - let msgInd = BitBufferHelper.readBits(8) & 0xFF, - msgCount = BitBufferHelper.readBits(8); - /* - * TS 23.040 V6.8.1 Sec 9.2.3.24.2 - * bits 1 0 : basic message indication type - * bits 4 3 2 : extended message indication type - * bits 6 5 : Profile id - * bit 7 : storage type - */ - let storeType = msgInd & PDU_MWI_STORE_TYPE_BIT; - header.mwi = {}; - mwi = header.mwi; - - if (storeType == PDU_MWI_STORE_TYPE_STORE) { - // Store message because TP_UDH indicates so, note this may override - // the setting in DCS, but that is expected - mwi.discard = false; - } else if (mwi.discard === undefined) { - // storeType == PDU_MWI_STORE_TYPE_DISCARD - // only override mwi.discard here if it hasn't already been set - mwi.discard = true; - } - - mwi.msgCount = msgCount & 0xFF; - mwi.active = mwi.msgCount > 0; - - if (DEBUG) { - this.context.debug("MWI in TP_UDH received: " + JSON.stringify(mwi)); - } - break; - } - default: - // Drop unsupported id - for (let i = 0; i < length; i++) { - BitBufferHelper.readBits(8); - } - } - } - - // Consume padding bits - if (headerPaddingBits) { - BitBufferHelper.readBits(headerPaddingBits); - } - - return header; - }, - - getCdmaMsgEncoding: function(encoding) { - // Determine encoding method - switch (encoding) { - case PDU_CDMA_MSG_CODING_7BITS_ASCII: - case PDU_CDMA_MSG_CODING_IA5: - case PDU_CDMA_MSG_CODING_7BITS_GSM: - return PDU_DCS_MSG_CODING_7BITS_ALPHABET; - case PDU_CDMA_MSG_CODING_OCTET: - case PDU_CDMA_MSG_CODING_IS_91: - case PDU_CDMA_MSG_CODING_LATIN_HEBREW: - case PDU_CDMA_MSG_CODING_LATIN: - return PDU_DCS_MSG_CODING_8BITS_ALPHABET; - case PDU_CDMA_MSG_CODING_UNICODE: - case PDU_CDMA_MSG_CODING_SHIFT_JIS: - case PDU_CDMA_MSG_CODING_KOREAN: - return PDU_DCS_MSG_CODING_16BITS_ALPHABET; - } - return null; - }, - - decodeCdmaPDUMsg: function(encoding, msgType, msgBodySize) { - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - let BitBufferHelper = this.context.BitBufferHelper; - let result = ""; - let msgDigit; - switch (encoding) { - case PDU_CDMA_MSG_CODING_OCTET: // TODO : Require Test - while(msgBodySize > 0) { - msgDigit = String.fromCharCode(BitBufferHelper.readBits(8)); - result += msgDigit; - msgBodySize--; - } - break; - case PDU_CDMA_MSG_CODING_IS_91: // TODO : Require Test - // Referenced from android code - switch (msgType) { - case PDU_CDMA_MSG_CODING_IS_91_TYPE_SMS: - case PDU_CDMA_MSG_CODING_IS_91_TYPE_SMS_FULL: - case PDU_CDMA_MSG_CODING_IS_91_TYPE_VOICEMAIL_STATUS: - while(msgBodySize > 0) { - msgDigit = String.fromCharCode(BitBufferHelper.readBits(6) + 0x20); - result += msgDigit; - msgBodySize--; - } - break; - case PDU_CDMA_MSG_CODING_IS_91_TYPE_CLI: - let addrInfo = {}; - addrInfo.digitMode = PDU_CDMA_MSG_ADDR_DIGIT_MODE_DTMF; - addrInfo.numberMode = PDU_CDMA_MSG_ADDR_NUMBER_MODE_ANSI; - addrInfo.numberType = PDU_CDMA_MSG_ADDR_NUMBER_TYPE_UNKNOWN; - addrInfo.numberPlan = PDU_CDMA_MSG_ADDR_NUMBER_PLAN_UNKNOWN; - addrInfo.addrLength = msgBodySize; - addrInfo.address = []; - for (let i = 0; i < addrInfo.addrLength; i++) { - addrInfo.address.push(BitBufferHelper.readBits(4)); - } - result = this.decodeAddr(addrInfo); - break; - } - // Fall through. - case PDU_CDMA_MSG_CODING_7BITS_ASCII: - case PDU_CDMA_MSG_CODING_IA5: // TODO : Require Test - while(msgBodySize > 0) { - msgDigit = BitBufferHelper.readBits(7); - if (msgDigit >= 32) { - msgDigit = String.fromCharCode(msgDigit); - } else { - if (msgDigit !== PDU_NL_EXTENDED_ESCAPE) { - msgDigit = langTable[msgDigit]; - } else { - msgDigit = BitBufferHelper.readBits(7); - msgBodySize--; - msgDigit = langShiftTable[msgDigit]; - } - } - result += msgDigit; - msgBodySize--; - } - break; - case PDU_CDMA_MSG_CODING_UNICODE: - while(msgBodySize > 0) { - msgDigit = String.fromCharCode(BitBufferHelper.readBits(16)); - result += msgDigit; - msgBodySize--; - } - break; - case PDU_CDMA_MSG_CODING_7BITS_GSM: // TODO : Require Test - while(msgBodySize > 0) { - msgDigit = BitBufferHelper.readBits(7); - if (msgDigit !== PDU_NL_EXTENDED_ESCAPE) { - msgDigit = langTable[msgDigit]; - } else { - msgDigit = BitBufferHelper.readBits(7); - msgBodySize--; - msgDigit = langShiftTable[msgDigit]; - } - result += msgDigit; - msgBodySize--; - } - break; - case PDU_CDMA_MSG_CODING_LATIN: // TODO : Require Test - // Reference : http://en.wikipedia.org/wiki/ISO/IEC_8859-1 - while(msgBodySize > 0) { - msgDigit = String.fromCharCode(BitBufferHelper.readBits(8)); - result += msgDigit; - msgBodySize--; - } - break; - case PDU_CDMA_MSG_CODING_LATIN_HEBREW: // TODO : Require Test - // Reference : http://en.wikipedia.org/wiki/ISO/IEC_8859-8 - while(msgBodySize > 0) { - msgDigit = BitBufferHelper.readBits(8); - if (msgDigit === 0xDF) { - msgDigit = String.fromCharCode(0x2017); - } else if (msgDigit === 0xFD) { - msgDigit = String.fromCharCode(0x200E); - } else if (msgDigit === 0xFE) { - msgDigit = String.fromCharCode(0x200F); - } else if (msgDigit >= 0xE0 && msgDigit <= 0xFA) { - msgDigit = String.fromCharCode(0x4F0 + msgDigit); - } else { - msgDigit = String.fromCharCode(msgDigit); - } - result += msgDigit; - msgBodySize--; - } - break; - case PDU_CDMA_MSG_CODING_SHIFT_JIS: - // Reference : http://msdn.microsoft.com/en-US/goglobal/cc305152.aspx - // http://demo.icu-project.org/icu-bin/convexp?conv=Shift_JIS - let shift_jis_message = []; - - while (msgBodySize > 0) { - shift_jis_message.push(BitBufferHelper.readBits(8)); - msgBodySize--; - } - - let decoder = new TextDecoder("shift_jis"); - result = decoder.decode(new Uint8Array(shift_jis_message)); - break; - case PDU_CDMA_MSG_CODING_KOREAN: - case PDU_CDMA_MSG_CODING_GSM_DCS: - // Fall through. - default: - break; - } - return result; - }, - - /** - * User data subparameter decoder : User Data - * - * @see 3GGP2 C.S0015-B 2.0, 4.5.2 User Data - */ - decodeUserDataMsg: function(hasUserHeader) { - let BitBufferHelper = this.context.BitBufferHelper; - let result = {}, - encoding = BitBufferHelper.readBits(5), - msgType; - - if (encoding === PDU_CDMA_MSG_CODING_IS_91) { - msgType = BitBufferHelper.readBits(8); - } - result.encoding = this.getCdmaMsgEncoding(encoding); - - let msgBodySize = BitBufferHelper.readBits(8); - - // For segmented SMS, a user header is included before sms content - if (hasUserHeader) { - result.header = this.decodeUserDataHeader(result.encoding); - // header size is included in body size, they are decoded - msgBodySize -= result.header.length; - } - - // Store original payload if enconding is OCTET for further handling of WAP Push, etc. - if (encoding === PDU_CDMA_MSG_CODING_OCTET && msgBodySize > 0) { - result.data = new Uint8Array(msgBodySize); - for (let i = 0; i < msgBodySize; i++) { - result.data[i] = BitBufferHelper.readBits(8); - } - BitBufferHelper.backwardReadPilot(8 * msgBodySize); - } - - // Decode sms content - result.body = this.decodeCdmaPDUMsg(encoding, msgType, msgBodySize); - - return result; - }, - - decodeBcd: function(value) { - return ((value >> 4) & 0xF) * 10 + (value & 0x0F); - }, - - /** - * User data subparameter decoder : Time Stamp - * - * @see 3GGP2 C.S0015-B 2.0, 4.5.4 Message Center Time Stamp - */ - decodeUserDataTimestamp: function() { - let BitBufferHelper = this.context.BitBufferHelper; - let year = this.decodeBcd(BitBufferHelper.readBits(8)), - month = this.decodeBcd(BitBufferHelper.readBits(8)) - 1, - date = this.decodeBcd(BitBufferHelper.readBits(8)), - hour = this.decodeBcd(BitBufferHelper.readBits(8)), - min = this.decodeBcd(BitBufferHelper.readBits(8)), - sec = this.decodeBcd(BitBufferHelper.readBits(8)); - - if (year >= 96 && year <= 99) { - year += 1900; - } else { - year += 2000; - } - - let result = (new Date(year, month, date, hour, min, sec, 0)).valueOf(); - - return result; - }, - - /** - * User data subparameter decoder : Reply Option - * - * @see 3GGP2 C.S0015-B 2.0, 4.5.11 Reply Option - */ - decodeUserDataReplyOption: function() { - let replyAction = this.context.BitBufferHelper.readBits(4), - result = { userAck: (replyAction & 0x8) ? true : false, - deliverAck: (replyAction & 0x4) ? true : false, - readAck: (replyAction & 0x2) ? true : false, - report: (replyAction & 0x1) ? true : false - }; - - return result; - }, - - /** - * User data subparameter decoder : Language Indicator - * - * @see 3GGP2 C.S0015-B 2.0, 4.5.14 Language Indicator - */ - decodeLanguageIndicator: function() { - let language = this.context.BitBufferHelper.readBits(8); - let result = CB_CDMA_LANG_GROUP[language]; - return result; - }, - - /** - * User data subparameter decoder : Call-Back Number - * - * @see 3GGP2 C.S0015-B 2.0, 4.5.15 Call-Back Number - */ - decodeUserDataCallbackNumber: function() { - let BitBufferHelper = this.context.BitBufferHelper; - let digitMode = BitBufferHelper.readBits(1); - if (digitMode) { - let numberType = BitBufferHelper.readBits(3), - numberPlan = BitBufferHelper.readBits(4); - } - let numberFields = BitBufferHelper.readBits(8), - result = ""; - for (let i = 0; i < numberFields; i++) { - if (digitMode === PDU_CDMA_MSG_ADDR_DIGIT_MODE_DTMF) { - let addrDigit = BitBufferHelper.readBits(4); - result += this.dtmfChars.charAt(addrDigit); - } else { - let addrDigit = BitBufferHelper.readBits(8); - result += String.fromCharCode(addrDigit); - } - } - - return result; - }, - - /** - * User data subparameter decoder : Message Status - * - * @see 3GGP2 C.S0015-B 2.0, 4.5.21 Message Status - */ - decodeUserDataMsgStatus: function() { - let BitBufferHelper = this.context.BitBufferHelper; - let result = { - errorClass: BitBufferHelper.readBits(2), - msgStatus: BitBufferHelper.readBits(6) - }; - - return result; - }, - - /** - * Decode information record parcel. - */ - decodeInformationRecord: function() { - let Buf = this.context.Buf; - let records = []; - let numOfRecords = Buf.readInt32(); - - let type; - let record; - for (let i = 0; i < numOfRecords; i++) { - record = {}; - type = Buf.readInt32(); - - switch (type) { - /* - * Every type is encaped by ril, except extended display - */ - case PDU_CDMA_INFO_REC_TYPE_DISPLAY: - case PDU_CDMA_INFO_REC_TYPE_EXTENDED_DISPLAY: - record.display = Buf.readString(); - break; - case PDU_CDMA_INFO_REC_TYPE_CALLED_PARTY_NUMBER: - record.calledNumber = {}; - record.calledNumber.number = Buf.readString(); - record.calledNumber.type = Buf.readInt32(); - record.calledNumber.plan = Buf.readInt32(); - record.calledNumber.pi = Buf.readInt32(); - record.calledNumber.si = Buf.readInt32(); - break; - case PDU_CDMA_INFO_REC_TYPE_CALLING_PARTY_NUMBER: - record.callingNumber = {}; - record.callingNumber.number = Buf.readString(); - record.callingNumber.type = Buf.readInt32(); - record.callingNumber.plan = Buf.readInt32(); - record.callingNumber.pi = Buf.readInt32(); - record.callingNumber.si = Buf.readInt32(); - break; - case PDU_CDMA_INFO_REC_TYPE_CONNECTED_NUMBER: - record.connectedNumber = {}; - record.connectedNumber.number = Buf.readString(); - record.connectedNumber.type = Buf.readInt32(); - record.connectedNumber.plan = Buf.readInt32(); - record.connectedNumber.pi = Buf.readInt32(); - record.connectedNumber.si = Buf.readInt32(); - break; - case PDU_CDMA_INFO_REC_TYPE_SIGNAL: - record.signal = {}; - if (!Buf.readInt32()) { // Non-zero if signal is present. - Buf.seekIncoming(3 * Buf.UINT32_SIZE); - continue; - } - record.signal.type = Buf.readInt32(); - record.signal.alertPitch = Buf.readInt32(); - record.signal.signal = Buf.readInt32(); - break; - case PDU_CDMA_INFO_REC_TYPE_REDIRECTING_NUMBER: - record.redirect = {}; - record.redirect.number = Buf.readString(); - record.redirect.type = Buf.readInt32(); - record.redirect.plan = Buf.readInt32(); - record.redirect.pi = Buf.readInt32(); - record.redirect.si = Buf.readInt32(); - record.redirect.reason = Buf.readInt32(); - break; - case PDU_CDMA_INFO_REC_TYPE_LINE_CONTROL: - record.lineControl = {}; - record.lineControl.polarityIncluded = Buf.readInt32(); - record.lineControl.toggle = Buf.readInt32(); - record.lineControl.reverse = Buf.readInt32(); - record.lineControl.powerDenial = Buf.readInt32(); - break; - case PDU_CDMA_INFO_REC_TYPE_T53_CLIR: - record.clirCause = Buf.readInt32(); - break; - case PDU_CDMA_INFO_REC_TYPE_T53_AUDIO_CONTROL: - record.audioControl = {}; - record.audioControl.upLink = Buf.readInt32(); - record.audioControl.downLink = Buf.readInt32(); - break; - case PDU_CDMA_INFO_REC_TYPE_T53_RELEASE: - // Fall through - default: - throw new Error("UNSOLICITED_CDMA_INFO_REC(), Unsupported information record type " + type + "\n"); - } - - records.push(record); - } - - return records; - } -}; - -/** - * Helper for processing ICC PDUs. - */ -function ICCPDUHelperObject(aContext) { - this.context = aContext; -} -ICCPDUHelperObject.prototype = { - context: null, - - /** - * Read GSM 8-bit unpacked octets, - * which are default 7-bit alphabets with bit 8 set to 0. - * - * @param numOctets - * Number of octets to be read. - */ - read8BitUnpackedToString: function(numOctets) { - let GsmPDUHelper = this.context.GsmPDUHelper; - - let ret = ""; - let escapeFound = false; - let i; - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - - for(i = 0; i < numOctets; i++) { - let octet = GsmPDUHelper.readHexOctet(); - if (octet == 0xff) { - i++; - break; - } - - if (escapeFound) { - escapeFound = false; - if (octet == PDU_NL_EXTENDED_ESCAPE) { - // According to 3GPP TS 23.038, section 6.2.1.1, NOTE 1, "On - // receipt of this code, a receiving entity shall display a space - // until another extensiion table is defined." - ret += " "; - } else if (octet == PDU_NL_RESERVED_CONTROL) { - // According to 3GPP TS 23.038 B.2, "This code represents a control - // character and therefore must not be used for language specific - // characters." - ret += " "; - } else { - ret += langShiftTable[octet]; - } - } else if (octet == PDU_NL_EXTENDED_ESCAPE) { - escapeFound = true; - } else { - ret += langTable[octet]; - } - } - - let Buf = this.context.Buf; - Buf.seekIncoming((numOctets - i) * Buf.PDU_HEX_OCTET_SIZE); - return ret; - }, - - /** - * Write GSM 8-bit unpacked octets. - * - * @param numOctets Number of total octets to be writen, including trailing - * 0xff. - * @param str String to be written. Could be null. - * - * @return The string has been written into Buf. "" if str is null. - */ - writeStringTo8BitUnpacked: function(numOctets, str) { - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - - let GsmPDUHelper = this.context.GsmPDUHelper; - - // If the character is GSM extended alphabet, two octets will be written. - // So we need to keep track of number of octets to be written. - let i, j; - let len = str ? str.length : 0; - for (i = 0, j = 0; i < len && j < numOctets; i++) { - let c = str.charAt(i); - let octet = langTable.indexOf(c); - - if (octet == -1) { - // Make sure we still have enough space to write two octets. - if (j + 2 > numOctets) { - break; - } - - octet = langShiftTable.indexOf(c); - if (octet == -1) { - // Fallback to ASCII space. - octet = langTable.indexOf(' '); - } else { - GsmPDUHelper.writeHexOctet(PDU_NL_EXTENDED_ESCAPE); - j++; - } - } - GsmPDUHelper.writeHexOctet(octet); - j++; - } - - // trailing 0xff - while (j++ < numOctets) { - GsmPDUHelper.writeHexOctet(0xff); - } - - return (str) ? str.substring(0, i) : ""; - }, - - /** - * Write UCS2 String on UICC. - * The default choose 0x81 or 0x82 encode, otherwise use 0x80 encode. - * - * @see TS 102.221, Annex A. - * @param numOctets - * Total number of octets to be written. This includes the length of - * alphaId and the length of trailing unused octets(0xff). - * @param str - * String to be written. - * - * @return The string has been written into Buf. - */ - writeICCUCS2String: function(numOctets, str) { - let GsmPDUHelper = this.context.GsmPDUHelper; - let scheme = 0x80; - let basePointer; - - if (str.length > 2) { - let min = 0xFFFF; - let max = 0; - for (let i = 0; i < str.length; i++) { - let code = str.charCodeAt(i); - // filter out GSM Default Alphabet character - if (code & 0xFF80) { - if (min > code) { - min = code; - } - if (max < code) { - max = code; - } - } - } - - // 0x81 and 0x82 only support 'half-page', i.e., 128 characters. - if ((max - min) >= 0 && (max - min) < 128) { - // 0x81 base pointer is 0hhh hhhh h000 0000, and bit 16 is set to zero, - // therefore it can't compute 0x8000~0xFFFF. - // Since 0x81 only support 128 characters, - // either XX00~XX7f(bit 8 are 0) or XX80~XXff(bit 8 are 1) - if (((min & 0x7f80) == (max & 0x7f80)) && - ((max & 0x8000) == 0)) { - scheme = 0x81; - basePointer = min & 0x7f80; - } else { - scheme = 0x82; - basePointer = min; - } - } - } - - switch (scheme) { - /** - * +------+---------+---------+---------+---------+------+------+ - * | 0x80 | Ch1_msb | Ch1_lsb | Ch2_msb | Ch2_lsb | 0xff | 0xff | - * +------+---------+---------+---------+---------+------+------+ - */ - case 0x80: { - // 0x80 support UCS2 0000~ffff - GsmPDUHelper.writeHexOctet(0x80); - numOctets--; - // Now the str is UCS2 string, each character will take 2 octets. - if (str.length * 2 > numOctets) { - str = str.substring(0, Math.floor(numOctets / 2)); - } - GsmPDUHelper.writeUCS2String(str); - - // trailing 0xff - for (let i = str.length * 2; i < numOctets; i++) { - GsmPDUHelper.writeHexOctet(0xff); - } - return str; - } - /** - * +------+-----+--------------+-----+-----+-----+--------+------+ - * | 0x81 | len | base_pointer | Ch1 | Ch2 | ... | Ch_len | 0xff | - * +------+-----+--------------+-----+-----+-----+--------+------+ - * - * len: The length of characters. - * base_pointer: 0hhh hhhh h000 0000 - * Ch_n: bit 8 = 0 - * GSM default alphabets - * bit 8 = 1 - * UCS2 character whose char code is (Ch_n - base_pointer) | 0x80 - * - */ - case 0x81: { - GsmPDUHelper.writeHexOctet(0x81); - - if (str.length > (numOctets - 3)) { - str = str.substring(0, numOctets - 3); - } - - GsmPDUHelper.writeHexOctet(str.length); - GsmPDUHelper.writeHexOctet((basePointer >> 7) & 0xff); - numOctets -= 3; - break; - } - /* +------+-----+------------------+------------------+-----+-----+-----+--------+ - * | 0x82 | len | base_pointer_msb | base_pointer_lsb | Ch1 | Ch2 | ... | Ch_len | - * +------+-----+------------------+------------------+-----+-----+-----+--------+ - * - * len: The length of characters. - * base_pointer_msb, base_pointer_lsn: base_pointer - * Ch_n: bit 8 = 0 - * GSM default alphabets - * bit 8 = 1 - * UCS2 character whose char code is (Ch_n - base_pointer) | 0x80 - */ - case 0x82: { - GsmPDUHelper.writeHexOctet(0x82); - - if (str.length > (numOctets - 4)) { - str = str.substring(0, numOctets - 4); - } - - GsmPDUHelper.writeHexOctet(str.length); - GsmPDUHelper.writeHexOctet((basePointer >> 8) & 0xff); - GsmPDUHelper.writeHexOctet(basePointer & 0xff); - numOctets -= 4; - break; - } - } - - if (scheme == 0x81 || scheme == 0x82) { - for (let i = 0; i < str.length; i++) { - let code = str.charCodeAt(i); - - // bit 8 = 0, - // GSM default alphabets - if (code >> 8 == 0) { - GsmPDUHelper.writeHexOctet(code & 0x7F); - } else { - // bit 8 = 1, - // UCS2 character whose char code is (code - basePointer) | 0x80 - GsmPDUHelper.writeHexOctet((code - basePointer) | 0x80); - } - } - - // trailing 0xff - for (let i = 0; i < numOctets - str.length; i++) { - GsmPDUHelper.writeHexOctet(0xff); - } - } - return str; - }, - - /** - * Read UCS2 String on UICC. - * - * @see TS 101.221, Annex A. - * @param scheme - * Coding scheme for UCS2 on UICC. One of 0x80, 0x81 or 0x82. - * @param numOctets - * Number of octets to be read as UCS2 string. - */ - readICCUCS2String: function(scheme, numOctets) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - - let str = ""; - switch (scheme) { - /** - * +------+---------+---------+---------+---------+------+------+ - * | 0x80 | Ch1_msb | Ch1_lsb | Ch2_msb | Ch2_lsb | 0xff | 0xff | - * +------+---------+---------+---------+---------+------+------+ - */ - case 0x80: - let isOdd = numOctets % 2; - let i; - for (i = 0; i < numOctets - isOdd; i += 2) { - let code = (GsmPDUHelper.readHexOctet() << 8) | GsmPDUHelper.readHexOctet(); - if (code == 0xffff) { - i += 2; - break; - } - str += String.fromCharCode(code); - } - - // Skip trailing 0xff - Buf.seekIncoming((numOctets - i) * Buf.PDU_HEX_OCTET_SIZE); - break; - case 0x81: // Fall through - case 0x82: - /** - * +------+-----+--------+-----+-----+-----+--------+------+ - * | 0x81 | len | offset | Ch1 | Ch2 | ... | Ch_len | 0xff | - * +------+-----+--------+-----+-----+-----+--------+------+ - * - * len : The length of characters. - * offset : 0hhh hhhh h000 0000 - * Ch_n: bit 8 = 0 - * GSM default alphabets - * bit 8 = 1 - * UCS2 character whose char code is (Ch_n & 0x7f) + offset - * - * +------+-----+------------+------------+-----+-----+-----+--------+ - * | 0x82 | len | offset_msb | offset_lsb | Ch1 | Ch2 | ... | Ch_len | - * +------+-----+------------+------------+-----+-----+-----+--------+ - * - * len : The length of characters. - * offset_msb, offset_lsn: offset - * Ch_n: bit 8 = 0 - * GSM default alphabets - * bit 8 = 1 - * UCS2 character whose char code is (Ch_n & 0x7f) + offset - */ - let len = GsmPDUHelper.readHexOctet(); - let offset, headerLen; - if (scheme == 0x81) { - offset = GsmPDUHelper.readHexOctet() << 7; - headerLen = 2; - } else { - offset = (GsmPDUHelper.readHexOctet() << 8) | GsmPDUHelper.readHexOctet(); - headerLen = 3; - } - - for (let i = 0; i < len; i++) { - let ch = GsmPDUHelper.readHexOctet(); - if (ch & 0x80) { - // UCS2 - str += String.fromCharCode((ch & 0x7f) + offset); - } else { - // GSM 8bit - let count = 0, gotUCS2 = 0; - while ((i + count + 1 < len)) { - count++; - if (GsmPDUHelper.readHexOctet() & 0x80) { - gotUCS2 = 1; - break; - } - } - // Unread. - // +1 for the GSM alphabet indexed at i, - Buf.seekIncoming(-1 * (count + 1) * Buf.PDU_HEX_OCTET_SIZE); - str += this.read8BitUnpackedToString(count + 1 - gotUCS2); - i += count - gotUCS2; - } - } - - // Skipping trailing 0xff - Buf.seekIncoming((numOctets - len - headerLen) * Buf.PDU_HEX_OCTET_SIZE); - break; - } - return str; - }, - - /** - * Read Alpha Id and Dialling number from TS TS 151.011 clause 10.5.1 - * - * @param recordSize The size of linear fixed record. - */ - readAlphaIdDiallingNumber: function(recordSize) { - let Buf = this.context.Buf; - let length = Buf.readInt32(); - - let alphaLen = recordSize - ADN_FOOTER_SIZE_BYTES; - let alphaId = this.readAlphaIdentifier(alphaLen); - - let number = this.readNumberWithLength(); - - // Skip unused octet, CCP - Buf.seekIncoming(Buf.PDU_HEX_OCTET_SIZE); - - let extRecordNumber = this.context.GsmPDUHelper.readHexOctet(); - Buf.readStringDelimiter(length); - - let contact = null; - if (alphaId || number) { - contact = {alphaId: alphaId, - number: number, - extRecordNumber: extRecordNumber}; - } - - return contact; - }, - - /** - * Write Alpha Identifier and Dialling number from TS 151.011 clause 10.5.1 - * - * @param recordSize The size of linear fixed record. - * @param alphaId Alpha Identifier to be written. - * @param number Dialling Number to be written. - * @param extRecordNumber The record identifier of the EXT. - * - * @return An object contains the alphaId and number - * that have been written into Buf. - */ - writeAlphaIdDiallingNumber: function(recordSize, alphaId, number, extRecordNumber) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - - // Write String length - let strLen = recordSize * 2; - Buf.writeInt32(strLen); - - let alphaLen = recordSize - ADN_FOOTER_SIZE_BYTES; - let writtenAlphaId = this.writeAlphaIdentifier(alphaLen, alphaId); - let writtenNumber = this.writeNumberWithLength(number); - - // Write unused CCP octet 0xff. - GsmPDUHelper.writeHexOctet(0xff); - GsmPDUHelper.writeHexOctet((extRecordNumber != null) ? extRecordNumber : 0xff); - - Buf.writeStringDelimiter(strLen); - - return {alphaId: writtenAlphaId, - number: writtenNumber}; - }, - - /** - * Read Alpha Identifier. - * - * @see TS 131.102 - * - * @param numOctets - * Number of octets to be read. - * - * It uses either - * 1. SMS default 7-bit alphabet with bit 8 set to 0. - * 2. UCS2 string. - * - * Unused bytes should be set to 0xff. - */ - readAlphaIdentifier: function(numOctets) { - if (numOctets === 0) { - return ""; - } - - let temp; - // Read the 1st octet to determine the encoding. - if ((temp = this.context.GsmPDUHelper.readHexOctet()) == 0x80 || - temp == 0x81 || - temp == 0x82) { - numOctets--; - return this.readICCUCS2String(temp, numOctets); - } else { - let Buf = this.context.Buf; - Buf.seekIncoming(-1 * Buf.PDU_HEX_OCTET_SIZE); - return this.read8BitUnpackedToString(numOctets); - } - }, - - /** - * Write Alpha Identifier. - * - * @param numOctets - * Total number of octets to be written. This includes the length of - * alphaId and the length of trailing unused octets(0xff). - * @param alphaId - * Alpha Identifier to be written. - * - * @return The Alpha Identifier has been written into Buf. - * - * Unused octets will be written as 0xff. - */ - writeAlphaIdentifier: function(numOctets, alphaId) { - if (numOctets === 0) { - return ""; - } - - // If alphaId is empty or it's of GSM 8 bit. - if (!alphaId || this.context.ICCUtilsHelper.isGsm8BitAlphabet(alphaId)) { - return this.writeStringTo8BitUnpacked(numOctets, alphaId); - } else { - return this.writeICCUCS2String(numOctets, alphaId); - } - }, - - /** - * Read Dialling number. - * - * @see TS 131.102 - * - * @param len - * The Length of BCD number. - * - * From TS 131.102, in EF_ADN, EF_FDN, the field 'Length of BCD number' - * means the total bytes should be allocated to store the TON/NPI and - * the dialing number. - * For example, if the dialing number is 1234567890, - * and the TON/NPI is 0x81, - * The field 'Length of BCD number' should be 06, which is - * 1 byte to store the TON/NPI, 0x81 - * 5 bytes to store the BCD number 2143658709. - * - * Here the definition of the length is different from SMS spec, - * TS 23.040 9.1.2.5, which the length means - * "number of useful semi-octets within the Address-Value field". - */ - readDiallingNumber: function(len) { - if (DEBUG) this.context.debug("PDU: Going to read Dialling number: " + len); - if (len === 0) { - return ""; - } - - let GsmPDUHelper = this.context.GsmPDUHelper; - - // TOA = TON + NPI - let toa = GsmPDUHelper.readHexOctet(); - - let number = GsmPDUHelper.readSwappedNibbleExtendedBcdString(len - 1); - if (number.length <= 0) { - if (DEBUG) this.context.debug("No number provided"); - return ""; - } - if ((toa >> 4) == (PDU_TOA_INTERNATIONAL >> 4)) { - number = '+' + number; - } - return number; - }, - - /** - * Write Dialling Number. - * - * @param number The Dialling number - */ - writeDiallingNumber: function(number) { - let GsmPDUHelper = this.context.GsmPDUHelper; - - let toa = PDU_TOA_ISDN; // 81 - if (number[0] == '+') { - toa = PDU_TOA_INTERNATIONAL | PDU_TOA_ISDN; // 91 - number = number.substring(1); - } - GsmPDUHelper.writeHexOctet(toa); - GsmPDUHelper.writeSwappedNibbleBCD(number); - }, - - readNumberWithLength: function() { - let Buf = this.context.Buf; - let number = ""; - let numLen = this.context.GsmPDUHelper.readHexOctet(); - if (numLen != 0xff) { - if (numLen > ADN_MAX_BCD_NUMBER_BYTES) { - if (DEBUG) { - this.context.debug( - "Error: invalid length of BCD number/SSC contents - " + numLen); - } - Buf.seekIncoming(ADN_MAX_BCD_NUMBER_BYTES * Buf.PDU_HEX_OCTET_SIZE); - return number; - } - - number = this.readDiallingNumber(numLen); - Buf.seekIncoming((ADN_MAX_BCD_NUMBER_BYTES - numLen) * Buf.PDU_HEX_OCTET_SIZE); - } else { - Buf.seekIncoming(ADN_MAX_BCD_NUMBER_BYTES * Buf.PDU_HEX_OCTET_SIZE); - } - - return number; - }, - - /** - * Write Number with Length - * - * @param number The value to be written. - * - * @return The number has been written into Buf. - */ - writeNumberWithLength: function(number) { - let GsmPDUHelper = this.context.GsmPDUHelper; - - if (number) { - let numStart = number[0] == "+" ? 1 : 0; - let writtenNumber = number.substring(0, numStart) + - number.substring(numStart) - .replace(/[^0-9*#,]/g, ""); - let numDigits = writtenNumber.length - numStart; - - if (numDigits > ADN_MAX_NUMBER_DIGITS) { - writtenNumber = writtenNumber.substring(0, ADN_MAX_NUMBER_DIGITS + numStart); - numDigits = writtenNumber.length - numStart; - } - - // +1 for TON/NPI - let numLen = Math.ceil(numDigits / 2) + 1; - GsmPDUHelper.writeHexOctet(numLen); - this.writeDiallingNumber(writtenNumber.replace(/\*/g, "a") - .replace(/\#/g, "b") - .replace(/\,/g, "c")); - // Write trailing 0xff of Dialling Number. - for (let i = 0; i < ADN_MAX_BCD_NUMBER_BYTES - numLen; i++) { - GsmPDUHelper.writeHexOctet(0xff); - } - return writtenNumber; - } else { - // +1 for numLen - for (let i = 0; i < ADN_MAX_BCD_NUMBER_BYTES + 1; i++) { - GsmPDUHelper.writeHexOctet(0xff); - } - return ""; - } - } -}; - -function StkCommandParamsFactoryObject(aContext) { - this.context = aContext; -} -StkCommandParamsFactoryObject.prototype = { - context: null, - - createParam: function(cmdDetails, ctlvs, onComplete) { - let method = this[cmdDetails.typeOfCommand]; - if (typeof method != "function") { - if (DEBUG) { - this.context.debug("Unknown proactive command " + - cmdDetails.typeOfCommand.toString(16)); - } - return; - } - method.call(this, cmdDetails, ctlvs, onComplete); - }, - - loadIcons: function(iconIdCtlvs, callback) { - if (!iconIdCtlvs || - !this.context.ICCUtilsHelper.isICCServiceAvailable("IMG")) { - callback(null); - return; - } - - let onerror = (function() { - callback(null); - }).bind(this); - - let onsuccess = (function(aIcons) { - callback(aIcons); - }).bind(this); - - this.context.IconLoader.loadIcons(iconIdCtlvs.map(aCtlv => aCtlv.value.identifier), - onsuccess, - onerror); - }, - - appendIconIfNecessary: function(iconIdCtlvs, result, onComplete) { - this.loadIcons(iconIdCtlvs, (aIcons) => { - if (aIcons) { - result.icons = aIcons[0]; - result.iconSelfExplanatory = - iconIdCtlvs[0].value.qualifier == 0 ? true : false; - } - - onComplete(result); - }); - }, - - /** - * Construct a param for Refresh. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processRefresh: function(cmdDetails, ctlvs, onComplete) { - let refreshType = cmdDetails.commandQualifier; - switch (refreshType) { - case STK_REFRESH_FILE_CHANGE: - case STK_REFRESH_NAA_INIT_AND_FILE_CHANGE: - let ctlv = this.context.StkProactiveCmdHelper.searchForTag( - COMPREHENSIONTLV_TAG_FILE_LIST, ctlvs); - if (ctlv) { - let list = ctlv.value.fileList; - if (DEBUG) { - this.context.debug("Refresh, list = " + list); - } - this.context.ICCRecordHelper.fetchICCRecords(); - } - break; - } - - onComplete(null); - }, - - /** - * Construct a param for Poll Interval. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processPollInterval: function(cmdDetails, ctlvs, onComplete) { - // Duration is mandatory. - let ctlv = this.context.StkProactiveCmdHelper.searchForTag( - COMPREHENSIONTLV_TAG_DURATION, ctlvs); - if (!ctlv) { - this.context.RIL.sendStkTerminalResponse({ - command: cmdDetails, - resultCode: STK_RESULT_REQUIRED_VALUES_MISSING}); - throw new Error("Stk Poll Interval: Required value missing : Duration"); - } - - onComplete(ctlv.value); - }, - - /** - * Construct a param for Poll Off. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processPollOff: function(cmdDetails, ctlvs, onComplete) { - onComplete(null); - }, - - /** - * Construct a param for Set Up Event list. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processSetUpEventList: function(cmdDetails, ctlvs, onComplete) { - // Event list is mandatory. - let ctlv = this.context.StkProactiveCmdHelper.searchForTag( - COMPREHENSIONTLV_TAG_EVENT_LIST, ctlvs); - if (!ctlv) { - this.context.RIL.sendStkTerminalResponse({ - command: cmdDetails, - resultCode: STK_RESULT_REQUIRED_VALUES_MISSING}); - throw new Error("Stk Event List: Required value missing : Event List"); - } - - onComplete(ctlv.value || { eventList: null }); - }, - - /** - * Construct a param for Setup Menu. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processSetupMenu: function(cmdDetails, ctlvs, onComplete) { - let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper; - let menu = { - // Help information available. - isHelpAvailable: !!(cmdDetails.commandQualifier & 0x80) - }; - - let selectedCtlvs = StkProactiveCmdHelper.searchForSelectedTags(ctlvs, [ - COMPREHENSIONTLV_TAG_ALPHA_ID, - COMPREHENSIONTLV_TAG_ITEM, - COMPREHENSIONTLV_TAG_ITEM_ID, - COMPREHENSIONTLV_TAG_NEXT_ACTION_IND, - COMPREHENSIONTLV_TAG_ICON_ID, - COMPREHENSIONTLV_TAG_ICON_ID_LIST - ]); - - // Alpha identifier is optional. - let ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - if (ctlv) { - menu.title = ctlv.value.identifier; - } - - // Item data object for item 1 is mandatory. - let menuCtlvs = selectedCtlvs[COMPREHENSIONTLV_TAG_ITEM]; - if (!menuCtlvs) { - this.context.RIL.sendStkTerminalResponse({ - command: cmdDetails, - resultCode: STK_RESULT_REQUIRED_VALUES_MISSING}); - throw new Error("Stk Menu: Required value missing : items"); - } - menu.items = menuCtlvs.map(aCtlv => aCtlv.value); - - // Item identifier is optional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ITEM_ID); - if (ctlv) { - menu.defaultItem = ctlv.value.identifier - 1; - } - - // Items next action indicator is optional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_NEXT_ACTION_IND); - if (ctlv) { - menu.nextActionList = ctlv.value; - } - - // Icon identifier is optional. - let iconIdCtlvs = null; - let menuIconCtlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ICON_ID); - if (menuIconCtlv) { - iconIdCtlvs = [menuIconCtlv]; - } - - // Item icon identifier list is optional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ICON_ID_LIST); - if (ctlv) { - if (!iconIdCtlvs) { - iconIdCtlvs = []; - }; - let iconIdList = ctlv.value; - iconIdCtlvs = iconIdCtlvs.concat(iconIdList.identifiers.map((aId) => { - return { - value: { qualifier: iconIdList.qualifier, identifier: aId } - }; - })); - } - - this.loadIcons(iconIdCtlvs, (aIcons) => { - if (aIcons) { - if (menuIconCtlv) { - menu.iconSelfExplanatory = - (iconIdCtlvs.shift().value.qualifier == 0) ? true: false; - menu.icons = aIcons.shift(); - } - - for (let i = 0; i < aIcons.length; i++) { - menu.items[i].icons = aIcons[i]; - menu.items[i].iconSelfExplanatory = - (iconIdCtlvs[i].value.qualifier == 0) ? true: false; - } - } - - onComplete(menu); - }); - }, - - /** - * Construct a param for Select Item. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processSelectItem: function(cmdDetails, ctlvs, onComplete) { - this.processSetupMenu(cmdDetails, ctlvs, (menu) => { - // The 1st bit and 2nd bit determines the presentation type. - menu.presentationType = cmdDetails.commandQualifier & 0x03; - onComplete(menu); - }); - }, - - /** - * Construct a param for Display Text. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processDisplayText: function(cmdDetails, ctlvs, onComplete) { - let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper; - let textMsg = { - isHighPriority: !!(cmdDetails.commandQualifier & 0x01), - userClear: !!(cmdDetails.commandQualifier & 0x80) - }; - - let selectedCtlvs = StkProactiveCmdHelper.searchForSelectedTags(ctlvs, [ - COMPREHENSIONTLV_TAG_TEXT_STRING, - COMPREHENSIONTLV_TAG_IMMEDIATE_RESPONSE, - COMPREHENSIONTLV_TAG_DURATION, - COMPREHENSIONTLV_TAG_ICON_ID - ]); - - // Text string is mandatory. - let ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_TEXT_STRING); - if (!ctlv) { - this.context.RIL.sendStkTerminalResponse({ - command: cmdDetails, - resultCode: STK_RESULT_REQUIRED_VALUES_MISSING}); - throw new Error("Stk Display Text: Required value missing : Text String"); - } - textMsg.text = ctlv.value.textString; - - // Immediate response is optional. - textMsg.responseNeeded = - !!(selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_IMMEDIATE_RESPONSE)); - - // Duration is optional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_DURATION); - if (ctlv) { - textMsg.duration = ctlv.value; - } - - // Icon identifier is optional. - this.appendIconIfNecessary(selectedCtlvs[COMPREHENSIONTLV_TAG_ICON_ID] || null, - textMsg, - onComplete); - }, - - /** - * Construct a param for Setup Idle Mode Text. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processSetUpIdleModeText: function(cmdDetails, ctlvs, onComplete) { - let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper; - let textMsg = {}; - - let selectedCtlvs = StkProactiveCmdHelper.searchForSelectedTags(ctlvs, [ - COMPREHENSIONTLV_TAG_TEXT_STRING, - COMPREHENSIONTLV_TAG_ICON_ID - ]); - - // Text string is mandatory. - let ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_TEXT_STRING); - if (!ctlv) { - this.context.RIL.sendStkTerminalResponse({ - command: cmdDetails, - resultCode: STK_RESULT_REQUIRED_VALUES_MISSING}); - throw new Error("Stk Set Up Idle Text: Required value missing : Text String"); - } - textMsg.text = ctlv.value.textString; - - // Icon identifier is optional. - this.appendIconIfNecessary(selectedCtlvs[COMPREHENSIONTLV_TAG_ICON_ID] || null, - textMsg, - onComplete); - }, - - /** - * Construct a param for Get Inkey. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processGetInkey: function(cmdDetails, ctlvs, onComplete) { - let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper; - let input = { - minLength: 1, - maxLength: 1, - isAlphabet: !!(cmdDetails.commandQualifier & 0x01), - isUCS2: !!(cmdDetails.commandQualifier & 0x02), - // Character sets defined in bit 1 and bit 2 are disable and - // the YES/NO reponse is required. - isYesNoRequested: !!(cmdDetails.commandQualifier & 0x04), - // Help information available. - isHelpAvailable: !!(cmdDetails.commandQualifier & 0x80) - }; - - let selectedCtlvs = StkProactiveCmdHelper.searchForSelectedTags(ctlvs, [ - COMPREHENSIONTLV_TAG_TEXT_STRING, - COMPREHENSIONTLV_TAG_DURATION, - COMPREHENSIONTLV_TAG_ICON_ID - ]); - - // Text string is mandatory. - let ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_TEXT_STRING); - if (!ctlv) { - this.context.RIL.sendStkTerminalResponse({ - command: cmdDetails, - resultCode: STK_RESULT_REQUIRED_VALUES_MISSING}); - throw new Error("Stk Get InKey: Required value missing : Text String"); - } - input.text = ctlv.value.textString; - - // Duration is optional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_DURATION); - if (ctlv) { - input.duration = ctlv.value; - } - - // Icon identifier is optional. - this.appendIconIfNecessary(selectedCtlvs[COMPREHENSIONTLV_TAG_ICON_ID] || null, - input, - onComplete); - }, - - /** - * Construct a param for Get Input. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processGetInput: function(cmdDetails, ctlvs, onComplete) { - let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper; - let input = { - isAlphabet: !!(cmdDetails.commandQualifier & 0x01), - isUCS2: !!(cmdDetails.commandQualifier & 0x02), - // User input shall not be revealed - hideInput: !!(cmdDetails.commandQualifier & 0x04), - // User input in SMS packed format - isPacked: !!(cmdDetails.commandQualifier & 0x08), - // Help information available. - isHelpAvailable: !!(cmdDetails.commandQualifier & 0x80) - }; - - let selectedCtlvs = StkProactiveCmdHelper.searchForSelectedTags(ctlvs, [ - COMPREHENSIONTLV_TAG_TEXT_STRING, - COMPREHENSIONTLV_TAG_RESPONSE_LENGTH, - COMPREHENSIONTLV_TAG_DEFAULT_TEXT, - COMPREHENSIONTLV_TAG_ICON_ID - ]); - - // Text string is mandatory. - let ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_TEXT_STRING); - if (!ctlv) { - this.context.RIL.sendStkTerminalResponse({ - command: cmdDetails, - resultCode: STK_RESULT_REQUIRED_VALUES_MISSING}); - throw new Error("Stk Get Input: Required value missing : Text String"); - } - input.text = ctlv.value.textString; - - // Response length is mandatory. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_RESPONSE_LENGTH); - if (!ctlv) { - this.context.RIL.sendStkTerminalResponse({ - command: cmdDetails, - resultCode: STK_RESULT_REQUIRED_VALUES_MISSING}); - throw new Error("Stk Get Input: Required value missing : Response Length"); - } - input.minLength = ctlv.value.minLength; - input.maxLength = ctlv.value.maxLength; - - // Default text is optional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_DEFAULT_TEXT); - if (ctlv) { - input.defaultText = ctlv.value.textString; - } - - // Icon identifier is optional. - this.appendIconIfNecessary(selectedCtlvs[COMPREHENSIONTLV_TAG_ICON_ID] || null, - input, - onComplete); - }, - - /** - * Construct a param for SendSS/SMS/USSD/DTMF. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processEventNotify: function(cmdDetails, ctlvs, onComplete) { - let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper; - let textMsg = {}; - - let selectedCtlvs = StkProactiveCmdHelper.searchForSelectedTags(ctlvs, [ - COMPREHENSIONTLV_TAG_ALPHA_ID, - COMPREHENSIONTLV_TAG_ICON_ID - ]); - - // Alpha identifier is optional. - let ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - if (ctlv) { - textMsg.text = ctlv.value.identifier; - } - - // According to section 6.4.10 of |ETSI TS 102 223|: - // - // - if the alpha identifier is provided by the UICC and is a null data - // object (i.e. length = '00' and no value part), this is an indication - // that the terminal should not give any information to the user on the - // fact that the terminal is sending a short message; - // - // - if the alpha identifier is not provided by the UICC, the terminal may - // give information to the user concerning what is happening. - // - // ICCPDUHelper reads alpha id as an empty string if the length is zero, - // hence we'll notify the caller when it's not an empty string. - if (textMsg.text !== "") { - // Icon identifier is optional. - this.appendIconIfNecessary(selectedCtlvs[COMPREHENSIONTLV_TAG_ICON_ID] || null, - textMsg, - onComplete); - } - }, - - /** - * Construct a param for Setup Call. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processSetupCall: function(cmdDetails, ctlvs, onComplete) { - let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper; - let call = {}; - let confirmMessage = {}; - let callMessage = {}; - - let selectedCtlvs = StkProactiveCmdHelper.searchForSelectedTags(ctlvs, [ - COMPREHENSIONTLV_TAG_ADDRESS, - COMPREHENSIONTLV_TAG_ALPHA_ID, - COMPREHENSIONTLV_TAG_ICON_ID, - COMPREHENSIONTLV_TAG_DURATION - ]); - - // Address is mandatory. - let ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ADDRESS); - if (!ctlv) { - this.context.RIL.sendStkTerminalResponse({ - command: cmdDetails, - resultCode: STK_RESULT_REQUIRED_VALUES_MISSING}); - throw new Error("Stk Set Up Call: Required value missing : Address"); - } - call.address = ctlv.value.number; - - // Alpha identifier (user confirmation phase) is optional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - if (ctlv) { - confirmMessage.text = ctlv.value.identifier; - call.confirmMessage = confirmMessage; - } - - // Alpha identifier (call set up phase) is optional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - if (ctlv) { - callMessage.text = ctlv.value.identifier; - call.callMessage = callMessage; - } - - // Duration is optional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_DURATION); - if (ctlv) { - call.duration = ctlv.value; - } - - // Icon identifier is optional. - let iconIdCtlvs = selectedCtlvs[COMPREHENSIONTLV_TAG_ICON_ID] || null; - this.loadIcons(iconIdCtlvs, (aIcons) => { - if (aIcons) { - confirmMessage.icons = aIcons[0]; - confirmMessage.iconSelfExplanatory = - (iconIdCtlvs[0].value.qualifier == 0) ? true: false; - call.confirmMessage = confirmMessage; - - if (aIcons.length > 1) { - callMessage.icons = aIcons[1]; - callMessage.iconSelfExplanatory = - (iconIdCtlvs[1].value.qualifier == 0) ? true: false; - call.callMessage = callMessage; - } - } - - onComplete(call); - }); - }, - - /** - * Construct a param for Launch Browser. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processLaunchBrowser: function(cmdDetails, ctlvs, onComplete) { - let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper; - let browser = { - mode: cmdDetails.commandQualifier & 0x03 - }; - let confirmMessage = {}; - - let selectedCtlvs = StkProactiveCmdHelper.searchForSelectedTags(ctlvs, [ - COMPREHENSIONTLV_TAG_URL, - COMPREHENSIONTLV_TAG_ALPHA_ID, - COMPREHENSIONTLV_TAG_ICON_ID - ]); - - // URL is mandatory. - let ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_URL); - if (!ctlv) { - this.context.RIL.sendStkTerminalResponse({ - command: cmdDetails, - resultCode: STK_RESULT_REQUIRED_VALUES_MISSING}); - throw new Error("Stk Launch Browser: Required value missing : URL"); - } - browser.url = ctlv.value.url; - - // Alpha identifier is optional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - if (ctlv) { - confirmMessage.text = ctlv.value.identifier; - browser.confirmMessage = confirmMessage; - } - - // Icon identifier is optional. - let iconIdCtlvs = selectedCtlvs[COMPREHENSIONTLV_TAG_ICON_ID] || null; - this.loadIcons(iconIdCtlvs, (aIcons) => { - if (aIcons) { - confirmMessage.icons = aIcons[0]; - confirmMessage.iconSelfExplanatory = - (iconIdCtlvs[0].value.qualifier == 0) ? true: false; - browser.confirmMessage = confirmMessage; - } - - onComplete(browser); - }); - }, - - /** - * Construct a param for Play Tone. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processPlayTone: function(cmdDetails, ctlvs, onComplete) { - let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper; - let playTone = { - // The vibrate is only defined in TS 102.223. - isVibrate: !!(cmdDetails.commandQualifier & 0x01) - }; - - let selectedCtlvs = StkProactiveCmdHelper.searchForSelectedTags(ctlvs, [ - COMPREHENSIONTLV_TAG_ALPHA_ID, - COMPREHENSIONTLV_TAG_TONE, - COMPREHENSIONTLV_TAG_DURATION, - COMPREHENSIONTLV_TAG_ICON_ID - ]); - - // Alpha identifier is optional. - let ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - if (ctlv) { - playTone.text = ctlv.value.identifier; - } - - // Tone is optional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_TONE); - if (ctlv) { - playTone.tone = ctlv.value.tone; - } - - // Duration is optional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_DURATION); - if (ctlv) { - playTone.duration = ctlv.value; - } - - // Icon identifier is optional. - this.appendIconIfNecessary(selectedCtlvs[COMPREHENSIONTLV_TAG_ICON_ID] || null, - playTone, - onComplete); - }, - - /** - * Construct a param for Provide Local Information. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processProvideLocalInfo: function(cmdDetails, ctlvs, onComplete) { - let provideLocalInfo = { - localInfoType: cmdDetails.commandQualifier - }; - - onComplete(provideLocalInfo); - }, - - /** - * Construct a param for Timer Management. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processTimerManagement: function(cmdDetails, ctlvs, onComplete) { - let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper; - let timer = { - timerAction: cmdDetails.commandQualifier - }; - - let selectedCtlvs = StkProactiveCmdHelper.searchForSelectedTags(ctlvs, [ - COMPREHENSIONTLV_TAG_TIMER_IDENTIFIER, - COMPREHENSIONTLV_TAG_TIMER_VALUE - ]); - - // Timer identifier is mandatory. - let ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_TIMER_IDENTIFIER); - if (!ctlv) { - this.context.RIL.sendStkTerminalResponse({ - command: cmdDetails, - resultCode: STK_RESULT_REQUIRED_VALUES_MISSING}); - throw new Error("Stk Timer Management: Required value missing : Timer Identifier"); - } - timer.timerId = ctlv.value.timerId; - - // Timer value is conditional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_TIMER_VALUE); - if (ctlv) { - timer.timerValue = ctlv.value.timerValue; - } - - onComplete(timer); - }, - - /** - * Construct a param for BIP commands. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processBipMessage: function(cmdDetails, ctlvs, onComplete) { - let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper; - let bipMsg = {}; - - let selectedCtlvs = StkProactiveCmdHelper.searchForSelectedTags(ctlvs, [ - COMPREHENSIONTLV_TAG_ALPHA_ID, - COMPREHENSIONTLV_TAG_ICON_ID - ]); - - // Alpha identifier is optional. - let ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - if (ctlv) { - bipMsg.text = ctlv.value.identifier; - } - - // Icon identifier is optional. - this.appendIconIfNecessary(selectedCtlvs[COMPREHENSIONTLV_TAG_ICON_ID] || null, - bipMsg, - onComplete); - } -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_REFRESH] = function STK_CMD_REFRESH(cmdDetails, ctlvs, onComplete) { - return this.processRefresh(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_POLL_INTERVAL] = function STK_CMD_POLL_INTERVAL(cmdDetails, ctlvs, onComplete) { - return this.processPollInterval(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_POLL_OFF] = function STK_CMD_POLL_OFF(cmdDetails, ctlvs, onComplete) { - return this.processPollOff(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_PROVIDE_LOCAL_INFO] = function STK_CMD_PROVIDE_LOCAL_INFO(cmdDetails, ctlvs, onComplete) { - return this.processProvideLocalInfo(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_SET_UP_EVENT_LIST] = function STK_CMD_SET_UP_EVENT_LIST(cmdDetails, ctlvs, onComplete) { - return this.processSetUpEventList(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_SET_UP_MENU] = function STK_CMD_SET_UP_MENU(cmdDetails, ctlvs, onComplete) { - return this.processSetupMenu(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_SELECT_ITEM] = function STK_CMD_SELECT_ITEM(cmdDetails, ctlvs, onComplete) { - return this.processSelectItem(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_DISPLAY_TEXT] = function STK_CMD_DISPLAY_TEXT(cmdDetails, ctlvs, onComplete) { - return this.processDisplayText(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_SET_UP_IDLE_MODE_TEXT] = function STK_CMD_SET_UP_IDLE_MODE_TEXT(cmdDetails, ctlvs, onComplete) { - return this.processSetUpIdleModeText(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_GET_INKEY] = function STK_CMD_GET_INKEY(cmdDetails, ctlvs, onComplete) { - return this.processGetInkey(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_GET_INPUT] = function STK_CMD_GET_INPUT(cmdDetails, ctlvs, onComplete) { - return this.processGetInput(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_SEND_SS] = function STK_CMD_SEND_SS(cmdDetails, ctlvs, onComplete) { - return this.processEventNotify(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_SEND_USSD] = function STK_CMD_SEND_USSD(cmdDetails, ctlvs, onComplete) { - return this.processEventNotify(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_SEND_SMS] = function STK_CMD_SEND_SMS(cmdDetails, ctlvs, onComplete) { - return this.processEventNotify(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_SEND_DTMF] = function STK_CMD_SEND_DTMF(cmdDetails, ctlvs, onComplete) { - return this.processEventNotify(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_SET_UP_CALL] = function STK_CMD_SET_UP_CALL(cmdDetails, ctlvs, onComplete) { - return this.processSetupCall(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_LAUNCH_BROWSER] = function STK_CMD_LAUNCH_BROWSER(cmdDetails, ctlvs, onComplete) { - return this.processLaunchBrowser(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_PLAY_TONE] = function STK_CMD_PLAY_TONE(cmdDetails, ctlvs, onComplete) { - return this.processPlayTone(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_TIMER_MANAGEMENT] = function STK_CMD_TIMER_MANAGEMENT(cmdDetails, ctlvs, onComplete) { - return this.processTimerManagement(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_OPEN_CHANNEL] = function STK_CMD_OPEN_CHANNEL(cmdDetails, ctlvs, onComplete) { - return this.processBipMessage(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_CLOSE_CHANNEL] = function STK_CMD_CLOSE_CHANNEL(cmdDetails, ctlvs, onComplete) { - return this.processBipMessage(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_RECEIVE_DATA] = function STK_CMD_RECEIVE_DATA(cmdDetails, ctlvs, onComplete) { - return this.processBipMessage(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_SEND_DATA] = function STK_CMD_SEND_DATA(cmdDetails, ctlvs, onComplete) { - return this.processBipMessage(cmdDetails, ctlvs, onComplete); -}; - -function StkProactiveCmdHelperObject(aContext) { - this.context = aContext; -} -StkProactiveCmdHelperObject.prototype = { - context: null, - - retrieve: function(tag, length) { - let method = this[tag]; - if (typeof method != "function") { - if (DEBUG) { - this.context.debug("Unknown comprehension tag " + tag.toString(16)); - } - let Buf = this.context.Buf; - Buf.seekIncoming(length * Buf.PDU_HEX_OCTET_SIZE); - return null; - } - return method.call(this, length); - }, - - /** - * Command Details. - * - * | Byte | Description | Length | - * | 1 | Command details Tag | 1 | - * | 2 | Length = 03 | 1 | - * | 3 | Command number | 1 | - * | 4 | Type of Command | 1 | - * | 5 | Command Qualifier | 1 | - */ - retrieveCommandDetails: function(length) { - let GsmPDUHelper = this.context.GsmPDUHelper; - let cmdDetails = { - commandNumber: GsmPDUHelper.readHexOctet(), - typeOfCommand: GsmPDUHelper.readHexOctet(), - commandQualifier: GsmPDUHelper.readHexOctet() - }; - return cmdDetails; - }, - - /** - * Device Identities. - * - * | Byte | Description | Length | - * | 1 | Device Identity Tag | 1 | - * | 2 | Length = 02 | 1 | - * | 3 | Source device Identity | 1 | - * | 4 | Destination device Id | 1 | - */ - retrieveDeviceId: function(length) { - let GsmPDUHelper = this.context.GsmPDUHelper; - let deviceId = { - sourceId: GsmPDUHelper.readHexOctet(), - destinationId: GsmPDUHelper.readHexOctet() - }; - return deviceId; - }, - - /** - * Alpha Identifier. - * - * | Byte | Description | Length | - * | 1 | Alpha Identifier Tag | 1 | - * | 2 ~ (Y-1)+2 | Length (X) | Y | - * | (Y-1)+3 ~ | Alpha identfier | X | - * | (Y-1)+X+2 | | | - */ - retrieveAlphaId: function(length) { - let alphaId = { - identifier: this.context.ICCPDUHelper.readAlphaIdentifier(length) - }; - return alphaId; - }, - - /** - * Duration. - * - * | Byte | Description | Length | - * | 1 | Response Length Tag | 1 | - * | 2 | Lenth = 02 | 1 | - * | 3 | Time unit | 1 | - * | 4 | Time interval | 1 | - */ - retrieveDuration: function(length) { - let GsmPDUHelper = this.context.GsmPDUHelper; - let duration = { - timeUnit: GsmPDUHelper.readHexOctet(), - timeInterval: GsmPDUHelper.readHexOctet(), - }; - return duration; - }, - - /** - * Address. - * - * | Byte | Description | Length | - * | 1 | Alpha Identifier Tag | 1 | - * | 2 ~ (Y-1)+2 | Length (X) | Y | - * | (Y-1)+3 | TON and NPI | 1 | - * | (Y-1)+4 ~ | Dialling number | X | - * | (Y-1)+X+2 | | | - */ - retrieveAddress: function(length) { - let address = { - number : this.context.ICCPDUHelper.readDiallingNumber(length) - }; - return address; - }, - - /** - * Text String. - * - * | Byte | Description | Length | - * | 1 | Text String Tag | 1 | - * | 2 ~ (Y-1)+2 | Length (X) | Y | - * | (Y-1)+3 | Data coding scheme | 1 | - * | (Y-1)+4~ | Text String | X | - * | (Y-1)+X+2 | | | - */ - retrieveTextString: function(length) { - if (!length) { - // null string. - return {textString: null}; - } - - let GsmPDUHelper = this.context.GsmPDUHelper; - let text = { - codingScheme: GsmPDUHelper.readHexOctet() - }; - - length--; // -1 for the codingScheme. - switch (text.codingScheme & 0x0c) { - case STK_TEXT_CODING_GSM_7BIT_PACKED: - text.textString = - GsmPDUHelper.readSeptetsToString(Math.floor(length * 8 / 7), 0, 0, 0); - break; - case STK_TEXT_CODING_GSM_8BIT: - text.textString = - this.context.ICCPDUHelper.read8BitUnpackedToString(length); - break; - case STK_TEXT_CODING_UCS2: - text.textString = GsmPDUHelper.readUCS2String(length); - break; - } - return text; - }, - - /** - * Tone. - * - * | Byte | Description | Length | - * | 1 | Tone Tag | 1 | - * | 2 | Lenth = 01 | 1 | - * | 3 | Tone | 1 | - */ - retrieveTone: function(length) { - let tone = { - tone: this.context.GsmPDUHelper.readHexOctet(), - }; - return tone; - }, - - /** - * Item. - * - * | Byte | Description | Length | - * | 1 | Item Tag | 1 | - * | 2 ~ (Y-1)+2 | Length (X) | Y | - * | (Y-1)+3 | Identifier of item | 1 | - * | (Y-1)+4 ~ | Text string of item | X | - * | (Y-1)+X+2 | | | - */ - retrieveItem: function(length) { - // TS 102.223 ,clause 6.6.7 SET-UP MENU - // If the "Item data object for item 1" is a null data object - // (i.e. length = '00' and no value part), this is an indication to the ME - // to remove the existing menu from the menu system in the ME. - if (!length) { - return null; - } - let item = { - identifier: this.context.GsmPDUHelper.readHexOctet(), - text: this.context.ICCPDUHelper.readAlphaIdentifier(length - 1) - }; - return item; - }, - - /** - * Item Identifier. - * - * | Byte | Description | Length | - * | 1 | Item Identifier Tag | 1 | - * | 2 | Lenth = 01 | 1 | - * | 3 | Identifier of Item chosen | 1 | - */ - retrieveItemId: function(length) { - let itemId = { - identifier: this.context.GsmPDUHelper.readHexOctet() - }; - return itemId; - }, - - /** - * Response Length. - * - * | Byte | Description | Length | - * | 1 | Response Length Tag | 1 | - * | 2 | Lenth = 02 | 1 | - * | 3 | Minimum length of response | 1 | - * | 4 | Maximum length of response | 1 | - */ - retrieveResponseLength: function(length) { - let GsmPDUHelper = this.context.GsmPDUHelper; - let rspLength = { - minLength : GsmPDUHelper.readHexOctet(), - maxLength : GsmPDUHelper.readHexOctet() - }; - return rspLength; - }, - - /** - * File List. - * - * | Byte | Description | Length | - * | 1 | File List Tag | 1 | - * | 2 ~ (Y-1)+2 | Length (X) | Y | - * | (Y-1)+3 | Number of files | 1 | - * | (Y-1)+4 ~ | Files | X | - * | (Y-1)+X+2 | | | - */ - retrieveFileList: function(length) { - let num = this.context.GsmPDUHelper.readHexOctet(); - let fileList = ""; - length--; // -1 for the num octet. - for (let i = 0; i < 2 * length; i++) { - // Didn't use readHexOctet here, - // otherwise 0x00 will be "0", not "00" - fileList += String.fromCharCode(this.context.Buf.readUint16()); - } - return { - fileList: fileList - }; - }, - - /** - * Default Text. - * - * Same as Text String. - */ - retrieveDefaultText: function(length) { - return this.retrieveTextString(length); - }, - - /** - * Event List. - */ - retrieveEventList: function(length) { - if (!length) { - // null means an indication to ME to remove the existing list of events - // in ME. - return null; - } - - let GsmPDUHelper = this.context.GsmPDUHelper; - let eventList = []; - for (let i = 0; i < length; i++) { - eventList.push(GsmPDUHelper.readHexOctet()); - } - return { - eventList: eventList - }; - }, - - /** - * Icon Id. - * - * | Byte | Description | Length | - * | 1 | Icon Identifier Tag | 1 | - * | 2 | Length = 02 | 1 | - * | 3 | Icon qualifier | 1 | - * | 4 | Icon identifier | 1 | - */ - retrieveIconId: function(length) { - if (!length) { - return null; - } - - let iconId = { - qualifier: this.context.GsmPDUHelper.readHexOctet(), - identifier: this.context.GsmPDUHelper.readHexOctet() - }; - return iconId; - }, - - /** - * Icon Id List. - * - * | Byte | Description | Length | - * | 1 | Icon Identifier Tag | 1 | - * | 2 | Length = X | 1 | - * | 3 | Icon qualifier | 1 | - * | 4~ | Icon identifier | X-1 | - * | 4+X-2 | | | - */ - retrieveIconIdList: function(length) { - if (!length) { - return null; - } - - let iconIdList = { - qualifier: this.context.GsmPDUHelper.readHexOctet(), - identifiers: [] - }; - for (let i = 0; i < length - 1; i++) { - iconIdList.identifiers.push(this.context.GsmPDUHelper.readHexOctet()); - } - return iconIdList; - }, - - /** - * Timer Identifier. - * - * | Byte | Description | Length | - * | 1 | Timer Identifier Tag | 1 | - * | 2 | Length = 01 | 1 | - * | 3 | Timer Identifier | 1 | - */ - retrieveTimerId: function(length) { - let id = { - timerId: this.context.GsmPDUHelper.readHexOctet() - }; - return id; - }, - - /** - * Timer Value. - * - * | Byte | Description | Length | - * | 1 | Timer Value Tag | 1 | - * | 2 | Length = 03 | 1 | - * | 3 | Hour | 1 | - * | 4 | Minute | 1 | - * | 5 | Second | 1 | - */ - retrieveTimerValue: function(length) { - let GsmPDUHelper = this.context.GsmPDUHelper; - let value = { - timerValue: (GsmPDUHelper.readSwappedNibbleBcdNum(1) * 60 * 60) + - (GsmPDUHelper.readSwappedNibbleBcdNum(1) * 60) + - (GsmPDUHelper.readSwappedNibbleBcdNum(1)) - }; - return value; - }, - - /** - * Immediate Response. - * - * | Byte | Description | Length | - * | 1 | Immediate Response Tag | 1 | - * | 2 | Length = 00 | 1 | - */ - retrieveImmediaResponse: function(length) { - return {}; - }, - - /** - * URL - * - * | Byte | Description | Length | - * | 1 | URL Tag | 1 | - * | 2 ~ (Y+1) | Length(X) | Y | - * | (Y+2) ~ | URL | X | - * | (Y+1+X) | | | - */ - retrieveUrl: function(length) { - let GsmPDUHelper = this.context.GsmPDUHelper; - let s = ""; - for (let i = 0; i < length; i++) { - s += String.fromCharCode(GsmPDUHelper.readHexOctet()); - } - return {url: s}; - }, - - /** - * Next Action Indicator List. - * - * | Byte | Description | Length | - * | 1 | Next Action tag | 1 | - * | 1 | Length(X) | 1 | - * | 3~ | Next Action List | X | - * | 3+X-1 | | | - */ - retrieveNextActionList: function(length) { - let GsmPDUHelper = this.context.GsmPDUHelper; - let nextActionList = []; - for (let i = 0; i < length; i++) { - nextActionList.push(GsmPDUHelper.readHexOctet()); - } - return nextActionList; - }, - - searchForTag: function(tag, ctlvs) { - for (let ctlv of ctlvs) { - if ((ctlv.tag & ~COMPREHENSIONTLV_FLAG_CR) == tag) { - return ctlv; - } - } - return null; - }, - - searchForSelectedTags: function(ctlvs, tags) { - let ret = { - // Handy utility to de-queue the 1st ctlv of the specified tag. - retrieve: function(aTag) { - return (this[aTag]) ? this[aTag].shift() : null; - } - }; - - ctlvs.forEach((aCtlv) => { - tags.forEach((aTag) => { - if ((aCtlv.tag & ~COMPREHENSIONTLV_FLAG_CR) == aTag) { - if (!ret[aTag]) { - ret[aTag] = []; - } - ret[aTag].push(aCtlv); - } - }); - }); - - return ret; - }, -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_COMMAND_DETAILS] = function COMPREHENSIONTLV_TAG_COMMAND_DETAILS(length) { - return this.retrieveCommandDetails(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_DEVICE_ID] = function COMPREHENSIONTLV_TAG_DEVICE_ID(length) { - return this.retrieveDeviceId(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_ALPHA_ID] = function COMPREHENSIONTLV_TAG_ALPHA_ID(length) { - return this.retrieveAlphaId(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_DURATION] = function COMPREHENSIONTLV_TAG_DURATION(length) { - return this.retrieveDuration(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_ADDRESS] = function COMPREHENSIONTLV_TAG_ADDRESS(length) { - return this.retrieveAddress(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_TEXT_STRING] = function COMPREHENSIONTLV_TAG_TEXT_STRING(length) { - return this.retrieveTextString(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_TONE] = function COMPREHENSIONTLV_TAG_TONE(length) { - return this.retrieveTone(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_ITEM] = function COMPREHENSIONTLV_TAG_ITEM(length) { - return this.retrieveItem(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_ITEM_ID] = function COMPREHENSIONTLV_TAG_ITEM_ID(length) { - return this.retrieveItemId(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_RESPONSE_LENGTH] = function COMPREHENSIONTLV_TAG_RESPONSE_LENGTH(length) { - return this.retrieveResponseLength(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_FILE_LIST] = function COMPREHENSIONTLV_TAG_FILE_LIST(length) { - return this.retrieveFileList(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_DEFAULT_TEXT] = function COMPREHENSIONTLV_TAG_DEFAULT_TEXT(length) { - return this.retrieveDefaultText(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_EVENT_LIST] = function COMPREHENSIONTLV_TAG_EVENT_LIST(length) { - return this.retrieveEventList(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_ICON_ID] = function COMPREHENSIONTLV_TAG_ICON_ID(length) { - return this.retrieveIconId(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_ICON_ID_LIST] = function COMPREHENSIONTLV_TAG_ICON_ID_LIST(length) { - return this.retrieveIconIdList(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_TIMER_IDENTIFIER] = function COMPREHENSIONTLV_TAG_TIMER_IDENTIFIER(length) { - return this.retrieveTimerId(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_TIMER_VALUE] = function COMPREHENSIONTLV_TAG_TIMER_VALUE(length) { - return this.retrieveTimerValue(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_IMMEDIATE_RESPONSE] = function COMPREHENSIONTLV_TAG_IMMEDIATE_RESPONSE(length) { - return this.retrieveImmediaResponse(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_URL] = function COMPREHENSIONTLV_TAG_URL(length) { - return this.retrieveUrl(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_NEXT_ACTION_IND] = function COMPREHENSIONTLV_TAG_NEXT_ACTION_IND(length) { - return this.retrieveNextActionList(length); -}; - -function ComprehensionTlvHelperObject(aContext) { - this.context = aContext; -} -ComprehensionTlvHelperObject.prototype = { - context: null, - - /** - * Decode raw data to a Comprehension-TLV. - */ - decode: function() { - let GsmPDUHelper = this.context.GsmPDUHelper; - - let hlen = 0; // For header(tag field + length field) length. - let temp = GsmPDUHelper.readHexOctet(); - hlen++; - - // TS 101.220, clause 7.1.1 - let tag, cr; - switch (temp) { - // TS 101.220, clause 7.1.1 - case 0x0: // Not used. - case 0xff: // Not used. - case 0x80: // Reserved for future use. - throw new Error("Invalid octet when parsing Comprehension TLV :" + temp); - case 0x7f: // Tag is three byte format. - // TS 101.220 clause 7.1.1.2. - // | Byte 1 | Byte 2 | Byte 3 | - // | | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | | - // | 0x7f |CR | Tag Value | - tag = (GsmPDUHelper.readHexOctet() << 8) | GsmPDUHelper.readHexOctet(); - hlen += 2; - cr = (tag & 0x8000) !== 0; - tag &= ~0x8000; - break; - default: // Tag is single byte format. - tag = temp; - // TS 101.220 clause 7.1.1.1. - // | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | - // |CR | Tag Value | - cr = (tag & 0x80) !== 0; - tag &= ~0x80; - } - - // TS 101.220 clause 7.1.2, Length Encoding. - // Length | Byte 1 | Byte 2 | Byte 3 | Byte 4 | - // 0 - 127 | 00 - 7f | N/A | N/A | N/A | - // 128-255 | 81 | 80 - ff| N/A | N/A | - // 256-65535| 82 | 0100 - ffff | N/A | - // 65536- | 83 | 010000 - ffffff | - // 16777215 - // - // Length errors: TS 11.14, clause 6.10.6 - - let length; // Data length. - temp = GsmPDUHelper.readHexOctet(); - hlen++; - if (temp < 0x80) { - length = temp; - } else if (temp == 0x81) { - length = GsmPDUHelper.readHexOctet(); - hlen++; - if (length < 0x80) { - throw new Error("Invalid length in Comprehension TLV :" + length); - } - } else if (temp == 0x82) { - length = (GsmPDUHelper.readHexOctet() << 8) | GsmPDUHelper.readHexOctet(); - hlen += 2; - if (lenth < 0x0100) { - throw new Error("Invalid length in 3-byte Comprehension TLV :" + length); - } - } else if (temp == 0x83) { - length = (GsmPDUHelper.readHexOctet() << 16) | - (GsmPDUHelper.readHexOctet() << 8) | - GsmPDUHelper.readHexOctet(); - hlen += 3; - if (length < 0x010000) { - throw new Error("Invalid length in 4-byte Comprehension TLV :" + length); - } - } else { - throw new Error("Invalid octet in Comprehension TLV :" + temp); - } - - let ctlv = { - tag: tag, - length: length, - value: this.context.StkProactiveCmdHelper.retrieve(tag, length), - cr: cr, - hlen: hlen - }; - return ctlv; - }, - - decodeChunks: function(length) { - let chunks = []; - let index = 0; - while (index < length) { - let tlv = this.decode(); - chunks.push(tlv); - index += tlv.length; - index += tlv.hlen; - } - return chunks; - }, - - /** - * Write Location Info Comprehension TLV. - * - * @param loc location Information. - */ - writeLocationInfoTlv: function(loc) { - let GsmPDUHelper = this.context.GsmPDUHelper; - - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_LOCATION_INFO | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(loc.gsmCellId > 0xffff ? 9 : 7); - // From TS 11.14, clause 12.19 - // "The mobile country code (MCC), the mobile network code (MNC), - // the location area code (LAC) and the cell ID are - // coded as in TS 04.08." - // And from TS 04.08 and TS 24.008, - // the format is as follows: - // - // MCC = MCC_digit_1 + MCC_digit_2 + MCC_digit_3 - // - // 8 7 6 5 4 3 2 1 - // +-------------+-------------+ - // | MCC digit 2 | MCC digit 1 | octet 2 - // | MNC digit 3 | MCC digit 3 | octet 3 - // | MNC digit 2 | MNC digit 1 | octet 4 - // +-------------+-------------+ - // - // Also in TS 24.008 - // "However a network operator may decide to - // use only two digits in the MNC in the LAI over the - // radio interface. In this case, bits 5 to 8 of octet 3 - // shall be coded as '1111'". - - // MCC & MNC, 3 octets - let mcc = loc.mcc, mnc; - if (loc.mnc.length == 2) { - mnc = "F" + loc.mnc; - } else { - mnc = loc.mnc[2] + loc.mnc[0] + loc.mnc[1]; - } - GsmPDUHelper.writeSwappedNibbleBCD(mcc + mnc); - - // LAC, 2 octets - GsmPDUHelper.writeHexOctet((loc.gsmLocationAreaCode >> 8) & 0xff); - GsmPDUHelper.writeHexOctet(loc.gsmLocationAreaCode & 0xff); - - // Cell Id - if (loc.gsmCellId > 0xffff) { - // UMTS/WCDMA, gsmCellId is 28 bits. - GsmPDUHelper.writeHexOctet((loc.gsmCellId >> 24) & 0xff); - GsmPDUHelper.writeHexOctet((loc.gsmCellId >> 16) & 0xff); - GsmPDUHelper.writeHexOctet((loc.gsmCellId >> 8) & 0xff); - GsmPDUHelper.writeHexOctet(loc.gsmCellId & 0xff); - } else { - // GSM, gsmCellId is 16 bits. - GsmPDUHelper.writeHexOctet((loc.gsmCellId >> 8) & 0xff); - GsmPDUHelper.writeHexOctet(loc.gsmCellId & 0xff); - } - }, - - /** - * Given a geckoError string, this function translates it into cause value - * and write the value into buffer. - * - * @param geckoError Error string that is passed to gecko. - */ - writeCauseTlv: function(geckoError) { - let GsmPDUHelper = this.context.GsmPDUHelper; - - let cause = -1; - for (let errorNo in RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR) { - if (geckoError == RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[errorNo]) { - cause = errorNo; - break; - } - } - - // Causes specified in 10.5.4.11 of TS 04.08 are less than 128. - // we can ignore causes > 127 since Cause TLV is optional in - // STK_EVENT_TYPE_CALL_DISCONNECTED. - if (cause > 127) { - return; - } - - cause = (cause == -1) ? ERROR_SUCCESS : cause; - - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_CAUSE | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(2); // For single cause value. - - // TS 04.08, clause 10.5.4.11: - // Code Standard : Standard defined for GSM PLMNS - // Location: User - GsmPDUHelper.writeHexOctet(0x60); - - // TS 04.08, clause 10.5.4.11: ext bit = 1 + 7 bits for cause. - // +-----------------+----------------------------------+ - // | Ext = 1 (1 bit) | Cause (7 bits) | - // +-----------------+----------------------------------+ - GsmPDUHelper.writeHexOctet(0x80 | cause); - }, - - writeDateTimeZoneTlv: function(date) { - let GsmPDUHelper = this.context.GsmPDUHelper; - - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_DATE_TIME_ZONE); - GsmPDUHelper.writeHexOctet(7); - GsmPDUHelper.writeTimestamp(date); - }, - - writeLanguageTlv: function(language) { - let GsmPDUHelper = this.context.GsmPDUHelper; - - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_LANGUAGE); - GsmPDUHelper.writeHexOctet(2); - - // ISO 639-1, Alpha-2 code - // TS 123.038, clause 6.2.1, GSM 7 bit Default Alphabet - GsmPDUHelper.writeHexOctet( - PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT].indexOf(language[0])); - GsmPDUHelper.writeHexOctet( - PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT].indexOf(language[1])); - }, - - /** - * Write Timer Value Comprehension TLV. - * - * @param seconds length of time during of the timer. - * @param cr Comprehension Required or not - */ - writeTimerValueTlv: function(seconds, cr) { - let GsmPDUHelper = this.context.GsmPDUHelper; - - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_TIMER_VALUE | - (cr ? COMPREHENSIONTLV_FLAG_CR : 0)); - GsmPDUHelper.writeHexOctet(3); - - // TS 102.223, clause 8.38 - // +----------------+------------------+-------------------+ - // | hours (1 byte) | minutes (1 btye) | seconds (1 byte) | - // +----------------+------------------+-------------------+ - GsmPDUHelper.writeSwappedNibbleBCDNum(Math.floor(seconds / 60 / 60)); - GsmPDUHelper.writeSwappedNibbleBCDNum(Math.floor(seconds / 60) % 60); - GsmPDUHelper.writeSwappedNibbleBCDNum(Math.floor(seconds) % 60); - }, - - writeTextStringTlv: function(text, coding) { - let GsmPDUHelper = this.context.GsmPDUHelper; - let buf = GsmPDUHelper.writeWithBuffer(() => { - // Write Coding. - GsmPDUHelper.writeHexOctet(coding); - - // Write Text String. - switch (coding) { - case STK_TEXT_CODING_UCS2: - GsmPDUHelper.writeUCS2String(text); - break; - case STK_TEXT_CODING_GSM_7BIT_PACKED: - GsmPDUHelper.writeStringAsSeptets(text, 0, 0, 0); - break; - case STK_TEXT_CODING_GSM_8BIT: - GsmPDUHelper.writeStringAs8BitUnpacked(text); - break; - } - }); - - let length = buf.length; - if (length) { - // Write Tag. - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_TEXT_STRING | - COMPREHENSIONTLV_FLAG_CR); - // Write Length. - this.writeLength(length); - // Write Value. - for (let i = 0; i < length; i++) { - GsmPDUHelper.writeHexOctet(buf[i]); - } - } - }, - - getSizeOfLengthOctets: function(length) { - if (length >= 0x10000) { - return 4; // 0x83, len_1, len_2, len_3 - } else if (length >= 0x100) { - return 3; // 0x82, len_1, len_2 - } else if (length >= 0x80) { - return 2; // 0x81, len - } else { - return 1; // len - } - }, - - writeLength: function(length) { - let GsmPDUHelper = this.context.GsmPDUHelper; - - // TS 101.220 clause 7.1.2, Length Encoding. - // Length | Byte 1 | Byte 2 | Byte 3 | Byte 4 | - // 0 - 127 | 00 - 7f | N/A | N/A | N/A | - // 128-255 | 81 | 80 - ff| N/A | N/A | - // 256-65535| 82 | 0100 - ffff | N/A | - // 65536- | 83 | 010000 - ffffff | - // 16777215 - if (length < 0x80) { - GsmPDUHelper.writeHexOctet(length); - } else if (0x80 <= length && length < 0x100) { - GsmPDUHelper.writeHexOctet(0x81); - GsmPDUHelper.writeHexOctet(length); - } else if (0x100 <= length && length < 0x10000) { - GsmPDUHelper.writeHexOctet(0x82); - GsmPDUHelper.writeHexOctet((length >> 8) & 0xff); - GsmPDUHelper.writeHexOctet(length & 0xff); - } else if (0x10000 <= length && length < 0x1000000) { - GsmPDUHelper.writeHexOctet(0x83); - GsmPDUHelper.writeHexOctet((length >> 16) & 0xff); - GsmPDUHelper.writeHexOctet((length >> 8) & 0xff); - GsmPDUHelper.writeHexOctet(length & 0xff); - } else { - throw new Error("Invalid length value :" + length); - } - }, -}; - -function BerTlvHelperObject(aContext) { - this.context = aContext; -} -BerTlvHelperObject.prototype = { - context: null, - - /** - * Decode Ber TLV. - * - * @param dataLen - * The length of data in bytes. - */ - decode: function(dataLen) { - let GsmPDUHelper = this.context.GsmPDUHelper; - - let hlen = 0; - let tag = GsmPDUHelper.readHexOctet(); - hlen++; - - // The length is coded onto 1 or 2 bytes. - // Length | Byte 1 | Byte 2 - // 0 - 127 | length ('00' to '7f') | N/A - // 128 - 255 | '81' | length ('80' to 'ff') - let length; - let temp = GsmPDUHelper.readHexOctet(); - hlen++; - if (temp < 0x80) { - length = temp; - } else if (temp === 0x81) { - length = GsmPDUHelper.readHexOctet(); - hlen++; - if (length < 0x80) { - throw new Error("Invalid length " + length); - } - } else { - throw new Error("Invalid length octet " + temp); - } - - // Header + body length check. - if (dataLen - hlen !== length) { - throw new Error("Unexpected BerTlvHelper value length!!"); - } - - let method = this[tag]; - if (typeof method != "function") { - throw new Error("Unknown Ber tag 0x" + tag.toString(16)); - } - - let value = method.call(this, length); - - return { - tag: tag, - length: length, - value: value - }; - }, - - /** - * Process the value part for FCP template TLV. - * - * @param length - * The length of data in bytes. - */ - processFcpTemplate: function(length) { - let tlvs = this.decodeChunks(length); - return tlvs; - }, - - /** - * Process the value part for proactive command TLV. - * - * @param length - * The length of data in bytes. - */ - processProactiveCommand: function(length) { - let ctlvs = this.context.ComprehensionTlvHelper.decodeChunks(length); - return ctlvs; - }, - - /** - * Decode raw data to a Ber-TLV. - */ - decodeInnerTlv: function() { - let GsmPDUHelper = this.context.GsmPDUHelper; - let tag = GsmPDUHelper.readHexOctet(); - let length = GsmPDUHelper.readHexOctet(); - return { - tag: tag, - length: length, - value: this.retrieve(tag, length) - }; - }, - - decodeChunks: function(length) { - let chunks = []; - let index = 0; - while (index < length) { - let tlv = this.decodeInnerTlv(); - if (tlv.value) { - chunks.push(tlv); - } - index += tlv.length; - // tag + length fields consume 2 bytes. - index += 2; - } - return chunks; - }, - - retrieve: function(tag, length) { - let method = this[tag]; - if (typeof method != "function") { - if (DEBUG) { - this.context.debug("Unknown Ber tag : 0x" + tag.toString(16)); - } - let Buf = this.context.Buf; - Buf.seekIncoming(length * Buf.PDU_HEX_OCTET_SIZE); - return null; - } - return method.call(this, length); - }, - - /** - * File Size Data. - * - * | Byte | Description | Length | - * | 1 | Tag | 1 | - * | 2 | Length | 1 | - * | 3 to X+24 | Number of allocated data bytes in the file | X | - * | | , excluding structural information | | - */ - retrieveFileSizeData: function(length) { - let GsmPDUHelper = this.context.GsmPDUHelper; - let fileSizeData = 0; - for (let i = 0; i < length; i++) { - fileSizeData = fileSizeData << 8; - fileSizeData += GsmPDUHelper.readHexOctet(); - } - - return {fileSizeData: fileSizeData}; - }, - - /** - * File Descriptor. - * - * | Byte | Description | Length | - * | 1 | Tag | 1 | - * | 2 | Length | 1 | - * | 3 | File descriptor byte | 1 | - * | 4 | Data coding byte | 1 | - * | 5 ~ 6 | Record length | 2 | - * | 7 | Number of records | 1 | - */ - retrieveFileDescriptor: function(length) { - let GsmPDUHelper = this.context.GsmPDUHelper; - let fileDescriptorByte = GsmPDUHelper.readHexOctet(); - let dataCodingByte = GsmPDUHelper.readHexOctet(); - // See TS 102 221 Table 11.5, we only care the least 3 bits for the - // structure of file. - let fileStructure = fileDescriptorByte & 0x07; - - let fileDescriptor = { - fileStructure: fileStructure - }; - // byte 5 ~ 7 are mandatory for linear fixed and cyclic files, otherwise - // they are not applicable. - if (fileStructure === UICC_EF_STRUCTURE[EF_STRUCTURE_LINEAR_FIXED] || - fileStructure === UICC_EF_STRUCTURE[EF_STRUCTURE_CYCLIC]) { - fileDescriptor.recordLength = (GsmPDUHelper.readHexOctet() << 8) + - GsmPDUHelper.readHexOctet(); - fileDescriptor.numOfRecords = GsmPDUHelper.readHexOctet(); - } - - return fileDescriptor; - }, - - /** - * File identifier. - * - * | Byte | Description | Length | - * | 1 | Tag | 1 | - * | 2 | Length | 1 | - * | 3 ~ 4 | File identifier | 2 | - */ - retrieveFileIdentifier: function(length) { - let GsmPDUHelper = this.context.GsmPDUHelper; - return {fileId : (GsmPDUHelper.readHexOctet() << 8) + - GsmPDUHelper.readHexOctet()}; - }, - - searchForNextTag: function(tag, iter) { - for (let tlv of iter) { - if (tlv.tag === tag) { - return tlv; - } - } - return null; - } -}; -BerTlvHelperObject.prototype[BER_FCP_TEMPLATE_TAG] = function BER_FCP_TEMPLATE_TAG(length) { - return this.processFcpTemplate(length); -}; -BerTlvHelperObject.prototype[BER_PROACTIVE_COMMAND_TAG] = function BER_PROACTIVE_COMMAND_TAG(length) { - return this.processProactiveCommand(length); -}; -BerTlvHelperObject.prototype[BER_FCP_FILE_SIZE_DATA_TAG] = function BER_FCP_FILE_SIZE_DATA_TAG(length) { - return this.retrieveFileSizeData(length); -}; -BerTlvHelperObject.prototype[BER_FCP_FILE_DESCRIPTOR_TAG] = function BER_FCP_FILE_DESCRIPTOR_TAG(length) { - return this.retrieveFileDescriptor(length); -}; -BerTlvHelperObject.prototype[BER_FCP_FILE_IDENTIFIER_TAG] = function BER_FCP_FILE_IDENTIFIER_TAG(length) { - return this.retrieveFileIdentifier(length); -}; - -/** - * ICC Helper for getting EF path. - */ -function ICCFileHelperObject(aContext) { - this.context = aContext; -} -ICCFileHelperObject.prototype = { - context: null, - - /** - * This function handles only EFs that are common to RUIM, SIM, USIM - * and other types of ICC cards. - */ - getCommonEFPath: function(fileId) { - switch (fileId) { - case ICC_EF_ICCID: - return EF_PATH_MF_SIM; - case ICC_EF_ADN: - case ICC_EF_SDN: // Fall through. - return EF_PATH_MF_SIM + EF_PATH_DF_TELECOM; - case ICC_EF_PBR: - return EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_DF_PHONEBOOK; - case ICC_EF_IMG: - return EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_GRAPHICS; - } - return null; - }, - - /** - * This function handles EFs for SIM. - */ - getSimEFPath: function(fileId) { - switch (fileId) { - case ICC_EF_FDN: - case ICC_EF_MSISDN: - case ICC_EF_SMS: - case ICC_EF_EXT1: - case ICC_EF_EXT2: - case ICC_EF_EXT3: - return EF_PATH_MF_SIM + EF_PATH_DF_TELECOM; - case ICC_EF_AD: - case ICC_EF_MBDN: - case ICC_EF_MWIS: - case ICC_EF_PLMNsel: - case ICC_EF_SPN: - case ICC_EF_SPDI: - case ICC_EF_SST: - case ICC_EF_PHASE: - case ICC_EF_CBMI: - case ICC_EF_CBMID: - case ICC_EF_CBMIR: - case ICC_EF_OPL: - case ICC_EF_PNN: - case ICC_EF_GID1: - case ICC_EF_CPHS_INFO: - case ICC_EF_CPHS_MBN: - return EF_PATH_MF_SIM + EF_PATH_DF_GSM; - default: - return null; - } - }, - - /** - * This function handles EFs for USIM. - */ - getUSimEFPath: function(fileId) { - switch (fileId) { - case ICC_EF_AD: - case ICC_EF_FDN: - case ICC_EF_MBDN: - case ICC_EF_MWIS: - case ICC_EF_UST: - case ICC_EF_MSISDN: - case ICC_EF_SPN: - case ICC_EF_SPDI: - case ICC_EF_CBMI: - case ICC_EF_CBMID: - case ICC_EF_CBMIR: - case ICC_EF_OPL: - case ICC_EF_PNN: - case ICC_EF_SMS: - case ICC_EF_GID1: - // CPHS spec was provided in 1997 based on SIM requirement, there is no - // detailed info about how these ICC_EF_CPHS_XXX are allocated in USIM. - // What we can do now is to follow what has been done in AOSP to have file - // path equal to MF_SIM/DF_GSM. - case ICC_EF_CPHS_INFO: - case ICC_EF_CPHS_MBN: - return EF_PATH_MF_SIM + EF_PATH_ADF_USIM; - default: - // The file ids in USIM phone book entries are decided by the - // card manufacturer. So if we don't match any of the cases - // above and if its a USIM return the phone book path. - return EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_DF_PHONEBOOK; - } - }, - - /** - * This function handles EFs for RUIM - */ - getRuimEFPath: function(fileId) { - switch(fileId) { - case ICC_EF_CSIM_IMSI_M: - case ICC_EF_CSIM_CDMAHOME: - case ICC_EF_CSIM_CST: - case ICC_EF_CSIM_SPN: - return EF_PATH_MF_SIM + EF_PATH_DF_CDMA; - case ICC_EF_FDN: - case ICC_EF_EXT1: - case ICC_EF_EXT2: - case ICC_EF_EXT3: - return EF_PATH_MF_SIM + EF_PATH_DF_TELECOM; - default: - return null; - } - }, - - /** - * Helper function for getting the pathId for the specific ICC record - * depeding on which type of ICC card we are using. - * - * @param fileId - * File id. - * @return The pathId or null in case of an error or invalid input. - */ - getEFPath: function(fileId) { - let path = this.getCommonEFPath(fileId); - if (path) { - return path; - } - - switch (this.context.RIL.appType) { - case CARD_APPTYPE_SIM: - return this.getSimEFPath(fileId); - case CARD_APPTYPE_USIM: - return this.getUSimEFPath(fileId); - case CARD_APPTYPE_RUIM: - return this.getRuimEFPath(fileId); - default: - return null; - } - } -}; - -/** - * Helper for ICC IO functionalities. - */ -function ICCIOHelperObject(aContext) { - this.context = aContext; -} -ICCIOHelperObject.prototype = { - context: null, - - /** - * Load EF with type 'Linear Fixed'. - * - * @param fileId - * The file to operate on, one of the ICC_EF_* constants. - * @param recordNumber [optional] - * The number of the record shall be loaded. - * @param recordSize [optional] - * The size of the record. - * @param callback [optional] - * The callback function shall be called when the record(s) is read. - * @param onerror [optional] - * The callback function shall be called when failure. - */ - loadLinearFixedEF: function(options) { - let cb; - let readRecord = (function(options) { - options.command = ICC_COMMAND_READ_RECORD; - options.p1 = options.recordNumber || 1; // Record number - options.p2 = READ_RECORD_ABSOLUTE_MODE; - options.p3 = options.recordSize; - options.callback = cb || options.callback; - this.context.RIL.iccIO(options); - }).bind(this); - - options.structure = EF_STRUCTURE_LINEAR_FIXED; - options.pathId = this.context.ICCFileHelper.getEFPath(options.fileId); - if (options.recordSize) { - readRecord(options); - return; - } - - cb = options.callback; - options.callback = readRecord; - this.getResponse(options); - }, - - /** - * Load next record from current record Id. - */ - loadNextRecord: function(options) { - options.p1++; - this.context.RIL.iccIO(options); - }, - - /** - * Update EF with type 'Linear Fixed'. - * - * @param fileId - * The file to operate on, one of the ICC_EF_* constants. - * @param recordNumber - * The number of the record shall be updated. - * @param dataWriter [optional] - * The function for writing string parameter for the ICC_COMMAND_UPDATE_RECORD. - * @param pin2 [optional] - * PIN2 is required when updating ICC_EF_FDN. - * @param callback [optional] - * The callback function shall be called when the record is updated. - * @param onerror [optional] - * The callback function shall be called when failure. - */ - updateLinearFixedEF: function(options) { - if (!options.fileId || !options.recordNumber) { - throw new Error("Unexpected fileId " + options.fileId + - " or recordNumber " + options.recordNumber); - } - - options.structure = EF_STRUCTURE_LINEAR_FIXED; - options.pathId = this.context.ICCFileHelper.getEFPath(options.fileId); - let cb = options.callback; - options.callback = function callback(options) { - options.callback = cb; - options.command = ICC_COMMAND_UPDATE_RECORD; - options.p1 = options.recordNumber; - options.p2 = READ_RECORD_ABSOLUTE_MODE; - options.p3 = options.recordSize; - this.context.RIL.iccIO(options); - }.bind(this); - this.getResponse(options); - }, - - /** - * Load EF with type 'Transparent'. - * - * @param fileId - * The file to operate on, one of the ICC_EF_* constants. - * @param callback [optional] - * The callback function shall be called when the record(s) is read. - * @param onerror [optional] - * The callback function shall be called when failure. - */ - loadTransparentEF: function(options) { - options.structure = EF_STRUCTURE_TRANSPARENT; - let cb = options.callback; - options.callback = function callback(options) { - options.callback = cb; - options.command = ICC_COMMAND_READ_BINARY; - options.p2 = 0x00; - options.p3 = options.fileSize; - this.context.RIL.iccIO(options); - }.bind(this); - this.getResponse(options); - }, - - /** - * Use ICC_COMMAND_GET_RESPONSE to query the EF. - * - * @param fileId - * The file to operate on, one of the ICC_EF_* constants. - */ - getResponse: function(options) { - options.command = ICC_COMMAND_GET_RESPONSE; - options.pathId = options.pathId || - this.context.ICCFileHelper.getEFPath(options.fileId); - if (!options.pathId) { - throw new Error("Unknown pathId for " + options.fileId.toString(16)); - } - options.p1 = 0; // For GET_RESPONSE, p1 = 0 - switch (this.context.RIL.appType) { - case CARD_APPTYPE_USIM: - options.p2 = GET_RESPONSE_FCP_TEMPLATE; - options.p3 = 0x00; - break; - // For RUIM, CSIM and ISIM, cf bug 955946: keep the old behavior - case CARD_APPTYPE_RUIM: - case CARD_APPTYPE_CSIM: - case CARD_APPTYPE_ISIM: - // For SIM, this is what we want - case CARD_APPTYPE_SIM: - default: - options.p2 = 0x00; - options.p3 = GET_RESPONSE_EF_SIZE_BYTES; - break; - } - this.context.RIL.iccIO(options); - }, - - /** - * Process ICC I/O response. - */ - processICCIO: function(options) { - let func = this[options.command]; - func.call(this, options); - }, - - /** - * Process a ICC_COMMAND_GET_RESPONSE type command for REQUEST_SIM_IO. - */ - processICCIOGetResponse: function(options) { - let Buf = this.context.Buf; - let strLen = Buf.readInt32(); - - let peek = this.context.GsmPDUHelper.readHexOctet(); - Buf.seekIncoming(-1 * Buf.PDU_HEX_OCTET_SIZE); - if (peek === BER_FCP_TEMPLATE_TAG) { - this.processUSimGetResponse(options, strLen / 2); - } else { - this.processSimGetResponse(options); - } - Buf.readStringDelimiter(strLen); - - if (options.callback) { - options.callback(options); - } - }, - - /** - * Helper function for processing USIM get response. - */ - processUSimGetResponse: function(options, octetLen) { - let BerTlvHelper = this.context.BerTlvHelper; - - let berTlv = BerTlvHelper.decode(octetLen); - // See TS 102 221 Table 11.4 for the content order of getResponse. - let iter = berTlv.value.values(); - let tlv = BerTlvHelper.searchForNextTag(BER_FCP_FILE_DESCRIPTOR_TAG, - iter); - if (!tlv || - (tlv.value.fileStructure !== UICC_EF_STRUCTURE[options.structure])) { - throw new Error("Expected EF structure " + - UICC_EF_STRUCTURE[options.structure] + - " but read " + tlv.value.fileStructure); - } - - if (tlv.value.fileStructure === UICC_EF_STRUCTURE[EF_STRUCTURE_LINEAR_FIXED] || - tlv.value.fileStructure === UICC_EF_STRUCTURE[EF_STRUCTURE_CYCLIC]) { - options.recordSize = tlv.value.recordLength; - options.totalRecords = tlv.value.numOfRecords; - } - - tlv = BerTlvHelper.searchForNextTag(BER_FCP_FILE_IDENTIFIER_TAG, iter); - if (!tlv || (tlv.value.fileId !== options.fileId)) { - throw new Error("Expected file ID " + options.fileId.toString(16) + - " but read " + fileId.toString(16)); - } - - tlv = BerTlvHelper.searchForNextTag(BER_FCP_FILE_SIZE_DATA_TAG, iter); - if (!tlv) { - throw new Error("Unexpected file size data"); - } - options.fileSize = tlv.value.fileSizeData; - }, - - /** - * Helper function for processing SIM get response. - */ - processSimGetResponse: function(options) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - - // The format is from TS 51.011, clause 9.2.1 - - // Skip RFU, data[0] data[1]. - Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE); - - // File size, data[2], data[3] - options.fileSize = (GsmPDUHelper.readHexOctet() << 8) | - GsmPDUHelper.readHexOctet(); - - // 2 bytes File id. data[4], data[5] - let fileId = (GsmPDUHelper.readHexOctet() << 8) | - GsmPDUHelper.readHexOctet(); - if (fileId != options.fileId) { - throw new Error("Expected file ID " + options.fileId.toString(16) + - " but read " + fileId.toString(16)); - } - - // Type of file, data[6] - let fileType = GsmPDUHelper.readHexOctet(); - if (fileType != TYPE_EF) { - throw new Error("Unexpected file type " + fileType); - } - - // Skip 1 byte RFU, data[7], - // 3 bytes Access conditions, data[8] data[9] data[10], - // 1 byte File status, data[11], - // 1 byte Length of the following data, data[12]. - Buf.seekIncoming(((RESPONSE_DATA_STRUCTURE - RESPONSE_DATA_FILE_TYPE - 1) * - Buf.PDU_HEX_OCTET_SIZE)); - - // Read Structure of EF, data[13] - let efStructure = GsmPDUHelper.readHexOctet(); - if (efStructure != options.structure) { - throw new Error("Expected EF structure " + options.structure + - " but read " + efStructure); - } - - // Length of a record, data[14]. - // Only available for LINEAR_FIXED and CYCLIC. - if (efStructure == EF_STRUCTURE_LINEAR_FIXED || - efStructure == EF_STRUCTURE_CYCLIC) { - options.recordSize = GsmPDUHelper.readHexOctet(); - options.totalRecords = options.fileSize / options.recordSize; - } else { - Buf.seekIncoming(1 * Buf.PDU_HEX_OCTET_SIZE); - } - }, - - /** - * Process a ICC_COMMAND_READ_RECORD type command for REQUEST_SIM_IO. - */ - processICCIOReadRecord: function(options) { - if (options.callback) { - options.callback(options); - } - }, - - /** - * Process a ICC_COMMAND_READ_BINARY type command for REQUEST_SIM_IO. - */ - processICCIOReadBinary: function(options) { - if (options.callback) { - options.callback(options); - } - }, - - /** - * Process a ICC_COMMAND_UPDATE_RECORD type command for REQUEST_SIM_IO. - */ - processICCIOUpdateRecord: function(options) { - if (options.callback) { - options.callback(options); - } - }, -}; -ICCIOHelperObject.prototype[ICC_COMMAND_SEEK] = null; -ICCIOHelperObject.prototype[ICC_COMMAND_READ_BINARY] = function ICC_COMMAND_READ_BINARY(options) { - this.processICCIOReadBinary(options); -}; -ICCIOHelperObject.prototype[ICC_COMMAND_READ_RECORD] = function ICC_COMMAND_READ_RECORD(options) { - this.processICCIOReadRecord(options); -}; -ICCIOHelperObject.prototype[ICC_COMMAND_GET_RESPONSE] = function ICC_COMMAND_GET_RESPONSE(options) { - this.processICCIOGetResponse(options); -}; -ICCIOHelperObject.prototype[ICC_COMMAND_UPDATE_BINARY] = null; -ICCIOHelperObject.prototype[ICC_COMMAND_UPDATE_RECORD] = function ICC_COMMAND_UPDATE_RECORD(options) { - this.processICCIOUpdateRecord(options); -}; - -/** - * Helper for ICC records. - */ -function ICCRecordHelperObject(aContext) { - this.context = aContext; - // Cache the possible free record id for all files, use fileId as key. - this._freeRecordIds = {}; -} -ICCRecordHelperObject.prototype = { - context: null, - - /** - * Fetch ICC records. - */ - fetchICCRecords: function() { - switch (this.context.RIL.appType) { - case CARD_APPTYPE_SIM: - case CARD_APPTYPE_USIM: - this.context.SimRecordHelper.fetchSimRecords(); - break; - case CARD_APPTYPE_RUIM: - this.context.RuimRecordHelper.fetchRuimRecords(); - break; - } - }, - - /** - * Read the ICCID. - */ - readICCID: function() { - function callback() { - let Buf = this.context.Buf; - let RIL = this.context.RIL; - let GsmPDUHelper = this.context.GsmPDUHelper; - - let strLen = Buf.readInt32(); - let octetLen = strLen / 2; - RIL.iccInfo.iccid = - GsmPDUHelper.readSwappedNibbleBcdString(octetLen, true); - // Consumes the remaining buffer if any. - let unReadBuffer = this.context.Buf.getReadAvailable() - - this.context.Buf.PDU_HEX_OCTET_SIZE; - if (unReadBuffer > 0) { - this.context.Buf.seekIncoming(unReadBuffer); - } - Buf.readStringDelimiter(strLen); - - if (DEBUG) this.context.debug("ICCID: " + RIL.iccInfo.iccid); - if (RIL.iccInfo.iccid) { - this.context.ICCUtilsHelper.handleICCInfoChange(); - RIL.reportStkServiceIsRunning(); - } - } - - this.context.ICCIOHelper.loadTransparentEF({ - fileId: ICC_EF_ICCID, - callback: callback.bind(this) - }); - }, - - /** - * Read ICC ADN like EF, i.e. EF_ADN, EF_FDN. - * - * @param fileId EF id of the ADN, FDN or SDN. - * @param extFileId EF id of the EXT. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readADNLike: function(fileId, extFileId, onsuccess, onerror) { - let ICCIOHelper = this.context.ICCIOHelper; - - function callback(options) { - let loadNextContactRecord = () => { - if (options.p1 < options.totalRecords) { - ICCIOHelper.loadNextRecord(options); - return; - } - if (DEBUG) { - for (let i = 0; i < contacts.length; i++) { - this.context.debug("contact [" + i + "] " + - JSON.stringify(contacts[i])); - } - } - if (onsuccess) { - onsuccess(contacts); - } - }; - - let contact = - this.context.ICCPDUHelper.readAlphaIdDiallingNumber(options.recordSize); - if (contact) { - let record = { - recordId: options.p1, - alphaId: contact.alphaId, - number: contact.number - }; - contacts.push(record); - - if (extFileId && contact.extRecordNumber != 0xff) { - this.readExtension(extFileId, contact.extRecordNumber, (number) => { - if (number) { - record.number += number; - } - loadNextContactRecord(); - }, () => loadNextContactRecord()); - return; - } - } - loadNextContactRecord(); - } - - let contacts = []; - ICCIOHelper.loadLinearFixedEF({fileId: fileId, - callback: callback.bind(this), - onerror: onerror}); - }, - - /** - * Update ICC ADN like EFs, like EF_ADN, EF_FDN. - * - * @param fileId EF id of the ADN or FDN. - * @param extRecordNumber The record identifier of the EXT. - * @param contact The contact will be updated. (Shall have recordId property) - * @param pin2 PIN2 is required when updating ICC_EF_FDN. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updateADNLike: function(fileId, extRecordNumber, contact, pin2, onsuccess, onerror) { - let updatedContact; - function dataWriter(recordSize) { - updatedContact = this.context.ICCPDUHelper.writeAlphaIdDiallingNumber(recordSize, - contact.alphaId, - contact.number, - extRecordNumber); - } - - function callback(options) { - if (onsuccess) { - onsuccess(updatedContact); - } - } - - if (!contact || !contact.recordId) { - if (onerror) onerror(GECKO_ERROR_INVALID_PARAMETER); - return; - } - - this.context.ICCIOHelper.updateLinearFixedEF({ - fileId: fileId, - recordNumber: contact.recordId, - dataWriter: dataWriter.bind(this), - pin2: pin2, - callback: callback.bind(this), - onerror: onerror - }); - }, - - /** - * Read USIM/RUIM Phonebook. - * - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readPBR: function(onsuccess, onerror) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - let ICCIOHelper = this.context.ICCIOHelper; - let ICCUtilsHelper = this.context.ICCUtilsHelper; - let RIL = this.context.RIL; - - function callback(options) { - let strLen = Buf.readInt32(); - let octetLen = strLen / 2, readLen = 0; - - let pbrTlvs = []; - while (readLen < octetLen) { - let tag = GsmPDUHelper.readHexOctet(); - if (tag == 0xff) { - readLen++; - Buf.seekIncoming((octetLen - readLen) * Buf.PDU_HEX_OCTET_SIZE); - break; - } - - let tlvLen = GsmPDUHelper.readHexOctet(); - let tlvs = ICCUtilsHelper.decodeSimTlvs(tlvLen); - pbrTlvs.push({tag: tag, - length: tlvLen, - value: tlvs}); - - readLen += tlvLen + 2; // +2 for tag and tlvLen - } - Buf.readStringDelimiter(strLen); - - if (pbrTlvs.length > 0) { - let pbr = ICCUtilsHelper.parsePbrTlvs(pbrTlvs); - // EF_ADN is mandatory if and only if DF_PHONEBOOK is present. - if (!pbr.adn) { - if (onerror) onerror("Cannot access ADN."); - return; - } - pbrs.push(pbr); - } - - if (options.p1 < options.totalRecords) { - ICCIOHelper.loadNextRecord(options); - } else { - if (onsuccess) { - RIL.iccInfoPrivate.pbrs = pbrs; - onsuccess(pbrs); - } - } - } - - if (RIL.iccInfoPrivate.pbrs) { - onsuccess(RIL.iccInfoPrivate.pbrs); - return; - } - - let pbrs = []; - ICCIOHelper.loadLinearFixedEF({fileId : ICC_EF_PBR, - callback: callback.bind(this), - onerror: onerror}); - }, - - /** - * Cache EF_IAP record size. - */ - _iapRecordSize: null, - - /** - * Read ICC EF_IAP. (Index Administration Phonebook) - * - * @see TS 131.102, clause 4.4.2.2 - * - * @param fileId EF id of the IAP. - * @param recordNumber The number of the record shall be loaded. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readIAP: function(fileId, recordNumber, onsuccess, onerror) { - function callback(options) { - let Buf = this.context.Buf; - let strLen = Buf.readInt32(); - let octetLen = strLen / 2; - this._iapRecordSize = options.recordSize; - - let iap = this.context.GsmPDUHelper.readHexOctetArray(octetLen); - Buf.readStringDelimiter(strLen); - - if (onsuccess) { - onsuccess(iap); - } - } - - this.context.ICCIOHelper.loadLinearFixedEF({ - fileId: fileId, - recordNumber: recordNumber, - recordSize: this._iapRecordSize, - callback: callback.bind(this), - onerror: onerror - }); - }, - - /** - * Update USIM/RUIM Phonebook EF_IAP. - * - * @see TS 131.102, clause 4.4.2.13 - * - * @param fileId EF id of the IAP. - * @param recordNumber The identifier of the record shall be updated. - * @param iap The IAP value to be written. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updateIAP: function(fileId, recordNumber, iap, onsuccess, onerror) { - let dataWriter = function dataWriter(recordSize) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - - // Write String length - let strLen = recordSize * 2; - Buf.writeInt32(strLen); - - for (let i = 0; i < iap.length; i++) { - GsmPDUHelper.writeHexOctet(iap[i]); - } - - Buf.writeStringDelimiter(strLen); - }.bind(this); - - this.context.ICCIOHelper.updateLinearFixedEF({ - fileId: fileId, - recordNumber: recordNumber, - dataWriter: dataWriter, - callback: onsuccess, - onerror: onerror - }); - }, - - /** - * Cache EF_Email record size. - */ - _emailRecordSize: null, - - /** - * Read USIM/RUIM Phonebook EF_EMAIL. - * - * @see TS 131.102, clause 4.4.2.13 - * - * @param fileId EF id of the EMAIL. - * @param fileType The type of the EMAIL, one of the ICC_USIM_TYPE* constants. - * @param recordNumber The number of the record shall be loaded. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readEmail: function(fileId, fileType, recordNumber, onsuccess, onerror) { - function callback(options) { - let Buf = this.context.Buf; - let ICCPDUHelper = this.context.ICCPDUHelper; - - let strLen = Buf.readInt32(); - let octetLen = strLen / 2; - let email = null; - this._emailRecordSize = options.recordSize; - - // Read contact's email - // - // | Byte | Description | Length | M/O - // | 1 ~ X | E-mail Address | X | M - // | X+1 | ADN file SFI | 1 | C - // | X+2 | ADN file Record Identifier | 1 | C - // Note: The fields marked as C above are mandatort if the file - // is not type 1 (as specified in EF_PBR) - if (fileType == ICC_USIM_TYPE1_TAG) { - email = ICCPDUHelper.read8BitUnpackedToString(octetLen); - } else { - email = ICCPDUHelper.read8BitUnpackedToString(octetLen - 2); - - // Consumes the remaining buffer - Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE); // For ADN SFI and Record Identifier - } - - Buf.readStringDelimiter(strLen); - - if (onsuccess) { - onsuccess(email); - } - } - - this.context.ICCIOHelper.loadLinearFixedEF({ - fileId: fileId, - recordNumber: recordNumber, - recordSize: this._emailRecordSize, - callback: callback.bind(this), - onerror: onerror - }); - }, - - /** - * Update USIM/RUIM Phonebook EF_EMAIL. - * - * @see TS 131.102, clause 4.4.2.13 - * - * @param pbr Phonebook Reference File. - * @param recordNumber The identifier of the record shall be updated. - * @param email The value to be written. - * @param adnRecordId The record Id of ADN, only needed if the fileType of Email is TYPE2. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updateEmail: function(pbr, recordNumber, email, adnRecordId, onsuccess, onerror) { - let fileId = pbr[USIM_PBR_EMAIL].fileId; - let fileType = pbr[USIM_PBR_EMAIL].fileType; - let writtenEmail; - let dataWriter = function dataWriter(recordSize) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - let ICCPDUHelper = this.context.ICCPDUHelper; - - // Write String length - let strLen = recordSize * 2; - Buf.writeInt32(strLen); - - if (fileType == ICC_USIM_TYPE1_TAG) { - writtenEmail = ICCPDUHelper.writeStringTo8BitUnpacked(recordSize, email); - } else { - writtenEmail = ICCPDUHelper.writeStringTo8BitUnpacked(recordSize - 2, email); - GsmPDUHelper.writeHexOctet(pbr.adn.sfi || 0xff); - GsmPDUHelper.writeHexOctet(adnRecordId); - } - - Buf.writeStringDelimiter(strLen); - }.bind(this); - - let callback = (options) => { - if (onsuccess) { - onsuccess(writtenEmail); - } - } - - this.context.ICCIOHelper.updateLinearFixedEF({ - fileId: fileId, - recordNumber: recordNumber, - dataWriter: dataWriter, - callback: callback, - onerror: onerror - }); - }, - - /** - * Cache EF_ANR record size. - */ - _anrRecordSize: null, - - /** - * Read USIM/RUIM Phonebook EF_ANR. - * - * @see TS 131.102, clause 4.4.2.9 - * - * @param fileId EF id of the ANR. - * @param fileType One of the ICC_USIM_TYPE* constants. - * @param recordNumber The number of the record shall be loaded. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readANR: function(fileId, fileType, recordNumber, onsuccess, onerror) { - function callback(options) { - let Buf = this.context.Buf; - let strLen = Buf.readInt32(); - let number = null; - this._anrRecordSize = options.recordSize; - - // Skip EF_AAS Record ID. - Buf.seekIncoming(1 * Buf.PDU_HEX_OCTET_SIZE); - - number = this.context.ICCPDUHelper.readNumberWithLength(); - - // Skip 2 unused octets, CCP and EXT1. - Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE); - - // For Type 2 there are two extra octets. - if (fileType == ICC_USIM_TYPE2_TAG) { - // Skip 2 unused octets, ADN SFI and Record Identifier. - Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE); - } - - Buf.readStringDelimiter(strLen); - - if (onsuccess) { - onsuccess(number); - } - } - - this.context.ICCIOHelper.loadLinearFixedEF({ - fileId: fileId, - recordNumber: recordNumber, - recordSize: this._anrRecordSize, - callback: callback.bind(this), - onerror: onerror - }); - }, - - /** - * Update USIM/RUIM Phonebook EF_ANR. - * - * @see TS 131.102, clause 4.4.2.9 - * - * @param pbr Phonebook Reference File. - * @param recordNumber The identifier of the record shall be updated. - * @param number The value to be written. - * @param adnRecordId The record Id of ADN, only needed if the fileType of Email is TYPE2. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updateANR: function(pbr, recordNumber, number, adnRecordId, onsuccess, onerror) { - let fileId = pbr[USIM_PBR_ANR0].fileId; - let fileType = pbr[USIM_PBR_ANR0].fileType; - let writtenNumber; - let dataWriter = function dataWriter(recordSize) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - - // Write String length - let strLen = recordSize * 2; - Buf.writeInt32(strLen); - - // EF_AAS record Id. Unused for now. - GsmPDUHelper.writeHexOctet(0xff); - - writtenNumber = this.context.ICCPDUHelper.writeNumberWithLength(number); - - // Write unused octets 0xff, CCP and EXT1. - GsmPDUHelper.writeHexOctet(0xff); - GsmPDUHelper.writeHexOctet(0xff); - - // For Type 2 there are two extra octets. - if (fileType == ICC_USIM_TYPE2_TAG) { - GsmPDUHelper.writeHexOctet(pbr.adn.sfi || 0xff); - GsmPDUHelper.writeHexOctet(adnRecordId); - } - - Buf.writeStringDelimiter(strLen); - }.bind(this); - - let callback = (options) => { - if (onsuccess) { - onsuccess(writtenNumber); - } - } - - this.context.ICCIOHelper.updateLinearFixedEF({ - fileId: fileId, - recordNumber: recordNumber, - dataWriter: dataWriter, - callback: callback, - onerror: onerror - }); - }, - - /** - * Cache the possible free record id for all files. - */ - _freeRecordIds: null, - - /** - * Find free record id. - * - * @param fileId EF id. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - findFreeRecordId: function(fileId, onsuccess, onerror) { - let ICCIOHelper = this.context.ICCIOHelper; - - function callback(options) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - - let strLen = Buf.readInt32(); - let octetLen = strLen / 2; - let readLen = 0; - - while (readLen < octetLen) { - let octet = GsmPDUHelper.readHexOctet(); - readLen++; - if (octet != 0xff) { - break; - } - } - - let nextRecord = (options.p1 % options.totalRecords) + 1; - - if (readLen == octetLen) { - // Find free record, assume next record is probably free. - this._freeRecordIds[fileId] = nextRecord; - if (onsuccess) { - onsuccess(options.p1); - } - return; - } else { - Buf.seekIncoming((octetLen - readLen) * Buf.PDU_HEX_OCTET_SIZE); - } - - Buf.readStringDelimiter(strLen); - - if (nextRecord !== recordNumber) { - options.p1 = nextRecord; - this.context.RIL.iccIO(options); - } else { - // No free record found. - delete this._freeRecordIds[fileId]; - if (DEBUG) { - this.context.debug(CONTACT_ERR_NO_FREE_RECORD_FOUND); - } - onerror(CONTACT_ERR_NO_FREE_RECORD_FOUND); - } - } - - // Start searching free records from the possible one. - let recordNumber = this._freeRecordIds[fileId] || 1; - ICCIOHelper.loadLinearFixedEF({fileId: fileId, - recordNumber: recordNumber, - callback: callback.bind(this), - onerror: onerror}); - }, - - /** - * Read Extension Number from TS 151.011 clause 10.5.10, TS 31.102, clause 4.4.2.4 - * - * @param fileId EF Extension id - * @param recordNumber The number of the record shall be loaded. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readExtension: function(fileId, recordNumber, onsuccess, onerror) { - let callback = (options) => { - let Buf = this.context.Buf; - let length = Buf.readInt32(); - let recordType = this.context.GsmPDUHelper.readHexOctet(); - let number = ""; - - // TS 31.102, clause 4.4.2.4 EFEXT1 - // Case 1, Extension1 record is additional data - if (recordType & 0x02) { - let numLen = this.context.GsmPDUHelper.readHexOctet(); - if (numLen != 0xff) { - if (numLen > EXT_MAX_BCD_NUMBER_BYTES) { - if (DEBUG) { - this.context.debug( - "Error: invalid length of BCD number/SSC contents - " + numLen); - } - // +1 to skip Identifier - Buf.seekIncoming((EXT_MAX_BCD_NUMBER_BYTES + 1) * Buf.PDU_HEX_OCTET_SIZE); - Buf.readStringDelimiter(length); - onerror(); - return; - } - - number = this.context.GsmPDUHelper.readSwappedNibbleExtendedBcdString(numLen); - if (DEBUG) this.context.debug("Contact Extension Number: "+ number); - Buf.seekIncoming((EXT_MAX_BCD_NUMBER_BYTES - numLen) * Buf.PDU_HEX_OCTET_SIZE); - } else { - Buf.seekIncoming(EXT_MAX_BCD_NUMBER_BYTES * Buf.PDU_HEX_OCTET_SIZE); - } - } else { - // Don't support Case 2, Extension1 record is Called Party Subaddress. - // +1 skip numLen - Buf.seekIncoming((EXT_MAX_BCD_NUMBER_BYTES + 1) * Buf.PDU_HEX_OCTET_SIZE); - } - - // Skip Identifier - Buf.seekIncoming(Buf.PDU_HEX_OCTET_SIZE); - Buf.readStringDelimiter(length); - onsuccess(number); - } - - this.context.ICCIOHelper.loadLinearFixedEF({ - fileId: fileId, - recordNumber: recordNumber, - callback: callback, - onerror: onerror - }); - }, - - /** - * Update Extension. - * - * @param fileId EF id of the EXT. - * @param recordNumber The number of the record shall be updated. - * @param number Dialling Number to be written. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updateExtension: function(fileId, recordNumber, number, onsuccess, onerror) { - let dataWriter = (recordSize) => { - let GsmPDUHelper = this.context.GsmPDUHelper; - // Write String length - let strLen = recordSize * 2; - let Buf = this.context.Buf; - Buf.writeInt32(strLen); - - // We don't support extension chain. - if (number.length > EXT_MAX_NUMBER_DIGITS) { - number = number.substring(0, EXT_MAX_NUMBER_DIGITS); - } - - let numLen = Math.ceil(number.length / 2); - // Write Extension record - GsmPDUHelper.writeHexOctet(0x02); - GsmPDUHelper.writeHexOctet(numLen); - GsmPDUHelper.writeSwappedNibbleBCD(number); - // Write trailing 0xff of Extension data. - for (let i = 0; i < EXT_MAX_BCD_NUMBER_BYTES - numLen; i++) { - GsmPDUHelper.writeHexOctet(0xff); - } - // Write trailing 0xff for Identifier. - GsmPDUHelper.writeHexOctet(0xff); - Buf.writeStringDelimiter(strLen); - }; - - this.context.ICCIOHelper.updateLinearFixedEF({ - fileId: fileId, - recordNumber: recordNumber, - dataWriter: dataWriter, - callback: onsuccess, - onerror: onerror - }); - }, - - /** - * Clean an EF record. - * - * @param fileId EF id. - * @param recordNumber The number of the record shall be updated. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - cleanEFRecord: function(fileId, recordNumber, onsuccess, onerror) { - let dataWriter = (recordSize) => { - let GsmPDUHelper = this.context.GsmPDUHelper; - let Buf = this.context.Buf; - // Write String length - let strLen = recordSize * 2; - - Buf.writeInt32(strLen); - // Write record to 0xff - for (let i = 0; i < recordSize; i++) { - GsmPDUHelper.writeHexOctet(0xff); - } - Buf.writeStringDelimiter(strLen); - } - - this.context.ICCIOHelper.updateLinearFixedEF({ - fileId: fileId, - recordNumber: recordNumber, - dataWriter: dataWriter, - callback: onsuccess, - onerror: onerror - }); - }, - - /** - * Get ADNLike extension record number. - * - * @param fileId EF id of the ADN or FDN. - * @param recordNumber EF record id of the ADN or FDN. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - getADNLikeExtensionRecordNumber: function(fileId, recordNumber, onsuccess, onerror) { - let callback = (options) => { - let Buf = this.context.Buf; - let length = Buf.readInt32(); - - // Skip alphaLen, numLen, BCD Number, CCP octets. - Buf.seekIncoming((options.recordSize -1) * Buf.PDU_HEX_OCTET_SIZE); - - let extRecordNumber = this.context.GsmPDUHelper.readHexOctet(); - Buf.readStringDelimiter(length); - - onsuccess(extRecordNumber); - } - - this.context.ICCIOHelper.loadLinearFixedEF({ - fileId: fileId, - recordNumber: recordNumber, - callback: callback, - onerror: onerror - }); - }, -}; - -/** - * Helper for (U)SIM Records. - */ -function SimRecordHelperObject(aContext) { - this.context = aContext; -} -SimRecordHelperObject.prototype = { - context: null, - - /** - * Fetch (U)SIM records. - */ - fetchSimRecords: function() { - this.context.RIL.getIMSI(); - this.readAD(); - // CPHS was widely introduced in Europe during GSM(2G) era to provide easier - // access to carrier's core service like voicemail, call forwarding, manual - // PLMN selection, and etc. - // Addition EF like EF_CPHS_MBN, EF_CPHS_CPHS_CFF, EF_CPHS_VWI, etc are - // introduced to support these feature. - // In USIM, the replancement of these EFs are provided. (EF_MBDN, EF_MWIS, ...) - // However, some carriers in Europe still rely on these EFs. - this.readCphsInfo(() => this.readSST(), - (aErrorMsg) => { - this.context.debug("Failed to read CPHS_INFO: " + aErrorMsg); - this.readSST(); - }); - }, - - /** - * Read EF_phase. - * This EF is only available in SIM. - */ - readSimPhase: function() { - function callback() { - let Buf = this.context.Buf; - let strLen = Buf.readInt32(); - - let GsmPDUHelper = this.context.GsmPDUHelper; - let phase = GsmPDUHelper.readHexOctet(); - // If EF_phase is coded '03' or greater, an ME supporting STK shall - // perform the PROFILE DOWNLOAD procedure. - if (RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD && - phase >= ICC_PHASE_2_PROFILE_DOWNLOAD_REQUIRED) { - this.context.RIL.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE); - } - - Buf.readStringDelimiter(strLen); - } - - this.context.ICCIOHelper.loadTransparentEF({ - fileId: ICC_EF_PHASE, - callback: callback.bind(this) - }); - }, - - /** - * Read the MSISDN from the (U)SIM. - */ - readMSISDN: function() { - function callback(options) { - let RIL = this.context.RIL; - - let contact = - this.context.ICCPDUHelper.readAlphaIdDiallingNumber(options.recordSize); - if (!contact || - (RIL.iccInfo.msisdn !== undefined && - RIL.iccInfo.msisdn === contact.number)) { - return; - } - RIL.iccInfo.msisdn = contact.number; - if (DEBUG) this.context.debug("MSISDN: " + RIL.iccInfo.msisdn); - this.context.ICCUtilsHelper.handleICCInfoChange(); - } - - this.context.ICCIOHelper.loadLinearFixedEF({ - fileId: ICC_EF_MSISDN, - callback: callback.bind(this) - }); - }, - - /** - * Read the AD (Administrative Data) from the (U)SIM. - */ - readAD: function() { - function callback() { - let Buf = this.context.Buf; - let strLen = Buf.readInt32(); - // Each octet is encoded into two chars. - let octetLen = strLen / 2; - let ad = this.context.GsmPDUHelper.readHexOctetArray(octetLen); - Buf.readStringDelimiter(strLen); - - if (DEBUG) { - let str = ""; - for (let i = 0; i < ad.length; i++) { - str += ad[i] + ", "; - } - this.context.debug("AD: " + str); - } - - let ICCUtilsHelper = this.context.ICCUtilsHelper; - let RIL = this.context.RIL; - // TS 31.102, clause 4.2.18 EFAD - let mncLength = 0; - if (ad && ad[3]) { - mncLength = ad[3] & 0x0f; - if (mncLength != 0x02 && mncLength != 0x03) { - mncLength = 0; - } - } - // The 4th byte of the response is the length of MNC. - let mccMnc = ICCUtilsHelper.parseMccMncFromImsi(RIL.iccInfoPrivate.imsi, - mncLength); - if (mccMnc) { - RIL.iccInfo.mcc = mccMnc.mcc; - RIL.iccInfo.mnc = mccMnc.mnc; - ICCUtilsHelper.handleICCInfoChange(); - } - } - - this.context.ICCIOHelper.loadTransparentEF({ - fileId: ICC_EF_AD, - callback: callback.bind(this) - }); - }, - - /** - * Read the SPN (Service Provider Name) from the (U)SIM. - */ - readSPN: function() { - function callback() { - let Buf = this.context.Buf; - let strLen = Buf.readInt32(); - // Each octet is encoded into two chars. - let octetLen = strLen / 2; - let spnDisplayCondition = this.context.GsmPDUHelper.readHexOctet(); - // Minus 1 because the first octet is used to store display condition. - let spn = this.context.ICCPDUHelper.readAlphaIdentifier(octetLen - 1); - Buf.readStringDelimiter(strLen); - - if (DEBUG) { - this.context.debug("SPN: spn = " + spn + - ", spnDisplayCondition = " + spnDisplayCondition); - } - - let RIL = this.context.RIL; - RIL.iccInfoPrivate.spnDisplayCondition = spnDisplayCondition; - RIL.iccInfo.spn = spn; - let ICCUtilsHelper = this.context.ICCUtilsHelper; - ICCUtilsHelper.updateDisplayCondition(); - ICCUtilsHelper.handleICCInfoChange(); - } - - this.context.ICCIOHelper.loadTransparentEF({ - fileId: ICC_EF_SPN, - callback: callback.bind(this) - }); - }, - - readIMG: function(recordNumber, onsuccess, onerror) { - function callback(options) { - let RIL = this.context.RIL; - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - let strLen = Buf.readInt32(); - // Each octet is encoded into two chars. - let octetLen = strLen / 2; - - let numInstances = GsmPDUHelper.readHexOctet(); - - // Data length is defined as 9n+1 or 9n+2. See TS 31.102, sub-clause - // 4.6.1.1. However, it's likely to have padding appended so we have a - // rather loose check. - if (octetLen < (9 * numInstances + 1)) { - Buf.seekIncoming((octetLen - 1) * Buf.PDU_HEX_OCTET_SIZE); - Buf.readStringDelimiter(strLen); - if (onerror) { - onerror(); - } - return; - } - - let imgDescriptors = []; - for (let i = 0; i < numInstances; i++) { - imgDescriptors[i] = { - width: GsmPDUHelper.readHexOctet(), - height: GsmPDUHelper.readHexOctet(), - codingScheme: GsmPDUHelper.readHexOctet(), - fileId: (GsmPDUHelper.readHexOctet() << 8) | - GsmPDUHelper.readHexOctet(), - offset: (GsmPDUHelper.readHexOctet() << 8) | - GsmPDUHelper.readHexOctet(), - dataLen: (GsmPDUHelper.readHexOctet() << 8) | - GsmPDUHelper.readHexOctet() - }; - } - Buf.seekIncoming((octetLen - 9 * numInstances - 1) * Buf.PDU_HEX_OCTET_SIZE); - Buf.readStringDelimiter(strLen); - - let instances = []; - let currentInstance = 0; - let readNextInstance = (function(img) { - instances[currentInstance] = img; - currentInstance++; - - if (currentInstance < numInstances) { - let imgDescriptor = imgDescriptors[currentInstance]; - this.readIIDF(imgDescriptor.fileId, - imgDescriptor.offset, - imgDescriptor.dataLen, - imgDescriptor.codingScheme, - readNextInstance, - onerror); - } else { - if (onsuccess) { - onsuccess(instances); - } - } - }).bind(this); - - this.readIIDF(imgDescriptors[0].fileId, - imgDescriptors[0].offset, - imgDescriptors[0].dataLen, - imgDescriptors[0].codingScheme, - readNextInstance, - onerror); - } - - this.context.ICCIOHelper.loadLinearFixedEF({ - fileId: ICC_EF_IMG, - recordNumber: recordNumber, - callback: callback.bind(this), - onerror: onerror - }); - }, - - readIIDF: function(fileId, offset, dataLen, codingScheme, onsuccess, onerror) { - // Valid fileId is '4FXX', see TS 31.102, clause 4.6.1.2. - if ((fileId >> 8) != 0x4F) { - if (onerror) { - onerror(); - } - return; - } - - function callback() { - let Buf = this.context.Buf; - let RIL = this.context.RIL; - let GsmPDUHelper = this.context.GsmPDUHelper; - let strLen = Buf.readInt32(); - // Each octet is encoded into two chars. - let octetLen = strLen / 2; - - if (octetLen < offset + dataLen) { - // Data length is not enough. See TS 31.102, clause 4.6.1.1, the - // paragraph "Bytes 8 and 9: Length of Image Instance Data." - Buf.seekIncoming(octetLen * Buf.PDU_HEX_OCTET_SIZE); - Buf.readStringDelimiter(strLen); - if (onerror) { - onerror(); - } - return; - } - - Buf.seekIncoming(offset * Buf.PDU_HEX_OCTET_SIZE); - - let rawData = { - width: GsmPDUHelper.readHexOctet(), - height: GsmPDUHelper.readHexOctet(), - codingScheme: codingScheme - }; - - switch (codingScheme) { - case ICC_IMG_CODING_SCHEME_BASIC: - rawData.body = GsmPDUHelper.readHexOctetArray( - dataLen - ICC_IMG_HEADER_SIZE_BASIC); - Buf.seekIncoming((octetLen - offset - dataLen) * Buf.PDU_HEX_OCTET_SIZE); - break; - - case ICC_IMG_CODING_SCHEME_COLOR: - case ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY: - rawData.bitsPerImgPoint = GsmPDUHelper.readHexOctet(); - let num = GsmPDUHelper.readHexOctet(); - // The value 0 shall be interpreted as 256. See TS 31.102, Annex B.2. - rawData.numOfClutEntries = (num === 0) ? 0x100 : num; - rawData.clutOffset = (GsmPDUHelper.readHexOctet() << 8) | - GsmPDUHelper.readHexOctet(); - rawData.body = GsmPDUHelper.readHexOctetArray( - dataLen - ICC_IMG_HEADER_SIZE_COLOR); - - Buf.seekIncoming((rawData.clutOffset - offset - dataLen) * - Buf.PDU_HEX_OCTET_SIZE); - let clut = GsmPDUHelper.readHexOctetArray(rawData.numOfClutEntries * - ICC_CLUT_ENTRY_SIZE); - - rawData.clut = clut; - } - - Buf.readStringDelimiter(strLen); - - if (onsuccess) { - onsuccess(rawData); - } - } - - this.context.ICCIOHelper.loadTransparentEF({ - fileId: fileId, - pathId: this.context.ICCFileHelper.getEFPath(ICC_EF_IMG), - callback: callback.bind(this), - onerror: onerror - }); - }, - - /** - * Read the (U)SIM Service Table from the (U)SIM. - */ - readSST: function() { - function callback() { - let Buf = this.context.Buf; - let RIL = this.context.RIL; - - let strLen = Buf.readInt32(); - // Each octet is encoded into two chars. - let octetLen = strLen / 2; - let sst = this.context.GsmPDUHelper.readHexOctetArray(octetLen); - Buf.readStringDelimiter(strLen); - RIL.iccInfoPrivate.sst = sst; - if (DEBUG) { - let str = ""; - for (let i = 0; i < sst.length; i++) { - str += sst[i] + ", "; - } - this.context.debug("SST: " + str); - } - - let ICCUtilsHelper = this.context.ICCUtilsHelper; - if (ICCUtilsHelper.isICCServiceAvailable("MSISDN")) { - if (DEBUG) this.context.debug("MSISDN: MSISDN is available"); - this.readMSISDN(); - } else { - if (DEBUG) this.context.debug("MSISDN: MSISDN service is not available"); - } - - // Fetch SPN and PLMN list, if some of them are available. - if (ICCUtilsHelper.isICCServiceAvailable("SPN")) { - if (DEBUG) this.context.debug("SPN: SPN is available"); - this.readSPN(); - } else { - if (DEBUG) this.context.debug("SPN: SPN service is not available"); - } - - if (ICCUtilsHelper.isICCServiceAvailable("MDN")) { - if (DEBUG) this.context.debug("MDN: MDN available."); - this.readMBDN(); - } else { - if (DEBUG) this.context.debug("MDN: MDN service is not available"); - - if (ICCUtilsHelper.isCphsServiceAvailable("MBN")) { - // read CPHS_MBN in advance if MBDN is not available. - this.readCphsMBN(); - } else { - if (DEBUG) this.context.debug("CPHS_MBN: CPHS_MBN service is not available"); - } - } - - if (ICCUtilsHelper.isICCServiceAvailable("MWIS")) { - if (DEBUG) this.context.debug("MWIS: MWIS is available"); - this.readMWIS(); - } else { - if (DEBUG) this.context.debug("MWIS: MWIS is not available"); - } - - if (ICCUtilsHelper.isICCServiceAvailable("SPDI")) { - if (DEBUG) this.context.debug("SPDI: SPDI available."); - this.readSPDI(); - } else { - if (DEBUG) this.context.debug("SPDI: SPDI service is not available"); - } - - if (ICCUtilsHelper.isICCServiceAvailable("PNN")) { - if (DEBUG) this.context.debug("PNN: PNN is available"); - this.readPNN(); - } else { - if (DEBUG) this.context.debug("PNN: PNN is not available"); - } - - if (ICCUtilsHelper.isICCServiceAvailable("OPL")) { - if (DEBUG) this.context.debug("OPL: OPL is available"); - this.readOPL(); - } else { - if (DEBUG) this.context.debug("OPL: OPL is not available"); - } - - if (ICCUtilsHelper.isICCServiceAvailable("GID1")) { - if (DEBUG) this.context.debug("GID1: GID1 is available"); - this.readGID1(); - } else { - if (DEBUG) this.context.debug("GID1: GID1 is not available"); - } - - if (ICCUtilsHelper.isICCServiceAvailable("CBMI")) { - this.readCBMI(); - } else { - RIL.cellBroadcastConfigs.CBMI = null; - } - if (ICCUtilsHelper.isICCServiceAvailable("DATA_DOWNLOAD_SMS_CB")) { - this.readCBMID(); - } else { - RIL.cellBroadcastConfigs.CBMID = null; - } - if (ICCUtilsHelper.isICCServiceAvailable("CBMIR")) { - this.readCBMIR(); - } else { - RIL.cellBroadcastConfigs.CBMIR = null; - } - RIL._mergeAllCellBroadcastConfigs(); - } - - // ICC_EF_UST has the same value with ICC_EF_SST. - this.context.ICCIOHelper.loadTransparentEF({ - fileId: ICC_EF_SST, - callback: callback.bind(this) - }); - }, - - /** - * Read (U)SIM MBDN. (Mailbox Dialling Number) - * - * @see TS 131.102, clause 4.2.60 - */ - readMBDN: function() { - function callback(options) { - let RIL = this.context.RIL; - let contact = - this.context.ICCPDUHelper.readAlphaIdDiallingNumber(options.recordSize); - if ((!contact || - ((!contact.alphaId || contact.alphaId == "") && - (!contact.number || contact.number == ""))) && - this.context.ICCUtilsHelper.isCphsServiceAvailable("MBN")) { - // read CPHS_MBN in advance if MBDN is invalid or empty. - this.readCphsMBN(); - return; - } - - if (!contact || - (RIL.iccInfoPrivate.mbdn !== undefined && - RIL.iccInfoPrivate.mbdn === contact.number)) { - return; - } - RIL.iccInfoPrivate.mbdn = contact.number; - if (DEBUG) { - this.context.debug("MBDN, alphaId=" + contact.alphaId + - " number=" + contact.number); - } - contact.rilMessageType = "iccmbdn"; - RIL.sendChromeMessage(contact); - } - - this.context.ICCIOHelper.loadLinearFixedEF({ - fileId: ICC_EF_MBDN, - callback: callback.bind(this) - }); - }, - - /** - * Read ICC MWIS. (Message Waiting Indication Status) - * - * @see TS 31.102, clause 4.2.63 for USIM and TS 51.011, clause 10.3.45 for SIM. - */ - readMWIS: function() { - function callback(options) { - let Buf = this.context.Buf; - let RIL = this.context.RIL; - - let strLen = Buf.readInt32(); - // Each octet is encoded into two chars. - let octetLen = strLen / 2; - let mwis = this.context.GsmPDUHelper.readHexOctetArray(octetLen); - Buf.readStringDelimiter(strLen); - if (!mwis) { - return; - } - RIL.iccInfoPrivate.mwis = mwis; //Keep raw MWIS for updateMWIS() - - let mwi = {}; - // b8 b7 B6 b5 b4 b3 b2 b1 4.2.63, TS 31.102 version 11.6.0 - // | | | | | | | |__ Voicemail - // | | | | | | |_____ Fax - // | | | | | |________ Electronic Mail - // | | | | |___________ Other - // | | | |______________ Videomail - // |__|__|_________________ RFU - mwi.active = ((mwis[0] & 0x01) != 0); - - if (mwi.active) { - // In TS 23.040 msgCount is in the range from 0 to 255. - // The value 255 shall be taken to mean 255 or greater. - // - // However, There is no definition about 0 when MWI is active. - // - // Normally, when mwi is active, the msgCount must be larger than 0. - // Refer to other reference phone, - // 0 is usually treated as UNKNOWN for storing 2nd level MWI status (DCS). - mwi.msgCount = (mwis[1] === 0) ? GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN - : mwis[1]; - } else { - mwi.msgCount = 0; - } - - RIL.sendChromeMessage({ rilMessageType: "iccmwis", - mwi: mwi }); - } - - this.context.ICCIOHelper.loadLinearFixedEF({ - fileId: ICC_EF_MWIS, - recordNumber: 1, // Get 1st Subscriber Profile. - callback: callback.bind(this) - }); - }, - - /** - * Update ICC MWIS. (Message Waiting Indication Status) - * - * @see TS 31.102, clause 4.2.63 for USIM and TS 51.011, clause 10.3.45 for SIM. - */ - updateMWIS: function(mwi) { - let RIL = this.context.RIL; - if (!RIL.iccInfoPrivate.mwis) { - return; - } - - function dataWriter(recordSize) { - let mwis = RIL.iccInfoPrivate.mwis; - - let msgCount = - (mwi.msgCount === GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN) ? 0 : mwi.msgCount; - - [mwis[0], mwis[1]] = (mwi.active) ? [(mwis[0] | 0x01), msgCount] - : [(mwis[0] & 0xFE), 0]; - - let strLen = recordSize * 2; - let Buf = this.context.Buf; - Buf.writeInt32(strLen); - - let GsmPDUHelper = this.context.GsmPDUHelper; - for (let i = 0; i < mwis.length; i++) { - GsmPDUHelper.writeHexOctet(mwis[i]); - } - - Buf.writeStringDelimiter(strLen); - } - - this.context.ICCIOHelper.updateLinearFixedEF({ - fileId: ICC_EF_MWIS, - recordNumber: 1, // Update 1st Subscriber Profile. - dataWriter: dataWriter.bind(this) - }); - }, - - /** - * Read the SPDI (Service Provider Display Information) from the (U)SIM. - * - * See TS 131.102 section 4.2.66 for USIM and TS 51.011 section 10.3.50 - * for SIM. - */ - readSPDI: function() { - function callback() { - let Buf = this.context.Buf; - let strLen = Buf.readInt32(); - let octetLen = strLen / 2; - let readLen = 0; - let endLoop = false; - - let RIL = this.context.RIL; - RIL.iccInfoPrivate.SPDI = null; - - let GsmPDUHelper = this.context.GsmPDUHelper; - while ((readLen < octetLen) && !endLoop) { - let tlvTag = GsmPDUHelper.readHexOctet(); - let tlvLen = GsmPDUHelper.readHexOctet(); - readLen += 2; // For tag and length fields. - switch (tlvTag) { - case SPDI_TAG_SPDI: - // The value part itself is a TLV. - continue; - case SPDI_TAG_PLMN_LIST: - // This PLMN list is what we want. - RIL.iccInfoPrivate.SPDI = this.readPLMNEntries(tlvLen / 3); - readLen += tlvLen; - endLoop = true; - break; - default: - // We don't care about its content if its tag is not SPDI nor - // PLMN_LIST. - endLoop = true; - break; - } - } - - // Consume unread octets. - Buf.seekIncoming((octetLen - readLen) * Buf.PDU_HEX_OCTET_SIZE); - Buf.readStringDelimiter(strLen); - - if (DEBUG) { - this.context.debug("SPDI: " + JSON.stringify(RIL.iccInfoPrivate.SPDI)); - } - let ICCUtilsHelper = this.context.ICCUtilsHelper; - if (ICCUtilsHelper.updateDisplayCondition()) { - ICCUtilsHelper.handleICCInfoChange(); - } - } - - // PLMN List is Servive 51 in USIM, EF_SPDI - this.context.ICCIOHelper.loadTransparentEF({ - fileId: ICC_EF_SPDI, - callback: callback.bind(this) - }); - }, - - _readCbmiHelper: function(which) { - let RIL = this.context.RIL; - - function callback() { - let Buf = this.context.Buf; - let strLength = Buf.readInt32(); - - // Each Message Identifier takes two octets and each octet is encoded - // into two chars. - let numIds = strLength / 4, list = null; - if (numIds) { - list = []; - let GsmPDUHelper = this.context.GsmPDUHelper; - for (let i = 0, id; i < numIds; i++) { - id = GsmPDUHelper.readHexOctet() << 8 | GsmPDUHelper.readHexOctet(); - // `Unused entries shall be set to 'FF FF'.` - if (id != 0xFFFF) { - list.push(id); - list.push(id + 1); - } - } - } - if (DEBUG) { - this.context.debug(which + ": " + JSON.stringify(list)); - } - - Buf.readStringDelimiter(strLength); - - RIL.cellBroadcastConfigs[which] = list; - RIL._mergeAllCellBroadcastConfigs(); - } - - function onerror() { - RIL.cellBroadcastConfigs[which] = null; - RIL._mergeAllCellBroadcastConfigs(); - } - - let fileId = GLOBAL["ICC_EF_" + which]; - this.context.ICCIOHelper.loadTransparentEF({ - fileId: fileId, - callback: callback.bind(this), - onerror: onerror.bind(this) - }); - }, - - /** - * Read EFcbmi (Cell Broadcast Message Identifier selection) - * - * @see 3GPP TS 31.102 v110.02.0 section 4.2.14 EFcbmi - * @see 3GPP TS 51.011 v5.0.0 section 10.3.13 EFcbmi - */ - readCBMI: function() { - this._readCbmiHelper("CBMI"); - }, - - /** - * Read EFcbmid (Cell Broadcast Message Identifier for Data Download) - * - * @see 3GPP TS 31.102 v110.02.0 section 4.2.20 EFcbmid - * @see 3GPP TS 51.011 v5.0.0 section 10.3.26 EFcbmid - */ - readCBMID: function() { - this._readCbmiHelper("CBMID"); - }, - - /** - * Read EFcbmir (Cell Broadcast Message Identifier Range selection) - * - * @see 3GPP TS 31.102 v110.02.0 section 4.2.22 EFcbmir - * @see 3GPP TS 51.011 v5.0.0 section 10.3.28 EFcbmir - */ - readCBMIR: function() { - let RIL = this.context.RIL; - - function callback() { - let Buf = this.context.Buf; - let strLength = Buf.readInt32(); - - // Each Message Identifier range takes four octets and each octet is - // encoded into two chars. - let numIds = strLength / 8, list = null; - if (numIds) { - list = []; - let GsmPDUHelper = this.context.GsmPDUHelper; - for (let i = 0, from, to; i < numIds; i++) { - // `Bytes one and two of each range identifier equal the lower value - // of a cell broadcast range, bytes three and four equal the upper - // value of a cell broadcast range.` - from = GsmPDUHelper.readHexOctet() << 8 | GsmPDUHelper.readHexOctet(); - to = GsmPDUHelper.readHexOctet() << 8 | GsmPDUHelper.readHexOctet(); - // `Unused entries shall be set to 'FF FF'.` - if ((from != 0xFFFF) && (to != 0xFFFF)) { - list.push(from); - list.push(to + 1); - } - } - } - if (DEBUG) { - this.context.debug("CBMIR: " + JSON.stringify(list)); - } - - Buf.readStringDelimiter(strLength); - - RIL.cellBroadcastConfigs.CBMIR = list; - RIL._mergeAllCellBroadcastConfigs(); - } - - function onerror() { - RIL.cellBroadcastConfigs.CBMIR = null; - RIL._mergeAllCellBroadcastConfigs(); - } - - this.context.ICCIOHelper.loadTransparentEF({ - fileId: ICC_EF_CBMIR, - callback: callback.bind(this), - onerror: onerror.bind(this) - }); - }, - - /** - * Read OPL (Operator PLMN List) from (U)SIM. - * - * See 3GPP TS 31.102 Sec. 4.2.59 for USIM - * 3GPP TS 51.011 Sec. 10.3.42 for SIM. - */ - readOPL: function() { - let ICCIOHelper = this.context.ICCIOHelper; - let opl = []; - function callback(options) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - - let strLen = Buf.readInt32(); - // The first 7 bytes are LAI (for UMTS) and the format of LAI is defined - // in 3GPP TS 23.003, Sec 4.1 - // +-------------+---------+ - // | Octet 1 - 3 | MCC/MNC | - // +-------------+---------+ - // | Octet 4 - 7 | LAC | - // +-------------+---------+ - let mccMnc = [GsmPDUHelper.readHexOctet(), - GsmPDUHelper.readHexOctet(), - GsmPDUHelper.readHexOctet()]; - if (mccMnc[0] != 0xFF || mccMnc[1] != 0xFF || mccMnc[2] != 0xFF) { - let oplElement = {}; - let semiOctets = []; - for (let i = 0; i < mccMnc.length; i++) { - semiOctets.push((mccMnc[i] & 0xf0) >> 4); - semiOctets.push(mccMnc[i] & 0x0f); - } - let reformat = [semiOctets[1], semiOctets[0], semiOctets[3], - semiOctets[5], semiOctets[4], semiOctets[2]]; - let buf = ""; - for (let i = 0; i < reformat.length; i++) { - if (reformat[i] != 0xF) { - buf += GsmPDUHelper.semiOctetToExtendedBcdChar(reformat[i]); - } - if (i === 2) { - // 0-2: MCC - oplElement.mcc = buf; - buf = ""; - } else if (i === 5) { - // 3-5: MNC - oplElement.mnc = buf; - } - } - // LAC/TAC - oplElement.lacTacStart = - (GsmPDUHelper.readHexOctet() << 8) | GsmPDUHelper.readHexOctet(); - oplElement.lacTacEnd = - (GsmPDUHelper.readHexOctet() << 8) | GsmPDUHelper.readHexOctet(); - // PLMN Network Name Record Identifier - oplElement.pnnRecordId = GsmPDUHelper.readHexOctet(); - if (DEBUG) { - this.context.debug("OPL: [" + (opl.length + 1) + "]: " + - JSON.stringify(oplElement)); - } - opl.push(oplElement); - } else { - Buf.seekIncoming(5 * Buf.PDU_HEX_OCTET_SIZE); - } - Buf.readStringDelimiter(strLen); - - let RIL = this.context.RIL; - if (options.p1 < options.totalRecords) { - ICCIOHelper.loadNextRecord(options); - } else { - RIL.iccInfoPrivate.OPL = opl; - RIL.overrideICCNetworkName(); - } - } - - ICCIOHelper.loadLinearFixedEF({fileId: ICC_EF_OPL, - callback: callback.bind(this)}); - }, - - /** - * Read PNN (PLMN Network Name) from (U)SIM. - * - * See 3GPP TS 31.102 Sec. 4.2.58 for USIM - * 3GPP TS 51.011 Sec. 10.3.41 for SIM. - */ - readPNN: function() { - let ICCIOHelper = this.context.ICCIOHelper; - function callback(options) { - let pnnElement; - let Buf = this.context.Buf; - let strLen = Buf.readInt32(); - let octetLen = strLen / 2; - let readLen = 0; - - let GsmPDUHelper = this.context.GsmPDUHelper; - while (readLen < octetLen) { - let tlvTag = GsmPDUHelper.readHexOctet(); - - if (tlvTag == 0xFF) { - // Unused byte - readLen++; - Buf.seekIncoming((octetLen - readLen) * Buf.PDU_HEX_OCTET_SIZE); - break; - } - - // Needs this check to avoid initializing twice. - pnnElement = pnnElement || {}; - - let tlvLen = GsmPDUHelper.readHexOctet(); - - switch (tlvTag) { - case PNN_IEI_FULL_NETWORK_NAME: - pnnElement.fullName = GsmPDUHelper.readNetworkName(tlvLen); - break; - case PNN_IEI_SHORT_NETWORK_NAME: - pnnElement.shortName = GsmPDUHelper.readNetworkName(tlvLen); - break; - default: - Buf.seekIncoming(tlvLen * Buf.PDU_HEX_OCTET_SIZE); - break; - } - - readLen += (tlvLen + 2); // +2 for tlvTag and tlvLen - } - Buf.readStringDelimiter(strLen); - - pnn.push(pnnElement); - - let RIL = this.context.RIL; - if (options.p1 < options.totalRecords) { - ICCIOHelper.loadNextRecord(options); - } else { - if (DEBUG) { - for (let i = 0; i < pnn.length; i++) { - this.context.debug("PNN: [" + i + "]: " + JSON.stringify(pnn[i])); - } - } - RIL.iccInfoPrivate.PNN = pnn; - RIL.overrideICCNetworkName(); - } - } - - let pnn = []; - ICCIOHelper.loadLinearFixedEF({fileId: ICC_EF_PNN, - callback: callback.bind(this)}); - }, - - /** - * Read the list of PLMN (Public Land Mobile Network) entries - * We cannot directly rely on readSwappedNibbleBcdToString(), - * since it will no correctly handle some corner-cases that are - * not a problem in our case (0xFF 0xFF 0xFF). - * - * @param length The number of PLMN records. - * @return An array of string corresponding to the PLMNs. - */ - readPLMNEntries: function(length) { - let plmnList = []; - // Each PLMN entry has 3 bytes. - if (DEBUG) { - this.context.debug("PLMN entries length = " + length); - } - let GsmPDUHelper = this.context.GsmPDUHelper; - let index = 0; - while (index < length) { - // Unused entries will be 0xFFFFFF, according to EF_SPDI - // specs (TS 131 102, section 4.2.66) - try { - let plmn = [GsmPDUHelper.readHexOctet(), - GsmPDUHelper.readHexOctet(), - GsmPDUHelper.readHexOctet()]; - if (DEBUG) { - this.context.debug("Reading PLMN entry: [" + index + "]: '" + plmn + "'"); - } - if (plmn[0] != 0xFF && - plmn[1] != 0xFF && - plmn[2] != 0xFF) { - let semiOctets = []; - for (let idx = 0; idx < plmn.length; idx++) { - semiOctets.push((plmn[idx] & 0xF0) >> 4); - semiOctets.push(plmn[idx] & 0x0F); - } - - // According to TS 24.301, 9.9.3.12, the semi octets is arranged - // in format: - // Byte 1: MCC[2] | MCC[1] - // Byte 2: MNC[3] | MCC[3] - // Byte 3: MNC[2] | MNC[1] - // Therefore, we need to rearrange them. - let reformat = [semiOctets[1], semiOctets[0], semiOctets[3], - semiOctets[5], semiOctets[4], semiOctets[2]]; - let buf = ""; - let plmnEntry = {}; - for (let i = 0; i < reformat.length; i++) { - if (reformat[i] != 0xF) { - buf += GsmPDUHelper.semiOctetToExtendedBcdChar(reformat[i]); - } - if (i === 2) { - // 0-2: MCC - plmnEntry.mcc = buf; - buf = ""; - } else if (i === 5) { - // 3-5: MNC - plmnEntry.mnc = buf; - } - } - if (DEBUG) { - this.context.debug("PLMN = " + plmnEntry.mcc + ", " + plmnEntry.mnc); - } - plmnList.push(plmnEntry); - } - } catch (e) { - if (DEBUG) { - this.context.debug("PLMN entry " + index + " is invalid."); - } - break; - } - index ++; - } - return plmnList; - }, - - /** - * Read the SMS from the ICC. - * - * @param recordNumber The number of the record shall be loaded. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readSMS: function(recordNumber, onsuccess, onerror) { - function callback(options) { - let Buf = this.context.Buf; - let strLen = Buf.readInt32(); - - // TS 51.011, 10.5.3 EF_SMS - // b3 b2 b1 - // 0 0 1 message received by MS from network; message read - // 0 1 1 message received by MS from network; message to be read - // 1 1 1 MS originating message; message to be sent - // 1 0 1 MS originating message; message sent to the network: - let GsmPDUHelper = this.context.GsmPDUHelper; - let status = GsmPDUHelper.readHexOctet(); - - let message = GsmPDUHelper.readMessage(); - message.simStatus = status; - - // Consumes the remaining buffer - Buf.seekIncoming(Buf.getReadAvailable() - Buf.PDU_HEX_OCTET_SIZE); - - Buf.readStringDelimiter(strLen); - - if (message) { - onsuccess(message); - } else { - onerror("Failed to decode SMS on SIM #" + recordNumber); - } - } - - this.context.ICCIOHelper.loadLinearFixedEF({ - fileId: ICC_EF_SMS, - recordNumber: recordNumber, - callback: callback.bind(this), - onerror: onerror - }); - }, - - readGID1: function() { - function callback() { - let Buf = this.context.Buf; - let RIL = this.context.RIL; - - RIL.iccInfoPrivate.gid1 = Buf.readString(); - if (DEBUG) { - this.context.debug("GID1: " + RIL.iccInfoPrivate.gid1); - } - } - - this.context.ICCIOHelper.loadTransparentEF({ - fileId: ICC_EF_GID1, - callback: callback.bind(this) - }); - }, - - /** - * Read CPHS Phase & Service Table from CPHS Info. - * - * @See B.3.1.1 CPHS Information in CPHS Phase 2. - * - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readCphsInfo: function(onsuccess, onerror) { - function callback() { - try { - let Buf = this.context.Buf; - let RIL = this.context.RIL; - - let strLen = Buf.readInt32(); - // Each octet is encoded into two chars. - let octetLen = strLen / 2; - let cphsInfo = this.context.GsmPDUHelper.readHexOctetArray(octetLen); - Buf.readStringDelimiter(strLen); - if (DEBUG) { - let str = ""; - for (let i = 0; i < cphsInfo.length; i++) { - str += cphsInfo[i] + ", "; - } - this.context.debug("CPHS INFO: " + str); - } - - /** - * CPHS INFORMATION - * - * Byte 1: CPHS Phase - * 01 phase 1 - * 02 phase 2 - * etc. - * - * Byte 2: CPHS Service Table - * +----+----+----+----+----+----+----+----+ - * | b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | - * +----+----+----+----+----+----+----+----+ - * | ONSF | MBN | SST | CSP | - * | Phase 2 | ALL | Phase 1 | All | - * +----+----+----+----+----+----+----+----+ - * - * Byte 3: CPHS Service Table continued - * +----+----+----+----+----+----+----+----+ - * | b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | - * +----+----+----+----+----+----+----+----+ - * | RFU | RFU | RFU | INFO_NUM| - * | | | | Phase 2 | - * +----+----+----+----+----+----+----+----+ - */ - let cphsPhase = cphsInfo[0]; - if (cphsPhase == 1) { - // Clear 'Phase 2 only' services. - cphsInfo[1] &= 0x3F; - // We don't know whether Byte 3 is available in CPHS phase 1 or not. - // Add boundary check before accessing it. - if (cphsInfo.length > 2) { - cphsInfo[2] = 0x00; - } - } else if (cphsPhase == 2) { - // Clear 'Phase 1 only' services. - cphsInfo[1] &= 0xF3; - } else { - throw new Error("Unknown CPHS phase: " + cphsPhase); - } - - RIL.iccInfoPrivate.cphsSt = cphsInfo.subarray(1); - onsuccess(); - } catch(e) { - onerror(e.toString()); - } - } - - this.context.ICCIOHelper.loadTransparentEF({ - fileId: ICC_EF_CPHS_INFO, - callback: callback.bind(this), - onerror: onerror - }); - }, - - /** - * Read CPHS MBN. (Mailbox Numbers) - * - * @See B.4.2.2 Voice Message Retrieval and Indicator Clearing - */ - readCphsMBN: function() { - function callback(options) { - let RIL = this.context.RIL; - let contact = - this.context.ICCPDUHelper.readAlphaIdDiallingNumber(options.recordSize); - if (!contact || - (RIL.iccInfoPrivate.mbdn !== undefined && - RIL.iccInfoPrivate.mbdn === contact.number)) { - return; - } - RIL.iccInfoPrivate.mbdn = contact.number; - if (DEBUG) { - this.context.debug("CPHS_MDN, alphaId=" + contact.alphaId + - " number=" + contact.number); - } - contact.rilMessageType = "iccmbdn"; - RIL.sendChromeMessage(contact); - } - - this.context.ICCIOHelper.loadLinearFixedEF({ - fileId: ICC_EF_CPHS_MBN, - callback: callback.bind(this) - }); - } -}; - -function RuimRecordHelperObject(aContext) { - this.context = aContext; -} -RuimRecordHelperObject.prototype = { - context: null, - - fetchRuimRecords: function() { - this.getIMSI_M(); - this.readCST(); - this.readCDMAHome(); - this.context.RIL.getCdmaSubscription(); - }, - - /** - * Get IMSI_M from CSIM/RUIM. - * See 3GPP2 C.S0065 Sec. 5.2.2 - */ - getIMSI_M: function() { - function callback() { - let Buf = this.context.Buf; - let strLen = Buf.readInt32(); - let encodedImsi = this.context.GsmPDUHelper.readHexOctetArray(strLen / 2); - Buf.readStringDelimiter(strLen); - - if ((encodedImsi[CSIM_IMSI_M_PROGRAMMED_BYTE] & 0x80)) { // IMSI_M programmed - let RIL = this.context.RIL; - RIL.iccInfoPrivate.imsi = this.decodeIMSI(encodedImsi); - RIL.sendChromeMessage({rilMessageType: "iccimsi", - imsi: RIL.iccInfoPrivate.imsi}); - - let ICCUtilsHelper = this.context.ICCUtilsHelper; - let mccMnc = ICCUtilsHelper.parseMccMncFromImsi(RIL.iccInfoPrivate.imsi); - if (mccMnc) { - RIL.iccInfo.mcc = mccMnc.mcc; - RIL.iccInfo.mnc = mccMnc.mnc; - ICCUtilsHelper.handleICCInfoChange(); - } - } - } - - this.context.ICCIOHelper.loadTransparentEF({ - fileId: ICC_EF_CSIM_IMSI_M, - callback: callback.bind(this) - }); - }, - - /** - * Decode IMSI from IMSI_M - * See 3GPP2 C.S0005 Sec. 2.3.1 - * +---+---------+------------+---+--------+---------+---+---------+--------+ - * |RFU| MCC | programmed |RFU| MNC | MIN1 |RFU| MIN2 | CLASS | - * +---+---------+------------+---+--------+---------+---+---------+--------+ - * | 6 | 10 bits | 8 bits | 1 | 7 bits | 24 bits | 6 | 10 bits | 8 bits | - * +---+---------+------------+---+--------+---------+---+---------+--------+ - */ - decodeIMSI: function(encodedImsi) { - // MCC: 10 bits, 3 digits - let encodedMCC = ((encodedImsi[CSIM_IMSI_M_MCC_BYTE + 1] & 0x03) << 8) + - (encodedImsi[CSIM_IMSI_M_MCC_BYTE] & 0xff); - let mcc = this.decodeIMSIValue(encodedMCC, 3); - - // MNC: 7 bits, 2 digits - let encodedMNC = encodedImsi[CSIM_IMSI_M_MNC_BYTE] & 0x7f; - let mnc = this.decodeIMSIValue(encodedMNC, 2); - - // MIN2: 10 bits, 3 digits - let encodedMIN2 = ((encodedImsi[CSIM_IMSI_M_MIN2_BYTE + 1] & 0x03) << 8) + - (encodedImsi[CSIM_IMSI_M_MIN2_BYTE] & 0xff); - let min2 = this.decodeIMSIValue(encodedMIN2, 3); - - // MIN1: 10+4+10 bits, 3+1+3 digits - let encodedMIN1First3 = ((encodedImsi[CSIM_IMSI_M_MIN1_BYTE + 2] & 0xff) << 2) + - ((encodedImsi[CSIM_IMSI_M_MIN1_BYTE + 1] & 0xc0) >> 6); - let min1First3 = this.decodeIMSIValue(encodedMIN1First3, 3); - - let encodedFourthDigit = (encodedImsi[CSIM_IMSI_M_MIN1_BYTE + 1] & 0x3c) >> 2; - if (encodedFourthDigit > 9) { - encodedFourthDigit = 0; - } - let fourthDigit = encodedFourthDigit.toString(); - - let encodedMIN1Last3 = ((encodedImsi[CSIM_IMSI_M_MIN1_BYTE + 1] & 0x03) << 8) + - (encodedImsi[CSIM_IMSI_M_MIN1_BYTE] & 0xff); - let min1Last3 = this.decodeIMSIValue(encodedMIN1Last3, 3); - - return mcc + mnc + min2 + min1First3 + fourthDigit + min1Last3; - }, - - /** - * Decode IMSI Helper function - * See 3GPP2 C.S0005 section 2.3.1.1 - */ - decodeIMSIValue: function(encoded, length) { - let offset = length === 3 ? 111 : 11; - let value = encoded + offset; - - for (let base = 10, temp = value, i = 0; i < length; i++) { - if (temp % 10 === 0) { - value -= base; - } - temp = Math.floor(value / base); - base = base * 10; - } - - let s = value.toString(); - while (s.length < length) { - s = "0" + s; - } - - return s; - }, - - /** - * Read CDMAHOME for CSIM. - * See 3GPP2 C.S0023 Sec. 3.4.8. - */ - readCDMAHome: function() { - let ICCIOHelper = this.context.ICCIOHelper; - - function callback(options) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - - let strLen = Buf.readInt32(); - let tempOctet = GsmPDUHelper.readHexOctet(); - cdmaHomeSystemId.push(((GsmPDUHelper.readHexOctet() & 0x7f) << 8) | tempOctet); - tempOctet = GsmPDUHelper.readHexOctet(); - cdmaHomeNetworkId.push(((GsmPDUHelper.readHexOctet() & 0xff) << 8) | tempOctet); - - // Consuming the last octet: band class. - Buf.seekIncoming(Buf.PDU_HEX_OCTET_SIZE); - - Buf.readStringDelimiter(strLen); - if (options.p1 < options.totalRecords) { - ICCIOHelper.loadNextRecord(options); - } else { - if (DEBUG) { - this.context.debug("CDMAHome system id: " + - JSON.stringify(cdmaHomeSystemId)); - this.context.debug("CDMAHome network id: " + - JSON.stringify(cdmaHomeNetworkId)); - } - this.context.RIL.cdmaHome = { - systemId: cdmaHomeSystemId, - networkId: cdmaHomeNetworkId - }; - } - } - - let cdmaHomeSystemId = [], cdmaHomeNetworkId = []; - ICCIOHelper.loadLinearFixedEF({fileId: ICC_EF_CSIM_CDMAHOME, - callback: callback.bind(this)}); - }, - - /** - * Read CDMA Service Table. - * See 3GPP2 C.S0023 Sec. 3.4.18 - */ - readCST: function() { - function callback() { - let Buf = this.context.Buf; - let RIL = this.context.RIL; - - let strLen = Buf.readInt32(); - // Each octet is encoded into two chars. - RIL.iccInfoPrivate.cst = - this.context.GsmPDUHelper.readHexOctetArray(strLen / 2); - Buf.readStringDelimiter(strLen); - - if (DEBUG) { - let str = ""; - for (let i = 0; i < RIL.iccInfoPrivate.cst.length; i++) { - str += RIL.iccInfoPrivate.cst[i] + ", "; - } - this.context.debug("CST: " + str); - } - - if (this.context.ICCUtilsHelper.isICCServiceAvailable("SPN")) { - if (DEBUG) this.context.debug("SPN: SPN is available"); - this.readSPN(); - } - } - this.context.ICCIOHelper.loadTransparentEF({ - fileId: ICC_EF_CSIM_CST, - callback: callback.bind(this) - }); - }, - - readSPN: function() { - function callback() { - let Buf = this.context.Buf; - let strLen = Buf.readInt32(); - let octetLen = strLen / 2; - - let GsmPDUHelper = this.context.GsmPDUHelper; - let displayCondition = GsmPDUHelper.readHexOctet(); - let codingScheme = GsmPDUHelper.readHexOctet(); - // Skip one octet: language indicator. - Buf.seekIncoming(Buf.PDU_HEX_OCTET_SIZE); - let readLen = 3; - - // SPN String ends up with 0xff. - let userDataBuffer = []; - - while (readLen < octetLen) { - let octet = GsmPDUHelper.readHexOctet(); - readLen++; - if (octet == 0xff) { - break; - } - userDataBuffer.push(octet); - } - - this.context.BitBufferHelper.startRead(userDataBuffer); - - let CdmaPDUHelper = this.context.CdmaPDUHelper; - let msgLen; - switch (CdmaPDUHelper.getCdmaMsgEncoding(codingScheme)) { - case PDU_DCS_MSG_CODING_7BITS_ALPHABET: - msgLen = Math.floor(userDataBuffer.length * 8 / 7); - break; - case PDU_DCS_MSG_CODING_8BITS_ALPHABET: - msgLen = userDataBuffer.length; - break; - case PDU_DCS_MSG_CODING_16BITS_ALPHABET: - msgLen = Math.floor(userDataBuffer.length / 2); - break; - } - - let RIL = this.context.RIL; - RIL.iccInfo.spn = CdmaPDUHelper.decodeCdmaPDUMsg(codingScheme, null, msgLen); - if (DEBUG) { - this.context.debug("CDMA SPN: " + RIL.iccInfo.spn + - ", Display condition: " + displayCondition); - } - RIL.iccInfoPrivate.spnDisplayCondition = displayCondition; - Buf.seekIncoming((octetLen - readLen) * Buf.PDU_HEX_OCTET_SIZE); - Buf.readStringDelimiter(strLen); - } - - this.context.ICCIOHelper.loadTransparentEF({ - fileId: ICC_EF_CSIM_SPN, - callback: callback.bind(this) - }); - } -}; - -/** - * Helper functions for ICC utilities. - */ -function ICCUtilsHelperObject(aContext) { - this.context = aContext; -} -ICCUtilsHelperObject.prototype = { - context: null, - - /** - * Get network names by using EF_OPL and EF_PNN - * - * @See 3GPP TS 31.102 sec. 4.2.58 and sec. 4.2.59 for USIM, - * 3GPP TS 51.011 sec. 10.3.41 and sec. 10.3.42 for SIM. - * - * @param mcc The mobile country code of the network. - * @param mnc The mobile network code of the network. - * @param lac The location area code of the network. - */ - getNetworkNameFromICC: function(mcc, mnc, lac) { - let RIL = this.context.RIL; - let iccInfoPriv = RIL.iccInfoPrivate; - let iccInfo = RIL.iccInfo; - let pnnEntry; - - if (!mcc || !mnc || lac == null || lac < 0) { - return null; - } - - // We won't get network name if there is no PNN file. - if (!iccInfoPriv.PNN) { - return null; - } - - if (!this.isICCServiceAvailable("OPL")) { - // When OPL is not present: - // According to 3GPP TS 31.102 Sec. 4.2.58 and 3GPP TS 51.011 Sec. 10.3.41, - // If EF_OPL is not present, the first record in this EF is used for the - // default network name when registered to the HPLMN. - // If we haven't get pnnEntry assigned, we should try to assign default - // value to it. - if (mcc == iccInfo.mcc && mnc == iccInfo.mnc) { - pnnEntry = iccInfoPriv.PNN[0]; - } - } else { - let GsmPDUHelper = this.context.GsmPDUHelper; - let wildChar = GsmPDUHelper.extendedBcdChars.charAt(0x0d); - // According to 3GPP TS 31.102 Sec. 4.2.59 and 3GPP TS 51.011 Sec. 10.3.42, - // the ME shall use this EF_OPL in association with the EF_PNN in place - // of any network name stored within the ME's internal list and any network - // name received when registered to the PLMN. - let length = iccInfoPriv.OPL ? iccInfoPriv.OPL.length : 0; - for (let i = 0; i < length; i++) { - let unmatch = false; - let opl = iccInfoPriv.OPL[i]; - // Try to match the MCC/MNC. Besides, A BCD value of 'D' in any of the - // MCC and/or MNC digits shall be used to indicate a "wild" value for - // that corresponding MCC/MNC digit. - if (opl.mcc.indexOf(wildChar) !== -1) { - for (let j = 0; j < opl.mcc.length; j++) { - if (opl.mcc[j] !== wildChar && opl.mcc[j] !== mcc[j]) { - unmatch = true; - break; - } - } - if (unmatch) { - continue; - } - } else { - if (mcc !== opl.mcc) { - continue; - } - } - - if (mnc.length !== opl.mnc.length) { - continue; - } - - if (opl.mnc.indexOf(wildChar) !== -1) { - for (let j = 0; j < opl.mnc.length; j++) { - if (opl.mnc[j] !== wildChar && opl.mnc[j] !== mnc[j]) { - unmatch = true; - break; - } - } - if (unmatch) { - continue; - } - } else { - if (mnc !== opl.mnc) { - continue; - } - } - - // Try to match the location area code. If current local area code is - // covered by lac range that specified in the OPL entry, use the PNN - // that specified in the OPL entry. - if ((opl.lacTacStart === 0x0 && opl.lacTacEnd == 0xFFFE) || - (opl.lacTacStart <= lac && opl.lacTacEnd >= lac)) { - if (opl.pnnRecordId === 0) { - // See 3GPP TS 31.102 Sec. 4.2.59 and 3GPP TS 51.011 Sec. 10.3.42, - // A value of '00' indicates that the name is to be taken from other - // sources. - return null; - } - pnnEntry = iccInfoPriv.PNN[opl.pnnRecordId - 1]; - break; - } - } - } - - if (!pnnEntry) { - return null; - } - - // Return a new object to avoid global variable, PNN, be modified by accident. - return { fullName: pnnEntry.fullName || "", - shortName: pnnEntry.shortName || "" }; - }, - - /** - * This will compute the spnDisplay field of the network. - * See TS 22.101 Annex A and TS 51.011 10.3.11 for details. - * - * @return True if some of iccInfo is changed in by this function. - */ - updateDisplayCondition: function() { - let RIL = this.context.RIL; - - // If EFspn isn't existed in SIM or it haven't been read yet, we should - // just set isDisplayNetworkNameRequired = true and - // isDisplaySpnRequired = false - let iccInfo = RIL.iccInfo; - let iccInfoPriv = RIL.iccInfoPrivate; - let displayCondition = iccInfoPriv.spnDisplayCondition; - let origIsDisplayNetworkNameRequired = iccInfo.isDisplayNetworkNameRequired; - let origIsDisplaySPNRequired = iccInfo.isDisplaySpnRequired; - - if (displayCondition === undefined) { - iccInfo.isDisplayNetworkNameRequired = true; - iccInfo.isDisplaySpnRequired = false; - } else if (RIL._isCdma) { - // CDMA family display rule. - let cdmaHome = RIL.cdmaHome; - let cell = RIL.voiceRegistrationState.cell; - let sid = cell && cell.cdmaSystemId; - let nid = cell && cell.cdmaNetworkId; - - iccInfo.isDisplayNetworkNameRequired = false; - - // If display condition is 0x0, we don't even need to check network id - // or system id. - if (displayCondition === 0x0) { - iccInfo.isDisplaySpnRequired = false; - } else { - // CDMA SPN Display condition dosen't specify whenever network name is - // reqired. - if (!cdmaHome || - !cdmaHome.systemId || - cdmaHome.systemId.length === 0 || - cdmaHome.systemId.length != cdmaHome.networkId.length || - !sid || !nid) { - // CDMA Home haven't been ready, or we haven't got the system id and - // network id of the network we register to, assuming we are in home - // network. - iccInfo.isDisplaySpnRequired = true; - } else { - // Determine if we are registered in the home service area. - // System ID and Network ID are described in 3GPP2 C.S0005 Sec. 2.6.5.2. - let inHomeArea = false; - for (let i = 0; i < cdmaHome.systemId.length; i++) { - let homeSid = cdmaHome.systemId[i], - homeNid = cdmaHome.networkId[i]; - if (homeSid === 0 || homeNid === 0 // Reserved system id/network id - || homeSid != sid) { - continue; - } - // According to 3GPP2 C.S0005 Sec. 2.6.5.2, NID number 65535 means - // all networks in the system should be considered as home. - if (homeNid == 65535 || homeNid == nid) { - inHomeArea = true; - break; - } - } - iccInfo.isDisplaySpnRequired = inHomeArea; - } - } - } else { - // GSM family display rule. - let operatorMnc = RIL.operator ? RIL.operator.mnc : -1; - let operatorMcc = RIL.operator ? RIL.operator.mcc : -1; - - // First detect if we are on HPLMN or one of the PLMN - // specified by the SIM card. - let isOnMatchingPlmn = false; - - // If the current network is the one defined as mcc/mnc - // in SIM card, it's okay. - if (iccInfo.mcc == operatorMcc && iccInfo.mnc == operatorMnc) { - isOnMatchingPlmn = true; - } - - // Test to see if operator's mcc/mnc match mcc/mnc of PLMN. - if (!isOnMatchingPlmn && iccInfoPriv.SPDI) { - let iccSpdi = iccInfoPriv.SPDI; // PLMN list - for (let plmn in iccSpdi) { - let plmnMcc = iccSpdi[plmn].mcc; - let plmnMnc = iccSpdi[plmn].mnc; - isOnMatchingPlmn = (plmnMcc == operatorMcc) && (plmnMnc == operatorMnc); - if (isOnMatchingPlmn) { - break; - } - } - } - - // See 3GPP TS 22.101 A.4 Service Provider Name indication, and TS 31.102 - // clause 4.2.12 EF_SPN for detail. - if (isOnMatchingPlmn) { - // The first bit of display condition tells us if we should display - // registered PLMN. - if (DEBUG) { - this.context.debug("PLMN is HPLMN or PLMN " + "is in PLMN list"); - } - - // TS 31.102 Sec. 4.2.66 and TS 51.011 Sec. 10.3.50 - // EF_SPDI contains a list of PLMNs in which the Service Provider Name - // shall be displayed. - iccInfo.isDisplaySpnRequired = true; - iccInfo.isDisplayNetworkNameRequired = (displayCondition & 0x01) !== 0; - } else { - // The second bit of display condition tells us if we should display - // registered PLMN. - if (DEBUG) { - this.context.debug("PLMN isn't HPLMN and PLMN isn't in PLMN list"); - } - - iccInfo.isDisplayNetworkNameRequired = true; - iccInfo.isDisplaySpnRequired = (displayCondition & 0x02) === 0; - } - } - - if (DEBUG) { - this.context.debug("isDisplayNetworkNameRequired = " + - iccInfo.isDisplayNetworkNameRequired); - this.context.debug("isDisplaySpnRequired = " + iccInfo.isDisplaySpnRequired); - } - - return ((origIsDisplayNetworkNameRequired !== iccInfo.isDisplayNetworkNameRequired) || - (origIsDisplaySPNRequired !== iccInfo.isDisplaySpnRequired)); - }, - - decodeSimTlvs: function(tlvsLen) { - let GsmPDUHelper = this.context.GsmPDUHelper; - - let index = 0; - let tlvs = []; - while (index < tlvsLen) { - let simTlv = { - tag : GsmPDUHelper.readHexOctet(), - length : GsmPDUHelper.readHexOctet(), - }; - simTlv.value = GsmPDUHelper.readHexOctetArray(simTlv.length); - tlvs.push(simTlv); - index += simTlv.length + 2; // The length of 'tag' and 'length' field. - } - return tlvs; - }, - - /** - * Parse those TLVs and convert it to an object. - */ - parsePbrTlvs: function(pbrTlvs) { - let pbr = {}; - for (let i = 0; i < pbrTlvs.length; i++) { - let pbrTlv = pbrTlvs[i]; - let anrIndex = 0; - for (let j = 0; j < pbrTlv.value.length; j++) { - let tlv = pbrTlv.value[j]; - let tagName = USIM_TAG_NAME[tlv.tag]; - - // ANR could have multiple files. We save it as anr0, anr1,...etc. - if (tlv.tag == ICC_USIM_EFANR_TAG) { - tagName += anrIndex; - anrIndex++; - } - pbr[tagName] = tlv; - pbr[tagName].fileType = pbrTlv.tag; - pbr[tagName].fileId = (tlv.value[0] << 8) | tlv.value[1]; - pbr[tagName].sfi = tlv.value[2]; - - // For Type 2, the order of files is in the same order in IAP. - if (pbrTlv.tag == ICC_USIM_TYPE2_TAG) { - pbr[tagName].indexInIAP = j; - } - } - } - - return pbr; - }, - - /** - * Update the ICC information to RadioInterfaceLayer. - */ - handleICCInfoChange: function() { - let RIL = this.context.RIL; - RIL.iccInfo.rilMessageType = "iccinfochange"; - RIL.sendChromeMessage(RIL.iccInfo); - }, - - /** - * Get whether specificed (U)SIM service is available. - * - * @param geckoService - * Service name like "ADN", "BDN", etc. - * - * @return true if the service is enabled, false otherwise. - */ - isICCServiceAvailable: function(geckoService) { - let RIL = this.context.RIL; - let serviceTable = RIL._isCdma ? RIL.iccInfoPrivate.cst: - RIL.iccInfoPrivate.sst; - let index, bitmask; - if (RIL.appType == CARD_APPTYPE_SIM || RIL.appType == CARD_APPTYPE_RUIM) { - /** - * Service id is valid in 1..N, and 2 bits are used to code each service. - * - * +----+-- --+----+----+ - * | b8 | ... | b2 | b1 | - * +----+-- --+----+----+ - * - * b1 = 0, service not allocated. - * 1, service allocated. - * b2 = 0, service not activated. - * 1, service activated. - * - * @see 3GPP TS 51.011 10.3.7. - */ - let simService; - if (RIL.appType == CARD_APPTYPE_SIM) { - simService = GECKO_ICC_SERVICES.sim[geckoService]; - } else { - simService = GECKO_ICC_SERVICES.ruim[geckoService]; - } - if (!simService) { - return false; - } - simService -= 1; - index = Math.floor(simService / 4); - bitmask = 2 << ((simService % 4) << 1); - } else if (RIL.appType == CARD_APPTYPE_USIM) { - /** - * Service id is valid in 1..N, and 1 bit is used to code each service. - * - * +----+-- --+----+----+ - * | b8 | ... | b2 | b1 | - * +----+-- --+----+----+ - * - * b1 = 0, service not avaiable. - * 1, service available. - * - * @see 3GPP TS 31.102 4.2.8. - */ - let usimService = GECKO_ICC_SERVICES.usim[geckoService]; - if (!usimService) { - return false; - } - usimService -= 1; - index = Math.floor(usimService / 8); - bitmask = 1 << ((usimService % 8) << 0); - } - - return (serviceTable !== null) && - (index < serviceTable.length) && - ((serviceTable[index] & bitmask) !== 0); - }, - - /** - * Get whether specificed CPHS service is available. - * - * @param geckoService - * Service name like "MDN", etc. - * - * @return true if the service is enabled, false otherwise. - */ - isCphsServiceAvailable: function(geckoService) { - let RIL = this.context.RIL; - let serviceTable = RIL.iccInfoPrivate.cphsSt; - - if (!(serviceTable instanceof Uint8Array)) { - return false; - } - - /** - * Service id is valid in 1..N, and 2 bits are used to code each service. - * - * +----+-- --+----+----+ - * | b8 | ... | b2 | b1 | - * +----+-- --+----+----+ - * - * b1 = 0, service not allocated. - * 1, service allocated. - * b2 = 0, service not activated. - * 1, service activated. - * - * @See B.3.1.1 CPHS Information in CPHS Phase 2. - */ - let cphsService = GECKO_ICC_SERVICES.cphs[geckoService]; - - if (!cphsService) { - return false; - } - cphsService -= 1; - let index = Math.floor(cphsService / 4); - let bitmask = 2 << ((cphsService % 4) << 1); - - return (index < serviceTable.length) && - ((serviceTable[index] & bitmask) !== 0); - }, - - /** - * Check if the string is of GSM default 7-bit coded alphabets with bit 8 - * set to 0. - * - * @param str String to be checked. - */ - isGsm8BitAlphabet: function(str) { - if (!str) { - return false; - } - - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - - for (let i = 0; i < str.length; i++) { - let c = str.charAt(i); - let octet = langTable.indexOf(c); - if (octet == -1) { - octet = langShiftTable.indexOf(c); - if (octet == -1) { - return false; - } - } - } - - return true; - }, - - /** - * Parse MCC/MNC from IMSI. If there is no available value for the length of - * mnc, it will use the data in MCC table to parse. - * - * @param imsi - * The imsi of icc. - * @param mncLength [optional] - * The length of mnc. - * Zero indicates we haven't got a valid mnc length. - * - * @return An object contains the parsing result of mcc and mnc. - * Or null if any error occurred. - */ - parseMccMncFromImsi: function(imsi, mncLength) { - if (!imsi) { - return null; - } - - // MCC is the first 3 digits of IMSI. - let mcc = imsi.substr(0,3); - if (!mncLength) { - // Check the MCC/MNC table for MNC length = 3 first for the case we don't - // have the 4th byte data from EF_AD. - if (PLMN_HAVING_3DIGITS_MNC[mcc] && - PLMN_HAVING_3DIGITS_MNC[mcc].indexOf(imsi.substr(3, 3)) !== -1) { - mncLength = 3; - } else { - // Check the MCC table to decide the length of MNC. - let index = MCC_TABLE_FOR_MNC_LENGTH_IS_3.indexOf(mcc); - mncLength = (index !== -1) ? 3 : 2; - } - } - let mnc = imsi.substr(3, mncLength); - if (DEBUG) { - this.context.debug("IMSI: " + imsi + " MCC: " + mcc + " MNC: " + mnc); - } - - return { mcc: mcc, mnc: mnc}; - }, -}; - -/** - * Helper for ICC Contacts. - */ -function ICCContactHelperObject(aContext) { - this.context = aContext; -} -ICCContactHelperObject.prototype = { - context: null, - - /** - * Helper function to check DF_PHONEBOOK. - */ - hasDfPhoneBook: function(appType) { - switch (appType) { - case CARD_APPTYPE_SIM: - return false; - case CARD_APPTYPE_USIM: - return true; - case CARD_APPTYPE_RUIM: - let ICCUtilsHelper = this.context.ICCUtilsHelper; - return ICCUtilsHelper.isICCServiceAvailable("ENHANCED_PHONEBOOK"); - default: - return false; - } - }, - - /** - * Helper function to read ICC contacts. - * - * @param appType One of CARD_APPTYPE_*. - * @param contactType One of GECKO_CARDCONTACT_TYPE_*. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readICCContacts: function(appType, contactType, onsuccess, onerror) { - let ICCRecordHelper = this.context.ICCRecordHelper; - let ICCUtilsHelper = this.context.ICCUtilsHelper; - - switch (contactType) { - case GECKO_CARDCONTACT_TYPE_ADN: - if (!this.hasDfPhoneBook(appType)) { - ICCRecordHelper.readADNLike(ICC_EF_ADN, - (ICCUtilsHelper.isICCServiceAvailable("EXT1")) ? ICC_EF_EXT1 : null, - onsuccess, onerror); - } else { - this.readUSimContacts(onsuccess, onerror); - } - break; - case GECKO_CARDCONTACT_TYPE_FDN: - if (!ICCUtilsHelper.isICCServiceAvailable("FDN")) { - onerror(CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED); - break; - } - ICCRecordHelper.readADNLike(ICC_EF_FDN, - (ICCUtilsHelper.isICCServiceAvailable("EXT2")) ? ICC_EF_EXT2 : null, - onsuccess, onerror); - break; - case GECKO_CARDCONTACT_TYPE_SDN: - if (!ICCUtilsHelper.isICCServiceAvailable("SDN")) { - onerror(CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED); - break; - } - - ICCRecordHelper.readADNLike(ICC_EF_SDN, - (ICCUtilsHelper.isICCServiceAvailable("EXT3")) ? ICC_EF_EXT3 : null, - onsuccess, onerror); - break; - default: - if (DEBUG) { - this.context.debug("Unsupported contactType :" + contactType); - } - onerror(CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED); - break; - } - }, - - /** - * Helper function to find free contact record. - * - * @param appType One of CARD_APPTYPE_*. - * @param contactType One of GECKO_CARDCONTACT_TYPE_*. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - findFreeICCContact: function(appType, contactType, onsuccess, onerror) { - let ICCRecordHelper = this.context.ICCRecordHelper; - - switch (contactType) { - case GECKO_CARDCONTACT_TYPE_ADN: - if (!this.hasDfPhoneBook(appType)) { - ICCRecordHelper.findFreeRecordId(ICC_EF_ADN, onsuccess.bind(null, 0), onerror); - } else { - let gotPbrCb = function gotPbrCb(pbrs) { - this.findUSimFreeADNRecordId(pbrs, onsuccess, onerror); - }.bind(this); - - ICCRecordHelper.readPBR(gotPbrCb, onerror); - } - break; - case GECKO_CARDCONTACT_TYPE_FDN: - ICCRecordHelper.findFreeRecordId(ICC_EF_FDN, onsuccess.bind(null, 0), onerror); - break; - default: - if (DEBUG) { - this.context.debug("Unsupported contactType :" + contactType); - } - onerror(CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED); - break; - } - }, - - /** - * Cache the pbr index of the possible free record. - */ - _freePbrIndex: 0, - - /** - * Find free ADN record id in USIM. - * - * @param pbrs All Phonebook Reference Files read. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - findUSimFreeADNRecordId: function(pbrs, onsuccess, onerror) { - let ICCRecordHelper = this.context.ICCRecordHelper; - - function callback(pbrIndex, recordId) { - // Assume other free records are probably in the same phonebook set. - this._freePbrIndex = pbrIndex; - onsuccess(pbrIndex, recordId); - } - - let nextPbrIndex = -1; - (function findFreeRecordId(pbrIndex) { - if (nextPbrIndex === this._freePbrIndex) { - // No free record found, reset the pbr index of free record. - this._freePbrIndex = 0; - if (DEBUG) { - this.context.debug(CONTACT_ERR_NO_FREE_RECORD_FOUND); - } - onerror(CONTACT_ERR_NO_FREE_RECORD_FOUND); - return; - } - - let pbr = pbrs[pbrIndex]; - nextPbrIndex = (pbrIndex + 1) % pbrs.length; - ICCRecordHelper.findFreeRecordId( - pbr.adn.fileId, - callback.bind(this, pbrIndex), - findFreeRecordId.bind(this, nextPbrIndex)); - }).call(this, this._freePbrIndex); - }, - - /** - * Helper function to add a new ICC contact. - * - * @param appType One of CARD_APPTYPE_*. - * @param contactType One of GECKO_CARDCONTACT_TYPE_*. - * @param contact The contact will be added. - * @param pin2 PIN2 is required for FDN. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - addICCContact: function(appType, contactType, contact, pin2, onsuccess, onerror) { - let foundFreeCb = (function foundFreeCb(pbrIndex, recordId) { - contact.pbrIndex = pbrIndex; - contact.recordId = recordId; - this.updateICCContact(appType, contactType, contact, pin2, onsuccess, onerror); - }).bind(this); - - // Find free record first. - this.findFreeICCContact(appType, contactType, foundFreeCb, onerror); - }, - - /** - * Helper function to update ICC contact. - * - * @param appType One of CARD_APPTYPE_*. - * @param contactType One of GECKO_CARDCONTACT_TYPE_*. - * @param contact The contact will be updated. - * @param pin2 PIN2 is required for FDN. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updateICCContact: function(appType, contactType, contact, pin2, onsuccess, onerror) { - let ICCRecordHelper = this.context.ICCRecordHelper; - let ICCUtilsHelper = this.context.ICCUtilsHelper; - - let updateContactCb = (updatedContact) => { - updatedContact.pbrIndex = contact.pbrIndex; - updatedContact.recordId = contact.recordId; - onsuccess(updatedContact); - } - - switch (contactType) { - case GECKO_CARDCONTACT_TYPE_ADN: - if (!this.hasDfPhoneBook(appType)) { - if (ICCUtilsHelper.isICCServiceAvailable("EXT1")) { - this.updateADNLikeWithExtension(ICC_EF_ADN, ICC_EF_EXT1, - contact, null, - updateContactCb, onerror); - } else { - ICCRecordHelper.updateADNLike(ICC_EF_ADN, 0xff, - contact, null, - updateContactCb, onerror); - } - } else { - this.updateUSimContact(contact, updateContactCb, onerror); - } - break; - case GECKO_CARDCONTACT_TYPE_FDN: - if (!pin2) { - onerror(GECKO_ERROR_SIM_PIN2); - return; - } - if (!ICCUtilsHelper.isICCServiceAvailable("FDN")) { - onerror(CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED); - break; - } - if (ICCUtilsHelper.isICCServiceAvailable("EXT2")) { - this.updateADNLikeWithExtension(ICC_EF_FDN, ICC_EF_EXT2, - contact, pin2, - updateContactCb, onerror); - } else { - ICCRecordHelper.updateADNLike(ICC_EF_FDN, - 0xff, - contact, pin2, - updateContactCb, onerror); - } - break; - default: - if (DEBUG) { - this.context.debug("Unsupported contactType :" + contactType); - } - onerror(CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED); - break; - } - }, - - /** - * Read contacts from USIM. - * - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readUSimContacts: function(onsuccess, onerror) { - let gotPbrCb = function gotPbrCb(pbrs) { - this.readAllPhonebookSets(pbrs, onsuccess, onerror); - }.bind(this); - - this.context.ICCRecordHelper.readPBR(gotPbrCb, onerror); - }, - - /** - * Read all Phonebook sets. - * - * @param pbrs All Phonebook Reference Files read. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readAllPhonebookSets: function(pbrs, onsuccess, onerror) { - let allContacts = [], pbrIndex = 0; - let readPhonebook = function(contacts) { - if (contacts) { - allContacts = allContacts.concat(contacts); - } - - let cLen = contacts ? contacts.length : 0; - for (let i = 0; i < cLen; i++) { - contacts[i].pbrIndex = pbrIndex; - } - - pbrIndex++; - if (pbrIndex >= pbrs.length) { - if (onsuccess) { - onsuccess(allContacts); - } - return; - } - - this.readPhonebookSet(pbrs[pbrIndex], readPhonebook, onerror); - }.bind(this); - - this.readPhonebookSet(pbrs[pbrIndex], readPhonebook, onerror); - }, - - /** - * Read from Phonebook Reference File. - * - * @param pbr Phonebook Reference File to be read. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readPhonebookSet: function(pbr, onsuccess, onerror) { - let ICCRecordHelper = this.context.ICCRecordHelper; - let gotAdnCb = function gotAdnCb(contacts) { - this.readSupportedPBRFields(pbr, contacts, onsuccess, onerror); - }.bind(this); - - ICCRecordHelper.readADNLike(pbr.adn.fileId, - (pbr.ext1) ? pbr.ext1.fileId : null, gotAdnCb, onerror); - }, - - /** - * Read supported Phonebook fields. - * - * @param pbr Phone Book Reference file. - * @param contacts Contacts stored on ICC. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readSupportedPBRFields: function(pbr, contacts, onsuccess, onerror) { - let fieldIndex = 0; - (function readField() { - let field = USIM_PBR_FIELDS[fieldIndex]; - fieldIndex += 1; - if (!field) { - if (onsuccess) { - onsuccess(contacts); - } - return; - } - - this.readPhonebookField(pbr, contacts, field, readField.bind(this), onerror); - }).call(this); - }, - - /** - * Read Phonebook field. - * - * @param pbr The phonebook reference file. - * @param contacts Contacts stored on ICC. - * @param field Phonebook field to be retrieved. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readPhonebookField: function(pbr, contacts, field, onsuccess, onerror) { - if (!pbr[field]) { - if (onsuccess) { - onsuccess(contacts); - } - return; - } - - (function doReadContactField(n) { - if (n >= contacts.length) { - // All contact's fields are read. - if (onsuccess) { - onsuccess(contacts); - } - return; - } - - // get n-th contact's field. - this.readContactField(pbr, contacts[n], field, - doReadContactField.bind(this, n + 1), onerror); - }).call(this, 0); - }, - - /** - * Read contact's field from USIM. - * - * @param pbr The phonebook reference file. - * @param contact The contact needs to get field. - * @param field Phonebook field to be retrieved. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readContactField: function(pbr, contact, field, onsuccess, onerror) { - let gotRecordIdCb = function gotRecordIdCb(recordId) { - if (recordId == 0xff) { - if (onsuccess) { - onsuccess(); - } - return; - } - - let fileId = pbr[field].fileId; - let fileType = pbr[field].fileType; - let gotFieldCb = function gotFieldCb(value) { - if (value) { - // Move anr0 anr1,.. into anr[]. - if (field.startsWith(USIM_PBR_ANR)) { - if (!contact[USIM_PBR_ANR]) { - contact[USIM_PBR_ANR] = []; - } - contact[USIM_PBR_ANR].push(value); - } else { - contact[field] = value; - } - } - - if (onsuccess) { - onsuccess(); - } - }.bind(this); - - let ICCRecordHelper = this.context.ICCRecordHelper; - // Detect EF to be read, for anr, it could have anr0, anr1,... - let ef = field.startsWith(USIM_PBR_ANR) ? USIM_PBR_ANR : field; - switch (ef) { - case USIM_PBR_EMAIL: - ICCRecordHelper.readEmail(fileId, fileType, recordId, gotFieldCb, onerror); - break; - case USIM_PBR_ANR: - ICCRecordHelper.readANR(fileId, fileType, recordId, gotFieldCb, onerror); - break; - default: - if (DEBUG) { - this.context.debug("Unsupported field :" + field); - } - onerror(CONTACT_ERR_FIELD_NOT_SUPPORTED); - break; - } - }.bind(this); - - this.getContactFieldRecordId(pbr, contact, field, gotRecordIdCb, onerror); - }, - - /** - * Get the recordId. - * - * If the fileType of field is ICC_USIM_TYPE1_TAG, use corresponding ADN recordId. - * otherwise get the recordId from IAP. - * - * @see TS 131.102, clause 4.4.2.2 - * - * @param pbr The phonebook reference file. - * @param contact The contact will be updated. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - getContactFieldRecordId: function(pbr, contact, field, onsuccess, onerror) { - if (pbr[field].fileType == ICC_USIM_TYPE1_TAG) { - // If the file type is ICC_USIM_TYPE1_TAG, use corresponding ADN recordId. - if (onsuccess) { - onsuccess(contact.recordId); - } - } else if (pbr[field].fileType == ICC_USIM_TYPE2_TAG) { - // If the file type is ICC_USIM_TYPE2_TAG, the recordId shall be got from IAP. - let gotIapCb = function gotIapCb(iap) { - let indexInIAP = pbr[field].indexInIAP; - let recordId = iap[indexInIAP]; - - if (onsuccess) { - onsuccess(recordId); - } - }.bind(this); - - this.context.ICCRecordHelper.readIAP(pbr.iap.fileId, contact.recordId, - gotIapCb, onerror); - } else { - if (DEBUG) { - this.context.debug("USIM PBR files in Type 3 format are not supported."); - } - onerror(CONTACT_ERR_REQUEST_NOT_SUPPORTED); - } - }, - - /** - * Update USIM contact. - * - * @param contact The contact will be updated. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updateUSimContact: function(contact, onsuccess, onerror) { - let gotPbrCb = function gotPbrCb(pbrs) { - let pbr = pbrs[contact.pbrIndex]; - if (!pbr) { - if (DEBUG) { - this.context.debug(CONTACT_ERR_CANNOT_ACCESS_PHONEBOOK); - } - onerror(CONTACT_ERR_CANNOT_ACCESS_PHONEBOOK); - return; - } - this.updatePhonebookSet(pbr, contact, onsuccess, onerror); - }.bind(this); - - this.context.ICCRecordHelper.readPBR(gotPbrCb, onerror); - }, - - /** - * Update fields in Phonebook Reference File. - * - * @param pbr Phonebook Reference File to be read. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updatePhonebookSet: function(pbr, contact, onsuccess, onerror) { - let updateAdnCb = function(updatedContact) { - this.updateSupportedPBRFields(pbr, contact, (updatedContactField) => { - onsuccess(Object.assign(updatedContact, updatedContactField)); - }, onerror); - }.bind(this); - - if (pbr.ext1) { - this.updateADNLikeWithExtension(pbr.adn.fileId, pbr.ext1.fileId, - contact, null, updateAdnCb, onerror); - } else { - this.context.ICCRecordHelper.updateADNLike(pbr.adn.fileId, 0xff, contact, - null, updateAdnCb, onerror); - } - }, - - /** - * Update supported Phonebook fields. - * - * @param pbr Phone Book Reference file. - * @param contact Contact to be updated. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updateSupportedPBRFields: function(pbr, contact, onsuccess, onerror) { - let fieldIndex = 0; - let contactField = {}; - - (function updateField() { - let field = USIM_PBR_FIELDS[fieldIndex]; - fieldIndex += 1; - - if (!field) { - if (onsuccess) { - onsuccess(contactField); - } - return; - } - - // Check if PBR has this field. - if (!pbr[field]) { - updateField.call(this); - return; - } - - this.updateContactField(pbr, contact, field, (fieldEntry) => { - contactField = Object.assign(contactField, fieldEntry); - updateField.call(this); - }, (errorMsg) => { - // Bug 1194149, there are some sim cards without sufficient - // Type 2 USIM contact fields record. We allow user continue - // importing contacts. - if (errorMsg === CONTACT_ERR_NO_FREE_RECORD_FOUND) { - updateField.call(this); - return; - } - onerror(errorMsg); - }); - }).call(this); - }, - - /** - * Update contact's field from USIM. - * - * @param pbr The phonebook reference file. - * @param contact The contact needs to be updated. - * @param field Phonebook field to be updated. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updateContactField: function(pbr, contact, field, onsuccess, onerror) { - if (pbr[field].fileType === ICC_USIM_TYPE1_TAG) { - this.updateContactFieldType1(pbr, contact, field, onsuccess, onerror); - } else if (pbr[field].fileType === ICC_USIM_TYPE2_TAG) { - this.updateContactFieldType2(pbr, contact, field, onsuccess, onerror); - } else { - if (DEBUG) { - this.context.debug("USIM PBR files in Type 3 format are not supported."); - } - onerror(CONTACT_ERR_REQUEST_NOT_SUPPORTED); - } - }, - - /** - * Update Type 1 USIM contact fields. - * - * @param pbr The phonebook reference file. - * @param contact The contact needs to be updated. - * @param field Phonebook field to be updated. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updateContactFieldType1: function(pbr, contact, field, onsuccess, onerror) { - let ICCRecordHelper = this.context.ICCRecordHelper; - - if (field === USIM_PBR_EMAIL) { - ICCRecordHelper.updateEmail(pbr, contact.recordId, contact.email, null, - (updatedEmail) => { - onsuccess({email: updatedEmail}); - }, onerror); - } else if (field === USIM_PBR_ANR0) { - let anr = Array.isArray(contact.anr) ? contact.anr[0] : null; - ICCRecordHelper.updateANR(pbr, contact.recordId, anr, null, - (updatedANR) => { - // ANR could have multiple files. If we support more than one anr, - // we will save it as anr0, anr1,...etc. - onsuccess((updatedANR) ? {anr: [updatedANR]} : null); - }, onerror); - } else { - if (DEBUG) { - this.context.debug("Unsupported field :" + field); - } - onerror(CONTACT_ERR_FIELD_NOT_SUPPORTED); - } - }, - - /** - * Update Type 2 USIM contact fields. - * - * @param pbr The phonebook reference file. - * @param contact The contact needs to be updated. - * @param field Phonebook field to be updated. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updateContactFieldType2: function(pbr, contact, field, onsuccess, onerror) { - let ICCRecordHelper = this.context.ICCRecordHelper; - - // Case 1 : EF_IAP[adnRecordId] doesn't have a value(0xff) - // Find a free recordId for EF_field - // Update field with that free recordId. - // Update IAP. - // - // Case 2: EF_IAP[adnRecordId] has a value - // update EF_field[iap[field.indexInIAP]] - - let gotIapCb = function gotIapCb(iap) { - let recordId = iap[pbr[field].indexInIAP]; - if (recordId === 0xff) { - // If the value in IAP[index] is 0xff, which means the contact stored on - // the SIM doesn't have the additional attribute (email or anr). - // So if the contact to be updated doesn't have the attribute either, - // we don't have to update it. - if ((field === USIM_PBR_EMAIL && contact.email) || - (field === USIM_PBR_ANR0 && - (Array.isArray(contact.anr) && contact.anr[0]))) { - // Case 1. - this.addContactFieldType2(pbr, contact, field, onsuccess, onerror); - } else { - if (onsuccess) { - onsuccess(); - } - } - return; - } - - // Case 2. - if (field === USIM_PBR_EMAIL) { - ICCRecordHelper.updateEmail(pbr, recordId, contact.email, contact.recordId, - (updatedEmail) => { - onsuccess({email: updatedEmail}); - }, onerror); - } else if (field === USIM_PBR_ANR0) { - let anr = Array.isArray(contact.anr) ? contact.anr[0] : null; - ICCRecordHelper.updateANR(pbr, recordId, anr, contact.recordId, - (updatedANR) => { - // ANR could have multiple files. If we support more than one anr, - // we will save it as anr0, anr1,...etc. - onsuccess((updatedANR) ? {anr: [updatedANR]} : null); - }, onerror); - } else { - if (DEBUG) { - this.context.debug("Unsupported field :" + field); - } - onerror(CONTACT_ERR_FIELD_NOT_SUPPORTED); - } - - }.bind(this); - - ICCRecordHelper.readIAP(pbr.iap.fileId, contact.recordId, gotIapCb, onerror); - }, - - /** - * Add Type 2 USIM contact fields. - * - * @param pbr The phonebook reference file. - * @param contact The contact needs to be updated. - * @param field Phonebook field to be updated. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - addContactFieldType2: function(pbr, contact, field, onsuccess, onerror) { - let ICCRecordHelper = this.context.ICCRecordHelper; - let successCb = function successCb(recordId) { - - let updateCb = function updateCb(contactField) { - this.updateContactFieldIndexInIAP(pbr, contact.recordId, field, recordId, () => { - onsuccess(contactField); - }, onerror); - }.bind(this); - - if (field === USIM_PBR_EMAIL) { - ICCRecordHelper.updateEmail(pbr, recordId, contact.email, contact.recordId, - (updatedEmail) => { - updateCb({email: updatedEmail}); - }, onerror); - } else if (field === USIM_PBR_ANR0) { - ICCRecordHelper.updateANR(pbr, recordId, contact.anr[0], contact.recordId, - (updatedANR) => { - // ANR could have multiple files. If we support more than one anr, - // we will save it as anr0, anr1,...etc. - updateCb((updatedANR) ? {anr: [updatedANR]} : null); - }, onerror); - } - }.bind(this); - - let errorCb = function errorCb(errorMsg) { - if (DEBUG) { - this.context.debug(errorMsg + " USIM field " + field); - } - onerror(errorMsg); - }.bind(this); - - ICCRecordHelper.findFreeRecordId(pbr[field].fileId, successCb, errorCb); - }, - - /** - * Update IAP value. - * - * @param pbr The phonebook reference file. - * @param recordNumber The record identifier of EF_IAP. - * @param field Phonebook field. - * @param value The value of 'field' in IAP. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - * - */ - updateContactFieldIndexInIAP: function(pbr, recordNumber, field, value, onsuccess, onerror) { - let ICCRecordHelper = this.context.ICCRecordHelper; - - let gotIAPCb = function gotIAPCb(iap) { - iap[pbr[field].indexInIAP] = value; - ICCRecordHelper.updateIAP(pbr.iap.fileId, recordNumber, iap, onsuccess, onerror); - }.bind(this); - ICCRecordHelper.readIAP(pbr.iap.fileId, recordNumber, gotIAPCb, onerror); - }, - - /** - * Update ICC ADN like EFs with Extension, like EF_ADN, EF_FDN. - * - * @param fileId EF id of the ADN or FDN. - * @param extFileId EF id of the EXT. - * @param contact The contact will be updated. (Shall have recordId property) - * @param pin2 PIN2 is required when updating ICC_EF_FDN. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updateADNLikeWithExtension: function(fileId, extFileId, contact, pin2, onsuccess, onerror) { - let ICCRecordHelper = this.context.ICCRecordHelper; - let extNumber; - - if (contact.number) { - let numStart = contact.number[0] == "+" ? 1 : 0; - let number = contact.number.substring(0, numStart) + - this.context.GsmPDUHelper.stringToExtendedBcd( - contact.number.substring(numStart)); - extNumber = number.substr(numStart + ADN_MAX_NUMBER_DIGITS, - EXT_MAX_NUMBER_DIGITS); - } - - ICCRecordHelper.getADNLikeExtensionRecordNumber(fileId, contact.recordId, - (extRecordNumber) => { - let updateADNLike = (extRecordNumber) => { - ICCRecordHelper.updateADNLike(fileId, extRecordNumber, contact, - pin2, (updatedContact) => { - if (extNumber && extRecordNumber != 0xff) { - updatedContact.number = updatedContact.number.concat(extNumber); - } - onsuccess(updatedContact); - }, onerror); - }; - - let updateExtension = (extRecordNumber) => { - ICCRecordHelper.updateExtension(extFileId, extRecordNumber, extNumber, - () => updateADNLike(extRecordNumber), - () => updateADNLike(0xff)); - }; - - if (extNumber) { - if (extRecordNumber != 0xff) { - updateExtension(extRecordNumber); - return; - } - - ICCRecordHelper.findFreeRecordId(extFileId, - (extRecordNumber) => updateExtension(extRecordNumber), - (errorMsg) => { - if (DEBUG) { - this.context.debug("Couldn't find free extension record Id for " + extFileId + ": " + errorMsg); - } - updateADNLike(0xff); - }); - return; - } - - if (extRecordNumber != 0xff) { - ICCRecordHelper.cleanEFRecord(extFileId, extRecordNumber, - () => updateADNLike(0xff), onerror); - return; - } - - updateADNLike(0xff); - }, onerror); - }, -}; - -function IconLoaderObject(aContext) { - this.context = aContext; -} -IconLoaderObject.prototype = { - context: null, - - /** - * Load icons. - * - * @param recordNumbers Array of the record identifiers of EF_IMG. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - loadIcons: function(recordNumbers, onsuccess, onerror) { - if (!recordNumbers || !recordNumbers.length) { - if (onerror) { - onerror(); - } - return; - } - - this._start({ - recordNumbers: recordNumbers, - onsuccess: onsuccess, - onerror: onerror}); - }, - - _start: function(options) { - let callback = (function(icons) { - if (!options.icons) { - options.icons = []; - } - for (let i = 0; i < icons.length; i++) { - icons[i] = this._parseRawData(icons[i]); - } - options.icons[options.currentRecordIndex] = icons; - options.currentRecordIndex++; - - let recordNumbers = options.recordNumbers; - if (options.currentRecordIndex < recordNumbers.length) { - let recordNumber = recordNumbers[options.currentRecordIndex]; - this.context.SimRecordHelper.readIMG(recordNumber, - callback, - options.onerror); - } else { - if (options.onsuccess) { - options.onsuccess(options.icons); - } - } - }).bind(this); - - options.currentRecordIndex = 0; - this.context.SimRecordHelper.readIMG(options.recordNumbers[0], - callback, - options.onerror); - }, - - _parseRawData: function(rawData) { - let codingScheme = rawData.codingScheme; - - switch (codingScheme) { - case ICC_IMG_CODING_SCHEME_BASIC: - return this._decodeBasicImage(rawData.width, rawData.height, rawData.body); - - case ICC_IMG_CODING_SCHEME_COLOR: - case ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY: - return this._decodeColorImage(codingScheme, - rawData.width, rawData.height, - rawData.bitsPerImgPoint, - rawData.numOfClutEntries, - rawData.clut, rawData.body); - } - - return null; - }, - - _decodeBasicImage: function(width, height, body) { - let numOfPixels = width * height; - let pixelIndex = 0; - let currentByteIndex = 0; - let currentByte = 0x00; - - const BLACK = 0x000000FF; - const WHITE = 0xFFFFFFFF; - - let pixels = []; - while (pixelIndex < numOfPixels) { - // Reassign data and index for every byte (8 bits). - if (pixelIndex % 8 == 0) { - currentByte = body[currentByteIndex++]; - } - let bit = (currentByte >> (7 - (pixelIndex % 8))) & 0x01; - pixels[pixelIndex++] = bit ? WHITE : BLACK; - } - - return {pixels: pixels, - codingScheme: GECKO_IMG_CODING_SCHEME_BASIC, - width: width, - height: height}; - }, - - _decodeColorImage: function(codingScheme, width, height, bitsPerImgPoint, - numOfClutEntries, clut, body) { - let mask = 0xff >> (8 - bitsPerImgPoint); - let bitsStartOffset = 8 - bitsPerImgPoint; - let bitIndex = bitsStartOffset; - let numOfPixels = width * height; - let pixelIndex = 0; - let currentByteIndex = 0; - let currentByte = body[currentByteIndex++]; - - let pixels = []; - while (pixelIndex < numOfPixels) { - // Reassign data and index for every byte (8 bits). - if (bitIndex < 0) { - currentByte = body[currentByteIndex++]; - bitIndex = bitsStartOffset; - } - let clutEntry = ((currentByte >> bitIndex) & mask); - let clutIndex = clutEntry * ICC_CLUT_ENTRY_SIZE; - let alpha = codingScheme == ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY && - clutEntry == numOfClutEntries - 1; - pixels[pixelIndex++] = alpha ? 0x00 - : (clut[clutIndex] << 24 | - clut[clutIndex + 1] << 16 | - clut[clutIndex + 2] << 8 | - 0xFF) >>> 0; - bitIndex -= bitsPerImgPoint; - } - - return {pixels: pixels, - codingScheme: ICC_IMG_CODING_SCHEME_TO_GECKO[codingScheme], - width: width, - height: height}; - }, -}; - -/** - * Global stuff. - */ - -function Context(aClientId) { - this.clientId = aClientId; - - this.Buf = new BufObject(this); - this.RIL = new RilObject(this); - this.RIL.initRILState(); -} -Context.prototype = { - clientId: null, - Buf: null, - RIL: null, - - debug: function(aMessage) { - GLOBAL.debug("[" + this.clientId + "] " + aMessage); - } -}; - -(function() { - let lazySymbols = [ - "BerTlvHelper", "BitBufferHelper", "CdmaPDUHelper", - "ComprehensionTlvHelper", "GsmPDUHelper", "ICCContactHelper", - "ICCFileHelper", "ICCIOHelper", "ICCPDUHelper", "ICCRecordHelper", - "ICCUtilsHelper", "RuimRecordHelper", "SimRecordHelper", - "StkCommandParamsFactory", "StkProactiveCmdHelper", "IconLoader", - ]; - - for (let i = 0; i < lazySymbols.length; i++) { - let symbol = lazySymbols[i]; - Object.defineProperty(Context.prototype, symbol, { - get: function() { - let real = new GLOBAL[symbol + "Object"](this); - Object.defineProperty(this, symbol, { - value: real, - enumerable: true - }); - return real; - }, - configurable: true, - enumerable: true - }); - } -})(); - -var ContextPool = { - _contexts: [], - - handleRilMessage: function(aClientId, aUint8Array) { - let context = this._contexts[aClientId]; - context.Buf.processIncoming(aUint8Array); - }, - - handleChromeMessage: function(aMessage) { - let clientId = aMessage.rilMessageClientId; - if (clientId != null) { - let context = this._contexts[clientId]; - context.RIL.handleChromeMessage(aMessage); - return; - } - - if (DEBUG) debug("Received global chrome message " + JSON.stringify(aMessage)); - let method = this[aMessage.rilMessageType]; - if (typeof method != "function") { - if (DEBUG) { - debug("Don't know what to do"); - } - return; - } - method.call(this, aMessage); - }, - - setInitialOptions: function(aOptions) { - DEBUG = DEBUG_WORKER || aOptions.debug; - - let quirks = aOptions.quirks; - RILQUIRKS_CALLSTATE_EXTRA_UINT32 = quirks.callstateExtraUint32; - RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL = quirks.requestUseDialEmergencyCall; - RILQUIRKS_SIM_APP_STATE_EXTRA_FIELDS = quirks.simAppStateExtraFields; - RILQUIRKS_EXTRA_UINT32_2ND_CALL = quirks.extraUint2ndCall; - RILQUIRKS_HAVE_QUERY_ICC_LOCK_RETRY_COUNT = quirks.haveQueryIccLockRetryCount; - RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD = quirks.sendStkProfileDownload; - RILQUIRKS_DATA_REGISTRATION_ON_DEMAND = quirks.dataRegistrationOnDemand; - RILQUIRKS_SUBSCRIPTION_CONTROL = quirks.subscriptionControl; - RILQUIRKS_SIGNAL_EXTRA_INT32 = quirks.signalExtraInt; - RILQUIRKS_AVAILABLE_NETWORKS_EXTRA_STRING = quirks.availableNetworkExtraStr; - RILQUIRKS_SMSC_ADDRESS_FORMAT = quirks.smscAddressFormat; - }, - - setDebugFlag: function(aOptions) { - DEBUG = DEBUG_WORKER || aOptions.debug; - }, - - registerClient: function(aOptions) { - let clientId = aOptions.clientId; - this._contexts[clientId] = new Context(clientId); - }, -}; - -function onRILMessage(aClientId, aUint8Array) { - ContextPool.handleRilMessage(aClientId, aUint8Array); -} - -onmessage = function onmessage(event) { - ContextPool.handleChromeMessage(event.data); -}; - -onerror = function onerror(event) { - if (DEBUG) debug("onerror" + event.message + "\n"); -}; diff --git a/dom/system/gonk/ril_worker_buf_object.js b/dom/system/gonk/ril_worker_buf_object.js deleted file mode 100644 index 70018c5b2..000000000 --- a/dom/system/gonk/ril_worker_buf_object.js +++ /dev/null @@ -1,168 +0,0 @@ -/* global require */ -/* global DEBUG, DEBUG_WORKER */ -/* global RESPONSE_TYPE_SOLICITED */ -/* global RESPONSE_TYPE_UNSOLICITED */ - -"use strict"; - -/** - * This is a specialized worker buffer for the Parcel protocol. - * - * NOTE: To prevent including/importing twice, this file should be included - * in a file which already includes 'ril_consts.js' and 'require.js'. - */ -(function(exports) { - - // Set to true in ril_consts.js to see debug messages - let DEBUG = DEBUG_WORKER; - // Need to inherit it. - let Buf = require("resource://gre/modules/workers/worker_buf.js").Buf; - - let BufObject = function(aContext) { - this.context = aContext; - // This gets incremented each time we send out a parcel. - this.mToken = 1; - // Maps tokens we send out with requests to the request type, so that - // when we get a response parcel back, we know what request it was for. - this.mTokenRequestMap = new Map(); - // This is because the underlying 'Buf' is still using the 'init' pattern, so - // this derived one needs to invoke it. - // Using 'apply' style to mark it's a parent method calling explicitly. - Buf._init.apply(this); - - // Remapping the request type to different values based on RIL version. - // We only have to do this for SUBSCRIPTION right now, so I just make it - // simple. A generic logic or structure could be discussed if we have more - // use cases, especially the cases from different partners. - this._requestMap = {}; - // RIL version 8. - // For the CAF's proprietary parcels. Please see - // https://www.codeaurora.org/cgit/quic/la/platform/hardware/ril/tree/include/telephony/ril.h?h=b2g_jb_3.2 - let map = {}; - map[REQUEST_SET_UICC_SUBSCRIPTION] = 114; - map[REQUEST_SET_DATA_SUBSCRIPTION] = 115; - this._requestMap[8] = map; - // RIL version 9. - // For the CAF's proprietary parcels. Please see - // https://www.codeaurora.org/cgit/quic/la/platform/hardware/ril/tree/include/telephony/ril.h?h=b2g_kk_3.5 - map = {}; - map[REQUEST_SET_UICC_SUBSCRIPTION] = 115; - map[REQUEST_SET_DATA_SUBSCRIPTION] = 116; - this._requestMap[9] = map; - }; - - /** - * "inherit" the basic worker buffer. - */ - BufObject.prototype = Object.create(Buf); - - /** - * Process one parcel. - */ - BufObject.prototype.processParcel = function() { - let responseType = this.readInt32(); - - let requestType, options; - if (responseType == RESPONSE_TYPE_SOLICITED) { - let token = this.readInt32(); - let error = this.readInt32(); - - options = this.mTokenRequestMap.get(token); - if (!options) { - if (DEBUG) { - this.context.debug("Suspicious uninvited request found: " + - token + ". Ignored!"); - } - return; - } - - this.mTokenRequestMap.delete(token); - requestType = options.rilRequestType; - - if (error !== ERROR_SUCCESS) { - options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[error] || - GECKO_ERROR_UNSPECIFIED_ERROR; - } - if (DEBUG) { - this.context.debug("Solicited response for request type " + requestType + - ", token " + token + ", error " + error); - } - } else if (responseType == RESPONSE_TYPE_UNSOLICITED) { - requestType = this.readInt32(); - if (DEBUG) { - this.context.debug("Unsolicited response for request type " + requestType); - } - } else { - if (DEBUG) { - this.context.debug("Unknown response type: " + responseType); - } - return; - } - - this.context.RIL.handleParcel(requestType, this.readAvailable, options); - }; - - /** - * Start a new outgoing parcel. - * - * @param type - * Integer specifying the request type. - * @param options [optional] - * Object containing information about the request, e.g. the - * original main thread message object that led to the RIL request. - */ - BufObject.prototype.newParcel = function(type, options) { - if (DEBUG) { - this.context.debug("New outgoing parcel of type " + type); - } - - // We're going to leave room for the parcel size at the beginning. - this.outgoingIndex = this.PARCEL_SIZE_SIZE; - this.writeInt32(this._reMapRequestType(type)); - this.writeInt32(this.mToken); - - if (!options) { - options = {}; - } - options.rilRequestType = type; - this.mTokenRequestMap.set(this.mToken, options); - this.mToken++; - return this.mToken; - }; - - BufObject.prototype.simpleRequest = function(type, options) { - this.newParcel(type, options); - this.sendParcel(); - }; - - BufObject.prototype.onSendParcel = function(parcel) { - self.postRILMessage(this.context.clientId, parcel); - }; - - /** - * Remapping the request type to different values based on RIL version. - * We only have to do this for SUBSCRIPTION right now, so I just make it - * simple. A generic logic or structure could be discussed if we have more - * use cases, especially the cases from different partners. - */ - BufObject.prototype._reMapRequestType = function(type) { - for (let version in this._requestMap) { - if (this.context.RIL.version <= version) { - let newType = this._requestMap[version][type]; - if (newType) { - if (DEBUG) { - this.context.debug("Remap request type to " + newType); - } - return newType; - } - } - } - return type; - }; - - // Before we make sure to form it as a module would not add extra - // overhead of module loading, we need to define it in this way - // rather than 'module.exports' it as a module component. - exports.BufObject = BufObject; -})(self); // in worker self is the global - diff --git a/dom/system/gonk/ril_worker_telephony_request_queue.js b/dom/system/gonk/ril_worker_telephony_request_queue.js deleted file mode 100644 index 4dba7a42f..000000000 --- a/dom/system/gonk/ril_worker_telephony_request_queue.js +++ /dev/null @@ -1,157 +0,0 @@ -/* global DEBUG, DEBUG_WORKER */ -/* global REQUEST_GET_CURRENT_CALLS */ -/* global REQUEST_ANSWER, REQUEST_CONFERENCE, REQUEST_DIAL */ -/* global REQUEST_DIAL_EMERGENCY_CALL, REQUEST_HANGUP */ -/* global REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND */ -/* global REQUEST_HANGUP_WAITING_OR_BACKGROUND */ -/* global REQUEST_SEPARATE_CONNECTION */ -/* global REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, REQUEST_UDUB */ - -"use strict"; - -(function(exports) { - - const TELEPHONY_REQUESTS = [ - REQUEST_GET_CURRENT_CALLS, - REQUEST_ANSWER, - REQUEST_CONFERENCE, - REQUEST_DIAL, - REQUEST_DIAL_EMERGENCY_CALL, - REQUEST_HANGUP, - REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, - REQUEST_HANGUP_WAITING_OR_BACKGROUND, - REQUEST_SEPARATE_CONNECTION, - REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, - REQUEST_UDUB - ]; - - // Set to true in ril_consts.js to see debug messages - let DEBUG = DEBUG_WORKER; - - /** - * Queue entry; only used in the queue. - */ - let TelephonyRequestEntry = function(request, callback) { - this.request = request; - this.callback = callback; - }; - - let TelephonyRequestQueue = function(ril) { - this.ril = ril; - this.currentQueue = null; // Point to the current running queue. - - this.queryQueue = []; - this.controlQueue = []; - }; - - TelephonyRequestQueue.prototype._getQueue = function(request) { - return (request === REQUEST_GET_CURRENT_CALLS) ? this.queryQueue - : this.controlQueue; - }; - - TelephonyRequestQueue.prototype._getAnotherQueue = function(queue) { - return (this.queryQueue === queue) ? this.controlQueue : this.queryQueue; - }; - - TelephonyRequestQueue.prototype._find = function(queue, request) { - for (let i = 0; i < queue.length; ++i) { - if (queue[i].request === request) { - return i; - } - } - return -1; - }; - - TelephonyRequestQueue.prototype._startQueue = function(queue) { - if (queue.length === 0) { - return; - } - - // We only need to keep one entry for queryQueue. - if (queue === this.queryQueue) { - queue.splice(1, queue.length - 1); - } - - this.currentQueue = queue; - for (let entry of queue) { - this._executeEntry(entry); - } - }; - - TelephonyRequestQueue.prototype._executeEntry = function(entry) { - if (DEBUG) { - this.debug("execute " + this._getRequestName(entry.request)); - } - entry.callback(); - }; - - TelephonyRequestQueue.prototype._getRequestName = function(request) { - let method = this.ril[request]; - return (typeof method === 'function') ? method.name : ""; - }; - - TelephonyRequestQueue.prototype.debug = function(msg) { - this.ril.context.debug("[TeleQ] " + msg); - }; - - TelephonyRequestQueue.prototype.isValidRequest = function(request) { - return TELEPHONY_REQUESTS.indexOf(request) !== -1; - }; - - TelephonyRequestQueue.prototype.push = function(request, callback) { - if (!this.isValidRequest(request)) { - if (DEBUG) { - this.debug("Error: " + this._getRequestName(request) + - " is not a telephony request"); - } - return; - } - - if (DEBUG) { - this.debug("push " + this._getRequestName(request)); - } - let entry = new TelephonyRequestEntry(request, callback); - let queue = this._getQueue(request); - queue.push(entry); - - // Try to run the request. - if (this.currentQueue === queue) { - this._executeEntry(entry); - } else if (!this.currentQueue) { - this._startQueue(queue); - } - }; - - TelephonyRequestQueue.prototype.pop = function(request) { - if (!this.isValidRequest(request)) { - if (DEBUG) { - this.debug("Error: " + this._getRequestName(request) + - " is not a telephony request"); - } - return; - } - - if (DEBUG) { - this.debug("pop " + this._getRequestName(request)); - } - let queue = this._getQueue(request); - let index = this._find(queue, request); - if (index === -1) { - throw new Error("Cannot find the request in telephonyRequestQueue."); - } else { - queue.splice(index, 1); - } - - if (queue.length === 0) { - this.currentQueue = null; - this._startQueue(this._getAnotherQueue(queue)); - } - }; - - - // Before we make sure to form it as a module would not add extra - // overhead of module loading, we need to define it in this way - // rather than 'module.exports' it as a module component. - exports.TelephonyRequestQueue = TelephonyRequestQueue; -})(self); // in worker self is the global - diff --git a/dom/system/gonk/systemlibs.js b/dom/system/gonk/systemlibs.js deleted file mode 100644 index a27b30e20..000000000 --- a/dom/system/gonk/systemlibs.js +++ /dev/null @@ -1,201 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -if (!this.ctypes) { - // We're likely being loaded as a JSM. - this.EXPORTED_SYMBOLS = [ "libcutils", "netHelpers" ]; - Components.utils.import("resource://gre/modules/ctypes.jsm"); -} - -const SYSTEM_PROPERTY_KEY_MAX = 32; -const SYSTEM_PROPERTY_VALUE_MAX = 92; - -// We leave this as 'undefined' instead of setting it to 'false'. That -// way a file that includes us can have it defined already without us -// overriding the value here. -var DEBUG; - -/** - * Expose some system-level functions. - */ -this.libcutils = (function() { - let lib; - try { - lib = ctypes.open("libcutils.so"); - } catch(ex) { - // Return a fallback option in case libcutils.so isn't present (e.g. - // when building Firefox with MOZ_B2G_RIL. - if (DEBUG) { - dump("Could not load libcutils.so. Using fake propdb.\n"); - } - let fake_propdb = Object.create(null); - return { - property_get: function(key, defaultValue) { - if (key in fake_propdb) { - return fake_propdb[key]; - } - return defaultValue === undefined ? null : defaultValue; - }, - property_set: function(key, value) { - fake_propdb[key] = value; - } - }; - } - - let c_property_get = lib.declare("property_get", ctypes.default_abi, - ctypes.int, // return value: length - ctypes.char.ptr, // key - ctypes.char.ptr, // value - ctypes.char.ptr); // default - let c_property_set = lib.declare("property_set", ctypes.default_abi, - ctypes.int, // return value: success - ctypes.char.ptr, // key - ctypes.char.ptr); // value - let c_value_buf = ctypes.char.array(SYSTEM_PROPERTY_VALUE_MAX)(); - - return { - - /** - * Get a system property. - * - * @param key - * Name of the property - * @param defaultValue [optional] - * Default value to return if the property isn't set (default: null) - */ - property_get: function(key, defaultValue) { - if (defaultValue === undefined) { - defaultValue = null; - } - c_property_get(key, c_value_buf, defaultValue); - return c_value_buf.readString(); - }, - - /** - * Set a system property - * - * @param key - * Name of the property - * @param value - * Value to set the property to. - */ - property_set: function(key, value) { - let rv = c_property_set(key, value); - if (rv) { - throw Error('libcutils.property_set("' + key + '", "' + value + - '") failed with error ' + rv); - } - } - - }; -})(); - -/** - * Helpers for conversions. - */ -this.netHelpers = { - - /** - * Swap byte orders for 32-bit value - */ - swap32: function(n) { - return (((n >> 24) & 0xFF) << 0) | - (((n >> 16) & 0xFF) << 8) | - (((n >> 8) & 0xFF) << 16) | - (((n >> 0) & 0xFF) << 24); - }, - - /** - * Convert network byte order to host byte order - * Note: Assume that the system is little endian - */ - ntohl: function(n) { - return this.swap32(n); - }, - - /** - * Convert host byte order to network byte order - * Note: Assume that the system is little endian - */ - htonl: function(n) { - return this.swap32(n); - }, - - /** - * Convert integer representation of an IP address to the string - * representation. - * - * @param ip - * IP address in number format. - */ - ipToString: function(ip) { - return ((ip >> 0) & 0xFF) + "." + - ((ip >> 8) & 0xFF) + "." + - ((ip >> 16) & 0xFF) + "." + - ((ip >> 24) & 0xFF); - }, - - /** - * Convert string representation of an IP address to the integer - * representation (network byte order). - * - * @param string - * String containing the IP address. - */ - stringToIP: function(string) { - if (!string) { - return null; - } - let ip = 0; - let start, end = -1; - for (let i = 0; i < 4; i++) { - start = end + 1; - end = string.indexOf(".", start); - if (end == -1) { - end = string.length; - } - let num = parseInt(string.slice(start, end), 10); - if (isNaN(num)) { - return null; - } - ip |= num << (i * 8); - } - return ip; - }, - - /** - * Make a subnet mask. - */ - makeMask: function(len) { - let mask = 0; - for (let i = 0; i < len; ++i) { - mask |= (0x80000000 >> i); - } - return this.ntohl(mask); - }, - - /** - * Get Mask length from given mask address - */ - getMaskLength: function(mask) { - let len = 0; - let netmask = this.ntohl(mask); - while (netmask & 0x80000000) { - len++; - netmask = netmask << 1; - } - return len; - } -}; diff --git a/dom/system/gonk/tests/header_helpers.js b/dom/system/gonk/tests/header_helpers.js deleted file mode 100644 index 8d1144f75..000000000 --- a/dom/system/gonk/tests/header_helpers.js +++ /dev/null @@ -1,217 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - - -var subscriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"] - .getService(Ci.mozIJSSubScriptLoader); - -/** - * Start a new RIL worker. - * - * @param custom_ns - * Namespace with symbols to be injected into the new worker - * namespace. - * - * @return an object that represents the worker's namespace. - * - * @note that this does not start an actual worker thread. The worker - * is executed on the main thread, within a separate namespace object. - */ -function newWorker(custom_ns) { - let worker_ns = { - importScripts: function() { - Array.slice(arguments).forEach(function(script) { - if (!script.startsWith("resource:")) { - script = "resource://gre/modules/" + script; - } - subscriptLoader.loadSubScript(script, this); - }, this); - }, - - postRILMessage: function(message) { - }, - - postMessage: function(message) { - }, - - // Define these variables inside the worker scope so ES5 strict mode - // doesn't flip out. - onmessage: undefined, - onerror: undefined, - - DEBUG: true - }; - // The 'self' variable in a worker points to the worker's own namespace. - worker_ns.self = worker_ns; - - // Copy the custom definitions over. - for (let key in custom_ns) { - worker_ns[key] = custom_ns[key]; - } - - // fake require() for toolkit/components/workerloader/require.js - let require = (function() { - return function require(script) { - worker_ns.module = {}; - worker_ns.importScripts(script); - return worker_ns; - } - })(); - - Object.freeze(require); - Object.defineProperty(worker_ns, "require", { - value: require, - enumerable: true, - configurable: false - }); - - // Load the RIL worker itself. - worker_ns.importScripts("ril_worker.js"); - - // Register at least one client. - worker_ns.ContextPool.registerClient({ clientId: 0 }); - - return worker_ns; -} - -/** - * Create a buffered RIL worker. - * - * @return A worker object that stores sending octets in a internal buffer. - */ -function newUint8Worker() { - let worker = newWorker(); - let index = 0; // index for read - let buf = []; - - let context = worker.ContextPool._contexts[0]; - context.Buf.writeUint8 = function(value) { - buf.push(value); - }; - - context.Buf.readUint8 = function() { - return buf[index++]; - }; - - context.Buf.seekIncoming = function(offset) { - index += offset; - }; - - context.Buf.getReadAvailable = function() { - return buf.length - index; - }; - - worker.debug = do_print; - - return worker; -} - -/** - * Create a worker that keeps posted chrome message. - */ -function newInterceptWorker() { - let postedMessage; - let worker = newWorker({ - postRILMessage: function(data) { - }, - postMessage: function(message) { - postedMessage = message; - } - }); - return { - get postedMessage() { - return postedMessage; - }, - get worker() { - return worker; - } - }; -} - -/** - * Create a parcel suitable for postRILMessage(). - * - * @param fakeParcelSize - * Value to be written to parcel size field for testing - * incorrect/incomplete parcel reading. Replaced with correct - * one determined length of data if negative. - * @param response - * Response code of the incoming parcel. - * @param request - * Request code of the incoming parcel. - * @param data - * Extra data to be appended. - * - * @return an Uint8Array carrying all parcel data. - */ -function newIncomingParcel(fakeParcelSize, response, request, data) { - const UINT32_SIZE = 4; - const PARCEL_SIZE_SIZE = 4; - - let realParcelSize = data.length + 2 * UINT32_SIZE; - let buffer = new ArrayBuffer(realParcelSize + PARCEL_SIZE_SIZE); - let bytes = new Uint8Array(buffer); - - let writeIndex = 0; - function writeUint8(value) { - bytes[writeIndex] = value; - ++writeIndex; - } - - function writeInt32(value) { - writeUint8(value & 0xff); - writeUint8((value >> 8) & 0xff); - writeUint8((value >> 16) & 0xff); - writeUint8((value >> 24) & 0xff); - } - - function writeParcelSize(value) { - writeUint8((value >> 24) & 0xff); - writeUint8((value >> 16) & 0xff); - writeUint8((value >> 8) & 0xff); - writeUint8(value & 0xff); - } - - if (fakeParcelSize < 0) { - fakeParcelSize = realParcelSize; - } - writeParcelSize(fakeParcelSize); - - writeInt32(response); - writeInt32(request); - - // write parcel data - for (let ii = 0; ii < data.length; ++ii) { - writeUint8(data[ii]); - } - - return bytes; -} - -/** - * Create a parcel buffer which represents the hex string. - * - * @param hexString - * The HEX string to be converted. - * - * @return an Uint8Array carrying all parcel data. - */ -function hexStringToParcelByteArrayData(hexString) { - let length = Math.ceil((hexString.length / 2)); - let bytes = new Uint8Array(4 + length); - - bytes[0] = length & 0xFF; - bytes[1] = (length >> 8) & 0xFF; - bytes[2] = (length >> 16) & 0xFF; - bytes[3] = (length >> 24) & 0xFF; - - for (let i = 0; i < length; i ++) { - bytes[i + 4] = Number.parseInt(hexString.substr(i * 2, 2), 16); - } - - return bytes; -} diff --git a/dom/system/gonk/tests/marionette/head.js b/dom/system/gonk/tests/marionette/head.js deleted file mode 100644 index 5a6ee1272..000000000 --- a/dom/system/gonk/tests/marionette/head.js +++ /dev/null @@ -1,345 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_CONTEXT = "chrome"; - -const SETTINGS_KEY_DATA_ENABLED = "ril.data.enabled"; -const SETTINGS_KEY_DATA_APN_SETTINGS = "ril.data.apnSettings"; -const SETTINGS_KEY_WIFI_ENABLED = "wifi.enabled"; - -const TOPIC_CONNECTION_STATE_CHANGED = "network-connection-state-changed"; -const TOPIC_NETWORK_ACTIVE_CHANGED = "network-active-changed"; - -const NETWORK_STATE_UNKNOWN = Ci.nsINetworkInfo.NETWORK_STATE_UNKNOWN; -const NETWORK_STATE_CONNECTING = Ci.nsINetworkInfo.NETWORK_STATE_CONNECTING; -const NETWORK_STATE_CONNECTED = Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED; -const NETWORK_STATE_DISCONNECTING = Ci.nsINetworkInfo.NETWORK_STATE_DISCONNECTING; -const NETWORK_STATE_DISCONNECTED = Ci.nsINetworkInfo.NETWORK_STATE_DISCONNECTED; - -const NETWORK_TYPE_MOBILE = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE; -const NETWORK_TYPE_MOBILE_MMS = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_MMS; -const NETWORK_TYPE_MOBILE_SUPL = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_SUPL; -const NETWORK_TYPE_MOBILE_IMS = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_IMS; -const NETWORK_TYPE_MOBILE_DUN = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN; -const NETWORK_TYPE_MOBILE_FOTA = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_FOTA; - -const networkTypes = [ - NETWORK_TYPE_MOBILE, - NETWORK_TYPE_MOBILE_MMS, - NETWORK_TYPE_MOBILE_SUPL, - NETWORK_TYPE_MOBILE_IMS, - NETWORK_TYPE_MOBILE_DUN, - NETWORK_TYPE_MOBILE_FOTA -]; - -var Promise = Cu.import("resource://gre/modules/Promise.jsm").Promise; - -var ril = Cc["@mozilla.org/ril;1"].getService(Ci.nsIRadioInterfaceLayer); -ok(ril, "ril.constructor is " + ril.constructor); - -var radioInterface = ril.getRadioInterface(0); -ok(radioInterface, "radioInterface.constructor is " + radioInterface.constrctor); - -var _pendingEmulatorShellCmdCount = 0; -var _pendingEmulatorCmdCount = 0; - -/** - * Send emulator shell command with safe guard. - * - * We should only call |finish()| after all emulator shell command transactions - * end, so here comes with the pending counter. Resolve when the emulator - * shell gives response. Never reject. - * - * Fulfill params: - * result -- an array of emulator shell response lines. - * - * @param aCommands - * A string array commands to be passed to emulator through adb shell. - * - * @return A deferred promise. - */ -function runEmulatorShellCmdSafe(aCommands) { - return new Promise(function(aResolve, aReject) { - ++_pendingEmulatorShellCmdCount; - runEmulatorShell(aCommands, function(aResult) { - --_pendingEmulatorShellCmdCount; - - log("Emulator shell response: " + JSON.stringify(aResult)); - aResolve(aResult); - }); - }); -} - -/** - * Send emulator command with safe guard. - * - * We should only call |finish()| after all emulator command transactions - * end, so here comes with the pending counter. Resolve when the emulator - * gives positive response, and reject otherwise. - * - * Fulfill params: - * result -- an array of emulator response lines. - * Reject params: - * result -- an array of emulator response lines. - * - * @param aCommand - * A string command to be passed to emulator through its telnet console. - * - * @return A deferred promise. - */ -function runEmulatorCmdSafe(aCommand) { - log(aCommand); - return new Promise(function(aResolve, aReject) { - ++_pendingEmulatorCmdCount; - runEmulatorCmd(aCommand, function(aResult) { - --_pendingEmulatorCmdCount; - - log("Emulator console response: " + JSON.stringify(aResult)); - if (Array.isArray(aResult) && - aResult[aResult.length - 1] === "OK") { - aResolve(aResult); - } else { - aReject(aResult); - } - }); - }); -} - -/** - * Get mozSettings value specified by @aKey. - * - * Resolve if that mozSettings value is retrieved successfully, reject - * otherwise. - * - * Fulfill params: The corresponding mozSettings value of the key. - * Reject params: (none) - * - * @param aKey - * A string. - * @param aAllowError [optional] - * A boolean value. If set to true, an error response won't be treated - * as test failure. Default: false. - * - * @return A deferred promise. - */ -function getSettings(aKey, aAllowError) { - let request = window.navigator.mozSettings.createLock().get(aKey); - return request.then(function resolve(aValue) { - log("getSettings(" + aKey + ") - success"); - return aValue[aKey]; - }, function reject(aError) { - ok(aAllowError, "getSettings(" + aKey + ") - error"); - }); -} - -/** - * Set mozSettings values. - * - * Resolve if that mozSettings value is set successfully, reject otherwise. - * - * Fulfill params: (none) - * Reject params: (none) - * - * @param aKey - * A string key. - * @param aValue - * An object value. - * @param aAllowError [optional] - * A boolean value. If set to true, an error response won't be treated - * as test failure. Default: false. - * - * @return A deferred promise. - */ -function setSettings(aKey, aValue, aAllowError) { - let settings = {}; - settings[aKey] = aValue; - let lock = window.navigator.mozSettings.createLock(); - let request = lock.set(settings); - let deferred = Promise.defer(); - lock.onsettingstransactionsuccess = function () { - log("setSettings(" + JSON.stringify(settings) + ") - success"); - deferred.resolve(); - }; - lock.onsettingstransactionfailure = function () { - ok(aAllowError, "setSettings(" + JSON.stringify(settings) + ") - error"); - // We resolve even though we've thrown an error, since the ok() - // will do that. - deferred.resolve(); - }; - return deferred.promise; -} - -/** - * Wait for observer event. - * - * Resolve if that topic event occurs. Never reject. - * - * Fulfill params: the subject passed. - * - * @param aTopic - * A string topic name. - * - * @return A deferred promise. - */ -function waitForObserverEvent(aTopic) { - let obs = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService); - let deferred = Promise.defer(); - - obs.addObserver(function observer(subject, topic, data) { - if (topic === aTopic) { - obs.removeObserver(observer, aTopic); - deferred.resolve(subject); - } - }, aTopic, false); - - return deferred.promise; -} - -/** - * Wait for one named event. - * - * Resolve if that named event occurs. Never reject. - * - * Fulfill params: the DOMEvent passed. - * - * @param aEventTarget - * An EventTarget object. - * @param aEventName - * A string event name. - * @param aMatchFun [optional] - * A matching function returns true or false to filter the event. - * - * @return A deferred promise. - */ -function waitForTargetEvent(aEventTarget, aEventName, aMatchFun) { - return new Promise(function(aResolve, aReject) { - aEventTarget.addEventListener(aEventName, function onevent(aEvent) { - if (!aMatchFun || aMatchFun(aEvent)) { - aEventTarget.removeEventListener(aEventName, onevent); - ok(true, "Event '" + aEventName + "' got."); - aResolve(aEvent); - } - }); - }); -} - -/** - * Set the default data connection enabling state, wait for - * "network-connection-state-changed" event and verify state. - * - * Fulfill params: instance of nsIRilNetworkInfo of the network connected. - * - * @param aEnabled - * A boolean state. - * - * @return A deferred promise. - */ -function setDataEnabledAndWait(aEnabled) { - let promises = []; - promises.push(waitForObserverEvent(TOPIC_CONNECTION_STATE_CHANGED) - .then(function(aSubject) { - ok(aSubject instanceof Ci.nsIRilNetworkInfo, - "subject should be an instance of nsIRilNetworkInfo"); - is(aSubject.type, NETWORK_TYPE_MOBILE, - "subject.type should be " + NETWORK_TYPE_MOBILE); - is(aSubject.state, - aEnabled ? Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED - : Ci.nsINetworkInfo.NETWORK_STATE_DISCONNECTED, - "subject.state should be " + aEnabled ? "CONNECTED" : "DISCONNECTED"); - - return aSubject; - })); - promises.push(setSettings(SETTINGS_KEY_DATA_ENABLED, aEnabled)); - - return Promise.all(promises).then(aValues => aValues[0]); -} - -/** - * Setup a certain type of data connection, wait for - * "network-connection-state-changed" event and verify state. - * - * Fulfill params: instance of nsIRilNetworkInfo of the network connected. - * - * @param aNetworkType - * The mobile network type to setup. - * - * @return A deferred promise. - */ -function setupDataCallAndWait(aNetworkType) { - log("setupDataCallAndWait: " + aNetworkType); - - let promises = []; - promises.push(waitForObserverEvent(TOPIC_CONNECTION_STATE_CHANGED) - .then(function(aSubject) { - ok(aSubject instanceof Ci.nsIRilNetworkInfo, - "subject should be an instance of nsIRilNetworkInfo"); - is(aSubject.type, aNetworkType, - "subject.type should be " + aNetworkType); - is(aSubject.state, Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED, - "subject.state should be CONNECTED"); - - return aSubject; - })); - promises.push(radioInterface.setupDataCallByType(aNetworkType)); - - return Promise.all(promises).then(aValues => aValues[0]); -} - -/** - * Deactivate a certain type of data connection, wait for - * "network-connection-state-changed" event and verify state. - * - * Fulfill params: (none) - * - * @param aNetworkType - * The mobile network type to deactivate. - * - * @return A deferred promise. - */ -function deactivateDataCallAndWait(aNetworkType) { - log("deactivateDataCallAndWait: " + aNetworkType); - - let promises = []; - promises.push(waitForObserverEvent(TOPIC_CONNECTION_STATE_CHANGED) - .then(function(aSubject) { - ok(aSubject instanceof Ci.nsIRilNetworkInfo, - "subject should be an instance of nsIRilNetworkInfo"); - is(aSubject.type, aNetworkType, - "subject.type should be " + aNetworkType); - is(aSubject.state, Ci.nsINetworkInfo.NETWORK_STATE_DISCONNECTED, - "subject.state should be DISCONNECTED"); - })); - promises.push(radioInterface.deactivateDataCallByType(aNetworkType)); - - return Promise.all(promises); -} - -/** - * Wait for pending emulator transactions and call |finish()|. - */ -function cleanUp() { - // Use ok here so that we have at least one test run. - ok(true, ":: CLEANING UP ::"); - - waitFor(finish, function() { - return _pendingEmulatorShellCmdCount === 0 && - _pendingEmulatorCmdCount === 0; - }); -} - -/** - * Basic test routine helper. - * - * This helper does nothing but clean-ups. - * - * @param aTestCaseMain - * A function that takes no parameter. - */ -function startTestBase(aTestCaseMain) { - Promise.resolve() - .then(aTestCaseMain) - .then(cleanUp, function(aException) { - ok(false, "promise rejects during test: " + aException); - cleanUp(); - }); -} diff --git a/dom/system/gonk/tests/marionette/manifest.ini b/dom/system/gonk/tests/marionette/manifest.ini deleted file mode 100644 index 528fe3baf..000000000 --- a/dom/system/gonk/tests/marionette/manifest.ini +++ /dev/null @@ -1,19 +0,0 @@ -[DEFAULT] -run-if = buildapp == 'b2g' - -[test_geolocation.js] -skip-if = true # Bug 808783 -[test_fakevolume.js] -[test_ril_code_quality.py] -[test_screen_state.js] -[test_dsds_numRadioInterfaces.js] -[test_data_connection.js] -[test_network_active_changed.js] -[test_multiple_data_connection.js] -[test_data_connection_proxy.js] -[test_network_interface_list_service.js] -[test_all_network_info.js] -[test_network_interface_mtu.js] -skip-if = android_version < '19' -[test_timezone_changes.js] -skip-if = android_version < '19' diff --git a/dom/system/gonk/tests/marionette/ril_jshint/README.md b/dom/system/gonk/tests/marionette/ril_jshint/README.md deleted file mode 100644 index a63967d63..000000000 --- a/dom/system/gonk/tests/marionette/ril_jshint/README.md +++ /dev/null @@ -1,9 +0,0 @@ -Test RIL Code Quality -===================== - -For more information, please refer to - -* Bug 880643 - B2G RIL: Add a code quality test on try server for RIL javascript code in gecko -* Slide: https://speakerdeck.com/aknow/improve-code-quality-of-ril-code-by-jshint -* Document: https://hackpad.com/Code-Quality-Test-For-RIL-Javascript-Code-In-Gecko-cz5j7YIGiw8 - diff --git a/dom/system/gonk/tests/marionette/ril_jshint/jshint.js b/dom/system/gonk/tests/marionette/ril_jshint/jshint.js deleted file mode 100644 index ec5263a5b..000000000 --- a/dom/system/gonk/tests/marionette/ril_jshint/jshint.js +++ /dev/null @@ -1,11096 +0,0 @@ -//2.1.3 -var JSHINT; -(function () { -var require; -require=(function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s<n.length;s++)i(n[s]);return i})({1:[function(require,module,exports){ -// shim for using process in browser - -var process = module.exports = {}; - -process.nextTick = (function () { - var canSetImmediate = typeof window !== 'undefined' - && window.setImmediate; - var canPost = typeof window !== 'undefined' - && window.postMessage && window.addEventListener - ; - - if (canSetImmediate) { - return function (f) { return window.setImmediate(f) }; - } - - if (canPost) { - var queue = []; - window.addEventListener('message', function (ev) { - if (ev.source === window && ev.data === 'process-tick') { - ev.stopPropagation(); - if (queue.length > 0) { - var fn = queue.shift(); - fn(); - } - } - }, true); - - return function nextTick(fn) { - queue.push(fn); - window.postMessage('process-tick', '*'); - }; - } - - return function nextTick(fn) { - setTimeout(fn, 0); - }; -})(); - -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; - -process.binding = function (name) { - throw new Error('process.binding is not supported'); -} - -// TODO(shtylman) -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; - -},{}],2:[function(require,module,exports){ -(function(process){if (!process.EventEmitter) process.EventEmitter = function () {}; - -var EventEmitter = exports.EventEmitter = process.EventEmitter; -var isArray = typeof Array.isArray === 'function' - ? Array.isArray - : function (xs) { - return Object.prototype.toString.call(xs) === '[object Array]' - } -; -function indexOf (xs, x) { - if (xs.indexOf) return xs.indexOf(x); - for (var i = 0; i < xs.length; i++) { - if (x === xs[i]) return i; - } - return -1; -} - -// By default EventEmitters will print a warning if more than -// 10 listeners are added to it. This is a useful default which -// helps finding memory leaks. -// -// Obviously not all Emitters should be limited to 10. This function allows -// that to be increased. Set to zero for unlimited. -var defaultMaxListeners = 10; -EventEmitter.prototype.setMaxListeners = function(n) { - if (!this._events) this._events = {}; - this._events.maxListeners = n; -}; - - -EventEmitter.prototype.emit = function(type) { - // If there is no 'error' event listener then throw. - if (type === 'error') { - if (!this._events || !this._events.error || - (isArray(this._events.error) && !this._events.error.length)) - { - if (arguments[1] instanceof Error) { - throw arguments[1]; // Unhandled 'error' event - } else { - throw new Error("Uncaught, unspecified 'error' event."); - } - return false; - } - } - - if (!this._events) return false; - var handler = this._events[type]; - if (!handler) return false; - - if (typeof handler == 'function') { - switch (arguments.length) { - // fast cases - case 1: - handler.call(this); - break; - case 2: - handler.call(this, arguments[1]); - break; - case 3: - handler.call(this, arguments[1], arguments[2]); - break; - // slower - default: - var args = Array.prototype.slice.call(arguments, 1); - handler.apply(this, args); - } - return true; - - } else if (isArray(handler)) { - var args = Array.prototype.slice.call(arguments, 1); - - var listeners = handler.slice(); - for (var i = 0, l = listeners.length; i < l; i++) { - listeners[i].apply(this, args); - } - return true; - - } else { - return false; - } -}; - -// EventEmitter is defined in src/node_events.cc -// EventEmitter.prototype.emit() is also defined there. -EventEmitter.prototype.addListener = function(type, listener) { - if ('function' !== typeof listener) { - throw new Error('addListener only takes instances of Function'); - } - - if (!this._events) this._events = {}; - - // To avoid recursion in the case that type == "newListeners"! Before - // adding it to the listeners, first emit "newListeners". - this.emit('newListener', type, listener); - - if (!this._events[type]) { - // Optimize the case of one listener. Don't need the extra array object. - this._events[type] = listener; - } else if (isArray(this._events[type])) { - - // Check for listener leak - if (!this._events[type].warned) { - var m; - if (this._events.maxListeners !== undefined) { - m = this._events.maxListeners; - } else { - m = defaultMaxListeners; - } - - if (m && m > 0 && this._events[type].length > m) { - this._events[type].warned = true; - console.error('(node) warning: possible EventEmitter memory ' + - 'leak detected. %d listeners added. ' + - 'Use emitter.setMaxListeners() to increase limit.', - this._events[type].length); - console.trace(); - } - } - - // If we've already got an array, just append. - this._events[type].push(listener); - } else { - // Adding the second element, need to change to array. - this._events[type] = [this._events[type], listener]; - } - - return this; -}; - -EventEmitter.prototype.on = EventEmitter.prototype.addListener; - -EventEmitter.prototype.once = function(type, listener) { - var self = this; - self.on(type, function g() { - self.removeListener(type, g); - listener.apply(this, arguments); - }); - - return this; -}; - -EventEmitter.prototype.removeListener = function(type, listener) { - if ('function' !== typeof listener) { - throw new Error('removeListener only takes instances of Function'); - } - - // does not use listeners(), so no side effect of creating _events[type] - if (!this._events || !this._events[type]) return this; - - var list = this._events[type]; - - if (isArray(list)) { - var i = indexOf(list, listener); - if (i < 0) return this; - list.splice(i, 1); - if (list.length == 0) - delete this._events[type]; - } else if (this._events[type] === listener) { - delete this._events[type]; - } - - return this; -}; - -EventEmitter.prototype.removeAllListeners = function(type) { - if (arguments.length === 0) { - this._events = {}; - return this; - } - - // does not use listeners(), so no side effect of creating _events[type] - if (type && this._events && this._events[type]) this._events[type] = null; - return this; -}; - -EventEmitter.prototype.listeners = function(type) { - if (!this._events) this._events = {}; - if (!this._events[type]) this._events[type] = []; - if (!isArray(this._events[type])) { - this._events[type] = [this._events[type]]; - } - return this._events[type]; -}; - -})(require("__browserify_process")) -},{"__browserify_process":1}],3:[function(require,module,exports){ -(function(){// jshint -W001 - -"use strict"; - -// Identifiers provided by the ECMAScript standard. - -exports.reservedVars = { - arguments : false, - NaN : false -}; - -exports.ecmaIdentifiers = { - Array : false, - Boolean : false, - Date : false, - decodeURI : false, - decodeURIComponent : false, - encodeURI : false, - encodeURIComponent : false, - Error : false, - "eval" : false, - EvalError : false, - Function : false, - hasOwnProperty : false, - isFinite : false, - isNaN : false, - JSON : false, - Math : false, - Map : false, - Number : false, - Object : false, - parseInt : false, - parseFloat : false, - RangeError : false, - ReferenceError : false, - RegExp : false, - Set : false, - String : false, - SyntaxError : false, - TypeError : false, - URIError : false, - WeakMap : false -}; - -// Global variables commonly provided by a web browser environment. - -exports.browser = { - ArrayBuffer : false, - ArrayBufferView : false, - Audio : false, - Blob : false, - addEventListener : false, - applicationCache : false, - atob : false, - blur : false, - btoa : false, - clearInterval : false, - clearTimeout : false, - close : false, - closed : false, - DataView : false, - DOMParser : false, - defaultStatus : false, - document : false, - Element : false, - ElementTimeControl : false, - event : false, - FileReader : false, - Float32Array : false, - Float64Array : false, - FormData : false, - focus : false, - frames : false, - getComputedStyle : false, - HTMLElement : false, - HTMLAnchorElement : false, - HTMLBaseElement : false, - HTMLBlockquoteElement: false, - HTMLBodyElement : false, - HTMLBRElement : false, - HTMLButtonElement : false, - HTMLCanvasElement : false, - HTMLDirectoryElement : false, - HTMLDivElement : false, - HTMLDListElement : false, - HTMLFieldSetElement : false, - HTMLFontElement : false, - HTMLFormElement : false, - HTMLFrameElement : false, - HTMLFrameSetElement : false, - HTMLHeadElement : false, - HTMLHeadingElement : false, - HTMLHRElement : false, - HTMLHtmlElement : false, - HTMLIFrameElement : false, - HTMLImageElement : false, - HTMLInputElement : false, - HTMLIsIndexElement : false, - HTMLLabelElement : false, - HTMLLayerElement : false, - HTMLLegendElement : false, - HTMLLIElement : false, - HTMLLinkElement : false, - HTMLMapElement : false, - HTMLMenuElement : false, - HTMLMetaElement : false, - HTMLModElement : false, - HTMLObjectElement : false, - HTMLOListElement : false, - HTMLOptGroupElement : false, - HTMLOptionElement : false, - HTMLParagraphElement : false, - HTMLParamElement : false, - HTMLPreElement : false, - HTMLQuoteElement : false, - HTMLScriptElement : false, - HTMLSelectElement : false, - HTMLStyleElement : false, - HTMLTableCaptionElement: false, - HTMLTableCellElement : false, - HTMLTableColElement : false, - HTMLTableElement : false, - HTMLTableRowElement : false, - HTMLTableSectionElement: false, - HTMLTextAreaElement : false, - HTMLTitleElement : false, - HTMLUListElement : false, - HTMLVideoElement : false, - history : false, - Int16Array : false, - Int32Array : false, - Int8Array : false, - Image : false, - length : false, - localStorage : false, - location : false, - MessageChannel : false, - MessageEvent : false, - MessagePort : false, - moveBy : false, - moveTo : false, - MutationObserver : false, - name : false, - Node : false, - NodeFilter : false, - navigator : false, - onbeforeunload : true, - onblur : true, - onerror : true, - onfocus : true, - onload : true, - onresize : true, - onunload : true, - open : false, - openDatabase : false, - opener : false, - Option : false, - parent : false, - print : false, - removeEventListener : false, - resizeBy : false, - resizeTo : false, - screen : false, - scroll : false, - scrollBy : false, - scrollTo : false, - sessionStorage : false, - setInterval : false, - setTimeout : false, - SharedWorker : false, - status : false, - SVGAElement : false, - SVGAltGlyphDefElement: false, - SVGAltGlyphElement : false, - SVGAltGlyphItemElement: false, - SVGAngle : false, - SVGAnimateColorElement: false, - SVGAnimateElement : false, - SVGAnimateMotionElement: false, - SVGAnimateTransformElement: false, - SVGAnimatedAngle : false, - SVGAnimatedBoolean : false, - SVGAnimatedEnumeration: false, - SVGAnimatedInteger : false, - SVGAnimatedLength : false, - SVGAnimatedLengthList: false, - SVGAnimatedNumber : false, - SVGAnimatedNumberList: false, - SVGAnimatedPathData : false, - SVGAnimatedPoints : false, - SVGAnimatedPreserveAspectRatio: false, - SVGAnimatedRect : false, - SVGAnimatedString : false, - SVGAnimatedTransformList: false, - SVGAnimationElement : false, - SVGCSSRule : false, - SVGCircleElement : false, - SVGClipPathElement : false, - SVGColor : false, - SVGColorProfileElement: false, - SVGColorProfileRule : false, - SVGComponentTransferFunctionElement: false, - SVGCursorElement : false, - SVGDefsElement : false, - SVGDescElement : false, - SVGDocument : false, - SVGElement : false, - SVGElementInstance : false, - SVGElementInstanceList: false, - SVGEllipseElement : false, - SVGExternalResourcesRequired: false, - SVGFEBlendElement : false, - SVGFEColorMatrixElement: false, - SVGFEComponentTransferElement: false, - SVGFECompositeElement: false, - SVGFEConvolveMatrixElement: false, - SVGFEDiffuseLightingElement: false, - SVGFEDisplacementMapElement: false, - SVGFEDistantLightElement: false, - SVGFEDropShadowElement: false, - SVGFEFloodElement : false, - SVGFEFuncAElement : false, - SVGFEFuncBElement : false, - SVGFEFuncGElement : false, - SVGFEFuncRElement : false, - SVGFEGaussianBlurElement: false, - SVGFEImageElement : false, - SVGFEMergeElement : false, - SVGFEMergeNodeElement: false, - SVGFEMorphologyElement: false, - SVGFEOffsetElement : false, - SVGFEPointLightElement: false, - SVGFESpecularLightingElement: false, - SVGFESpotLightElement: false, - SVGFETileElement : false, - SVGFETurbulenceElement: false, - SVGFilterElement : false, - SVGFilterPrimitiveStandardAttributes: false, - SVGFitToViewBox : false, - SVGFontElement : false, - SVGFontFaceElement : false, - SVGFontFaceFormatElement: false, - SVGFontFaceNameElement: false, - SVGFontFaceSrcElement: false, - SVGFontFaceUriElement: false, - SVGForeignObjectElement: false, - SVGGElement : false, - SVGGlyphElement : false, - SVGGlyphRefElement : false, - SVGGradientElement : false, - SVGHKernElement : false, - SVGICCColor : false, - SVGImageElement : false, - SVGLangSpace : false, - SVGLength : false, - SVGLengthList : false, - SVGLineElement : false, - SVGLinearGradientElement: false, - SVGLocatable : false, - SVGMPathElement : false, - SVGMarkerElement : false, - SVGMaskElement : false, - SVGMatrix : false, - SVGMetadataElement : false, - SVGMissingGlyphElement: false, - SVGNumber : false, - SVGNumberList : false, - SVGPaint : false, - SVGPathElement : false, - SVGPathSeg : false, - SVGPathSegArcAbs : false, - SVGPathSegArcRel : false, - SVGPathSegClosePath : false, - SVGPathSegCurvetoCubicAbs: false, - SVGPathSegCurvetoCubicRel: false, - SVGPathSegCurvetoCubicSmoothAbs: false, - SVGPathSegCurvetoCubicSmoothRel: false, - SVGPathSegCurvetoQuadraticAbs: false, - SVGPathSegCurvetoQuadraticRel: false, - SVGPathSegCurvetoQuadraticSmoothAbs: false, - SVGPathSegCurvetoQuadraticSmoothRel: false, - SVGPathSegLinetoAbs : false, - SVGPathSegLinetoHorizontalAbs: false, - SVGPathSegLinetoHorizontalRel: false, - SVGPathSegLinetoRel : false, - SVGPathSegLinetoVerticalAbs: false, - SVGPathSegLinetoVerticalRel: false, - SVGPathSegList : false, - SVGPathSegMovetoAbs : false, - SVGPathSegMovetoRel : false, - SVGPatternElement : false, - SVGPoint : false, - SVGPointList : false, - SVGPolygonElement : false, - SVGPolylineElement : false, - SVGPreserveAspectRatio: false, - SVGRadialGradientElement: false, - SVGRect : false, - SVGRectElement : false, - SVGRenderingIntent : false, - SVGSVGElement : false, - SVGScriptElement : false, - SVGSetElement : false, - SVGStopElement : false, - SVGStringList : false, - SVGStylable : false, - SVGStyleElement : false, - SVGSwitchElement : false, - SVGSymbolElement : false, - SVGTRefElement : false, - SVGTSpanElement : false, - SVGTests : false, - SVGTextContentElement: false, - SVGTextElement : false, - SVGTextPathElement : false, - SVGTextPositioningElement: false, - SVGTitleElement : false, - SVGTransform : false, - SVGTransformList : false, - SVGTransformable : false, - SVGURIReference : false, - SVGUnitTypes : false, - SVGUseElement : false, - SVGVKernElement : false, - SVGViewElement : false, - SVGViewSpec : false, - SVGZoomAndPan : false, - TimeEvent : false, - top : false, - Uint16Array : false, - Uint32Array : false, - Uint8Array : false, - Uint8ClampedArray : false, - WebSocket : false, - window : false, - Worker : false, - XMLHttpRequest : false, - XMLSerializer : false, - XPathEvaluator : false, - XPathException : false, - XPathExpression : false, - XPathNSResolver : false, - XPathResult : false -}; - -exports.devel = { - alert : false, - confirm: false, - console: false, - Debug : false, - opera : false, - prompt : false -}; - -exports.worker = { - importScripts: true, - postMessage : true, - self : true -}; - -// Widely adopted global names that are not part of ECMAScript standard -exports.nonstandard = { - escape : false, - unescape: false -}; - -// Globals provided by popular JavaScript environments. - -exports.couch = { - "require" : false, - respond : false, - getRow : false, - emit : false, - send : false, - start : false, - sum : false, - log : false, - exports : false, - module : false, - provides : false -}; - -exports.node = { - __filename : false, - __dirname : false, - Buffer : false, - DataView : false, - console : false, - exports : true, // In Node it is ok to exports = module.exports = foo(); - GLOBAL : false, - global : false, - module : false, - process : false, - require : false, - setTimeout : false, - clearTimeout : false, - setInterval : false, - clearInterval : false, - setImmediate : false, // v0.9.1+ - clearImmediate: false // v0.9.1+ -}; - -exports.phantom = { - phantom : true, - require : true, - WebPage : true -}; - -exports.rhino = { - defineClass : false, - deserialize : false, - gc : false, - help : false, - importPackage: false, - "java" : false, - load : false, - loadClass : false, - print : false, - quit : false, - readFile : false, - readUrl : false, - runCommand : false, - seal : false, - serialize : false, - spawn : false, - sync : false, - toint32 : false, - version : false -}; - -exports.wsh = { - ActiveXObject : true, - Enumerator : true, - GetObject : true, - ScriptEngine : true, - ScriptEngineBuildVersion : true, - ScriptEngineMajorVersion : true, - ScriptEngineMinorVersion : true, - VBArray : true, - WSH : true, - WScript : true, - XDomainRequest : true -}; - -// Globals provided by popular JavaScript libraries. - -exports.dojo = { - dojo : false, - dijit : false, - dojox : false, - define : false, - "require": false -}; - -exports.jquery = { - "$" : false, - jQuery : false -}; - -exports.mootools = { - "$" : false, - "$$" : false, - Asset : false, - Browser : false, - Chain : false, - Class : false, - Color : false, - Cookie : false, - Core : false, - Document : false, - DomReady : false, - DOMEvent : false, - DOMReady : false, - Drag : false, - Element : false, - Elements : false, - Event : false, - Events : false, - Fx : false, - Group : false, - Hash : false, - HtmlTable : false, - Iframe : false, - IframeShim : false, - InputValidator: false, - instanceOf : false, - Keyboard : false, - Locale : false, - Mask : false, - MooTools : false, - Native : false, - Options : false, - OverText : false, - Request : false, - Scroller : false, - Slick : false, - Slider : false, - Sortables : false, - Spinner : false, - Swiff : false, - Tips : false, - Type : false, - typeOf : false, - URI : false, - Window : false -}; - -exports.prototypejs = { - "$" : false, - "$$" : false, - "$A" : false, - "$F" : false, - "$H" : false, - "$R" : false, - "$break" : false, - "$continue" : false, - "$w" : false, - Abstract : false, - Ajax : false, - Class : false, - Enumerable : false, - Element : false, - Event : false, - Field : false, - Form : false, - Hash : false, - Insertion : false, - ObjectRange : false, - PeriodicalExecuter: false, - Position : false, - Prototype : false, - Selector : false, - Template : false, - Toggle : false, - Try : false, - Autocompleter : false, - Builder : false, - Control : false, - Draggable : false, - Draggables : false, - Droppables : false, - Effect : false, - Sortable : false, - SortableObserver : false, - Sound : false, - Scriptaculous : false -}; - -exports.yui = { - YUI : false, - Y : false, - YUI_config: false -}; - - -})() -},{}],4:[function(require,module,exports){ -"use strict"; - -var state = { - syntax: {}, - - reset: function () { - this.tokens = { - prev: null, - next: null, - curr: null - }; - - this.option = {}; - this.ignored = {}; - this.directive = {}; - this.jsonMode = false; - this.jsonWarnings = []; - this.lines = []; - this.tab = ""; - this.cache = {}; // Node.JS doesn't have Map. Sniff. - } -}; - -exports.state = state; - -},{}],5:[function(require,module,exports){ -(function(){"use strict"; - -exports.register = function (linter) { - // Check for properties named __proto__. This special property was - // deprecated and then re-introduced for ES6. - - linter.on("Identifier", function style_scanProto(data) { - if (linter.getOption("proto")) { - return; - } - - if (data.name === "__proto__") { - linter.warn("W103", { - line: data.line, - char: data.char, - data: [ data.name ] - }); - } - }); - - // Check for properties named __iterator__. This is a special property - // available only in browsers with JavaScript 1.7 implementation. - - linter.on("Identifier", function style_scanIterator(data) { - if (linter.getOption("iterator")) { - return; - } - - if (data.name === "__iterator__") { - linter.warn("W104", { - line: data.line, - char: data.char, - data: [ data.name ] - }); - } - }); - - // Check for dangling underscores. - - linter.on("Identifier", function style_scanDangling(data) { - if (!linter.getOption("nomen")) { - return; - } - - // Underscore.js - if (data.name === "_") { - return; - } - - // In Node, __dirname and __filename should be ignored. - if (linter.getOption("node")) { - if (/^(__dirname|__filename)$/.test(data.name) && !data.isProperty) { - return; - } - } - - if (/^(_+.*|.*_+)$/.test(data.name)) { - linter.warn("W105", { - line: data.line, - char: data.from, - data: [ "dangling '_'", data.name ] - }); - } - }); - - // Check that all identifiers are using camelCase notation. - // Exceptions: names like MY_VAR and _myVar. - - linter.on("Identifier", function style_scanCamelCase(data) { - if (!linter.getOption("camelcase")) { - return; - } - - if (data.name.replace(/^_+/, "").indexOf("_") > -1 && !data.name.match(/^[A-Z0-9_]*$/)) { - linter.warn("W106", { - line: data.line, - char: data.from, - data: [ data.name ] - }); - } - }); - - // Enforce consistency in style of quoting. - - linter.on("String", function style_scanQuotes(data) { - var quotmark = linter.getOption("quotmark"); - var code; - - if (!quotmark) { - return; - } - - // If quotmark is set to 'single' warn about all double-quotes. - - if (quotmark === "single" && data.quote !== "'") { - code = "W109"; - } - - // If quotmark is set to 'double' warn about all single-quotes. - - if (quotmark === "double" && data.quote !== "\"") { - code = "W108"; - } - - // If quotmark is set to true, remember the first quotation style - // and then warn about all others. - - if (quotmark === true) { - if (!linter.getCache("quotmark")) { - linter.setCache("quotmark", data.quote); - } - - if (linter.getCache("quotmark") !== data.quote) { - code = "W110"; - } - } - - if (code) { - linter.warn(code, { - line: data.line, - char: data.char, - }); - } - }); - - linter.on("Number", function style_scanNumbers(data) { - if (data.value.charAt(0) === ".") { - // Warn about a leading decimal point. - linter.warn("W008", { - line: data.line, - char: data.char, - data: [ data.value ] - }); - } - - if (data.value.substr(data.value.length - 1) === ".") { - // Warn about a trailing decimal point. - linter.warn("W047", { - line: data.line, - char: data.char, - data: [ data.value ] - }); - } - - if (/^00+/.test(data.value)) { - // Multiple leading zeroes. - linter.warn("W046", { - line: data.line, - char: data.char, - data: [ data.value ] - }); - } - }); - - // Warn about script URLs. - - linter.on("String", function style_scanJavaScriptURLs(data) { - var re = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i; - - if (linter.getOption("scripturl")) { - return; - } - - if (re.test(data.value)) { - linter.warn("W107", { - line: data.line, - char: data.char - }); - } - }); -}; -})() -},{}],6:[function(require,module,exports){ -/* - * Regular expressions. Some of these are stupidly long. - */ - -/*jshint maxlen:1000 */ - -"use string"; - -// Unsafe comment or string (ax) -exports.unsafeString = - /@cc|<\/?|script|\]\s*\]|<\s*!|</i; - -// Unsafe characters that are silently deleted by one or more browsers (cx) -exports.unsafeChars = - /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/; - -// Characters in strings that need escaping (nx and nxg) -exports.needEsc = - /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/; - -exports.needEscGlobal = - /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; - -// Star slash (lx) -exports.starSlash = /\*\//; - -// Identifier (ix) -exports.identifier = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/; - -// JavaScript URL (jx) -exports.javascriptURL = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i; - -// Catches /* falls through */ comments (ft) -//exports.fallsThrough = /^\s*\/\*\s*falls?\sthrough\s*\*\/\s*$/; -exports.fallsThrough = /^\s*\/\/\s*Falls?\sthrough.*\s*$/; - -},{}],7:[function(require,module,exports){ -(function(global){/*global window, global*/ -var util = require("util") -var assert = require("assert") - -var slice = Array.prototype.slice -var console -var times = {} - -if (typeof global !== "undefined" && global.console) { - console = global.console -} else if (typeof window !== "undefined" && window.console) { - console = window.console -} else { - console = window.console = {} -} - -var functions = [ - [log, "log"] - , [info, "info"] - , [warn, "warn"] - , [error, "error"] - , [time, "time"] - , [timeEnd, "timeEnd"] - , [trace, "trace"] - , [dir, "dir"] - , [assert, "assert"] -] - -for (var i = 0; i < functions.length; i++) { - var tuple = functions[i] - var f = tuple[0] - var name = tuple[1] - - if (!console[name]) { - console[name] = f - } -} - -module.exports = console - -function log() {} - -function info() { - console.log.apply(console, arguments) -} - -function warn() { - console.log.apply(console, arguments) -} - -function error() { - console.warn.apply(console, arguments) -} - -function time(label) { - times[label] = Date.now() -} - -function timeEnd(label) { - var time = times[label] - if (!time) { - throw new Error("No such label: " + label) - } - - var duration = Date.now() - time - console.log(label + ": " + duration + "ms") -} - -function trace() { - var err = new Error() - err.name = "Trace" - err.message = util.format.apply(null, arguments) - console.error(err.stack) -} - -function dir(object) { - console.log(util.inspect(object) + "\n") -} - -function assert(expression) { - if (!expression) { - var arr = slice.call(arguments, 1) - assert.ok(false, util.format.apply(null, arr)) - } -} - -})(window) -},{"util":8,"assert":9}],10:[function(require,module,exports){ -(function(){/* - * Lexical analysis and token construction. - */ - -"use strict"; - -var _ = require("underscore"); -var events = require("events"); -var reg = require("./reg.js"); -var state = require("./state.js").state; - -// Some of these token types are from JavaScript Parser API -// while others are specific to JSHint parser. -// JS Parser API: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API - -var Token = { - Identifier: 1, - Punctuator: 2, - NumericLiteral: 3, - StringLiteral: 4, - Comment: 5, - Keyword: 6, - NullLiteral: 7, - BooleanLiteral: 8, - RegExp: 9 -}; - -// This is auto generated from the unicode tables. -// The tables are at: -// http://www.fileformat.info/info/unicode/category/Lu/list.htm -// http://www.fileformat.info/info/unicode/category/Ll/list.htm -// http://www.fileformat.info/info/unicode/category/Lt/list.htm -// http://www.fileformat.info/info/unicode/category/Lm/list.htm -// http://www.fileformat.info/info/unicode/category/Lo/list.htm -// http://www.fileformat.info/info/unicode/category/Nl/list.htm - -var unicodeLetterTable = [ - 170, 170, 181, 181, 186, 186, 192, 214, - 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, - 880, 884, 886, 887, 890, 893, 902, 902, 904, 906, 908, 908, - 910, 929, 931, 1013, 1015, 1153, 1162, 1319, 1329, 1366, - 1369, 1369, 1377, 1415, 1488, 1514, 1520, 1522, 1568, 1610, - 1646, 1647, 1649, 1747, 1749, 1749, 1765, 1766, 1774, 1775, - 1786, 1788, 1791, 1791, 1808, 1808, 1810, 1839, 1869, 1957, - 1969, 1969, 1994, 2026, 2036, 2037, 2042, 2042, 2048, 2069, - 2074, 2074, 2084, 2084, 2088, 2088, 2112, 2136, 2308, 2361, - 2365, 2365, 2384, 2384, 2392, 2401, 2417, 2423, 2425, 2431, - 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, - 2486, 2489, 2493, 2493, 2510, 2510, 2524, 2525, 2527, 2529, - 2544, 2545, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, - 2610, 2611, 2613, 2614, 2616, 2617, 2649, 2652, 2654, 2654, - 2674, 2676, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, - 2738, 2739, 2741, 2745, 2749, 2749, 2768, 2768, 2784, 2785, - 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, - 2869, 2873, 2877, 2877, 2908, 2909, 2911, 2913, 2929, 2929, - 2947, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, - 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, - 3024, 3024, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, - 3125, 3129, 3133, 3133, 3160, 3161, 3168, 3169, 3205, 3212, - 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3261, 3261, - 3294, 3294, 3296, 3297, 3313, 3314, 3333, 3340, 3342, 3344, - 3346, 3386, 3389, 3389, 3406, 3406, 3424, 3425, 3450, 3455, - 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, - 3585, 3632, 3634, 3635, 3648, 3654, 3713, 3714, 3716, 3716, - 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, - 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3760, - 3762, 3763, 3773, 3773, 3776, 3780, 3782, 3782, 3804, 3805, - 3840, 3840, 3904, 3911, 3913, 3948, 3976, 3980, 4096, 4138, - 4159, 4159, 4176, 4181, 4186, 4189, 4193, 4193, 4197, 4198, - 4206, 4208, 4213, 4225, 4238, 4238, 4256, 4293, 4304, 4346, - 4348, 4348, 4352, 4680, 4682, 4685, 4688, 4694, 4696, 4696, - 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, - 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, - 4882, 4885, 4888, 4954, 4992, 5007, 5024, 5108, 5121, 5740, - 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5872, 5888, 5900, - 5902, 5905, 5920, 5937, 5952, 5969, 5984, 5996, 5998, 6000, - 6016, 6067, 6103, 6103, 6108, 6108, 6176, 6263, 6272, 6312, - 6314, 6314, 6320, 6389, 6400, 6428, 6480, 6509, 6512, 6516, - 6528, 6571, 6593, 6599, 6656, 6678, 6688, 6740, 6823, 6823, - 6917, 6963, 6981, 6987, 7043, 7072, 7086, 7087, 7104, 7141, - 7168, 7203, 7245, 7247, 7258, 7293, 7401, 7404, 7406, 7409, - 7424, 7615, 7680, 7957, 7960, 7965, 7968, 8005, 8008, 8013, - 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, - 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, - 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, - 8305, 8305, 8319, 8319, 8336, 8348, 8450, 8450, 8455, 8455, - 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, - 8488, 8488, 8490, 8493, 8495, 8505, 8508, 8511, 8517, 8521, - 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, - 11360, 11492, 11499, 11502, 11520, 11557, 11568, 11621, - 11631, 11631, 11648, 11670, 11680, 11686, 11688, 11694, - 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, - 11728, 11734, 11736, 11742, 11823, 11823, 12293, 12295, - 12321, 12329, 12337, 12341, 12344, 12348, 12353, 12438, - 12445, 12447, 12449, 12538, 12540, 12543, 12549, 12589, - 12593, 12686, 12704, 12730, 12784, 12799, 13312, 13312, - 19893, 19893, 19968, 19968, 40907, 40907, 40960, 42124, - 42192, 42237, 42240, 42508, 42512, 42527, 42538, 42539, - 42560, 42606, 42623, 42647, 42656, 42735, 42775, 42783, - 42786, 42888, 42891, 42894, 42896, 42897, 42912, 42921, - 43002, 43009, 43011, 43013, 43015, 43018, 43020, 43042, - 43072, 43123, 43138, 43187, 43250, 43255, 43259, 43259, - 43274, 43301, 43312, 43334, 43360, 43388, 43396, 43442, - 43471, 43471, 43520, 43560, 43584, 43586, 43588, 43595, - 43616, 43638, 43642, 43642, 43648, 43695, 43697, 43697, - 43701, 43702, 43705, 43709, 43712, 43712, 43714, 43714, - 43739, 43741, 43777, 43782, 43785, 43790, 43793, 43798, - 43808, 43814, 43816, 43822, 43968, 44002, 44032, 44032, - 55203, 55203, 55216, 55238, 55243, 55291, 63744, 64045, - 64048, 64109, 64112, 64217, 64256, 64262, 64275, 64279, - 64285, 64285, 64287, 64296, 64298, 64310, 64312, 64316, - 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, - 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, - 65136, 65140, 65142, 65276, 65313, 65338, 65345, 65370, - 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, - 65498, 65500, 65536, 65547, 65549, 65574, 65576, 65594, - 65596, 65597, 65599, 65613, 65616, 65629, 65664, 65786, - 65856, 65908, 66176, 66204, 66208, 66256, 66304, 66334, - 66352, 66378, 66432, 66461, 66464, 66499, 66504, 66511, - 66513, 66517, 66560, 66717, 67584, 67589, 67592, 67592, - 67594, 67637, 67639, 67640, 67644, 67644, 67647, 67669, - 67840, 67861, 67872, 67897, 68096, 68096, 68112, 68115, - 68117, 68119, 68121, 68147, 68192, 68220, 68352, 68405, - 68416, 68437, 68448, 68466, 68608, 68680, 69635, 69687, - 69763, 69807, 73728, 74606, 74752, 74850, 77824, 78894, - 92160, 92728, 110592, 110593, 119808, 119892, 119894, 119964, - 119966, 119967, 119970, 119970, 119973, 119974, 119977, 119980, - 119982, 119993, 119995, 119995, 119997, 120003, 120005, 120069, - 120071, 120074, 120077, 120084, 120086, 120092, 120094, 120121, - 120123, 120126, 120128, 120132, 120134, 120134, 120138, 120144, - 120146, 120485, 120488, 120512, 120514, 120538, 120540, 120570, - 120572, 120596, 120598, 120628, 120630, 120654, 120656, 120686, - 120688, 120712, 120714, 120744, 120746, 120770, 120772, 120779, - 131072, 131072, 173782, 173782, 173824, 173824, 177972, 177972, - 177984, 177984, 178205, 178205, 194560, 195101 -]; - -var identifierStartTable = []; - -for (var i = 0; i < 128; i++) { - identifierStartTable[i] = - i === 36 || // $ - i >= 65 && i <= 90 || // A-Z - i === 95 || // _ - i >= 97 && i <= 122; // a-z -} - -var identifierPartTable = []; - -for (var i = 0; i < 128; i++) { - identifierPartTable[i] = - identifierStartTable[i] || // $, _, A-Z, a-z - i >= 48 && i <= 57; // 0-9 -} - -// Object that handles postponed lexing verifications that checks the parsed -// environment state. - -function asyncTrigger() { - var _checks = []; - - return { - push: function (fn) { - _checks.push(fn); - }, - - check: function () { - for (var check in _checks) { - _checks[check](); - } - - _checks.splice(0, _checks.length); - } - }; -} - -/* - * Lexer for JSHint. - * - * This object does a char-by-char scan of the provided source code - * and produces a sequence of tokens. - * - * var lex = new Lexer("var i = 0;"); - * lex.start(); - * lex.token(); // returns the next token - * - * You have to use the token() method to move the lexer forward - * but you don't have to use its return value to get tokens. In addition - * to token() method returning the next token, the Lexer object also - * emits events. - * - * lex.on("Identifier", function (data) { - * if (data.name.indexOf("_") >= 0) { - * // Produce a warning. - * } - * }); - * - * Note that the token() method returns tokens in a JSLint-compatible - * format while the event emitter uses a slightly modified version of - * Mozilla's JavaScript Parser API. Eventually, we will move away from - * JSLint format. - */ -function Lexer(source) { - var lines = source; - - if (typeof lines === "string") { - lines = lines - .replace(/\r\n/g, "\n") - .replace(/\r/g, "\n") - .split("\n"); - } - - // If the first line is a shebang (#!), make it a blank and move on. - // Shebangs are used by Node scripts. - - if (lines[0] && lines[0].substr(0, 2) === "#!") { - lines[0] = ""; - } - - this.emitter = new events.EventEmitter(); - this.source = source; - this.lines = lines; - this.prereg = true; - - this.line = 0; - this.char = 1; - this.from = 1; - this.input = ""; - - for (var i = 0; i < state.option.indent; i += 1) { - state.tab += " "; - } -} - -Lexer.prototype = { - _lines: [], - - get lines() { - this._lines = state.lines; - return this._lines; - }, - - set lines(val) { - this._lines = val; - state.lines = this._lines; - }, - - /* - * Return the next i character without actually moving the - * char pointer. - */ - peek: function (i) { - return this.input.charAt(i || 0); - }, - - /* - * Move the char pointer forward i times. - */ - skip: function (i) { - i = i || 1; - this.char += i; - this.input = this.input.slice(i); - }, - - /* - * Subscribe to a token event. The API for this method is similar - * Underscore.js i.e. you can subscribe to multiple events with - * one call: - * - * lex.on("Identifier Number", function (data) { - * // ... - * }); - */ - on: function (names, listener) { - names.split(" ").forEach(function (name) { - this.emitter.on(name, listener); - }.bind(this)); - }, - - /* - * Trigger a token event. All arguments will be passed to each - * listener. - */ - trigger: function () { - this.emitter.emit.apply(this.emitter, Array.prototype.slice.call(arguments)); - }, - - /* - * Postpone a token event. the checking condition is set as - * last parameter, and the trigger function is called in a - * stored callback. To be later called using the check() function - * by the parser. This avoids parser's peek() to give the lexer - * a false context. - */ - triggerAsync: function (type, args, checks, fn) { - checks.push(function () { - if (fn()) { - this.trigger(type, args); - } - }.bind(this)); - }, - - /* - * Extract a punctuator out of the next sequence of characters - * or return 'null' if its not possible. - * - * This method's implementation was heavily influenced by the - * scanPunctuator function in the Esprima parser's source code. - */ - scanPunctuator: function () { - var ch1 = this.peek(); - var ch2, ch3, ch4; - - switch (ch1) { - // Most common single-character punctuators - case ".": - if ((/^[0-9]$/).test(this.peek(1))) { - return null; - } - if (this.peek(1) === "." && this.peek(2) === ".") { - return { - type: Token.Punctuator, - value: "..." - }; - } - /* falls through */ - case "(": - case ")": - case ";": - case ",": - case "{": - case "}": - case "[": - case "]": - case ":": - case "~": - case "?": - return { - type: Token.Punctuator, - value: ch1 - }; - - // A pound sign (for Node shebangs) - case "#": - return { - type: Token.Punctuator, - value: ch1 - }; - - // We're at the end of input - case "": - return null; - } - - // Peek more characters - - ch2 = this.peek(1); - ch3 = this.peek(2); - ch4 = this.peek(3); - - // 4-character punctuator: >>>= - - if (ch1 === ">" && ch2 === ">" && ch3 === ">" && ch4 === "=") { - return { - type: Token.Punctuator, - value: ">>>=" - }; - } - - // 3-character punctuators: === !== >>> <<= >>= - - if (ch1 === "=" && ch2 === "=" && ch3 === "=") { - return { - type: Token.Punctuator, - value: "===" - }; - } - - if (ch1 === "!" && ch2 === "=" && ch3 === "=") { - return { - type: Token.Punctuator, - value: "!==" - }; - } - - if (ch1 === ">" && ch2 === ">" && ch3 === ">") { - return { - type: Token.Punctuator, - value: ">>>" - }; - } - - if (ch1 === "<" && ch2 === "<" && ch3 === "=") { - return { - type: Token.Punctuator, - value: "<<=" - }; - } - - if (ch1 === ">" && ch2 === ">" && ch3 === "=") { - return { - type: Token.Punctuator, - value: ">>=" - }; - } - - // Fat arrow punctuator - if (ch1 === "=" && ch2 === ">") { - return { - type: Token.Punctuator, - value: ch1 + ch2 - }; - } - - // 2-character punctuators: <= >= == != ++ -- << >> && || - // += -= *= %= &= |= ^= (but not /=, see below) - if (ch1 === ch2 && ("+-<>&|".indexOf(ch1) >= 0)) { - return { - type: Token.Punctuator, - value: ch1 + ch2 - }; - } - - if ("<>=!+-*%&|^".indexOf(ch1) >= 0) { - if (ch2 === "=") { - return { - type: Token.Punctuator, - value: ch1 + ch2 - }; - } - - return { - type: Token.Punctuator, - value: ch1 - }; - } - - // Special case: /=. We need to make sure that this is an - // operator and not a regular expression. - - if (ch1 === "/") { - if (ch2 === "=" && /\/=(?!(\S*\/[gim]?))/.test(this.input)) { - // /= is not a part of a regular expression, return it as a - // punctuator. - return { - type: Token.Punctuator, - value: "/=" - }; - } - - return { - type: Token.Punctuator, - value: "/" - }; - } - - return null; - }, - - /* - * Extract a comment out of the next sequence of characters and/or - * lines or return 'null' if its not possible. Since comments can - * span across multiple lines this method has to move the char - * pointer. - * - * In addition to normal JavaScript comments (// and /*) this method - * also recognizes JSHint- and JSLint-specific comments such as - * /*jshint, /*jslint, /*globals and so on. - */ - scanComments: function () { - var ch1 = this.peek(); - var ch2 = this.peek(1); - var rest = this.input.substr(2); - var startLine = this.line; - var startChar = this.char; - - // Create a comment token object and make sure it - // has all the data JSHint needs to work with special - // comments. - - function commentToken(label, body, opt) { - var special = ["jshint", "jslint", "members", "member", "globals", "global", "exported"]; - var isSpecial = false; - var value = label + body; - var commentType = "plain"; - opt = opt || {}; - - if (opt.isMultiline) { - value += "*/"; - } - - special.forEach(function (str) { - if (isSpecial) { - return; - } - - // Don't recognize any special comments other than jshint for single-line - // comments. This introduced many problems with legit comments. - if (label === "//" && str !== "jshint") { - return; - } - - if (body.substr(0, str.length) === str) { - isSpecial = true; - label = label + str; - body = body.substr(str.length); - } - - if (!isSpecial && body.charAt(0) === " " && body.substr(1, str.length) === str) { - isSpecial = true; - label = label + " " + str; - body = body.substr(str.length + 1); - } - - if (!isSpecial) { - return; - } - - switch (str) { - case "member": - commentType = "members"; - break; - case "global": - commentType = "globals"; - break; - default: - commentType = str; - } - }); - - return { - type: Token.Comment, - commentType: commentType, - value: value, - body: body, - isSpecial: isSpecial, - isMultiline: opt.isMultiline || false, - isMalformed: opt.isMalformed || false - }; - } - - // End of unbegun comment. Raise an error and skip that input. - if (ch1 === "*" && ch2 === "/") { - this.trigger("error", { - code: "E018", - line: startLine, - character: startChar - }); - - this.skip(2); - return null; - } - - // Comments must start either with // or /* - if (ch1 !== "/" || (ch2 !== "*" && ch2 !== "/")) { - return null; - } - - // One-line comment - if (ch2 === "/") { - this.skip(this.input.length); // Skip to the EOL. - return commentToken("//", rest); - } - - var body = ""; - - /* Multi-line comment */ - if (ch2 === "*") { - this.skip(2); - - while (this.peek() !== "*" || this.peek(1) !== "/") { - if (this.peek() === "") { // End of Line - body += "\n"; - - // If we hit EOF and our comment is still unclosed, - // trigger an error and end the comment implicitly. - if (!this.nextLine()) { - this.trigger("error", { - code: "E017", - line: startLine, - character: startChar - }); - - return commentToken("/*", body, { - isMultiline: true, - isMalformed: true - }); - } - } else { - body += this.peek(); - this.skip(); - } - } - - this.skip(2); - return commentToken("/*", body, { isMultiline: true }); - } - }, - - /* - * Extract a keyword out of the next sequence of characters or - * return 'null' if its not possible. - */ - scanKeyword: function () { - var result = /^[a-zA-Z_$][a-zA-Z0-9_$]*/.exec(this.input); - var keywords = [ - "if", "in", "do", "var", "for", "new", - "try", "let", "this", "else", "case", - "void", "with", "enum", "while", "break", - "catch", "throw", "const", "yield", "class", - "super", "return", "typeof", "delete", - "switch", "export", "import", "default", - "finally", "extends", "function", "continue", - "debugger", "instanceof" - ]; - - if (result && keywords.indexOf(result[0]) >= 0) { - return { - type: Token.Keyword, - value: result[0] - }; - } - - return null; - }, - - /* - * Extract a JavaScript identifier out of the next sequence of - * characters or return 'null' if its not possible. In addition, - * to Identifier this method can also produce BooleanLiteral - * (true/false) and NullLiteral (null). - */ - scanIdentifier: function () { - var id = ""; - var index = 0; - var type, char; - - // Detects any character in the Unicode categories "Uppercase - // letter (Lu)", "Lowercase letter (Ll)", "Titlecase letter - // (Lt)", "Modifier letter (Lm)", "Other letter (Lo)", or - // "Letter number (Nl)". - // - // Both approach and unicodeLetterTable were borrowed from - // Google's Traceur. - - function isUnicodeLetter(code) { - for (var i = 0; i < unicodeLetterTable.length;) { - if (code < unicodeLetterTable[i++]) { - return false; - } - - if (code <= unicodeLetterTable[i++]) { - return true; - } - } - - return false; - } - - function isHexDigit(str) { - return (/^[0-9a-fA-F]$/).test(str); - } - - var readUnicodeEscapeSequence = function () { - /*jshint validthis:true */ - index += 1; - - if (this.peek(index) !== "u") { - return null; - } - - var ch1 = this.peek(index + 1); - var ch2 = this.peek(index + 2); - var ch3 = this.peek(index + 3); - var ch4 = this.peek(index + 4); - var code; - - if (isHexDigit(ch1) && isHexDigit(ch2) && isHexDigit(ch3) && isHexDigit(ch4)) { - code = parseInt(ch1 + ch2 + ch3 + ch4, 16); - - if (isUnicodeLetter(code)) { - index += 5; - return "\\u" + ch1 + ch2 + ch3 + ch4; - } - - return null; - } - - return null; - }.bind(this); - - var getIdentifierStart = function () { - /*jshint validthis:true */ - var chr = this.peek(index); - var code = chr.charCodeAt(0); - - if (code === 92) { - return readUnicodeEscapeSequence(); - } - - if (code < 128) { - if (identifierStartTable[code]) { - index += 1; - return chr; - } - - return null; - } - - if (isUnicodeLetter(code)) { - index += 1; - return chr; - } - - return null; - }.bind(this); - - var getIdentifierPart = function () { - /*jshint validthis:true */ - var chr = this.peek(index); - var code = chr.charCodeAt(0); - - if (code === 92) { - return readUnicodeEscapeSequence(); - } - - if (code < 128) { - if (identifierPartTable[code]) { - index += 1; - return chr; - } - - return null; - } - - if (isUnicodeLetter(code)) { - index += 1; - return chr; - } - - return null; - }.bind(this); - - char = getIdentifierStart(); - if (char === null) { - return null; - } - - id = char; - for (;;) { - char = getIdentifierPart(); - - if (char === null) { - break; - } - - id += char; - } - - switch (id) { - case "true": - case "false": - type = Token.BooleanLiteral; - break; - case "null": - type = Token.NullLiteral; - break; - default: - type = Token.Identifier; - } - - return { - type: type, - value: id - }; - }, - - /* - * Extract a numeric literal out of the next sequence of - * characters or return 'null' if its not possible. This method - * supports all numeric literals described in section 7.8.3 - * of the EcmaScript 5 specification. - * - * This method's implementation was heavily influenced by the - * scanNumericLiteral function in the Esprima parser's source code. - */ - scanNumericLiteral: function () { - var index = 0; - var value = ""; - var length = this.input.length; - var char = this.peek(index); - var bad; - - function isDecimalDigit(str) { - return (/^[0-9]$/).test(str); - } - - function isOctalDigit(str) { - return (/^[0-7]$/).test(str); - } - - function isHexDigit(str) { - return (/^[0-9a-fA-F]$/).test(str); - } - - function isIdentifierStart(ch) { - return (ch === "$") || (ch === "_") || (ch === "\\") || - (ch >= "a" && ch <= "z") || (ch >= "A" && ch <= "Z"); - } - - // Numbers must start either with a decimal digit or a point. - - if (char !== "." && !isDecimalDigit(char)) { - return null; - } - - if (char !== ".") { - value = this.peek(index); - index += 1; - char = this.peek(index); - - if (value === "0") { - // Base-16 numbers. - if (char === "x" || char === "X") { - index += 1; - value += char; - - while (index < length) { - char = this.peek(index); - if (!isHexDigit(char)) { - break; - } - value += char; - index += 1; - } - - if (value.length <= 2) { // 0x - return { - type: Token.NumericLiteral, - value: value, - isMalformed: true - }; - } - - if (index < length) { - char = this.peek(index); - if (isIdentifierStart(char)) { - return null; - } - } - - return { - type: Token.NumericLiteral, - value: value, - base: 16, - isMalformed: false - }; - } - - // Base-8 numbers. - if (isOctalDigit(char)) { - index += 1; - value += char; - bad = false; - - while (index < length) { - char = this.peek(index); - - // Numbers like '019' (note the 9) are not valid octals - // but we still parse them and mark as malformed. - - if (isDecimalDigit(char)) { - bad = true; - } else if (!isOctalDigit(char)) { - break; - } - value += char; - index += 1; - } - - if (index < length) { - char = this.peek(index); - if (isIdentifierStart(char)) { - return null; - } - } - - return { - type: Token.NumericLiteral, - value: value, - base: 8, - isMalformed: false - }; - } - - // Decimal numbers that start with '0' such as '09' are illegal - // but we still parse them and return as malformed. - - if (isDecimalDigit(char)) { - index += 1; - value += char; - } - } - - while (index < length) { - char = this.peek(index); - if (!isDecimalDigit(char)) { - break; - } - value += char; - index += 1; - } - } - - // Decimal digits. - - if (char === ".") { - value += char; - index += 1; - - while (index < length) { - char = this.peek(index); - if (!isDecimalDigit(char)) { - break; - } - value += char; - index += 1; - } - } - - // Exponent part. - - if (char === "e" || char === "E") { - value += char; - index += 1; - char = this.peek(index); - - if (char === "+" || char === "-") { - value += this.peek(index); - index += 1; - } - - char = this.peek(index); - if (isDecimalDigit(char)) { - value += char; - index += 1; - - while (index < length) { - char = this.peek(index); - if (!isDecimalDigit(char)) { - break; - } - value += char; - index += 1; - } - } else { - return null; - } - } - - if (index < length) { - char = this.peek(index); - if (isIdentifierStart(char)) { - return null; - } - } - - return { - type: Token.NumericLiteral, - value: value, - base: 10, - isMalformed: !isFinite(value) - }; - }, - - /* - * Extract a string out of the next sequence of characters and/or - * lines or return 'null' if its not possible. Since strings can - * span across multiple lines this method has to move the char - * pointer. - * - * This method recognizes pseudo-multiline JavaScript strings: - * - * var str = "hello\ - * world"; - */ - scanStringLiteral: function (checks) { - /*jshint loopfunc:true */ - var quote = this.peek(); - - // String must start with a quote. - if (quote !== "\"" && quote !== "'") { - return null; - } - - // In JSON strings must always use double quotes. - this.triggerAsync("warning", { - code: "W108", - line: this.line, - character: this.char // +1? - }, checks, function () { return state.jsonMode && quote !== "\""; }); - - var value = ""; - var startLine = this.line; - var startChar = this.char; - var allowNewLine = false; - - this.skip(); - - while (this.peek() !== quote) { - while (this.peek() === "") { // End Of Line - - // If an EOL is not preceded by a backslash, show a warning - // and proceed like it was a legit multi-line string where - // author simply forgot to escape the newline symbol. - // - // Another approach is to implicitly close a string on EOL - // but it generates too many false positives. - - if (!allowNewLine) { - this.trigger("warning", { - code: "W112", - line: this.line, - character: this.char - }); - } else { - allowNewLine = false; - - // Otherwise show a warning if multistr option was not set. - // For JSON, show warning no matter what. - - this.triggerAsync("warning", { - code: "W043", - line: this.line, - character: this.char - }, checks, function () { return !state.option.multistr; }); - - this.triggerAsync("warning", { - code: "W042", - line: this.line, - character: this.char - }, checks, function () { return state.jsonMode && state.option.multistr; }); - } - - // If we get an EOF inside of an unclosed string, show an - // error and implicitly close it at the EOF point. - - if (!this.nextLine()) { - this.trigger("error", { - code: "E029", - line: startLine, - character: startChar - }); - - return { - type: Token.StringLiteral, - value: value, - isUnclosed: true, - quote: quote - }; - } - } - - allowNewLine = false; - var char = this.peek(); - var jump = 1; // A length of a jump, after we're done - // parsing this character. - - if (char < " ") { - // Warn about a control character in a string. - this.trigger("warning", { - code: "W113", - line: this.line, - character: this.char, - data: [ "<non-printable>" ] - }); - } - - // Special treatment for some escaped characters. - - if (char === "\\") { - this.skip(); - char = this.peek(); - - switch (char) { - case "'": - this.triggerAsync("warning", { - code: "W114", - line: this.line, - character: this.char, - data: [ "\\'" ] - }, checks, function () {return state.jsonMode; }); - break; - case "b": - char = "\b"; - break; - case "f": - char = "\f"; - break; - case "n": - char = "\n"; - break; - case "r": - char = "\r"; - break; - case "t": - char = "\t"; - break; - case "0": - char = "\0"; - - // Octal literals fail in strict mode. - // Check if the number is between 00 and 07. - var n = parseInt(this.peek(1), 10); - this.triggerAsync("warning", { - code: "W115", - line: this.line, - character: this.char - }, checks, - function () { return n >= 0 && n <= 7 && state.directive["use strict"]; }); - break; - case "u": - char = String.fromCharCode(parseInt(this.input.substr(1, 4), 16)); - jump = 5; - break; - case "v": - this.triggerAsync("warning", { - code: "W114", - line: this.line, - character: this.char, - data: [ "\\v" ] - }, checks, function () { return state.jsonMode; }); - - char = "\v"; - break; - case "x": - var x = parseInt(this.input.substr(1, 2), 16); - - this.triggerAsync("warning", { - code: "W114", - line: this.line, - character: this.char, - data: [ "\\x-" ] - }, checks, function () { return state.jsonMode; }); - - char = String.fromCharCode(x); - jump = 3; - break; - case "\\": - case "\"": - case "/": - break; - case "": - allowNewLine = true; - char = ""; - break; - case "!": - if (value.slice(value.length - 2) === "<") { - break; - } - - /*falls through */ - default: - // Weird escaping. - this.trigger("warning", { - code: "W044", - line: this.line, - character: this.char - }); - } - } - - value += char; - this.skip(jump); - } - - this.skip(); - return { - type: Token.StringLiteral, - value: value, - isUnclosed: false, - quote: quote - }; - }, - - /* - * Extract a regular expression out of the next sequence of - * characters and/or lines or return 'null' if its not possible. - * - * This method is platform dependent: it accepts almost any - * regular expression values but then tries to compile and run - * them using system's RegExp object. This means that there are - * rare edge cases where one JavaScript engine complains about - * your regular expression while others don't. - */ - scanRegExp: function () { - var index = 0; - var length = this.input.length; - var char = this.peek(); - var value = char; - var body = ""; - var flags = []; - var malformed = false; - var isCharSet = false; - var terminated; - - var scanUnexpectedChars = function () { - // Unexpected control character - if (char < " ") { - malformed = true; - this.trigger("warning", { - code: "W048", - line: this.line, - character: this.char - }); - } - - // Unexpected escaped character - if (char === "<") { - malformed = true; - this.trigger("warning", { - code: "W049", - line: this.line, - character: this.char, - data: [ char ] - }); - } - }.bind(this); - - // Regular expressions must start with '/' - if (!this.prereg || char !== "/") { - return null; - } - - index += 1; - terminated = false; - - // Try to get everything in between slashes. A couple of - // cases aside (see scanUnexpectedChars) we don't really - // care whether the resulting expression is valid or not. - // We will check that later using the RegExp object. - - while (index < length) { - char = this.peek(index); - value += char; - body += char; - - if (isCharSet) { - if (char === "]") { - if (this.peek(index - 1) !== "\\" || this.peek(index - 2) === "\\") { - isCharSet = false; - } - } - - if (char === "\\") { - index += 1; - char = this.peek(index); - body += char; - value += char; - - scanUnexpectedChars(); - } - - index += 1; - continue; - } - - if (char === "\\") { - index += 1; - char = this.peek(index); - body += char; - value += char; - - scanUnexpectedChars(); - - if (char === "/") { - index += 1; - continue; - } - - if (char === "[") { - index += 1; - continue; - } - } - - if (char === "[") { - isCharSet = true; - index += 1; - continue; - } - - if (char === "/") { - body = body.substr(0, body.length - 1); - terminated = true; - index += 1; - break; - } - - index += 1; - } - - // A regular expression that was never closed is an - // error from which we cannot recover. - - if (!terminated) { - this.trigger("error", { - code: "E015", - line: this.line, - character: this.from - }); - - return void this.trigger("fatal", { - line: this.line, - from: this.from - }); - } - - // Parse flags (if any). - - while (index < length) { - char = this.peek(index); - if (!/[gim]/.test(char)) { - break; - } - flags.push(char); - value += char; - index += 1; - } - - // Check regular expression for correctness. - - try { - new RegExp(body, flags.join("")); - } catch (err) { - malformed = true; - this.trigger("error", { - code: "E016", - line: this.line, - character: this.char, - data: [ err.message ] // Platform dependent! - }); - } - - return { - type: Token.RegExp, - value: value, - flags: flags, - isMalformed: malformed - }; - }, - - /* - * Scan for any occurence of mixed tabs and spaces. If smarttabs option - * is on, ignore tabs followed by spaces. - * - * Tabs followed by one space followed by a block comment are allowed. - */ - scanMixedSpacesAndTabs: function () { - var at, match; - - if (state.option.smarttabs) { - // Negative look-behind for "//" - match = this.input.match(/(\/\/|^\s?\*)? \t/); - at = match && !match[1] ? 0 : -1; - } else { - at = this.input.search(/ \t|\t [^\*]/); - } - - return at; - }, - - /* - * Scan for characters that get silently deleted by one or more browsers. - */ - scanUnsafeChars: function () { - return this.input.search(reg.unsafeChars); - }, - - /* - * Produce the next raw token or return 'null' if no tokens can be matched. - * This method skips over all space characters. - */ - next: function (checks) { - this.from = this.char; - - // Move to the next non-space character. - var start; - if (/\s/.test(this.peek())) { - start = this.char; - - while (/\s/.test(this.peek())) { - this.from += 1; - this.skip(); - } - - if (this.peek() === "") { // EOL - if (!/^\s*$/.test(this.lines[this.line - 1]) && state.option.trailing) { - this.trigger("warning", { code: "W102", line: this.line, character: start }); - } - } - } - - // Methods that work with multi-line structures and move the - // character pointer. - - var match = this.scanComments() || - this.scanStringLiteral(checks); - - if (match) { - return match; - } - - // Methods that don't move the character pointer. - - match = - this.scanRegExp() || - this.scanPunctuator() || - this.scanKeyword() || - this.scanIdentifier() || - this.scanNumericLiteral(); - - if (match) { - this.skip(match.value.length); - return match; - } - - // No token could be matched, give up. - - return null; - }, - - /* - * Switch to the next line and reset all char pointers. Once - * switched, this method also checks for mixed spaces and tabs - * and other minor warnings. - */ - nextLine: function () { - var char; - - if (this.line >= this.lines.length) { - return false; - } - - this.input = this.lines[this.line]; - this.line += 1; - this.char = 1; - this.from = 1; - - char = this.scanMixedSpacesAndTabs(); - if (char >= 0) { - this.trigger("warning", { code: "W099", line: this.line, character: char + 1 }); - } - - this.input = this.input.replace(/\t/g, state.tab); - char = this.scanUnsafeChars(); - - if (char >= 0) { - this.trigger("warning", { code: "W100", line: this.line, character: char }); - } - - // If there is a limit on line length, warn when lines get too - // long. - - if (state.option.maxlen && state.option.maxlen < this.input.length) { - this.trigger("warning", { code: "W101", line: this.line, character: this.input.length }); - } - - return true; - }, - - /* - * This is simply a synonym for nextLine() method with a friendlier - * public name. - */ - start: function () { - this.nextLine(); - }, - - /* - * Produce the next token. This function is called by advance() to get - * the next token. It retuns a token in a JSLint-compatible format. - */ - token: function () { - /*jshint loopfunc:true */ - var checks = asyncTrigger(); - var token; - - - function isReserved(token, isProperty) { - if (!token.reserved) { - return false; - } - - if (token.meta && token.meta.isFutureReservedWord) { - // ES3 FutureReservedWord in an ES5 environment. - if (state.option.inES5(true) && !token.meta.es5) { - return false; - } - - // Some ES5 FutureReservedWord identifiers are active only - // within a strict mode environment. - if (token.meta.strictOnly) { - if (!state.option.strict && !state.directive["use strict"]) { - return false; - } - } - - if (isProperty) { - return false; - } - } - - return true; - } - - // Produce a token object. - var create = function (type, value, isProperty) { - /*jshint validthis:true */ - var obj; - - if (type !== "(endline)" && type !== "(end)") { - this.prereg = false; - } - - if (type === "(punctuator)") { - switch (value) { - case ".": - case ")": - case "~": - case "#": - case "]": - this.prereg = false; - break; - default: - this.prereg = true; - } - - obj = Object.create(state.syntax[value] || state.syntax["(error)"]); - } - - if (type === "(identifier)") { - if (value === "return" || value === "case" || value === "typeof") { - this.prereg = true; - } - - if (_.has(state.syntax, value)) { - obj = Object.create(state.syntax[value] || state.syntax["(error)"]); - - // If this can't be a reserved keyword, reset the object. - if (!isReserved(obj, isProperty && type === "(identifier)")) { - obj = null; - } - } - } - - if (!obj) { - obj = Object.create(state.syntax[type]); - } - - obj.identifier = (type === "(identifier)"); - obj.type = obj.type || type; - obj.value = value; - obj.line = this.line; - obj.character = this.char; - obj.from = this.from; - - if (isProperty && obj.identifier) { - obj.isProperty = isProperty; - } - - obj.check = checks.check; - - return obj; - }.bind(this); - - for (;;) { - if (!this.input.length) { - return create(this.nextLine() ? "(endline)" : "(end)", ""); - } - - token = this.next(checks); - - if (!token) { - if (this.input.length) { - // Unexpected character. - this.trigger("error", { - code: "E024", - line: this.line, - character: this.char, - data: [ this.peek() ] - }); - - this.input = ""; - } - - continue; - } - - switch (token.type) { - case Token.StringLiteral: - this.triggerAsync("String", { - line: this.line, - char: this.char, - from: this.from, - value: token.value, - quote: token.quote - }, checks, function () { return true; }); - - return create("(string)", token.value); - case Token.Identifier: - this.trigger("Identifier", { - line: this.line, - char: this.char, - from: this.form, - name: token.value, - isProperty: state.tokens.curr.id === "." - }); - - /* falls through */ - case Token.Keyword: - case Token.NullLiteral: - case Token.BooleanLiteral: - return create("(identifier)", token.value, state.tokens.curr.id === "."); - - case Token.NumericLiteral: - if (token.isMalformed) { - this.trigger("warning", { - code: "W045", - line: this.line, - character: this.char, - data: [ token.value ] - }); - } - - this.triggerAsync("warning", { - code: "W114", - line: this.line, - character: this.char, - data: [ "0x-" ] - }, checks, function () { return token.base === 16 && state.jsonMode; }); - - this.triggerAsync("warning", { - code: "W115", - line: this.line, - character: this.char - }, checks, function () { - return state.directive["use strict"] && token.base === 8; - }); - - this.trigger("Number", { - line: this.line, - char: this.char, - from: this.from, - value: token.value, - base: token.base, - isMalformed: token.malformed - }); - - return create("(number)", token.value); - - case Token.RegExp: - return create("(regexp)", token.value); - - case Token.Comment: - state.tokens.curr.comment = true; - - if (token.isSpecial) { - return { - value: token.value, - body: token.body, - type: token.commentType, - isSpecial: token.isSpecial, - line: this.line, - character: this.char, - from: this.from - }; - } - - break; - - case "": - break; - - default: - return create("(punctuator)", token.value); - } - } - } -}; - -exports.Lexer = Lexer; - -})() -},{"events":2,"./reg.js":6,"./state.js":4,"underscore":11}],"jshint":[function(require,module,exports){ -module.exports=require('E/GbHF'); -},{}],"E/GbHF":[function(require,module,exports){ -(function(){/*! - * JSHint, by JSHint Community. - * - * This file (and this file only) is licensed under the same slightly modified - * MIT license that JSLint is. It stops evil-doers everywhere: - * - * Copyright (c) 2002 Douglas Crockford (www.JSLint.com) - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom - * the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * The Software shall be used for Good, not Evil. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - */ - -/*jshint quotmark:double */ -/*global console:true */ -/*exported console */ - -var _ = require("underscore"); -var events = require("events"); -var vars = require("../shared/vars.js"); -var messages = require("../shared/messages.js"); -var Lexer = require("./lex.js").Lexer; -var reg = require("./reg.js"); -var state = require("./state.js").state; -var style = require("./style.js"); - -// We need this module here because environments such as IE and Rhino -// don't necessarilly expose the 'console' API and browserify uses -// it to log things. It's a sad state of affair, really. -var console = require("console-browserify"); - -// We build the application inside a function so that we produce only a singleton -// variable. That function will be invoked immediately, and its return value is -// the JSHINT function itself. - -var JSHINT = (function () { - "use strict"; - - var anonname, // The guessed name for anonymous functions. - api, // Extension API - - // These are operators that should not be used with the ! operator. - bang = { - "<" : true, - "<=" : true, - "==" : true, - "===": true, - "!==": true, - "!=" : true, - ">" : true, - ">=" : true, - "+" : true, - "-" : true, - "*" : true, - "/" : true, - "%" : true - }, - - // These are the JSHint boolean options. - boolOptions = { - asi : true, // if automatic semicolon insertion should be tolerated - bitwise : true, // if bitwise operators should not be allowed - boss : true, // if advanced usage of assignments should be allowed - browser : true, // if the standard browser globals should be predefined - camelcase : true, // if identifiers should be required in camel case - couch : true, // if CouchDB globals should be predefined - curly : true, // if curly braces around all blocks should be required - debug : true, // if debugger statements should be allowed - devel : true, // if logging globals should be predefined (console, alert, etc.) - dojo : true, // if Dojo Toolkit globals should be predefined - eqeqeq : true, // if === should be required - eqnull : true, // if == null comparisons should be tolerated - es3 : true, // if ES3 syntax should be allowed - es5 : true, // if ES5 syntax should be allowed (is now set per default) - esnext : true, // if es.next specific syntax should be allowed - moz : true, // if mozilla specific syntax should be allowed - evil : true, // if eval should be allowed - expr : true, // if ExpressionStatement should be allowed as Programs - forin : true, // if for in statements must filter - funcscope : true, // if only function scope should be used for scope tests - gcl : true, // if JSHint should be compatible with Google Closure Linter - globalstrict: true, // if global "use strict"; should be allowed (also enables 'strict') - immed : true, // if immediate invocations must be wrapped in parens - iterator : true, // if the `__iterator__` property should be allowed - jquery : true, // if jQuery globals should be predefined - lastsemic : true, // if semicolons may be ommitted for the trailing - // statements inside of a one-line blocks. - laxbreak : true, // if line breaks should not be checked - laxcomma : true, // if line breaks should not be checked around commas - loopfunc : true, // if functions should be allowed to be defined within - // loops - mootools : true, // if MooTools globals should be predefined - multistr : true, // allow multiline strings - newcap : true, // if constructor names must be capitalized - noarg : true, // if arguments.caller and arguments.callee should be - // disallowed - node : true, // if the Node.js environment globals should be - // predefined - noempty : true, // if empty blocks should be disallowed - nonew : true, // if using `new` for side-effects should be disallowed - nonstandard : true, // if non-standard (but widely adopted) globals should - // be predefined - nomen : true, // if names should be checked - onevar : true, // if only one var statement per function should be - // allowed - passfail : true, // if the scan should stop on first error - phantom : true, // if PhantomJS symbols should be allowed - plusplus : true, // if increment/decrement should not be allowed - proto : true, // if the `__proto__` property should be allowed - prototypejs : true, // if Prototype and Scriptaculous globals should be - // predefined - rhino : true, // if the Rhino environment globals should be predefined - undef : true, // if variables should be declared before used - scripturl : true, // if script-targeted URLs should be tolerated - shadow : true, // if variable shadowing should be tolerated - smarttabs : true, // if smarttabs should be tolerated - // (http://www.emacswiki.org/emacs/SmartTabs) - strict : true, // require the "use strict"; pragma - sub : true, // if all forms of subscript notation are tolerated - supernew : true, // if `new function () { ... };` and `new Object;` - // should be tolerated - trailing : true, // if trailing whitespace rules apply - validthis : true, // if 'this' inside a non-constructor function is valid. - // This is a function scoped option only. - withstmt : true, // if with statements should be allowed - white : true, // if strict whitespace rules apply - worker : true, // if Web Worker script symbols should be allowed - wsh : true, // if the Windows Scripting Host environment globals - // should be predefined - yui : true, // YUI variables should be predefined - - // Obsolete options - onecase : true, // if one case switch statements should be allowed - regexp : true, // if the . should not be allowed in regexp literals - regexdash : true // if unescaped first/last dash (-) inside brackets - // should be tolerated - }, - - // These are the JSHint options that can take any value - // (we use this object to detect invalid options) - valOptions = { - maxlen : false, - indent : false, - maxerr : false, - predef : false, - quotmark : false, //'single'|'double'|true - scope : false, - maxstatements: false, // {int} max statements per function - maxdepth : false, // {int} max nested block depth per function - maxparams : false, // {int} max params per function - maxcomplexity: false, // {int} max cyclomatic complexity per function - unused : true, // warn if variables are unused. Available options: - // false - don't check for unused variables - // true - "vars" + check last function param - // "vars" - skip checking unused function params - // "strict" - "vars" + check all function params - latedef : false // warn if the variable is used before its definition - // false - don't emit any warnings - // true - warn if any variable is used before its definition - // "nofunc" - warn for any variable but function declarations - }, - - // These are JSHint boolean options which are shared with JSLint - // where the definition in JSHint is opposite JSLint - invertedOptions = { - bitwise : true, - forin : true, - newcap : true, - nomen : true, - plusplus: true, - regexp : true, - undef : true, - white : true, - - // Inverted and renamed, use JSHint name here - eqeqeq : true, - onevar : true, - strict : true - }, - - // These are JSHint boolean options which are shared with JSLint - // where the name has been changed but the effect is unchanged - renamedOptions = { - eqeq : "eqeqeq", - vars : "onevar", - windows: "wsh", - sloppy : "strict" - }, - - declared, // Globals that were declared using /*global ... */ syntax. - exported, // Variables that are used outside of the current file. - - functionicity = [ - "closure", "exception", "global", "label", - "outer", "unused", "var" - ], - - funct, // The current function - functions, // All of the functions - - global, // The global scope - implied, // Implied globals - inblock, - indent, - lookahead, - lex, - member, - membersOnly, - noreach, - predefined, // Global variables defined by option - - scope, // The current scope - stack, - unuseds, - urls, - warnings, - - extraModules = [], - emitter = new events.EventEmitter(); - - function checkOption(name, t) { - name = name.trim(); - - if (/^[+-]W\d{3}$/g.test(name)) { - return true; - } - - if (valOptions[name] === undefined && boolOptions[name] === undefined) { - if (t.type !== "jslint") { - error("E001", t, name); - return false; - } - } - - return true; - } - - function isString(obj) { - return Object.prototype.toString.call(obj) === "[object String]"; - } - - function isIdentifier(tkn, value) { - if (!tkn) - return false; - - if (!tkn.identifier || tkn.value !== value) - return false; - - return true; - } - - function isReserved(token) { - if (!token.reserved) { - return false; - } - - if (token.meta && token.meta.isFutureReservedWord) { - // ES3 FutureReservedWord in an ES5 environment. - if (state.option.inES5(true) && !token.meta.es5) { - return false; - } - - // Some ES5 FutureReservedWord identifiers are active only - // within a strict mode environment. - if (token.meta.strictOnly) { - if (!state.option.strict && !state.directive["use strict"]) { - return false; - } - } - - if (token.isProperty) { - return false; - } - } - - return true; - } - - function supplant(str, data) { - return str.replace(/\{([^{}]*)\}/g, function (a, b) { - var r = data[b]; - return typeof r === "string" || typeof r === "number" ? r : a; - }); - } - - function combine(t, o) { - var n; - for (n in o) { - if (_.has(o, n) && !_.has(JSHINT.blacklist, n)) { - t[n] = o[n]; - } - } - } - - function updatePredefined() { - Object.keys(JSHINT.blacklist).forEach(function (key) { - delete predefined[key]; - }); - } - - function assume() { - if (state.option.es5) { - warning("I003"); - } - if (state.option.couch) { - combine(predefined, vars.couch); - } - - if (state.option.rhino) { - combine(predefined, vars.rhino); - } - - if (state.option.phantom) { - combine(predefined, vars.phantom); - } - - if (state.option.prototypejs) { - combine(predefined, vars.prototypejs); - } - - if (state.option.node) { - combine(predefined, vars.node); - } - - if (state.option.devel) { - combine(predefined, vars.devel); - } - - if (state.option.dojo) { - combine(predefined, vars.dojo); - } - - if (state.option.browser) { - combine(predefined, vars.browser); - } - - if (state.option.nonstandard) { - combine(predefined, vars.nonstandard); - } - - if (state.option.jquery) { - combine(predefined, vars.jquery); - } - - if (state.option.mootools) { - combine(predefined, vars.mootools); - } - - if (state.option.worker) { - combine(predefined, vars.worker); - } - - if (state.option.wsh) { - combine(predefined, vars.wsh); - } - - if (state.option.globalstrict && state.option.strict !== false) { - state.option.strict = true; - } - - if (state.option.yui) { - combine(predefined, vars.yui); - } - - // Let's assume that chronologically ES3 < ES5 < ES6/ESNext < Moz - - state.option.inMoz = function (strict) { - if (strict) { - return state.option.moz && !state.option.esnext; - } - return state.option.moz; - }; - - state.option.inESNext = function (strict) { - if (strict) { - return !state.option.moz && state.option.esnext; - } - return state.option.moz || state.option.esnext; - }; - - state.option.inES5 = function (/* strict */) { - return !state.option.es3; - }; - - state.option.inES3 = function (strict) { - if (strict) { - return !state.option.moz && !state.option.esnext && state.option.es3; - } - return state.option.es3; - }; - } - - // Produce an error warning. - function quit(code, line, chr) { - var percentage = Math.floor((line / state.lines.length) * 100); - var message = messages.errors[code].desc; - - throw { - name: "JSHintError", - line: line, - character: chr, - message: message + " (" + percentage + "% scanned).", - raw: message - }; - } - - function isundef(scope, code, token, a) { - return JSHINT.undefs.push([scope, code, token, a]); - } - - function warning(code, t, a, b, c, d) { - var ch, l, w, msg; - - if (/^W\d{3}$/.test(code)) { - if (state.ignored[code]) - return; - - msg = messages.warnings[code]; - } else if (/E\d{3}/.test(code)) { - msg = messages.errors[code]; - } else if (/I\d{3}/.test(code)) { - msg = messages.info[code]; - } - - t = t || state.tokens.next; - if (t.id === "(end)") { // `~ - t = state.tokens.curr; - } - - l = t.line || 0; - ch = t.from || 0; - - w = { - id: "(error)", - raw: msg.desc, - code: msg.code, - evidence: state.lines[l - 1] || "", - line: l, - character: ch, - scope: JSHINT.scope, - a: a, - b: b, - c: c, - d: d - }; - - w.reason = supplant(msg.desc, w); - JSHINT.errors.push(w); - - if (state.option.passfail) { - quit("E042", l, ch); - } - - warnings += 1; - if (warnings >= state.option.maxerr) { - quit("E043", l, ch); - } - - return w; - } - - function warningAt(m, l, ch, a, b, c, d) { - return warning(m, { - line: l, - from: ch - }, a, b, c, d); - } - - function error(m, t, a, b, c, d) { - warning(m, t, a, b, c, d); - } - - function errorAt(m, l, ch, a, b, c, d) { - return error(m, { - line: l, - from: ch - }, a, b, c, d); - } - - // Tracking of "internal" scripts, like eval containing a static string - function addInternalSrc(elem, src) { - var i; - i = { - id: "(internal)", - elem: elem, - value: src - }; - JSHINT.internals.push(i); - return i; - } - - function addlabel(t, type, tkn, islet) { - // Define t in the current function in the current scope. - if (type === "exception") { - if (_.has(funct["(context)"], t)) { - if (funct[t] !== true && !state.option.node) { - warning("W002", state.tokens.next, t); - } - } - } - - if (_.has(funct, t) && !funct["(global)"]) { - if (funct[t] === true) { - if (state.option.latedef) { - if ((state.option.latedef === true && _.contains([funct[t], type], "unction")) || - !_.contains([funct[t], type], "unction")) { - warning("W003", state.tokens.next, t); - } - } - } else { - if (!state.option.shadow && type !== "exception" || - (funct["(blockscope)"].getlabel(t))) { - warning("W004", state.tokens.next, t); - } - } - } - - // a double definition of a let variable in same block throws a TypeError - //if (funct["(blockscope)"] && funct["(blockscope)"].current.has(t)) { - // error("E044", state.tokens.next, t); - //} - - // if the identifier is from a let, adds it only to the current blockscope - if (islet) { - funct["(blockscope)"].current.add(t, type, state.tokens.curr); - } else { - - funct[t] = type; - - if (tkn) { - funct["(tokens)"][t] = tkn; - } - - if (funct["(global)"]) { - global[t] = funct; - if (_.has(implied, t)) { - if (state.option.latedef) { - if ((state.option.latedef === true && _.contains([funct[t], type], "unction")) || - !_.contains([funct[t], type], "unction")) { - warning("W003", state.tokens.next, t); - } - } - - delete implied[t]; - } - } else { - scope[t] = funct; - } - } - } - - function doOption() { - var nt = state.tokens.next; - var body = nt.body.split(",").map(function (s) { return s.trim(); }); - var predef = {}; - - if (nt.type === "globals") { - body.forEach(function (g) { - g = g.split(":"); - var key = g[0]; - var val = g[1]; - - if (key.charAt(0) === "-") { - key = key.slice(1); - val = false; - - JSHINT.blacklist[key] = key; - updatePredefined(); - } else { - predef[key] = (val === "true"); - } - }); - - combine(predefined, predef); - - for (var key in predef) { - if (_.has(predef, key)) { - declared[key] = nt; - } - } - } - - if (nt.type === "exported") { - body.forEach(function (e) { - exported[e] = true; - }); - } - - if (nt.type === "members") { - membersOnly = membersOnly || {}; - - body.forEach(function (m) { - var ch1 = m.charAt(0); - var ch2 = m.charAt(m.length - 1); - - if (ch1 === ch2 && (ch1 === "\"" || ch1 === "'")) { - m = m - .substr(1, m.length - 2) - .replace("\\b", "\b") - .replace("\\t", "\t") - .replace("\\n", "\n") - .replace("\\v", "\v") - .replace("\\f", "\f") - .replace("\\r", "\r") - .replace("\\\\", "\\") - .replace("\\\"", "\""); - } - - membersOnly[m] = false; - }); - } - - var numvals = [ - "maxstatements", - "maxparams", - "maxdepth", - "maxcomplexity", - "maxerr", - "maxlen", - "indent" - ]; - - if (nt.type === "jshint" || nt.type === "jslint") { - body.forEach(function (g) { - g = g.split(":"); - var key = (g[0] || "").trim(); - var val = (g[1] || "").trim(); - - if (!checkOption(key, nt)) { - return; - } - - if (numvals.indexOf(key) >= 0) { - - // GH988 - numeric options can be disabled by setting them to `false` - if (val !== "false") { - val = +val; - - if (typeof val !== "number" || !isFinite(val) || val <= 0 || Math.floor(val) !== val) { - error("E032", nt, g[1].trim()); - return; - } - - if (key === "indent") { - state.option["(explicitIndent)"] = true; - } - state.option[key] = val; - } else { - if (key === "indent") { - state.option["(explicitIndent)"] = false; - } else { - state.option[key] = false; - } - } - - return; - } - - if (key === "validthis") { - // `validthis` is valid only within a function scope. - if (funct["(global)"]) { - error("E009"); - } else { - if (val === "true" || val === "false") { - state.option.validthis = (val === "true"); - } else { - error("E002", nt); - } - } - return; - } - - if (key === "quotmark") { - switch (val) { - case "true": - case "false": - state.option.quotmark = (val === "true"); - break; - case "double": - case "single": - state.option.quotmark = val; - break; - default: - error("E002", nt); - } - return; - } - - if (key === "unused") { - switch (val) { - case "true": - state.option.unused = true; - break; - case "false": - state.option.unused = false; - break; - case "vars": - case "strict": - state.option.unused = val; - break; - default: - error("E002", nt); - } - return; - } - - if (key === "latedef") { - switch (val) { - case "true": - state.option.latedef = true; - break; - case "false": - state.option.latedef = false; - break; - case "nofunc": - state.option.latedef = "nofunc"; - break; - default: - error("E002", nt); - } - return; - } - - var match = /^([+-])(W\d{3})$/g.exec(key); - if (match) { - // ignore for -W..., unignore for +W... - state.ignored[match[2]] = (match[1] === "-"); - return; - } - - var tn; - if (val === "true" || val === "false") { - if (nt.type === "jslint") { - tn = renamedOptions[key] || key; - state.option[tn] = (val === "true"); - - if (invertedOptions[tn] !== undefined) { - state.option[tn] = !state.option[tn]; - } - } else { - state.option[key] = (val === "true"); - } - - if (key === "newcap") { - state.option["(explicitNewcap)"] = true; - } - return; - } - - error("E002", nt); - }); - - assume(); - } - } - - // We need a peek function. If it has an argument, it peeks that much farther - // ahead. It is used to distinguish - // for ( var i in ... - // from - // for ( var i = ... - - function peek(p) { - var i = p || 0, j = 0, t; - - while (j <= i) { - t = lookahead[j]; - if (!t) { - t = lookahead[j] = lex.token(); - } - j += 1; - } - return t; - } - - // Produce the next token. It looks for programming errors. - - function advance(id, t) { - switch (state.tokens.curr.id) { - case "(number)": - if (state.tokens.next.id === ".") { - warning("W005", state.tokens.curr); - } - break; - case "-": - if (state.tokens.next.id === "-" || state.tokens.next.id === "--") { - warning("W006"); - } - break; - case "+": - if (state.tokens.next.id === "+" || state.tokens.next.id === "++") { - warning("W007"); - } - break; - } - - if (state.tokens.curr.type === "(string)" || state.tokens.curr.identifier) { - anonname = state.tokens.curr.value; - } - - if (id && state.tokens.next.id !== id) { - if (t) { - if (state.tokens.next.id === "(end)") { - error("E019", t, t.id); - } else { - error("E020", state.tokens.next, id, t.id, t.line, state.tokens.next.value); - } - } else if (state.tokens.next.type !== "(identifier)" || state.tokens.next.value !== id) { - warning("W116", state.tokens.next, id, state.tokens.next.value); - } - } - - state.tokens.prev = state.tokens.curr; - state.tokens.curr = state.tokens.next; - for (;;) { - state.tokens.next = lookahead.shift() || lex.token(); - - if (!state.tokens.next) { // No more tokens left, give up - quit("E041", state.tokens.curr.line); - } - - if (state.tokens.next.id === "(end)" || state.tokens.next.id === "(error)") { - return; - } - - if (state.tokens.next.check) { - state.tokens.next.check(); - } - - if (state.tokens.next.isSpecial) { - doOption(); - } else { - if (state.tokens.next.id !== "(endline)") { - break; - } - } - } - } - - // This is the heart of JSHINT, the Pratt parser. In addition to parsing, it - // is looking for ad hoc lint patterns. We add .fud to Pratt's model, which is - // like .nud except that it is only used on the first token of a statement. - // Having .fud makes it much easier to define statement-oriented languages like - // JavaScript. I retained Pratt's nomenclature. - - // .nud Null denotation - // .fud First null denotation - // .led Left denotation - // lbp Left binding power - // rbp Right binding power - - // They are elements of the parsing method called Top Down Operator Precedence. - - function expression(rbp, initial) { - var left, isArray = false, isObject = false, isLetExpr = false; - - // if current expression is a let expression - if (!initial && state.tokens.next.value === "let" && peek(0).value === "(") { - if (!state.option.inMoz(true)) { - warning("W118", state.tokens.next, "let expressions"); - } - isLetExpr = true; - // create a new block scope we use only for the current expression - funct["(blockscope)"].stack(); - advance("let"); - advance("("); - state.syntax["let"].fud.call(state.syntax["let"].fud, false); - advance(")"); - } - - if (state.tokens.next.id === "(end)") - error("E006", state.tokens.curr); - - advance(); - - if (initial) { - anonname = "anonymous"; - funct["(verb)"] = state.tokens.curr.value; - } - - if (initial === true && state.tokens.curr.fud) { - left = state.tokens.curr.fud(); - } else { - if (state.tokens.curr.nud) { - left = state.tokens.curr.nud(); - } else { - error("E030", state.tokens.curr, state.tokens.curr.id); - } - - var end_of_expr = state.tokens.next.identifier && - !state.tokens.curr.led && - state.tokens.curr.line !== state.tokens.next.line; - while (rbp < state.tokens.next.lbp && !end_of_expr) { - isArray = state.tokens.curr.value === "Array"; - isObject = state.tokens.curr.value === "Object"; - - // #527, new Foo.Array(), Foo.Array(), new Foo.Object(), Foo.Object() - // Line breaks in IfStatement heads exist to satisfy the checkJSHint - // "Line too long." error. - if (left && (left.value || (left.first && left.first.value))) { - // If the left.value is not "new", or the left.first.value is a "." - // then safely assume that this is not "new Array()" and possibly - // not "new Object()"... - if (left.value !== "new" || - (left.first && left.first.value && left.first.value === ".")) { - isArray = false; - // ...In the case of Object, if the left.value and state.tokens.curr.value - // are not equal, then safely assume that this not "new Object()" - if (left.value !== state.tokens.curr.value) { - isObject = false; - } - } - } - - advance(); - - if (isArray && state.tokens.curr.id === "(" && state.tokens.next.id === ")") { - warning("W009", state.tokens.curr); - } - - if (isObject && state.tokens.curr.id === "(" && state.tokens.next.id === ")") { - warning("W010", state.tokens.curr); - } - - if (left && state.tokens.curr.led) { - left = state.tokens.curr.led(left); - } else { - error("E033", state.tokens.curr, state.tokens.curr.id); - } - } - } - if (isLetExpr) { - funct["(blockscope)"].unstack(); - } - return left; - } - - -// Functions for conformance of style. - - function adjacent(left, right) { - left = left || state.tokens.curr; - right = right || state.tokens.next; - if (state.option.white) { - if (left.character !== right.from && left.line === right.line) { - left.from += (left.character - left.from); - warning("W011", left, left.value); - } - } - } - - function nobreak(left, right) { - left = left || state.tokens.curr; - right = right || state.tokens.next; - if (state.option.white && (left.character !== right.from || left.line !== right.line)) { - warning("W012", right, right.value); - } - } - - function nospace(left, right) { - left = left || state.tokens.curr; - right = right || state.tokens.next; - if (state.option.white && !left.comment) { - if (left.line === right.line) { - adjacent(left, right); - } - } - } - - function nonadjacent(left, right) { - if (state.option.white) { - left = left || state.tokens.curr; - right = right || state.tokens.next; - - if (left.value === ";" && right.value === ";") { - return; - } - - if (left.line === right.line && left.character === right.from) { - left.from += (left.character - left.from); - warning("W013", left, left.value); - } - } - } - - function nobreaknonadjacent(left, right) { - left = left || state.tokens.curr; - right = right || state.tokens.next; - if (!state.option.laxbreak && left.line !== right.line) { - warning("W014", right, right.id); - } else if (state.option.white) { - left = left || state.tokens.curr; - right = right || state.tokens.next; - if (left.character === right.from) { - left.from += (left.character - left.from); - warning("W013", left, left.value); - } - } - } - - function indentation(bias) { - if (!state.option.white && !state.option["(explicitIndent)"]) { - return; - } - - if (state.tokens.next.id === "(end)") { - return; - } - - var i = indent + (bias || 0); - if (state.tokens.next.from !== i) { - warning("W015", state.tokens.next, state.tokens.next.value, i, state.tokens.next.from); - } - } - - function nolinebreak(t) { - t = t || state.tokens.curr; - if (t.line !== state.tokens.next.line) { - warning("E022", t, t.value); - } - } - - - function comma(opts) { - opts = opts || {}; - - if (!opts.peek) { - if (state.tokens.curr.line !== state.tokens.next.line) { - if (!state.option.laxcomma) { - if (comma.first) { - warning("I001"); - comma.first = false; - } - warning("W014", state.tokens.curr, state.tokens.next.value); - } - } else if (!state.tokens.curr.comment && - state.tokens.curr.character !== state.tokens.next.from && state.option.white) { - state.tokens.curr.from += (state.tokens.curr.character - state.tokens.curr.from); - warning("W011", state.tokens.curr, state.tokens.curr.value); - } - - advance(","); - } - - // TODO: This is a temporary solution to fight against false-positives in - // arrays and objects with trailing commas (see GH-363). The best solution - // would be to extract all whitespace rules out of parser. - - if (state.tokens.next.value !== "]" && state.tokens.next.value !== "}") { - nonadjacent(state.tokens.curr, state.tokens.next); - } - - if (state.tokens.next.identifier && !(opts.property && state.option.inES5())) { - // Keywords that cannot follow a comma operator. - switch (state.tokens.next.value) { - case "break": - case "case": - case "catch": - case "continue": - case "default": - case "do": - case "else": - case "finally": - case "for": - case "if": - case "in": - case "instanceof": - case "return": - case "yield": - case "switch": - case "throw": - case "try": - case "var": - case "let": - case "while": - case "with": - error("E024", state.tokens.next, state.tokens.next.value); - return false; - } - } - - if (state.tokens.next.type === "(punctuator)") { - switch (state.tokens.next.value) { - case "}": - case "]": - case ",": - if (opts.allowTrailing) { - return true; - } - - /* falls through */ - case ")": - error("E024", state.tokens.next, state.tokens.next.value); - return false; - } - } - return true; - } - - // Functional constructors for making the symbols that will be inherited by - // tokens. - - function symbol(s, p) { - var x = state.syntax[s]; - if (!x || typeof x !== "object") { - state.syntax[s] = x = { - id: s, - lbp: p, - value: s - }; - } - return x; - } - - function delim(s) { - return symbol(s, 0); - } - - function stmt(s, f) { - var x = delim(s); - x.identifier = x.reserved = true; - x.fud = f; - return x; - } - - function blockstmt(s, f) { - var x = stmt(s, f); - x.block = true; - return x; - } - - function reserveName(x) { - var c = x.id.charAt(0); - if ((c >= "a" && c <= "z") || (c >= "A" && c <= "Z")) { - x.identifier = x.reserved = true; - } - return x; - } - - function prefix(s, f) { - var x = symbol(s, 150); - reserveName(x); - x.nud = (typeof f === "function") ? f : function () { - this.right = expression(150); - this.arity = "unary"; - if (this.id === "++" || this.id === "--") { - if (state.option.plusplus) { - warning("W016", this, this.id); - } else if ((!this.right.identifier || isReserved(this.right)) && - this.right.id !== "." && this.right.id !== "[") { - warning("W017", this); - } - } - return this; - }; - return x; - } - - function type(s, f) { - var x = delim(s); - x.type = s; - x.nud = f; - return x; - } - - function reserve(name, func) { - var x = type(name, func); - x.identifier = true; - x.reserved = true; - return x; - } - - function FutureReservedWord(name, meta) { - var x = type(name, (meta && meta.nud) || function () { - return this; - }); - - meta = meta || {}; - meta.isFutureReservedWord = true; - - x.value = name; - x.identifier = true; - x.reserved = true; - x.meta = meta; - - return x; - } - - function reservevar(s, v) { - return reserve(s, function () { - if (typeof v === "function") { - v(this); - } - return this; - }); - } - - function infix(s, f, p, w) { - var x = symbol(s, p); - reserveName(x); - x.led = function (left) { - if (!w) { - nobreaknonadjacent(state.tokens.prev, state.tokens.curr); - nonadjacent(state.tokens.curr, state.tokens.next); - } - if (s === "in" && left.id === "!") { - warning("W018", left, "!"); - } - if (typeof f === "function") { - return f(left, this); - } else { - this.left = left; - this.right = expression(p); - return this; - } - }; - return x; - } - - - function application(s) { - var x = symbol(s, 42); - - x.led = function (left) { - if (!state.option.inESNext()) { - warning("W104", state.tokens.curr, "arrow function syntax (=>)"); - } - - nobreaknonadjacent(state.tokens.prev, state.tokens.curr); - nonadjacent(state.tokens.curr, state.tokens.next); - - this.left = left; - this.right = doFunction(undefined, undefined, false, left); - return this; - }; - return x; - } - - function relation(s, f) { - var x = symbol(s, 100); - - x.led = function (left) { - nobreaknonadjacent(state.tokens.prev, state.tokens.curr); - nonadjacent(state.tokens.curr, state.tokens.next); - var right = expression(100); - - if (isIdentifier(left, "NaN") || isIdentifier(right, "NaN")) { - warning("W019", this); - } else if (f) { - f.apply(this, [left, right]); - } - - if (!left || !right) { - quit("E041", state.tokens.curr.line); - } - - if (left.id === "!") { - warning("W018", left, "!"); - } - - if (right.id === "!") { - warning("W018", right, "!"); - } - - this.left = left; - this.right = right; - return this; - }; - return x; - } - - function isPoorRelation(node) { - return node && - ((node.type === "(number)" && +node.value === 0) || - (node.type === "(string)" && node.value === "") || - (node.type === "null" && !state.option.eqnull) || - node.type === "true" || - node.type === "false" || - node.type === "undefined"); - } - - function assignop(s) { - symbol(s, 20).exps = true; - - return infix(s, function (left, that) { - that.left = left; - - if (left) { - if (predefined[left.value] === false && - scope[left.value]["(global)"] === true) { - warning("W020", left); - } else if (left["function"]) { - warning("W021", left, left.value); - } - - if (funct[left.value] === "const") { - error("E013", left, left.value); - } - - if (left.id === ".") { - if (!left.left) { - warning("E031", that); - } else if (left.left.value === "arguments" && !state.directive["use strict"]) { - warning("E031", that); - } - - that.right = expression(19); - return that; - } else if (left.id === "[") { - if (state.tokens.curr.left.first) { - state.tokens.curr.left.first.forEach(function (t) { - if (funct[t.value] === "const") { - error("E013", t, t.value); - } - }); - } else if (!left.left) { - warning("E031", that); - } else if (left.left.value === "arguments" && !state.directive["use strict"]) { - warning("E031", that); - } - that.right = expression(19); - return that; - } else if (left.identifier && !isReserved(left)) { - if (funct[left.value] === "exception") { - warning("W022", left); - } - that.right = expression(19); - return that; - } - - if (left === state.syntax["function"]) { - warning("W023", state.tokens.curr); - } - } - - error("E031", that); - }, 20); - } - - - function bitwise(s, f, p) { - var x = symbol(s, p); - reserveName(x); - x.led = (typeof f === "function") ? f : function (left) { - if (state.option.bitwise) { - warning("W016", this, this.id); - } - this.left = left; - this.right = expression(p); - return this; - }; - return x; - } - - - function bitwiseassignop(s) { - symbol(s, 20).exps = true; - return infix(s, function (left, that) { - if (state.option.bitwise) { - warning("W016", that, that.id); - } - nonadjacent(state.tokens.prev, state.tokens.curr); - nonadjacent(state.tokens.curr, state.tokens.next); - if (left) { - if (left.id === "." || left.id === "[" || - (left.identifier && !isReserved(left))) { - expression(19); - return that; - } - if (left === state.syntax["function"]) { - warning("W023", state.tokens.curr); - } - return that; - } - error("E031", that); - }, 20); - } - - - function suffix(s) { - var x = symbol(s, 150); - - x.led = function (left) { - if (state.option.plusplus) { - warning("W016", this, this.id); - } else if ((!left.identifier || isReserved(left)) && left.id !== "." && left.id !== "[") { - warning("W017", this); - } - - this.left = left; - return this; - }; - return x; - } - - // fnparam means that this identifier is being defined as a function - // argument (see identifier()) - // prop means that this identifier is that of an object property - - function optionalidentifier(fnparam, prop) { - if (!state.tokens.next.identifier) { - return; - } - - advance(); - - var curr = state.tokens.curr; - var meta = curr.meta || {}; - var val = state.tokens.curr.value; - - if (!isReserved(curr)) { - return val; - } - - if (prop) { - if (state.option.inES5() || meta.isFutureReservedWord) { - return val; - } - } - - if (fnparam && val === "undefined") { - return val; - } - - // Display an info message about reserved words as properties - // and ES5 but do it only once. - if (prop && !api.getCache("displayed:I002")) { - api.setCache("displayed:I002", true); - warning("I002"); - } - - warning("W024", state.tokens.curr, state.tokens.curr.id); - return val; - } - - // fnparam means that this identifier is being defined as a function - // argument - // prop means that this identifier is that of an object property - function identifier(fnparam, prop) { - var i = optionalidentifier(fnparam, prop); - if (i) { - return i; - } - if (state.tokens.curr.id === "function" && state.tokens.next.id === "(") { - warning("W025"); - } else { - error("E030", state.tokens.next, state.tokens.next.value); - } - } - - - function reachable(s) { - var i = 0, t; - if (state.tokens.next.id !== ";" || noreach) { - return; - } - for (;;) { - t = peek(i); - if (t.reach) { - return; - } - if (t.id !== "(endline)") { - if (t.id === "function") { - if (!state.option.latedef) { - break; - } - - warning("W026", t); - break; - } - - warning("W027", t, t.value, s); - break; - } - i += 1; - } - } - - - function statement(noindent) { - var values; - var i = indent, r, s = scope, t = state.tokens.next; - - if (t.id === ";") { - advance(";"); - return; - } - - // Is this a labelled statement? - var res = isReserved(t); - - // We're being more tolerant here: if someone uses - // a FutureReservedWord as a label, we warn but proceed - // anyway. - - if (res && t.meta && t.meta.isFutureReservedWord && peek().id === ":") { - warning("W024", t, t.id); - res = false; - } - - // detect a destructuring assignment - if (_.has(["[", "{"], t.value)) { - if (lookupBlockType().isDestAssign) { - if (!state.option.inESNext()) { - warning("W104", state.tokens.curr, "destructuring expression"); - } - values = destructuringExpression(); - values.forEach(function (tok) { - isundef(funct, "W117", tok.token, tok.id); - }); - advance("="); - destructuringExpressionMatch(values, expression(5, true)); - advance(";"); - return; - } - } - if (t.identifier && !res && peek().id === ":") { - advance(); - advance(":"); - scope = Object.create(s); - addlabel(t.value, "label"); - - if (!state.tokens.next.labelled && state.tokens.next.value !== "{") { - warning("W028", state.tokens.next, t.value, state.tokens.next.value); - } - - state.tokens.next.label = t.value; - t = state.tokens.next; - } - - // Is it a lonely block? - - if (t.id === "{") { - // Is it a switch case block? - // - // switch (foo) { - // case bar: { <= here. - // ... - // } - // } - var iscase = (funct["(verb)"] === "case" && state.tokens.curr.value === ":"); - block(true, true, false, false, iscase); - return; - } - - // Parse the statement. - - if (!noindent) { - indentation(); - } - r = expression(0, true); - - // Look for the final semicolon. - - if (!t.block) { - if (!state.option.expr && (!r || !r.exps)) { - warning("W030", state.tokens.curr); - } else if (state.option.nonew && r && r.left && r.id === "(" && r.left.id === "new") { - warning("W031", t); - } - - if (state.tokens.next.id !== ";") { - if (!state.option.asi) { - // If this is the last statement in a block that ends on - // the same line *and* option lastsemic is on, ignore the warning. - // Otherwise, complain about missing semicolon. - if (!state.option.lastsemic || state.tokens.next.id !== "}" || - state.tokens.next.line !== state.tokens.curr.line) { - warningAt("W033", state.tokens.curr.line, state.tokens.curr.character); - } - } - } else { - adjacent(state.tokens.curr, state.tokens.next); - advance(";"); - nonadjacent(state.tokens.curr, state.tokens.next); - } - } - - // Restore the indentation. - - indent = i; - scope = s; - return r; - } - - - function statements(startLine) { - var a = [], p; - - while (!state.tokens.next.reach && state.tokens.next.id !== "(end)") { - if (state.tokens.next.id === ";") { - p = peek(); - - if (!p || (p.id !== "(" && p.id !== "[")) { - warning("W032"); - } - - advance(";"); - } else { - a.push(statement(startLine === state.tokens.next.line)); - } - } - return a; - } - - - /* - * read all directives - * recognizes a simple form of asi, but always - * warns, if it is used - */ - function directives() { - var i, p, pn; - - for (;;) { - if (state.tokens.next.id === "(string)") { - p = peek(0); - if (p.id === "(endline)") { - i = 1; - do { - pn = peek(i); - i = i + 1; - } while (pn.id === "(endline)"); - - if (pn.id !== ";") { - if (pn.id !== "(string)" && pn.id !== "(number)" && - pn.id !== "(regexp)" && pn.identifier !== true && - pn.id !== "}") { - break; - } - warning("W033", state.tokens.next); - } else { - p = pn; - } - } else if (p.id === "}") { - // Directive with no other statements, warn about missing semicolon - warning("W033", p); - } else if (p.id !== ";") { - break; - } - - indentation(); - advance(); - if (state.directive[state.tokens.curr.value]) { - warning("W034", state.tokens.curr, state.tokens.curr.value); - } - - if (state.tokens.curr.value === "use strict") { - if (!state.option["(explicitNewcap)"]) - state.option.newcap = true; - state.option.undef = true; - } - - // there's no directive negation, so always set to true - state.directive[state.tokens.curr.value] = true; - - if (p.id === ";") { - advance(";"); - } - continue; - } - break; - } - } - - - /* - * Parses a single block. A block is a sequence of statements wrapped in - * braces. - * - * ordinary - true for everything but function bodies and try blocks. - * stmt - true if block can be a single statement (e.g. in if/for/while). - * isfunc - true if block is a function body - * isfatarrow - - * iscase - true if block is a switch case block - */ - function block(ordinary, stmt, isfunc, isfatarrow, iscase) { - var a, - b = inblock, - old_indent = indent, - m, - s = scope, - t, - line, - d; - - inblock = ordinary; - - if (!ordinary || !state.option.funcscope) - scope = Object.create(scope); - - nonadjacent(state.tokens.curr, state.tokens.next); - t = state.tokens.next; - - var metrics = funct["(metrics)"]; - metrics.nestedBlockDepth += 1; - metrics.verifyMaxNestedBlockDepthPerFunction(); - - if (state.tokens.next.id === "{") { - advance("{"); - - // create a new block scope - funct["(blockscope)"].stack(); - - line = state.tokens.curr.line; - if (state.tokens.next.id !== "}") { - indent += state.option.indent; - while (!ordinary && state.tokens.next.from > indent) { - indent += state.option.indent; - } - - if (isfunc) { - m = {}; - for (d in state.directive) { - if (_.has(state.directive, d)) { - m[d] = state.directive[d]; - } - } - directives(); - - if (state.option.strict && funct["(context)"]["(global)"]) { - if (!m["use strict"] && !state.directive["use strict"]) { - warning("E007"); - } - } - } - - a = statements(line); - - metrics.statementCount += a.length; - - if (isfunc) { - state.directive = m; - } - - indent -= state.option.indent; - if (line !== state.tokens.next.line) { - indentation(); - } - } else if (line !== state.tokens.next.line) { - indentation(); - } - advance("}", t); - - funct["(blockscope)"].unstack(); - - indent = old_indent; - } else if (!ordinary) { - if (isfunc) { - m = {}; - if (stmt && !isfatarrow && !state.option.inMoz(true)) { - error("W118", state.tokens.curr, "function closure expressions"); - } - - if (!stmt) { - for (d in state.directive) { - if (_.has(state.directive, d)) { - m[d] = state.directive[d]; - } - } - } - expression(5); - - if (state.option.strict && funct["(context)"]["(global)"]) { - if (!m["use strict"] && !state.directive["use strict"]) { - warning("E007"); - } - } - } else { - error("E021", state.tokens.next, "{", state.tokens.next.value); - } - } else { - - // check to avoid let declaration not within a block - funct["(nolet)"] = true; - - if (!stmt || state.option.curly) { - warning("W116", state.tokens.next, "{", state.tokens.next.value); - } - - noreach = true; - indent += state.option.indent; - // test indentation only if statement is in new line - a = [statement(state.tokens.next.line === state.tokens.curr.line)]; - indent -= state.option.indent; - noreach = false; - - delete funct["(nolet)"]; - } - // If it is a "break" in switch case, don't clear and let it propagate out. - if (!(iscase && funct["(verb)"] === "break")) funct["(verb)"] = null; - - if (!ordinary || !state.option.funcscope) scope = s; - inblock = b; - if (ordinary && state.option.noempty && (!a || a.length === 0)) { - warning("W035"); - } - metrics.nestedBlockDepth -= 1; - return a; - } - - - function countMember(m) { - if (membersOnly && typeof membersOnly[m] !== "boolean") { - warning("W036", state.tokens.curr, m); - } - if (typeof member[m] === "number") { - member[m] += 1; - } else { - member[m] = 1; - } - } - - - function note_implied(tkn) { - var name = tkn.value, line = tkn.line, a = implied[name]; - if (typeof a === "function") { - a = false; - } - - if (!a) { - a = [line]; - implied[name] = a; - } else if (a[a.length - 1] !== line) { - a.push(line); - } - } - - - // Build the syntax table by declaring the syntactic elements of the language. - - type("(number)", function () { - return this; - }); - - type("(string)", function () { - return this; - }); - - state.syntax["(identifier)"] = { - type: "(identifier)", - lbp: 0, - identifier: true, - nud: function () { - var v = this.value, - s = scope[v], - f; - - if (typeof s === "function") { - // Protection against accidental inheritance. - s = undefined; - } else if (typeof s === "boolean") { - f = funct; - funct = functions[0]; - addlabel(v, "var"); - s = funct; - funct = f; - } - var block; - if (_.has(funct, "(blockscope)")) { - block = funct["(blockscope)"].getlabel(v); - } - - // The name is in scope and defined in the current function. - if (funct === s || block) { - // Change 'unused' to 'var', and reject labels. - // the name is in a block scope - switch (block ? block[v]["(type)"] : funct[v]) { - case "unused": - if (block) block[v]["(type)"] = "var"; - else funct[v] = "var"; - break; - case "unction": - if (block) block[v]["(type)"] = "function"; - else funct[v] = "function"; - this["function"] = true; - break; - case "function": - this["function"] = true; - break; - case "label": - warning("W037", state.tokens.curr, v); - break; - } - } else if (funct["(global)"]) { - // The name is not defined in the function. If we are in the global - // scope, then we have an undefined variable. - // - // Operators typeof and delete do not raise runtime errors even if - // the base object of a reference is null so no need to display warning - // if we're inside of typeof or delete. - - if (typeof predefined[v] !== "boolean") { - // Attempting to subscript a null reference will throw an - // error, even within the typeof and delete operators - if (!(anonname === "typeof" || anonname === "delete") || - (state.tokens.next && (state.tokens.next.value === "." || - state.tokens.next.value === "["))) { - - // if we're in a list comprehension, variables are declared - // locally and used before being defined. So we check - // the presence of the given variable in the comp array - // before declaring it undefined. - - if (!funct["(comparray)"].check(v)) { - isundef(funct, "W117", state.tokens.curr, v); - } - } - } - - note_implied(state.tokens.curr); - } else { - // If the name is already defined in the current - // function, but not as outer, then there is a scope error. - - switch (funct[v]) { - case "closure": - case "function": - case "var": - case "unused": - warning("W038", state.tokens.curr, v); - break; - case "label": - warning("W037", state.tokens.curr, v); - break; - case "outer": - case "global": - break; - default: - // If the name is defined in an outer function, make an outer entry, - // and if it was unused, make it var. - if (s === true) { - funct[v] = true; - } else if (s === null) { - warning("W039", state.tokens.curr, v); - note_implied(state.tokens.curr); - } else if (typeof s !== "object") { - // Operators typeof and delete do not raise runtime errors even - // if the base object of a reference is null so no need to - // - // display warning if we're inside of typeof or delete. - // Attempting to subscript a null reference will throw an - // error, even within the typeof and delete operators - if (!(anonname === "typeof" || anonname === "delete") || - (state.tokens.next && - (state.tokens.next.value === "." || state.tokens.next.value === "["))) { - - isundef(funct, "W117", state.tokens.curr, v); - } - funct[v] = true; - note_implied(state.tokens.curr); - } else { - switch (s[v]) { - case "function": - case "unction": - this["function"] = true; - s[v] = "closure"; - funct[v] = s["(global)"] ? "global" : "outer"; - break; - case "var": - case "unused": - s[v] = "closure"; - funct[v] = s["(global)"] ? "global" : "outer"; - break; - case "closure": - funct[v] = s["(global)"] ? "global" : "outer"; - break; - case "label": - warning("W037", state.tokens.curr, v); - } - } - } - } - return this; - }, - led: function () { - error("E033", state.tokens.next, state.tokens.next.value); - } - }; - - type("(regexp)", function () { - return this; - }); - - // ECMAScript parser - - delim("(endline)"); - delim("(begin)"); - delim("(end)").reach = true; - delim("(error)").reach = true; - delim("}").reach = true; - delim(")"); - delim("]"); - delim("\"").reach = true; - delim("'").reach = true; - delim(";"); - delim(":").reach = true; - delim("#"); - - reserve("else"); - reserve("case").reach = true; - reserve("catch"); - reserve("default").reach = true; - reserve("finally"); - reservevar("arguments", function (x) { - if (state.directive["use strict"] && funct["(global)"]) { - warning("E008", x); - } - }); - reservevar("eval"); - reservevar("false"); - reservevar("Infinity"); - reservevar("null"); - reservevar("this", function (x) { - if (state.directive["use strict"] && !state.option.validthis && ((funct["(statement)"] && - funct["(name)"].charAt(0) > "Z") || funct["(global)"])) { - warning("W040", x); - } - }); - reservevar("true"); - reservevar("undefined"); - - assignop("=", "assign", 20); - assignop("+=", "assignadd", 20); - assignop("-=", "assignsub", 20); - assignop("*=", "assignmult", 20); - assignop("/=", "assigndiv", 20).nud = function () { - error("E014"); - }; - assignop("%=", "assignmod", 20); - - bitwiseassignop("&=", "assignbitand", 20); - bitwiseassignop("|=", "assignbitor", 20); - bitwiseassignop("^=", "assignbitxor", 20); - bitwiseassignop("<<=", "assignshiftleft", 20); - bitwiseassignop(">>=", "assignshiftright", 20); - bitwiseassignop(">>>=", "assignshiftrightunsigned", 20); - infix(",", function (left, that) { - var expr; - that.exprs = [left]; - if (!comma({peek: true})) { - return that; - } - while (true) { - if (!(expr = expression(5))) { - break; - } - that.exprs.push(expr); - if (state.tokens.next.value !== "," || !comma()) { - break; - } - } - return that; - }, 5, true); - infix("?", function (left, that) { - that.left = left; - that.right = expression(10); - advance(":"); - that["else"] = expression(10); - return that; - }, 30); - - infix("||", "or", 40); - infix("&&", "and", 50); - bitwise("|", "bitor", 70); - bitwise("^", "bitxor", 80); - bitwise("&", "bitand", 90); - relation("==", function (left, right) { - var eqnull = state.option.eqnull && (left.value === "null" || right.value === "null"); - - if (!eqnull && state.option.eqeqeq) - warning("W116", this, "===", "=="); - else if (isPoorRelation(left)) - warning("W041", this, "===", left.value); - else if (isPoorRelation(right)) - warning("W041", this, "===", right.value); - - return this; - }); - relation("==="); - relation("!=", function (left, right) { - var eqnull = state.option.eqnull && - (left.value === "null" || right.value === "null"); - - if (!eqnull && state.option.eqeqeq) { - warning("W116", this, "!==", "!="); - } else if (isPoorRelation(left)) { - warning("W041", this, "!==", left.value); - } else if (isPoorRelation(right)) { - warning("W041", this, "!==", right.value); - } - return this; - }); - relation("!=="); - relation("<"); - relation(">"); - relation("<="); - relation(">="); - bitwise("<<", "shiftleft", 120); - bitwise(">>", "shiftright", 120); - bitwise(">>>", "shiftrightunsigned", 120); - infix("in", "in", 120); - infix("instanceof", "instanceof", 120); - infix("+", function (left, that) { - var right = expression(130); - if (left && right && left.id === "(string)" && right.id === "(string)") { - left.value += right.value; - left.character = right.character; - if (!state.option.scripturl && reg.javascriptURL.test(left.value)) { - warning("W050", left); - } - return left; - } - that.left = left; - that.right = right; - return that; - }, 130); - prefix("+", "num"); - prefix("+++", function () { - warning("W007"); - this.right = expression(150); - this.arity = "unary"; - return this; - }); - infix("+++", function (left) { - warning("W007"); - this.left = left; - this.right = expression(130); - return this; - }, 130); - infix("-", "sub", 130); - prefix("-", "neg"); - prefix("---", function () { - warning("W006"); - this.right = expression(150); - this.arity = "unary"; - return this; - }); - infix("---", function (left) { - warning("W006"); - this.left = left; - this.right = expression(130); - return this; - }, 130); - infix("*", "mult", 140); - infix("/", "div", 140); - infix("%", "mod", 140); - - suffix("++", "postinc"); - prefix("++", "preinc"); - state.syntax["++"].exps = true; - - suffix("--", "postdec"); - prefix("--", "predec"); - state.syntax["--"].exps = true; - prefix("delete", function () { - var p = expression(5); - if (!p || (p.id !== "." && p.id !== "[")) { - warning("W051"); - } - this.first = p; - return this; - }).exps = true; - - prefix("~", function () { - if (state.option.bitwise) { - warning("W052", this, "~"); - } - expression(150); - return this; - }); - - prefix("...", function () { - if (!state.option.inESNext()) { - warning("W104", this, "spread/rest operator"); - } - if (!state.tokens.next.identifier) { - error("E030", state.tokens.next, state.tokens.next.value); - } - expression(150); - return this; - }); - - prefix("!", function () { - this.right = expression(150); - this.arity = "unary"; - - if (!this.right) { // '!' followed by nothing? Give up. - quit("E041", this.line || 0); - } - - if (bang[this.right.id] === true) { - warning("W018", this, "!"); - } - return this; - }); - - prefix("typeof", "typeof"); - prefix("new", function () { - var c = expression(155), i; - if (c && c.id !== "function") { - if (c.identifier) { - c["new"] = true; - switch (c.value) { - case "Number": - case "String": - case "Boolean": - case "Math": - case "JSON": - warning("W053", state.tokens.prev, c.value); - break; - case "Function": - if (!state.option.evil) { - warning("W054"); - } - break; - case "Date": - case "RegExp": - break; - default: - if (c.id !== "function") { - i = c.value.substr(0, 1); - if (state.option.newcap && (i < "A" || i > "Z") && !_.has(global, c.value)) { - warning("W055", state.tokens.curr); - } - } - } - } else { - if (c.id !== "." && c.id !== "[" && c.id !== "(") { - warning("W056", state.tokens.curr); - } - } - } else { - if (!state.option.supernew) - warning("W057", this); - } - adjacent(state.tokens.curr, state.tokens.next); - if (state.tokens.next.id !== "(" && !state.option.supernew) { - warning("W058", state.tokens.curr, state.tokens.curr.value); - } - this.first = c; - return this; - }); - state.syntax["new"].exps = true; - - prefix("void").exps = true; - - infix(".", function (left, that) { - adjacent(state.tokens.prev, state.tokens.curr); - nobreak(); - var m = identifier(false, true); - - if (typeof m === "string") { - countMember(m); - } - - that.left = left; - that.right = m; - - if (m && m === "hasOwnProperty" && state.tokens.next.value === "=") { - warning("W001"); - } - - if (left && left.value === "arguments" && (m === "callee" || m === "caller")) { - if (state.option.noarg) - warning("W059", left, m); - else if (state.directive["use strict"]) - error("E008"); - } else if (!state.option.evil && left && left.value === "document" && - (m === "write" || m === "writeln")) { - warning("W060", left); - } - - if (!state.option.evil && (m === "eval" || m === "execScript")) { - warning("W061"); - } - - return that; - }, 160, true); - - infix("(", function (left, that) { - if (state.tokens.prev.id !== "}" && state.tokens.prev.id !== ")") { - nobreak(state.tokens.prev, state.tokens.curr); - } - - nospace(); - if (state.option.immed && left && !left.immed && left.id === "function") { - warning("W062"); - } - - var n = 0; - var p = []; - - if (left) { - if (left.type === "(identifier)") { - if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) { - if ("Number String Boolean Date Object".indexOf(left.value) === -1) { - if (left.value === "Math") { - warning("W063", left); - } else if (state.option.newcap) { - warning("W064", left); - } - } - } - } - } - - if (state.tokens.next.id !== ")") { - for (;;) { - p[p.length] = expression(10); - n += 1; - if (state.tokens.next.id !== ",") { - break; - } - comma(); - } - } - - advance(")"); - nospace(state.tokens.prev, state.tokens.curr); - - if (typeof left === "object") { - if (left.value === "parseInt" && n === 1) { - warning("W065", state.tokens.curr); - } - if (!state.option.evil) { - if (left.value === "eval" || left.value === "Function" || - left.value === "execScript") { - warning("W061", left); - - if (p[0] && [0].id === "(string)") { - addInternalSrc(left, p[0].value); - } - } else if (p[0] && p[0].id === "(string)" && - (left.value === "setTimeout" || - left.value === "setInterval")) { - warning("W066", left); - addInternalSrc(left, p[0].value); - - // window.setTimeout/setInterval - } else if (p[0] && p[0].id === "(string)" && - left.value === "." && - left.left.value === "window" && - (left.right === "setTimeout" || - left.right === "setInterval")) { - warning("W066", left); - addInternalSrc(left, p[0].value); - } - } - if (!left.identifier && left.id !== "." && left.id !== "[" && - left.id !== "(" && left.id !== "&&" && left.id !== "||" && - left.id !== "?") { - warning("W067", left); - } - } - - that.left = left; - return that; - }, 155, true).exps = true; - - prefix("(", function () { - nospace(); - var bracket, brackets = []; - var pn, pn1, i = 0; - - do { - pn = peek(i); - i += 1; - pn1 = peek(i); - i += 1; - } while (pn.value !== ")" && pn1.value !== "=>" && pn1.value !== ";" && pn1.type !== "(end)"); - - if (state.tokens.next.id === "function") { - state.tokens.next.immed = true; - } - - var exprs = []; - - if (state.tokens.next.id !== ")") { - for (;;) { - if (pn1.value === "=>" && state.tokens.next.value === "{") { - bracket = state.tokens.next; - bracket.left = destructuringExpression(); - brackets.push(bracket); - for (var t in bracket.left) { - exprs.push(bracket.left[t].token); - } - } else { - exprs.push(expression(5)); - } - if (state.tokens.next.id !== ",") { - break; - } - comma(); - } - } - - advance(")", this); - nospace(state.tokens.prev, state.tokens.curr); - if (state.option.immed && exprs[0] && exprs[0].id === "function") { - if (state.tokens.next.id !== "(" && - (state.tokens.next.id !== "." || (peek().value !== "call" && peek().value !== "apply"))) { - warning("W068", this); - } - } - - if (state.tokens.next.value === "=>") { - return exprs; - } - if (!exprs.length) { - return; - } - exprs[exprs.length - 1].paren = true; - if (exprs.length > 1) { - return Object.create(state.syntax[","], { exprs: { value: exprs } }); - } - return exprs[0]; - }); - - application("=>"); - - infix("[", function (left, that) { - nobreak(state.tokens.prev, state.tokens.curr); - nospace(); - var e = expression(5), s; - if (e && e.type === "(string)") { - if (!state.option.evil && (e.value === "eval" || e.value === "execScript")) { - warning("W061", that); - } - - countMember(e.value); - if (!state.option.sub && reg.identifier.test(e.value)) { - s = state.syntax[e.value]; - if (!s || !isReserved(s)) { - warning("W069", state.tokens.prev, e.value); - } - } - } - advance("]", that); - - if (e && e.value === "hasOwnProperty" && state.tokens.next.value === "=") { - warning("W001"); - } - - nospace(state.tokens.prev, state.tokens.curr); - that.left = left; - that.right = e; - return that; - }, 160, true); - - function comprehensiveArrayExpression() { - var res = {}; - res.exps = true; - funct["(comparray)"].stack(); - - res.right = expression(5); - advance("for"); - if (state.tokens.next.value === "each") { - advance("each"); - if (!state.option.inMoz(true)) { - warning("W118", state.tokens.curr, "for each"); - } - } - advance("("); - funct["(comparray)"].setState("define"); - res.left = expression(5); - advance(")"); - if (state.tokens.next.value === "if") { - advance("if"); - advance("("); - funct["(comparray)"].setState("filter"); - res.filter = expression(5); - advance(")"); - } - advance("]"); - funct["(comparray)"].unstack(); - return res; - } - - prefix("[", function () { - var blocktype = lookupBlockType(true); - if (blocktype.isCompArray) { - if (!state.option.inMoz(true)) { - warning("W118", state.tokens.curr, "array comprehension"); - } - return comprehensiveArrayExpression(); - } else if (blocktype.isDestAssign && !state.option.inESNext()) { - warning("W104", state.tokens.curr, "destructuring assignment"); - } - var b = state.tokens.curr.line !== state.tokens.next.line; - this.first = []; - if (b) { - indent += state.option.indent; - if (state.tokens.next.from === indent + state.option.indent) { - indent += state.option.indent; - } - } - while (state.tokens.next.id !== "(end)") { - while (state.tokens.next.id === ",") { - if (!state.option.inES5()) - warning("W070"); - advance(","); - } - if (state.tokens.next.id === "]") { - break; - } - if (b && state.tokens.curr.line !== state.tokens.next.line) { - indentation(); - } - this.first.push(expression(10)); - if (state.tokens.next.id === ",") { - comma({ allowTrailing: true }); - if (state.tokens.next.id === "]" && !state.option.inES5(true)) { - warning("W070", state.tokens.curr); - break; - } - } else { - break; - } - } - if (b) { - indent -= state.option.indent; - indentation(); - } - advance("]", this); - return this; - }, 160); - - - function property_name() { - var id = optionalidentifier(false, true); - - if (!id) { - if (state.tokens.next.id === "(string)") { - id = state.tokens.next.value; - advance(); - } else if (state.tokens.next.id === "(number)") { - id = state.tokens.next.value.toString(); - advance(); - } - } - - if (id === "hasOwnProperty") { - warning("W001"); - } - - return id; - } - - - function functionparams(parsed) { - var curr, next; - var params = []; - var ident; - var tokens = []; - var t; - - if (parsed) { - if (parsed instanceof Array) { - for (var i in parsed) { - curr = parsed[i]; - if (_.contains(["{", "["], curr.id)) { - for (t in curr.left) { - t = tokens[t]; - if (t.id) { - params.push(t.id); - addlabel(t.id, "unused", t.token); - } - } - } else if (curr.value === "...") { - if (!state.option.inESNext()) { - warning("W104", curr, "spread/rest operator"); - } - continue; - } else { - addlabel(curr.value, "unused", curr); - } - } - return params; - } else { - if (parsed.identifier === true) { - addlabel(parsed.value, "unused", parsed); - return [parsed]; - } - } - } - - next = state.tokens.next; - - advance("("); - nospace(); - - if (state.tokens.next.id === ")") { - advance(")"); - return; - } - - for (;;) { - if (_.contains(["{", "["], state.tokens.next.id)) { - tokens = destructuringExpression(); - for (t in tokens) { - t = tokens[t]; - if (t.id) { - params.push(t.id); - addlabel(t.id, "unused", t.token); - } - } - } else if (state.tokens.next.value === "...") { - if (!state.option.inESNext()) { - warning("W104", state.tokens.next, "spread/rest operator"); - } - advance("..."); - nospace(); - ident = identifier(true); - params.push(ident); - addlabel(ident, "unused", state.tokens.curr); - } else { - ident = identifier(true); - params.push(ident); - addlabel(ident, "unused", state.tokens.curr); - } - if (state.tokens.next.id === ",") { - comma(); - } else { - advance(")", next); - nospace(state.tokens.prev, state.tokens.curr); - return params; - } - } - } - - - function doFunction(name, statement, generator, fatarrowparams) { - var f; - var oldOption = state.option; - var oldIgnored = state.ignored; - var oldScope = scope; - - state.option = Object.create(state.option); - state.ignored = Object.create(state.ignored); - scope = Object.create(scope); - - funct = { - "(name)" : name || "\"" + anonname + "\"", - "(line)" : state.tokens.next.line, - "(character)" : state.tokens.next.character, - "(context)" : funct, - "(breakage)" : 0, - "(loopage)" : 0, - "(metrics)" : createMetrics(state.tokens.next), - "(scope)" : scope, - "(statement)" : statement, - "(tokens)" : {}, - "(blockscope)": funct["(blockscope)"], - "(comparray)" : funct["(comparray)"] - }; - - if (generator) { - funct["(generator)"] = true; - } - - f = funct; - state.tokens.curr.funct = funct; - - functions.push(funct); - - if (name) { - addlabel(name, "function"); - } - - funct["(params)"] = functionparams(fatarrowparams); - - funct["(metrics)"].verifyMaxParametersPerFunction(funct["(params)"]); - - block(false, true, true, fatarrowparams ? true:false); - - if (generator && funct["(generator)"] !== "yielded") { - error("E047", state.tokens.curr); - } - - funct["(metrics)"].verifyMaxStatementsPerFunction(); - funct["(metrics)"].verifyMaxComplexityPerFunction(); - funct["(unusedOption)"] = state.option.unused; - - scope = oldScope; - state.option = oldOption; - state.ignored = oldIgnored; - funct["(last)"] = state.tokens.curr.line; - funct["(lastcharacter)"] = state.tokens.curr.character; - funct = funct["(context)"]; - - return f; - } - - function createMetrics(functionStartToken) { - return { - statementCount: 0, - nestedBlockDepth: -1, - ComplexityCount: 1, - verifyMaxStatementsPerFunction: function () { - if (state.option.maxstatements && - this.statementCount > state.option.maxstatements) { - warning("W071", functionStartToken, this.statementCount); - } - }, - - verifyMaxParametersPerFunction: function (params) { - params = params || []; - - if (state.option.maxparams && params.length > state.option.maxparams) { - warning("W072", functionStartToken, params.length); - } - }, - - verifyMaxNestedBlockDepthPerFunction: function () { - if (state.option.maxdepth && - this.nestedBlockDepth > 0 && - this.nestedBlockDepth === state.option.maxdepth + 1) { - warning("W073", null, this.nestedBlockDepth); - } - }, - - verifyMaxComplexityPerFunction: function () { - var max = state.option.maxcomplexity; - var cc = this.ComplexityCount; - if (max && cc > max) { - warning("W074", functionStartToken, cc); - } - } - }; - } - - function increaseComplexityCount() { - funct["(metrics)"].ComplexityCount += 1; - } - - // Parse assignments that were found instead of conditionals. - // For example: if (a = 1) { ... } - - function checkCondAssignment(expr) { - var id = expr.id; - if (id === ",") { - expr = expr.exprs[expr.exprs.length - 1]; - id = expr.id; - } - switch (id) { - case "=": - case "+=": - case "-=": - case "*=": - case "%=": - case "&=": - case "|=": - case "^=": - case "/=": - if (!expr.paren && !state.option.boss) { - warning("W084"); - } - } - } - - - (function (x) { - x.nud = function (isclassdef) { - var b, f, i, p, t, g; - var props = {}; // All properties, including accessors - var tag = ""; - - function saveProperty(name, tkn) { - if (props[name] && _.has(props, name)) - warning("W075", state.tokens.next, i); - else - props[name] = {}; - - props[name].basic = true; - props[name].basictkn = tkn; - } - - function saveSetter(name, tkn) { - if (props[name] && _.has(props, name)) { - if (props[name].basic || props[name].setter) - warning("W075", state.tokens.next, i); - } else { - props[name] = {}; - } - - props[name].setter = true; - props[name].setterToken = tkn; - } - - function saveGetter(name) { - if (props[name] && _.has(props, name)) { - if (props[name].basic || props[name].getter) - warning("W075", state.tokens.next, i); - } else { - props[name] = {}; - } - - props[name].getter = true; - props[name].getterToken = state.tokens.curr; - } - - b = state.tokens.curr.line !== state.tokens.next.line; - if (b) { - indent += state.option.indent; - if (state.tokens.next.from === indent + state.option.indent) { - indent += state.option.indent; - } - } - - for (;;) { - if (state.tokens.next.id === "}") { - break; - } - - if (b) { - indentation(); - } - - if (isclassdef && state.tokens.next.value === "static") { - advance("static"); - tag = "static "; - } - - if (state.tokens.next.value === "get" && peek().id !== ":") { - advance("get"); - - if (!state.option.inES5(!isclassdef)) { - error("E034"); - } - - i = property_name(); - if (!i) { - error("E035"); - } - - // It is a Syntax Error if PropName of MethodDefinition is - // "constructor" and SpecialMethod of MethodDefinition is true. - if (isclassdef && i === "constructor") { - error("E049", state.tokens.next, "class getter method", i); - } - - saveGetter(tag + i); - t = state.tokens.next; - adjacent(state.tokens.curr, state.tokens.next); - f = doFunction(); - p = f["(params)"]; - - if (p) { - warning("W076", t, p[0], i); - } - - adjacent(state.tokens.curr, state.tokens.next); - } else if (state.tokens.next.value === "set" && peek().id !== ":") { - advance("set"); - - if (!state.option.inES5(!isclassdef)) { - error("E034"); - } - - i = property_name(); - if (!i) { - error("E035"); - } - - // It is a Syntax Error if PropName of MethodDefinition is - // "constructor" and SpecialMethod of MethodDefinition is true. - if (isclassdef && i === "constructor") { - error("E049", state.tokens.next, "class setter method", i); - } - - saveSetter(tag + i, state.tokens.next); - t = state.tokens.next; - adjacent(state.tokens.curr, state.tokens.next); - f = doFunction(); - p = f["(params)"]; - - if (!p || p.length !== 1) { - warning("W077", t, i); - } - } else { - g = false; - if (state.tokens.next.value === "*" && state.tokens.next.type === "(punctuator)") { - if (!state.option.inESNext()) { - warning("W104", state.tokens.next, "generator functions"); - } - advance("*"); - g = true; - } - i = property_name(); - saveProperty(tag + i, state.tokens.next); - - if (typeof i !== "string") { - break; - } - - if (state.tokens.next.value === "(") { - if (!state.option.inESNext()) { - warning("W104", state.tokens.curr, "concise methods"); - } - doFunction(i, undefined, g); - } else if (!isclassdef) { - advance(":"); - nonadjacent(state.tokens.curr, state.tokens.next); - expression(10); - } - } - // It is a Syntax Error if PropName of MethodDefinition is "prototype". - if (isclassdef && i === "prototype") { - error("E049", state.tokens.next, "class method", i); - } - - countMember(i); - if (isclassdef) { - tag = ""; - continue; - } - if (state.tokens.next.id === ",") { - comma({ allowTrailing: true, property: true }); - if (state.tokens.next.id === ",") { - warning("W070", state.tokens.curr); - } else if (state.tokens.next.id === "}" && !state.option.inES5(true)) { - warning("W070", state.tokens.curr); - } - } else { - break; - } - } - if (b) { - indent -= state.option.indent; - indentation(); - } - advance("}", this); - - // Check for lonely setters if in the ES5 mode. - if (state.option.inES5()) { - for (var name in props) { - if (_.has(props, name) && props[name].setter && !props[name].getter) { - warning("W078", props[name].setterToken); - } - } - } - return this; - }; - x.fud = function () { - error("E036", state.tokens.curr); - }; - }(delim("{"))); - - function destructuringExpression() { - var id, ids; - var identifiers = []; - if (!state.option.inESNext()) { - warning("W104", state.tokens.curr, "destructuring expression"); - } - var nextInnerDE = function () { - var ident; - if (_.contains(["[", "{"], state.tokens.next.value)) { - ids = destructuringExpression(); - for (var id in ids) { - id = ids[id]; - identifiers.push({ id: id.id, token: id.token }); - } - } else if (state.tokens.next.value === ",") { - identifiers.push({ id: null, token: state.tokens.curr }); - } else { - ident = identifier(); - if (ident) - identifiers.push({ id: ident, token: state.tokens.curr }); - } - }; - if (state.tokens.next.value === "[") { - advance("["); - nextInnerDE(); - while (state.tokens.next.value !== "]") { - advance(","); - nextInnerDE(); - } - advance("]"); - } else if (state.tokens.next.value === "{") { - advance("{"); - id = identifier(); - if (state.tokens.next.value === ":") { - advance(":"); - nextInnerDE(); - } else { - identifiers.push({ id: id, token: state.tokens.curr }); - } - while (state.tokens.next.value !== "}") { - advance(","); - id = identifier(); - if (state.tokens.next.value === ":") { - advance(":"); - nextInnerDE(); - } else { - identifiers.push({ id: id, token: state.tokens.curr }); - } - } - advance("}"); - } - return identifiers; - } - function destructuringExpressionMatch(tokens, value) { - if (value.first) { - _.zip(tokens, value.first).forEach(function (val) { - var token = val[0]; - var value = val[1]; - if (token && value) { - token.first = value; - } else if (token && token.first && !value) { - warning("W080", token.first, token.first.value); - } /* else { - XXX value is discarded: wouldn't it need a warning ? - } */ - }); - } - } - - var conststatement = stmt("const", function (prefix) { - var tokens, value; - // state variable to know if it is a lone identifier, or a destructuring statement. - var lone; - - if (!state.option.inESNext()) { - warning("W104", state.tokens.curr, "const"); - } - - this.first = []; - for (;;) { - var names = []; - nonadjacent(state.tokens.curr, state.tokens.next); - if (_.contains(["{", "["], state.tokens.next.value)) { - tokens = destructuringExpression(); - lone = false; - } else { - tokens = [ { id: identifier(), token: state.tokens.curr } ]; - lone = true; - } - for (var t in tokens) { - t = tokens[t]; - if (funct[t.id] === "const") { - warning("E011", null, t.id); - } - if (funct["(global)"] && predefined[t.id] === false) { - warning("W079", t.token, t.id); - } - if (t.id) { - addlabel(t.id, "const"); - names.push(t.token); - } - } - if (prefix) { - break; - } - - this.first = this.first.concat(names); - - if (state.tokens.next.id !== "=") { - warning("E012", state.tokens.curr, state.tokens.curr.value); - } - - if (state.tokens.next.id === "=") { - nonadjacent(state.tokens.curr, state.tokens.next); - advance("="); - nonadjacent(state.tokens.curr, state.tokens.next); - if (state.tokens.next.id === "undefined") { - warning("W080", state.tokens.prev, state.tokens.prev.value); - } - if (peek(0).id === "=" && state.tokens.next.identifier) { - error("E037", state.tokens.next, state.tokens.next.value); - } - value = expression(5); - if (lone) { - tokens[0].first = value; - } else { - destructuringExpressionMatch(names, value); - } - } - - if (state.tokens.next.id !== ",") { - break; - } - comma(); - } - return this; - }); - conststatement.exps = true; - var varstatement = stmt("var", function (prefix) { - // JavaScript does not have block scope. It only has function scope. So, - // declaring a variable in a block can have unexpected consequences. - var tokens, lone, value; - - if (funct["(onevar)"] && state.option.onevar) { - warning("W081"); - } else if (!funct["(global)"]) { - funct["(onevar)"] = true; - } - - this.first = []; - for (;;) { - var names = []; - nonadjacent(state.tokens.curr, state.tokens.next); - if (_.contains(["{", "["], state.tokens.next.value)) { - tokens = destructuringExpression(); - lone = false; - } else { - tokens = [ { id: identifier(), token: state.tokens.curr } ]; - lone = true; - } - for (var t in tokens) { - t = tokens[t]; - if (state.option.inESNext() && funct[t.id] === "const") { - warning("E011", null, t.id); - } - if (funct["(global)"] && predefined[t.id] === false) { - warning("W079", t.token, t.id); - } - if (t.id) { - addlabel(t.id, "unused", t.token); - names.push(t.token); - } - } - if (prefix) { - break; - } - - this.first = this.first.concat(names); - - if (state.tokens.next.id === "=") { - nonadjacent(state.tokens.curr, state.tokens.next); - advance("="); - nonadjacent(state.tokens.curr, state.tokens.next); - if (state.tokens.next.id === "undefined") { - warning("W080", state.tokens.prev, state.tokens.prev.value); - } - if (peek(0).id === "=" && state.tokens.next.identifier) { - error("E038", state.tokens.next, state.tokens.next.value); - } - value = expression(5); - if (lone) { - tokens[0].first = value; - } else { - destructuringExpressionMatch(names, value); - } - } - - if (state.tokens.next.id !== ",") { - break; - } - comma(); - } - return this; - }); - varstatement.exps = true; - var letstatement = stmt("let", function (prefix) { - var tokens, lone, value, letblock; - - if (!state.option.inESNext()) { - warning("W104", state.tokens.curr, "let"); - } - - if (state.tokens.next.value === "(") { - if (!state.option.inMoz(true)) { - warning("W118", state.tokens.next, "let block"); - } - advance("("); - funct["(blockscope)"].stack(); - letblock = true; - } else if (funct["(nolet)"]) { - error("E048", state.tokens.curr); - } - - if (funct["(onevar)"] && state.option.onevar) { - warning("W081"); - } else if (!funct["(global)"]) { - funct["(onevar)"] = true; - } - - this.first = []; - for (;;) { - var names = []; - nonadjacent(state.tokens.curr, state.tokens.next); - if (_.contains(["{", "["], state.tokens.next.value)) { - tokens = destructuringExpression(); - lone = false; - } else { - tokens = [ { id: identifier(), token: state.tokens.curr.value } ]; - lone = true; - } - for (var t in tokens) { - t = tokens[t]; - if (state.option.inESNext() && funct[t.id] === "const") { - warning("E011", null, t.id); - } - if (funct["(global)"] && predefined[t.id] === false) { - warning("W079", t.token, t.id); - } - if (t.id && !funct["(nolet)"]) { - addlabel(t.id, "unused", t.token, true); - names.push(t.token); - } - } - if (prefix) { - break; - } - - this.first = this.first.concat(names); - - if (state.tokens.next.id === "=") { - nonadjacent(state.tokens.curr, state.tokens.next); - advance("="); - nonadjacent(state.tokens.curr, state.tokens.next); - if (state.tokens.next.id === "undefined") { - warning("W080", state.tokens.prev, state.tokens.prev.value); - } - if (peek(0).id === "=" && state.tokens.next.identifier) { - error("E037", state.tokens.next, state.tokens.next.value); - } - value = expression(5); - if (lone) { - tokens[0].first = value; - } else { - destructuringExpressionMatch(names, value); - } - } - - if (state.tokens.next.id !== ",") { - break; - } - comma(); - } - if (letblock) { - advance(")"); - block(true, true); - this.block = true; - funct["(blockscope)"].unstack(); - } - - return this; - }); - letstatement.exps = true; - - blockstmt("class", function () { - return classdef.call(this, true); - }); - - function classdef(stmt) { - /*jshint validthis:true */ - if (!state.option.inESNext()) { - warning("W104", state.tokens.curr, "class"); - } - if (stmt) { - // BindingIdentifier - this.name = identifier(); - addlabel(this.name, "unused", state.tokens.curr); - } else if (state.tokens.next.identifier && state.tokens.next.value !== "extends") { - // BindingIdentifier(opt) - this.name = identifier(); - } - classtail(this); - return this; - } - - function classtail(c) { - var strictness = state.directive["use strict"]; - - // ClassHeritage(opt) - if (state.tokens.next.value === "extends") { - advance("extends"); - c.heritage = expression(10); - } - - // A ClassBody is always strict code. - state.directive["use strict"] = true; - advance("{"); - // ClassBody(opt) - c.body = state.syntax["{"].nud(true); - state.directive["use strict"] = strictness; - } - - blockstmt("function", function () { - var generator = false; - if (state.tokens.next.value === "*") { - advance("*"); - if (state.option.inESNext(true)) { - generator = true; - } else { - warning("W119", state.tokens.curr, "function*"); - } - } - if (inblock) { - warning("W082", state.tokens.curr); - - } - var i = identifier(); - if (funct[i] === "const") { - warning("E011", null, i); - } - adjacent(state.tokens.curr, state.tokens.next); - addlabel(i, "unction", state.tokens.curr); - - doFunction(i, { statement: true }, generator); - if (state.tokens.next.id === "(" && state.tokens.next.line === state.tokens.curr.line) { - error("E039"); - } - return this; - }); - - prefix("function", function () { - var generator = false; - if (state.tokens.next.value === "*") { - if (!state.option.inESNext()) { - warning("W119", state.tokens.curr, "function*"); - } - advance("*"); - generator = true; - } - var i = optionalidentifier(); - if (i || state.option.gcl) { - adjacent(state.tokens.curr, state.tokens.next); - } else { - nonadjacent(state.tokens.curr, state.tokens.next); - } - doFunction(i, undefined, generator); - if (!state.option.loopfunc && funct["(loopage)"]) { - warning("W083"); - } - return this; - }); - - blockstmt("if", function () { - var t = state.tokens.next; - increaseComplexityCount(); - state.condition = true; - advance("("); - nonadjacent(this, t); - nospace(); - checkCondAssignment(expression(0)); - advance(")", t); - state.condition = false; - nospace(state.tokens.prev, state.tokens.curr); - block(true, true); - if (state.tokens.next.id === "else") { - nonadjacent(state.tokens.curr, state.tokens.next); - advance("else"); - if (state.tokens.next.id === "if" || state.tokens.next.id === "switch") { - statement(true); - } else { - block(true, true); - } - } - return this; - }); - - blockstmt("try", function () { - var b; - - function doCatch() { - var oldScope = scope; - var e; - - advance("catch"); - nonadjacent(state.tokens.curr, state.tokens.next); - advance("("); - - scope = Object.create(oldScope); - - e = state.tokens.next.value; - if (state.tokens.next.type !== "(identifier)") { - e = null; - warning("E030", state.tokens.next, e); - } - - advance(); - - funct = { - "(name)" : "(catch)", - "(line)" : state.tokens.next.line, - "(character)": state.tokens.next.character, - "(context)" : funct, - "(breakage)" : funct["(breakage)"], - "(loopage)" : funct["(loopage)"], - "(scope)" : scope, - "(statement)": false, - "(metrics)" : createMetrics(state.tokens.next), - "(catch)" : true, - "(tokens)" : {}, - "(blockscope)": funct["(blockscope)"], - "(comparray)": funct["(comparray)"] - }; - - if (e) { - addlabel(e, "exception"); - } - - if (state.tokens.next.value === "if") { - if (!state.option.inMoz(true)) { - warning("W118", state.tokens.curr, "catch filter"); - } - advance("if"); - expression(0); - } - - advance(")"); - - state.tokens.curr.funct = funct; - functions.push(funct); - - block(false); - - scope = oldScope; - - funct["(last)"] = state.tokens.curr.line; - funct["(lastcharacter)"] = state.tokens.curr.character; - funct = funct["(context)"]; - } - - block(false); - - while (state.tokens.next.id === "catch") { - increaseComplexityCount(); - if (b && (!state.option.inMoz(true))) { - warning("W118", state.tokens.next, "multiple catch blocks"); - } - doCatch(); - b = true; - } - - if (state.tokens.next.id === "finally") { - advance("finally"); - block(false); - return; - } - - if (!b) { - error("E021", state.tokens.next, "catch", state.tokens.next.value); - } - - return this; - }); - - blockstmt("while", function () { - var t = state.tokens.next; - funct["(breakage)"] += 1; - funct["(loopage)"] += 1; - increaseComplexityCount(); - advance("("); - nonadjacent(this, t); - nospace(); - checkCondAssignment(expression(0)); - advance(")", t); - nospace(state.tokens.prev, state.tokens.curr); - block(true, true); - funct["(breakage)"] -= 1; - funct["(loopage)"] -= 1; - return this; - }).labelled = true; - - blockstmt("with", function () { - var t = state.tokens.next; - if (state.directive["use strict"]) { - error("E010", state.tokens.curr); - } else if (!state.option.withstmt) { - warning("W085", state.tokens.curr); - } - - advance("("); - nonadjacent(this, t); - nospace(); - expression(0); - advance(")", t); - nospace(state.tokens.prev, state.tokens.curr); - block(true, true); - - return this; - }); - - blockstmt("switch", function () { - var t = state.tokens.next, - g = false; - funct["(breakage)"] += 1; - advance("("); - nonadjacent(this, t); - nospace(); - checkCondAssignment(expression(0)); - advance(")", t); - nospace(state.tokens.prev, state.tokens.curr); - nonadjacent(state.tokens.curr, state.tokens.next); - t = state.tokens.next; - advance("{"); - nonadjacent(state.tokens.curr, state.tokens.next); - indent += state.option.indent; - this.cases = []; - - for (;;) { - switch (state.tokens.next.id) { - case "case": - switch (funct["(verb)"]) { - case "yield": - case "break": - case "case": - case "continue": - case "return": - case "switch": - case "throw": - break; - default: - // You can tell JSHint that you don't use break intentionally by - // adding a comment /* falls through */ on a line just before - // the next `case`. - if (!reg.fallsThrough.test(state.lines[state.tokens.next.line - 2])) { - warning("W086", state.tokens.curr, "case"); - } - } - indentation(-state.option.indent); - advance("case"); - this.cases.push(expression(20)); - increaseComplexityCount(); - g = true; - advance(":"); - funct["(verb)"] = "case"; - break; - case "default": - switch (funct["(verb)"]) { - case "yield": - case "break": - case "continue": - case "return": - case "throw": - break; - default: - // Do not display a warning if 'default' is the first statement or if - // there is a special /* falls through */ comment. - if (this.cases.length) { - if (!reg.fallsThrough.test(state.lines[state.tokens.next.line - 2])) { - warning("W086", state.tokens.curr, "default"); - } - } - } - indentation(-state.option.indent); - advance("default"); - g = true; - advance(":"); - break; - case "}": - indent -= state.option.indent; - indentation(); - advance("}", t); - funct["(breakage)"] -= 1; - funct["(verb)"] = undefined; - return; - case "(end)": - error("E023", state.tokens.next, "}"); - return; - default: - if (g) { - switch (state.tokens.curr.id) { - case ",": - error("E040"); - return; - case ":": - g = false; - statements(); - break; - default: - error("E025", state.tokens.curr); - return; - } - } else { - if (state.tokens.curr.id === ":") { - advance(":"); - error("E024", state.tokens.curr, ":"); - statements(); - } else { - error("E021", state.tokens.next, "case", state.tokens.next.value); - return; - } - } - } - } - }).labelled = true; - - stmt("debugger", function () { - if (!state.option.debug) { - warning("W087"); - } - return this; - }).exps = true; - - (function () { - var x = stmt("do", function () { - funct["(breakage)"] += 1; - funct["(loopage)"] += 1; - increaseComplexityCount(); - - this.first = block(true, true); - advance("while"); - var t = state.tokens.next; - nonadjacent(state.tokens.curr, t); - advance("("); - nospace(); - checkCondAssignment(expression(0)); - advance(")", t); - nospace(state.tokens.prev, state.tokens.curr); - funct["(breakage)"] -= 1; - funct["(loopage)"] -= 1; - return this; - }); - x.labelled = true; - x.exps = true; - }()); - - blockstmt("for", function () { - var s, t = state.tokens.next; - var letscope = false; - var foreachtok = null; - - if (t.value === "each") { - foreachtok = t; - advance("each"); - if (!state.option.inMoz(true)) { - warning("W118", state.tokens.curr, "for each"); - } - } - - funct["(breakage)"] += 1; - funct["(loopage)"] += 1; - increaseComplexityCount(); - advance("("); - nonadjacent(this, t); - nospace(); - - // what kind of for(…) statement it is? for(…of…)? for(…in…)? for(…;…;…)? - var nextop; // contains the token of the "in" or "of" operator - var i = 0; - var inof = ["in", "of"]; - do { - nextop = peek(i); - ++i; - } while (!_.contains(inof, nextop.value) && nextop.value !== ";" && - nextop.type !== "(end)"); - - // if we're in a for (… in|of …) statement - if (_.contains(inof, nextop.value)) { - if (!state.option.inESNext() && nextop.value === "of") { - error("W104", nextop, "for of"); - } - if (state.tokens.next.id === "var") { - advance("var"); - state.syntax["var"].fud.call(state.syntax["var"].fud, true); - } else if (state.tokens.next.id === "let") { - advance("let"); - // create a new block scope - letscope = true; - funct["(blockscope)"].stack(); - state.syntax["let"].fud.call(state.syntax["let"].fud, true); - } else { - switch (funct[state.tokens.next.value]) { - case "unused": - funct[state.tokens.next.value] = "var"; - break; - case "var": - break; - default: - if (!funct["(blockscope)"].getlabel(state.tokens.next.value)) - warning("W088", state.tokens.next, state.tokens.next.value); - } - advance(); - } - advance(nextop.value); - expression(20); - advance(")", t); - s = block(true, true); - if (state.option.forin && s && (s.length > 1 || typeof s[0] !== "object" || - s[0].value !== "if")) { - warning("W089", this); - } - funct["(breakage)"] -= 1; - funct["(loopage)"] -= 1; - } else { - if (foreachtok) { - error("E045", foreachtok); - } - if (state.tokens.next.id !== ";") { - if (state.tokens.next.id === "var") { - advance("var"); - state.syntax["var"].fud.call(state.syntax["var"].fud); - } else if (state.tokens.next.id === "let") { - advance("let"); - // create a new block scope - letscope = true; - funct["(blockscope)"].stack(); - state.syntax["let"].fud.call(state.syntax["let"].fud); - } else { - for (;;) { - expression(0, "for"); - if (state.tokens.next.id !== ",") { - break; - } - comma(); - } - } - } - nolinebreak(state.tokens.curr); - advance(";"); - if (state.tokens.next.id !== ";") { - checkCondAssignment(expression(0)); - } - nolinebreak(state.tokens.curr); - advance(";"); - if (state.tokens.next.id === ";") { - error("E021", state.tokens.next, ")", ";"); - } - if (state.tokens.next.id !== ")") { - for (;;) { - expression(0, "for"); - if (state.tokens.next.id !== ",") { - break; - } - comma(); - } - } - advance(")", t); - nospace(state.tokens.prev, state.tokens.curr); - block(true, true); - funct["(breakage)"] -= 1; - funct["(loopage)"] -= 1; - - } - // unstack loop blockscope - if (letscope) { - funct["(blockscope)"].unstack(); - } - return this; - }).labelled = true; - - - stmt("break", function () { - var v = state.tokens.next.value; - - if (funct["(breakage)"] === 0) - warning("W052", state.tokens.next, this.value); - - if (!state.option.asi) - nolinebreak(this); - - if (state.tokens.next.id !== ";") { - if (state.tokens.curr.line === state.tokens.next.line) { - if (funct[v] !== "label") { - warning("W090", state.tokens.next, v); - } else if (scope[v] !== funct) { - warning("W091", state.tokens.next, v); - } - this.first = state.tokens.next; - advance(); - } - } - reachable("break"); - return this; - }).exps = true; - - - stmt("continue", function () { - var v = state.tokens.next.value; - - if (funct["(breakage)"] === 0) - warning("W052", state.tokens.next, this.value); - - if (!state.option.asi) - nolinebreak(this); - - if (state.tokens.next.id !== ";") { - if (state.tokens.curr.line === state.tokens.next.line) { - if (funct[v] !== "label") { - warning("W090", state.tokens.next, v); - } else if (scope[v] !== funct) { - warning("W091", state.tokens.next, v); - } - this.first = state.tokens.next; - advance(); - } - } else if (!funct["(loopage)"]) { - warning("W052", state.tokens.next, this.value); - } - reachable("continue"); - return this; - }).exps = true; - - - stmt("return", function () { - if (this.line === state.tokens.next.line) { - if (state.tokens.next.id === "(regexp)") - warning("W092"); - - if (state.tokens.next.id !== ";" && !state.tokens.next.reach) { - nonadjacent(state.tokens.curr, state.tokens.next); - this.first = expression(0); - - if (this.first && - this.first.type === "(punctuator)" && this.first.value === "=" && !state.option.boss) { - warningAt("W093", this.first.line, this.first.character); - } - } - } else { - if (state.tokens.next.type === "(punctuator)" && - ["[", "{", "+", "-"].indexOf(state.tokens.next.value) > -1) { - nolinebreak(this); // always warn (Line breaking error) - } - } - reachable("return"); - return this; - }).exps = true; - - stmt("yield", function () { - if (state.option.inESNext(true) && funct["(generator)"] !== true) { - error("E046", state.tokens.curr, "yield"); - } else if (!state.option.inESNext()) { - warning("W104", state.tokens.curr, "yield"); - } - funct["(generator)"] = "yielded"; - if (this.line === state.tokens.next.line) { - if (state.tokens.next.id === "(regexp)") - warning("W092"); - - if (state.tokens.next.id !== ";" && !state.tokens.next.reach) { - nonadjacent(state.tokens.curr, state.tokens.next); - this.first = expression(0); - - if (this.first.type === "(punctuator)" && this.first.value === "=" && !state.option.boss) { - warningAt("W093", this.first.line, this.first.character); - } - } - } else if (!state.option.asi) { - nolinebreak(this); // always warn (Line breaking error) - } - return this; - }).exps = true; - - - stmt("throw", function () { - nolinebreak(this); - nonadjacent(state.tokens.curr, state.tokens.next); - this.first = expression(20); - reachable("throw"); - return this; - }).exps = true; - - // Future Reserved Words - - FutureReservedWord("abstract"); - FutureReservedWord("boolean"); - FutureReservedWord("byte"); - FutureReservedWord("char"); - FutureReservedWord("class", { es5: true, nud: classdef }); - FutureReservedWord("double"); - FutureReservedWord("enum", { es5: true }); - FutureReservedWord("export", { es5: true }); - FutureReservedWord("extends", { es5: true }); - FutureReservedWord("final"); - FutureReservedWord("float"); - FutureReservedWord("goto"); - FutureReservedWord("implements", { es5: true, strictOnly: true }); - FutureReservedWord("import", { es5: true }); - FutureReservedWord("int"); - FutureReservedWord("interface", { es5: true, strictOnly: true }); - FutureReservedWord("long"); - FutureReservedWord("native"); - FutureReservedWord("package", { es5: true, strictOnly: true }); - FutureReservedWord("private", { es5: true, strictOnly: true }); - FutureReservedWord("protected", { es5: true, strictOnly: true }); - FutureReservedWord("public", { es5: true, strictOnly: true }); - FutureReservedWord("short"); - FutureReservedWord("static", { es5: true, strictOnly: true }); - FutureReservedWord("super", { es5: true }); - FutureReservedWord("synchronized"); - FutureReservedWord("throws"); - FutureReservedWord("transient"); - FutureReservedWord("volatile"); - - // this function is used to determine wether a squarebracket or a curlybracket - // expression is a comprehension array, destructuring assignment or a json value. - - var lookupBlockType = function () { - var pn, pn1; - var i = 0; - var bracketStack = 0; - var ret = {}; - if (_.contains(["[", "{"], state.tokens.curr.value)) - bracketStack += 1; - if (_.contains(["[", "{"], state.tokens.next.value)) - bracketStack += 1; - if (_.contains(["]", "}"], state.tokens.next.value)) - bracketStack -= 1; - do { - pn = peek(i); - pn1 = peek(i + 1); - i = i + 1; - if (_.contains(["[", "{"], pn.value)) { - bracketStack += 1; - } else if (_.contains(["]", "}"], pn.value)) { - bracketStack -= 1; - } - if (pn.identifier && pn.value === "for" && bracketStack === 1) { - ret.isCompArray = true; - ret.notJson = true; - break; - } - if (_.contains(["}", "]"], pn.value) && pn1.value === "=") { - ret.isDestAssign = true; - ret.notJson = true; - break; - } - if (pn.value === ";") { - ret.isBlock = true; - ret.notJson = true; - } - } while (bracketStack > 0 && pn.id !== "(end)" && i < 15); - return ret; - }; - - // Check whether this function has been reached for a destructuring assign with undeclared values - function destructuringAssignOrJsonValue() { - // lookup for the assignment (esnext only) - // if it has semicolons, it is a block, so go parse it as a block - // or it's not a block, but there are assignments, check for undeclared variables - - var block = lookupBlockType(); - if (block.notJson) { - if (!state.option.inESNext() && block.isDestAssign) { - warning("W104", state.tokens.curr, "destructuring assignment"); - } - statements(); - // otherwise parse json value - } else { - state.option.laxbreak = true; - state.jsonMode = true; - jsonValue(); - } - } - - // array comprehension parsing function - // parses and defines the three states of the list comprehension in order - // to avoid defining global variables, but keeping them to the list comprehension scope - // only. The order of the states are as follows: - // * "use" which will be the returned iterative part of the list comprehension - // * "define" which will define the variables local to the list comprehension - // * "filter" which will help filter out values - - var arrayComprehension = function () { - var CompArray = function () { - this.mode = "use"; - this.variables = []; - }; - var _carrays = []; - var _current; - function declare(v) { - var l = _current.variables.filter(function (elt) { - // if it has, change its undef state - if (elt.value === v) { - elt.undef = false; - return v; - } - }).length; - return l !== 0; - } - function use(v) { - var l = _current.variables.filter(function (elt) { - // and if it has been defined - if (elt.value === v && !elt.undef) { - if (elt.unused === true) { - elt.unused = false; - } - return v; - } - }).length; - // otherwise we warn about it - return (l === 0); - } - return {stack: function () { - _current = new CompArray(); - _carrays.push(_current); - }, - unstack: function () { - _current.variables.filter(function (v) { - if (v.unused) - warning("W098", v.token, v.value); - if (v.undef) - isundef(v.funct, "W117", v.token, v.value); - }); - _carrays.splice(_carrays[_carrays.length - 1], 1); - _current = _carrays[_carrays.length - 1]; - }, - setState: function (s) { - if (_.contains(["use", "define", "filter"], s)) - _current.mode = s; - }, - check: function (v) { - // When we are in "use" state of the list comp, we enqueue that var - if (_current && _current.mode === "use") { - _current.variables.push({funct: funct, - token: state.tokens.curr, - value: v, - undef: true, - unused: false}); - return true; - // When we are in "define" state of the list comp, - } else if (_current && _current.mode === "define") { - // check if the variable has been used previously - if (!declare(v)) { - _current.variables.push({funct: funct, - token: state.tokens.curr, - value: v, - undef: false, - unused: true}); - } - return true; - // When we are in "filter" state, - } else if (_current && _current.mode === "filter") { - // we check whether current variable has been declared - if (use(v)) { - // if not we warn about it - isundef(funct, "W117", state.tokens.curr, v); - } - return true; - } - return false; - } - }; - }; - - - // Parse JSON - - function jsonValue() { - - function jsonObject() { - var o = {}, t = state.tokens.next; - advance("{"); - if (state.tokens.next.id !== "}") { - for (;;) { - if (state.tokens.next.id === "(end)") { - error("E026", state.tokens.next, t.line); - } else if (state.tokens.next.id === "}") { - warning("W094", state.tokens.curr); - break; - } else if (state.tokens.next.id === ",") { - error("E028", state.tokens.next); - } else if (state.tokens.next.id !== "(string)") { - warning("W095", state.tokens.next, state.tokens.next.value); - } - if (o[state.tokens.next.value] === true) { - warning("W075", state.tokens.next, state.tokens.next.value); - } else if ((state.tokens.next.value === "__proto__" && - !state.option.proto) || (state.tokens.next.value === "__iterator__" && - !state.option.iterator)) { - warning("W096", state.tokens.next, state.tokens.next.value); - } else { - o[state.tokens.next.value] = true; - } - advance(); - advance(":"); - jsonValue(); - if (state.tokens.next.id !== ",") { - break; - } - advance(","); - } - } - advance("}"); - } - - function jsonArray() { - var t = state.tokens.next; - advance("["); - if (state.tokens.next.id !== "]") { - for (;;) { - if (state.tokens.next.id === "(end)") { - error("E027", state.tokens.next, t.line); - } else if (state.tokens.next.id === "]") { - warning("W094", state.tokens.curr); - break; - } else if (state.tokens.next.id === ",") { - error("E028", state.tokens.next); - } - jsonValue(); - if (state.tokens.next.id !== ",") { - break; - } - advance(","); - } - } - advance("]"); - } - - switch (state.tokens.next.id) { - case "{": - jsonObject(); - break; - case "[": - jsonArray(); - break; - case "true": - case "false": - case "null": - case "(number)": - case "(string)": - advance(); - break; - case "-": - advance("-"); - if (state.tokens.curr.character !== state.tokens.next.from) { - warning("W011", state.tokens.curr); - } - adjacent(state.tokens.curr, state.tokens.next); - advance("(number)"); - break; - default: - error("E003", state.tokens.next); - } - } - - var blockScope = function () { - var _current = {}; - var _variables = [_current]; - - function _checkBlockLabels() { - for (var t in _current) { - if (_current[t]["(type)"] === "unused") { - if (state.option.unused) { - var tkn = _current[t]["(token)"]; - var line = tkn.line; - var chr = tkn.character; - warningAt("W098", line, chr, t); - } - } - } - } - - return { - stack: function () { - _current = {}; - _variables.push(_current); - }, - - unstack: function () { - _checkBlockLabels(); - _variables.splice(_variables.length - 1, 1); - _current = _.last(_variables); - }, - - getlabel: function (l) { - for (var i = _variables.length - 1 ; i >= 0; --i) { - if (_.has(_variables[i], l)) { - return _variables[i]; - } - } - }, - - current: { - has: function (t) { - return _.has(_current, t); - }, - add: function (t, type, tok) { - _current[t] = { "(type)" : type, - "(token)": tok }; - } - } - }; - }; - - // The actual JSHINT function itself. - var itself = function (s, o, g) { - var a, i, k, x; - var optionKeys; - var newOptionObj = {}; - var newIgnoredObj = {}; - - state.reset(); - - if (o && o.scope) { - JSHINT.scope = o.scope; - } else { - JSHINT.errors = []; - JSHINT.undefs = []; - JSHINT.internals = []; - JSHINT.blacklist = {}; - JSHINT.scope = "(main)"; - } - - predefined = Object.create(null); - combine(predefined, vars.ecmaIdentifiers); - combine(predefined, vars.reservedVars); - - combine(predefined, g || {}); - - declared = Object.create(null); - exported = Object.create(null); - - if (o) { - a = o.predef; - if (a) { - if (!Array.isArray(a) && typeof a === "object") { - a = Object.keys(a); - } - - a.forEach(function (item) { - var slice, prop; - - if (item[0] === "-") { - slice = item.slice(1); - JSHINT.blacklist[slice] = slice; - } else { - prop = Object.getOwnPropertyDescriptor(o.predef, item); - predefined[item] = prop ? prop.value : false; - } - }); - } - - optionKeys = Object.keys(o); - for (x = 0; x < optionKeys.length; x++) { - if (/^-W\d{3}$/g.test(optionKeys[x])) { - newIgnoredObj[optionKeys[x].slice(1)] = true; - } else { - newOptionObj[optionKeys[x]] = o[optionKeys[x]]; - - if (optionKeys[x] === "newcap" && o[optionKeys[x]] === false) - newOptionObj["(explicitNewcap)"] = true; - - if (optionKeys[x] === "indent") - newOptionObj["(explicitIndent)"] = o[optionKeys[x]] === false ? false : true; - } - } - } - - state.option = newOptionObj; - state.ignored = newIgnoredObj; - - state.option.indent = state.option.indent || 4; - state.option.maxerr = state.option.maxerr || 50; - - indent = 1; - global = Object.create(predefined); - scope = global; - funct = { - "(global)": true, - "(name)": "(global)", - "(scope)": scope, - "(breakage)": 0, - "(loopage)": 0, - "(tokens)": {}, - "(metrics)": createMetrics(state.tokens.next), - "(blockscope)": blockScope(), - "(comparray)": arrayComprehension() - }; - functions = [funct]; - urls = []; - stack = null; - member = {}; - membersOnly = null; - implied = {}; - inblock = false; - lookahead = []; - warnings = 0; - unuseds = []; - - if (!isString(s) && !Array.isArray(s)) { - errorAt("E004", 0); - return false; - } - - api = { - get isJSON() { - return state.jsonMode; - }, - - getOption: function (name) { - return state.option[name] || null; - }, - - getCache: function (name) { - return state.cache[name]; - }, - - setCache: function (name, value) { - state.cache[name] = value; - }, - - warn: function (code, data) { - warningAt.apply(null, [ code, data.line, data.char ].concat(data.data)); - }, - - on: function (names, listener) { - names.split(" ").forEach(function (name) { - emitter.on(name, listener); - }.bind(this)); - } - }; - - emitter.removeAllListeners(); - (extraModules || []).forEach(function (func) { - func(api); - }); - - state.tokens.prev = state.tokens.curr = state.tokens.next = state.syntax["(begin)"]; - - lex = new Lexer(s); - - lex.on("warning", function (ev) { - warningAt.apply(null, [ ev.code, ev.line, ev.character].concat(ev.data)); - }); - - lex.on("error", function (ev) { - errorAt.apply(null, [ ev.code, ev.line, ev.character ].concat(ev.data)); - }); - - lex.on("fatal", function (ev) { - quit("E041", ev.line, ev.from); - }); - - lex.on("Identifier", function (ev) { - emitter.emit("Identifier", ev); - }); - - lex.on("String", function (ev) { - emitter.emit("String", ev); - }); - - lex.on("Number", function (ev) { - emitter.emit("Number", ev); - }); - - lex.start(); - - // Check options - for (var name in o) { - if (_.has(o, name)) { - checkOption(name, state.tokens.curr); - } - } - - assume(); - - // combine the passed globals after we've assumed all our options - combine(predefined, g || {}); - - //reset values - comma.first = true; - - try { - advance(); - switch (state.tokens.next.id) { - case "{": - case "[": - destructuringAssignOrJsonValue(); - break; - default: - directives(); - - if (state.directive["use strict"]) { - if (!state.option.globalstrict && !state.option.node) { - warning("W097", state.tokens.prev); - } - } - - statements(); - } - advance((state.tokens.next && state.tokens.next.value !== ".") ? "(end)" : undefined); - funct["(blockscope)"].unstack(); - - var markDefined = function (name, context) { - do { - if (typeof context[name] === "string") { - // JSHINT marks unused variables as 'unused' and - // unused function declaration as 'unction'. This - // code changes such instances back 'var' and - // 'closure' so that the code in JSHINT.data() - // doesn't think they're unused. - - if (context[name] === "unused") - context[name] = "var"; - else if (context[name] === "unction") - context[name] = "closure"; - - return true; - } - - context = context["(context)"]; - } while (context); - - return false; - }; - - var clearImplied = function (name, line) { - if (!implied[name]) - return; - - var newImplied = []; - for (var i = 0; i < implied[name].length; i += 1) { - if (implied[name][i] !== line) - newImplied.push(implied[name][i]); - } - - if (newImplied.length === 0) - delete implied[name]; - else - implied[name] = newImplied; - }; - - var warnUnused = function (name, tkn, type, unused_opt) { - var line = tkn.line; - var chr = tkn.character; - - if (unused_opt === undefined) { - unused_opt = state.option.unused; - } - - if (unused_opt === true) { - unused_opt = "last-param"; - } - - var warnable_types = { - "vars": ["var"], - "last-param": ["var", "param"], - "strict": ["var", "param", "last-param"] - }; - - if (unused_opt) { - if (warnable_types[unused_opt] && warnable_types[unused_opt].indexOf(type) !== -1) { - warningAt("W098", line, chr, name); - } - } - - unuseds.push({ - name: name, - line: line, - character: chr - }); - }; - - var checkUnused = function (func, key) { - var type = func[key]; - var tkn = func["(tokens)"][key]; - - if (key.charAt(0) === "(") - return; - - if (type !== "unused" && type !== "unction") - return; - - // Params are checked separately from other variables. - if (func["(params)"] && func["(params)"].indexOf(key) !== -1) - return; - - // Variable is in global scope and defined as exported. - if (func["(global)"] && _.has(exported, key)) { - return; - } - - warnUnused(key, tkn, "var"); - }; - - // Check queued 'x is not defined' instances to see if they're still undefined. - for (i = 0; i < JSHINT.undefs.length; i += 1) { - k = JSHINT.undefs[i].slice(0); - - if (markDefined(k[2].value, k[0])) { - clearImplied(k[2].value, k[2].line); - } else if (state.option.undef) { - warning.apply(warning, k.slice(1)); - } - } - - functions.forEach(function (func) { - if (func["(unusedOption)"] === false) { - return; - } - - for (var key in func) { - if (_.has(func, key)) { - checkUnused(func, key); - } - } - - if (!func["(params)"]) - return; - - var params = func["(params)"].slice(); - var param = params.pop(); - var type, unused_opt; - - while (param) { - type = func[param]; - unused_opt = func["(unusedOption)"] || state.option.unused; - unused_opt = unused_opt === true ? "last-param" : unused_opt; - - // 'undefined' is a special case for (function (window, undefined) { ... })(); - // patterns. - - if (param === "undefined") - return; - - if (type === "unused" || type === "unction") { - warnUnused(param, func["(tokens)"][param], "param", func["(unusedOption)"]); - } else if (unused_opt === "last-param") { - return; - } - - param = params.pop(); - } - }); - - for (var key in declared) { - if (_.has(declared, key) && !_.has(global, key)) { - warnUnused(key, declared[key], "var"); - } - } - - } catch (err) { - if (err && err.name === "JSHintError") { - var nt = state.tokens.next || {}; - JSHINT.errors.push({ - scope : "(main)", - raw : err.raw, - reason : err.message, - line : err.line || nt.line, - character : err.character || nt.from - }, null); - } else { - throw err; - } - } - - // Loop over the listed "internals", and check them as well. - - if (JSHINT.scope === "(main)") { - o = o || {}; - - for (i = 0; i < JSHINT.internals.length; i += 1) { - k = JSHINT.internals[i]; - o.scope = k.elem; - itself(k.value, o, g); - } - } - - return JSHINT.errors.length === 0; - }; - - // Modules. - itself.addModule = function (func) { - extraModules.push(func); - }; - - itself.addModule(style.register); - - // Data summary. - itself.data = function () { - var data = { - functions: [], - options: state.option - }; - var implieds = []; - var members = []; - var fu, f, i, j, n, globals; - - if (itself.errors.length) { - data.errors = itself.errors; - } - - if (state.jsonMode) { - data.json = true; - } - - for (n in implied) { - if (_.has(implied, n)) { - implieds.push({ - name: n, - line: implied[n] - }); - } - } - - if (implieds.length > 0) { - data.implieds = implieds; - } - - if (urls.length > 0) { - data.urls = urls; - } - - globals = Object.keys(scope); - if (globals.length > 0) { - data.globals = globals; - } - - for (i = 1; i < functions.length; i += 1) { - f = functions[i]; - fu = {}; - - for (j = 0; j < functionicity.length; j += 1) { - fu[functionicity[j]] = []; - } - - for (j = 0; j < functionicity.length; j += 1) { - if (fu[functionicity[j]].length === 0) { - delete fu[functionicity[j]]; - } - } - - fu.name = f["(name)"]; - fu.param = f["(params)"]; - fu.line = f["(line)"]; - fu.character = f["(character)"]; - fu.last = f["(last)"]; - fu.lastcharacter = f["(lastcharacter)"]; - data.functions.push(fu); - } - - if (unuseds.length > 0) { - data.unused = unuseds; - } - - members = []; - for (n in member) { - if (typeof member[n] === "number") { - data.member = member; - break; - } - } - - return data; - }; - - itself.jshint = itself; - - return itself; -}()); - -// Make JSHINT a Node module, if possible. -if (typeof exports === "object" && exports) { - exports.JSHINT = JSHINT; -} - -})() -},{"events":2,"../shared/vars.js":3,"./lex.js":10,"./reg.js":6,"./state.js":4,"../shared/messages.js":12,"./style.js":5,"console-browserify":7,"underscore":11}],12:[function(require,module,exports){ -(function(){"use strict"; - -var _ = require("underscore"); - -var errors = { - // JSHint options - E001: "Bad option: '{a}'.", - E002: "Bad option value.", - - // JSHint input - E003: "Expected a JSON value.", - E004: "Input is neither a string nor an array of strings.", - E005: "Input is empty.", - E006: "Unexpected early end of program.", - - // Strict mode - E007: "Missing \"use strict\" statement.", - E008: "Strict violation.", - E009: "Option 'validthis' can't be used in a global scope.", - E010: "'with' is not allowed in strict mode.", - - // Constants - E011: "const '{a}' has already been declared.", - E012: "const '{a}' is initialized to 'undefined'.", - E013: "Attempting to override '{a}' which is a constant.", - - // Regular expressions - E014: "A regular expression literal can be confused with '/='.", - E015: "Unclosed regular expression.", - E016: "Invalid regular expression.", - - // Tokens - E017: "Unclosed comment.", - E018: "Unbegun comment.", - E019: "Unmatched '{a}'.", - E020: "Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.", - E021: "Expected '{a}' and instead saw '{b}'.", - E022: "Line breaking error '{a}'.", - E023: "Missing '{a}'.", - E024: "Unexpected '{a}'.", - E025: "Missing ':' on a case clause.", - E026: "Missing '}' to match '{' from line {a}.", - E027: "Missing ']' to match '[' form line {a}.", - E028: "Illegal comma.", - E029: "Unclosed string.", - - // Everything else - E030: "Expected an identifier and instead saw '{a}'.", - E031: "Bad assignment.", // FIXME: Rephrase - E032: "Expected a small integer or 'false' and instead saw '{a}'.", - E033: "Expected an operator and instead saw '{a}'.", - E034: "get/set are ES5 features.", - E035: "Missing property name.", - E036: "Expected to see a statement and instead saw a block.", - E037: "Constant {a} was not declared correctly.", - E038: "Variable {a} was not declared correctly.", - E039: "Function declarations are not invocable. Wrap the whole function invocation in parens.", - E040: "Each value should have its own case label.", - E041: "Unrecoverable syntax error.", - E042: "Stopping.", - E043: "Too many errors.", - E044: "'{a}' is already defined and can't be redefined.", - E045: "Invalid for each loop.", - E046: "A yield statement shall be within a generator function (with syntax: `function*`)", - E047: "A generator function shall contain a yield statement.", - E048: "Let declaration not directly within block.", - E049: "A {a} cannot be named '{b}'." -}; - -var warnings = { - W001: "'hasOwnProperty' is a really bad name.", - W002: "Value of '{a}' may be overwritten in IE.", - W003: "'{a}' was used before it was defined.", - W004: "'{a}' is already defined.", - W005: "A dot following a number can be confused with a decimal point.", - W006: "Confusing minuses.", - W007: "Confusing pluses.", - W008: "A leading decimal point can be confused with a dot: '{a}'.", - W009: "The array literal notation [] is preferrable.", - W010: "The object literal notation {} is preferrable.", - W011: "Unexpected space after '{a}'.", - W012: "Unexpected space before '{a}'.", - W013: "Missing space after '{a}'.", - W014: "Bad line breaking before '{a}'.", - W015: "Expected '{a}' to have an indentation at {b} instead at {c}.", - W016: "Unexpected use of '{a}'.", - W017: "Bad operand.", - W018: "Confusing use of '{a}'.", - W019: "Use the isNaN function to compare with NaN.", - W020: "Read only.", - W021: "'{a}' is a function.", - W022: "Do not assign to the exception parameter.", - W023: "Expected an identifier in an assignment and instead saw a function invocation.", - W024: "Expected an identifier and instead saw '{a}' (a reserved word).", - W025: "Missing name in function declaration.", - W026: "Inner functions should be listed at the top of the outer function.", - W027: "Unreachable '{a}' after '{b}'.", - W028: "Label '{a}' on {b} statement.", - W030: "Expected an assignment or function call and instead saw an expression.", - W031: "Do not use 'new' for side effects.", - W032: "Unnecessary semicolon.", - W033: "Missing semicolon.", - W034: "Unnecessary directive \"{a}\".", - W035: "Empty block.", - W036: "Unexpected /*member '{a}'.", - W037: "'{a}' is a statement label.", - W038: "'{a}' used out of scope.", - W039: "'{a}' is not allowed.", - W040: "Possible strict violation.", - W041: "Use '{a}' to compare with '{b}'.", - W042: "Avoid EOL escaping.", - W043: "Bad escaping of EOL. Use option multistr if needed.", - W044: "Bad or unnecessary escaping.", - W045: "Bad number '{a}'.", - W046: "Don't use extra leading zeros '{a}'.", - W047: "A trailing decimal point can be confused with a dot: '{a}'.", - W048: "Unexpected control character in regular expression.", - W049: "Unexpected escaped character '{a}' in regular expression.", - W050: "JavaScript URL.", - W051: "Variables should not be deleted.", - W052: "Unexpected '{a}'.", - W053: "Do not use {a} as a constructor.", - W054: "The Function constructor is a form of eval.", - W055: "A constructor name should start with an uppercase letter.", - W056: "Bad constructor.", - W057: "Weird construction. Is 'new' unnecessary?", - W058: "Missing '()' invoking a constructor.", - W059: "Avoid arguments.{a}.", - W060: "document.write can be a form of eval.", - W061: "eval can be harmful.", - W062: "Wrap an immediate function invocation in parens " + - "to assist the reader in understanding that the expression " + - "is the result of a function, and not the function itself.", - W063: "Math is not a function.", - W064: "Missing 'new' prefix when invoking a constructor.", - W065: "Missing radix parameter.", - W066: "Implied eval. Consider passing a function instead of a string.", - W067: "Bad invocation.", - W068: "Wrapping non-IIFE function literals in parens is unnecessary.", - W069: "['{a}'] is better written in dot notation.", - W070: "Extra comma. (it breaks older versions of IE)", - W071: "This function has too many statements. ({a})", - W072: "This function has too many parameters. ({a})", - W073: "Blocks are nested too deeply. ({a})", - W074: "This function's cyclomatic complexity is too high. ({a})", - W075: "Duplicate key '{a}'.", - W076: "Unexpected parameter '{a}' in get {b} function.", - W077: "Expected a single parameter in set {a} function.", - W078: "Setter is defined without getter.", - W079: "Redefinition of '{a}'.", - W080: "It's not necessary to initialize '{a}' to 'undefined'.", - W081: "Too many var statements.", - W082: "Function declarations should not be placed in blocks. " + - "Use a function expression or move the statement to the top of " + - "the outer function.", - W083: "Don't make functions within a loop.", - W084: "Expected a conditional expression and instead saw an assignment.", - W085: "Don't use 'with'.", - W086: "Expected a 'break' statement before '{a}'.", - W087: "Forgotten 'debugger' statement?", - W088: "Creating global 'for' variable. Should be 'for (var {a} ...'.", - W089: "The body of a for in should be wrapped in an if statement to filter " + - "unwanted properties from the prototype.", - W090: "'{a}' is not a statement label.", - W091: "'{a}' is out of scope.", - W092: "Wrap the /regexp/ literal in parens to disambiguate the slash operator.", - W093: "Did you mean to return a conditional instead of an assignment?", - W094: "Unexpected comma.", - W095: "Expected a string and instead saw {a}.", - W096: "The '{a}' key may produce unexpected results.", - W097: "Use the function form of \"use strict\".", - W098: "'{a}' is defined but never used.", - W099: "Mixed spaces and tabs.", - W100: "This character may get silently deleted by one or more browsers.", - W101: "Line is too long.", - W102: "Trailing whitespace.", - W103: "The '{a}' property is deprecated.", - W104: "'{a}' is only available in JavaScript 1.7.", - W105: "Unexpected {a} in '{b}'.", - W106: "Identifier '{a}' is not in camel case.", - W107: "Script URL.", - W108: "Strings must use doublequote.", - W109: "Strings must use singlequote.", - W110: "Mixed double and single quotes.", - W112: "Unclosed string.", - W113: "Control character in string: {a}.", - W114: "Avoid {a}.", - W115: "Octal literals are not allowed in strict mode.", - W116: "Expected '{a}' and instead saw '{b}'.", - W117: "'{a}' is not defined.", - W118: "'{a}' is only available in Mozilla JavaScript extensions (use moz option).", - W119: "'{a}' is only available in ES6 (use esnext option)." -}; - -var info = { - I001: "Comma warnings can be turned off with 'laxcomma'.", - I002: "Reserved words as properties can be used under the 'es5' option.", - I003: "ES5 option is now set per default" -}; - -exports.errors = {}; -exports.warnings = {}; -exports.info = {}; - -_.each(errors, function (desc, code) { - exports.errors[code] = { code: code, desc: desc }; -}); - -_.each(warnings, function (desc, code) { - exports.warnings[code] = { code: code, desc: desc }; -}); - -_.each(info, function (desc, code) { - exports.info[code] = { code: code, desc: desc }; -}); - -})() -},{"underscore":11}],8:[function(require,module,exports){ -var events = require('events'); - -exports.isArray = isArray; -exports.isDate = function(obj){return Object.prototype.toString.call(obj) === '[object Date]'}; -exports.isRegExp = function(obj){return Object.prototype.toString.call(obj) === '[object RegExp]'}; - - -exports.print = function () {}; -exports.puts = function () {}; -exports.debug = function() {}; - -exports.inspect = function(obj, showHidden, depth, colors) { - var seen = []; - - var stylize = function(str, styleType) { - // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics - var styles = - { 'bold' : [1, 22], - 'italic' : [3, 23], - 'underline' : [4, 24], - 'inverse' : [7, 27], - 'white' : [37, 39], - 'grey' : [90, 39], - 'black' : [30, 39], - 'blue' : [34, 39], - 'cyan' : [36, 39], - 'green' : [32, 39], - 'magenta' : [35, 39], - 'red' : [31, 39], - 'yellow' : [33, 39] }; - - var style = - { 'special': 'cyan', - 'number': 'blue', - 'boolean': 'yellow', - 'undefined': 'grey', - 'null': 'bold', - 'string': 'green', - 'date': 'magenta', - // "name": intentionally not styling - 'regexp': 'red' }[styleType]; - - if (style) { - return '\033[' + styles[style][0] + 'm' + str + - '\033[' + styles[style][1] + 'm'; - } else { - return str; - } - }; - if (! colors) { - stylize = function(str, styleType) { return str; }; - } - - function format(value, recurseTimes) { - // Provide a hook for user-specified inspect functions. - // Check that value is an object with an inspect function on it - if (value && typeof value.inspect === 'function' && - // Filter out the util module, it's inspect function is special - value !== exports && - // Also filter out any prototype objects using the circular check. - !(value.constructor && value.constructor.prototype === value)) { - return value.inspect(recurseTimes); - } - - // Primitive types cannot have properties - switch (typeof value) { - case 'undefined': - return stylize('undefined', 'undefined'); - - case 'string': - var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') - .replace(/'/g, "\\'") - .replace(/\\"/g, '"') + '\''; - return stylize(simple, 'string'); - - case 'number': - return stylize('' + value, 'number'); - - case 'boolean': - return stylize('' + value, 'boolean'); - } - // For some reason typeof null is "object", so special case here. - if (value === null) { - return stylize('null', 'null'); - } - - // Look up the keys of the object. - var visible_keys = Object_keys(value); - var keys = showHidden ? Object_getOwnPropertyNames(value) : visible_keys; - - // Functions without properties can be shortcutted. - if (typeof value === 'function' && keys.length === 0) { - if (isRegExp(value)) { - return stylize('' + value, 'regexp'); - } else { - var name = value.name ? ': ' + value.name : ''; - return stylize('[Function' + name + ']', 'special'); - } - } - - // Dates without properties can be shortcutted - if (isDate(value) && keys.length === 0) { - return stylize(value.toUTCString(), 'date'); - } - - var base, type, braces; - // Determine the object type - if (isArray(value)) { - type = 'Array'; - braces = ['[', ']']; - } else { - type = 'Object'; - braces = ['{', '}']; - } - - // Make functions say that they are functions - if (typeof value === 'function') { - var n = value.name ? ': ' + value.name : ''; - base = (isRegExp(value)) ? ' ' + value : ' [Function' + n + ']'; - } else { - base = ''; - } - - // Make dates with properties first say the date - if (isDate(value)) { - base = ' ' + value.toUTCString(); - } - - if (keys.length === 0) { - return braces[0] + base + braces[1]; - } - - if (recurseTimes < 0) { - if (isRegExp(value)) { - return stylize('' + value, 'regexp'); - } else { - return stylize('[Object]', 'special'); - } - } - - seen.push(value); - - var output = keys.map(function(key) { - var name, str; - if (value.__lookupGetter__) { - if (value.__lookupGetter__(key)) { - if (value.__lookupSetter__(key)) { - str = stylize('[Getter/Setter]', 'special'); - } else { - str = stylize('[Getter]', 'special'); - } - } else { - if (value.__lookupSetter__(key)) { - str = stylize('[Setter]', 'special'); - } - } - } - if (visible_keys.indexOf(key) < 0) { - name = '[' + key + ']'; - } - if (!str) { - if (seen.indexOf(value[key]) < 0) { - if (recurseTimes === null) { - str = format(value[key]); - } else { - str = format(value[key], recurseTimes - 1); - } - if (str.indexOf('\n') > -1) { - if (isArray(value)) { - str = str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n').substr(2); - } else { - str = '\n' + str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n'); - } - } - } else { - str = stylize('[Circular]', 'special'); - } - } - if (typeof name === 'undefined') { - if (type === 'Array' && key.match(/^\d+$/)) { - return str; - } - name = JSON.stringify('' + key); - if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { - name = name.substr(1, name.length - 2); - name = stylize(name, 'name'); - } else { - name = name.replace(/'/g, "\\'") - .replace(/\\"/g, '"') - .replace(/(^"|"$)/g, "'"); - name = stylize(name, 'string'); - } - } - - return name + ': ' + str; - }); - - seen.pop(); - - var numLinesEst = 0; - var length = output.reduce(function(prev, cur) { - numLinesEst++; - if (cur.indexOf('\n') >= 0) numLinesEst++; - return prev + cur.length + 1; - }, 0); - - if (length > 50) { - output = braces[0] + - (base === '' ? '' : base + '\n ') + - ' ' + - output.join(',\n ') + - ' ' + - braces[1]; - - } else { - output = braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; - } - - return output; - } - return format(obj, (typeof depth === 'undefined' ? 2 : depth)); -}; - - -function isArray(ar) { - return ar instanceof Array || - Array.isArray(ar) || - (ar && ar !== Object.prototype && isArray(ar.__proto__)); -} - - -function isRegExp(re) { - return re instanceof RegExp || - (typeof re === 'object' && Object.prototype.toString.call(re) === '[object RegExp]'); -} - - -function isDate(d) { - if (d instanceof Date) return true; - if (typeof d !== 'object') return false; - var properties = Date.prototype && Object_getOwnPropertyNames(Date.prototype); - var proto = d.__proto__ && Object_getOwnPropertyNames(d.__proto__); - return JSON.stringify(proto) === JSON.stringify(properties); -} - -function pad(n) { - return n < 10 ? '0' + n.toString(10) : n.toString(10); -} - -var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', - 'Oct', 'Nov', 'Dec']; - -// 26 Feb 16:19:34 -function timestamp() { - var d = new Date(); - var time = [pad(d.getHours()), - pad(d.getMinutes()), - pad(d.getSeconds())].join(':'); - return [d.getDate(), months[d.getMonth()], time].join(' '); -} - -exports.log = function (msg) {}; - -exports.pump = null; - -var Object_keys = Object.keys || function (obj) { - var res = []; - for (var key in obj) res.push(key); - return res; -}; - -var Object_getOwnPropertyNames = Object.getOwnPropertyNames || function (obj) { - var res = []; - for (var key in obj) { - if (Object.hasOwnProperty.call(obj, key)) res.push(key); - } - return res; -}; - -var Object_create = Object.create || function (prototype, properties) { - // from es5-shim - var object; - if (prototype === null) { - object = { '__proto__' : null }; - } - else { - if (typeof prototype !== 'object') { - throw new TypeError( - 'typeof prototype[' + (typeof prototype) + '] != \'object\'' - ); - } - var Type = function () {}; - Type.prototype = prototype; - object = new Type(); - object.__proto__ = prototype; - } - if (typeof properties !== 'undefined' && Object.defineProperties) { - Object.defineProperties(object, properties); - } - return object; -}; - -exports.inherits = function(ctor, superCtor) { - ctor.super_ = superCtor; - ctor.prototype = Object_create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); -}; - -var formatRegExp = /%[sdj%]/g; -exports.format = function(f) { - if (typeof f !== 'string') { - var objects = []; - for (var i = 0; i < arguments.length; i++) { - objects.push(exports.inspect(arguments[i])); - } - return objects.join(' '); - } - - var i = 1; - var args = arguments; - var len = args.length; - var str = String(f).replace(formatRegExp, function(x) { - if (x === '%%') return '%'; - if (i >= len) return x; - switch (x) { - case '%s': return String(args[i++]); - case '%d': return Number(args[i++]); - case '%j': return JSON.stringify(args[i++]); - default: - return x; - } - }); - for(var x = args[i]; i < len; x = args[++i]){ - if (x === null || typeof x !== 'object') { - str += ' ' + x; - } else { - str += ' ' + exports.inspect(x); - } - } - return str; -}; - -},{"events":2}],9:[function(require,module,exports){ -(function(){// UTILITY -var util = require('util'); -var Buffer = require("buffer").Buffer; -var pSlice = Array.prototype.slice; - -function objectKeys(object) { - if (Object.keys) return Object.keys(object); - var result = []; - for (var name in object) { - if (Object.prototype.hasOwnProperty.call(object, name)) { - result.push(name); - } - } - return result; -} - -// 1. The assert module provides functions that throw -// AssertionError's when particular conditions are not met. The -// assert module must conform to the following interface. - -var assert = module.exports = ok; - -// 2. The AssertionError is defined in assert. -// new assert.AssertionError({ message: message, -// actual: actual, -// expected: expected }) - -assert.AssertionError = function AssertionError(options) { - this.name = 'AssertionError'; - this.message = options.message; - this.actual = options.actual; - this.expected = options.expected; - this.operator = options.operator; - var stackStartFunction = options.stackStartFunction || fail; - - if (Error.captureStackTrace) { - Error.captureStackTrace(this, stackStartFunction); - } -}; -util.inherits(assert.AssertionError, Error); - -function replacer(key, value) { - if (value === undefined) { - return '' + value; - } - if (typeof value === 'number' && (isNaN(value) || !isFinite(value))) { - return value.toString(); - } - if (typeof value === 'function' || value instanceof RegExp) { - return value.toString(); - } - return value; -} - -function truncate(s, n) { - if (typeof s == 'string') { - return s.length < n ? s : s.slice(0, n); - } else { - return s; - } -} - -assert.AssertionError.prototype.toString = function() { - if (this.message) { - return [this.name + ':', this.message].join(' '); - } else { - return [ - this.name + ':', - truncate(JSON.stringify(this.actual, replacer), 128), - this.operator, - truncate(JSON.stringify(this.expected, replacer), 128) - ].join(' '); - } -}; - -// assert.AssertionError instanceof Error - -assert.AssertionError.__proto__ = Error.prototype; - -// At present only the three keys mentioned above are used and -// understood by the spec. Implementations or sub modules can pass -// other keys to the AssertionError's constructor - they will be -// ignored. - -// 3. All of the following functions must throw an AssertionError -// when a corresponding condition is not met, with a message that -// may be undefined if not provided. All assertion methods provide -// both the actual and expected values to the assertion error for -// display purposes. - -function fail(actual, expected, message, operator, stackStartFunction) { - throw new assert.AssertionError({ - message: message, - actual: actual, - expected: expected, - operator: operator, - stackStartFunction: stackStartFunction - }); -} - -// EXTENSION! allows for well behaved errors defined elsewhere. -assert.fail = fail; - -// 4. Pure assertion tests whether a value is truthy, as determined -// by !!guard. -// assert.ok(guard, message_opt); -// This statement is equivalent to assert.equal(true, guard, -// message_opt);. To test strictly for the value true, use -// assert.strictEqual(true, guard, message_opt);. - -function ok(value, message) { - if (!!!value) fail(value, true, message, '==', assert.ok); -} -assert.ok = ok; - -// 5. The equality assertion tests shallow, coercive equality with -// ==. -// assert.equal(actual, expected, message_opt); - -assert.equal = function equal(actual, expected, message) { - if (actual != expected) fail(actual, expected, message, '==', assert.equal); -}; - -// 6. The non-equality assertion tests for whether two objects are not equal -// with != assert.notEqual(actual, expected, message_opt); - -assert.notEqual = function notEqual(actual, expected, message) { - if (actual == expected) { - fail(actual, expected, message, '!=', assert.notEqual); - } -}; - -// 7. The equivalence assertion tests a deep equality relation. -// assert.deepEqual(actual, expected, message_opt); - -assert.deepEqual = function deepEqual(actual, expected, message) { - if (!_deepEqual(actual, expected)) { - fail(actual, expected, message, 'deepEqual', assert.deepEqual); - } -}; - -function _deepEqual(actual, expected) { - // 7.1. All identical values are equivalent, as determined by ===. - if (actual === expected) { - return true; - - } else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) { - if (actual.length != expected.length) return false; - - for (var i = 0; i < actual.length; i++) { - if (actual[i] !== expected[i]) return false; - } - - return true; - - // 7.2. If the expected value is a Date object, the actual value is - // equivalent if it is also a Date object that refers to the same time. - } else if (actual instanceof Date && expected instanceof Date) { - return actual.getTime() === expected.getTime(); - - // 7.3. Other pairs that do not both pass typeof value == 'object', - // equivalence is determined by ==. - } else if (typeof actual != 'object' && typeof expected != 'object') { - return actual == expected; - - // 7.4. For all other Object pairs, including Array objects, equivalence is - // determined by having the same number of owned properties (as verified - // with Object.prototype.hasOwnProperty.call), the same set of keys - // (although not necessarily the same order), equivalent values for every - // corresponding key, and an identical 'prototype' property. Note: this - // accounts for both named and indexed properties on Arrays. - } else { - return objEquiv(actual, expected); - } -} - -function isUndefinedOrNull(value) { - return value === null || value === undefined; -} - -function isArguments(object) { - return Object.prototype.toString.call(object) == '[object Arguments]'; -} - -function objEquiv(a, b) { - if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) - return false; - // an identical 'prototype' property. - if (a.prototype !== b.prototype) return false; - //~~~I've managed to break Object.keys through screwy arguments passing. - // Converting to array solves the problem. - if (isArguments(a)) { - if (!isArguments(b)) { - return false; - } - a = pSlice.call(a); - b = pSlice.call(b); - return _deepEqual(a, b); - } - try { - var ka = objectKeys(a), - kb = objectKeys(b), - key, i; - } catch (e) {//happens when one is a string literal and the other isn't - return false; - } - // having the same number of owned properties (keys incorporates - // hasOwnProperty) - if (ka.length != kb.length) - return false; - //the same set of keys (although not necessarily the same order), - ka.sort(); - kb.sort(); - //~~~cheap key test - for (i = ka.length - 1; i >= 0; i--) { - if (ka[i] != kb[i]) - return false; - } - //equivalent values for every corresponding key, and - //~~~possibly expensive deep test - for (i = ka.length - 1; i >= 0; i--) { - key = ka[i]; - if (!_deepEqual(a[key], b[key])) return false; - } - return true; -} - -// 8. The non-equivalence assertion tests for any deep inequality. -// assert.notDeepEqual(actual, expected, message_opt); - -assert.notDeepEqual = function notDeepEqual(actual, expected, message) { - if (_deepEqual(actual, expected)) { - fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); - } -}; - -// 9. The strict equality assertion tests strict equality, as determined by ===. -// assert.strictEqual(actual, expected, message_opt); - -assert.strictEqual = function strictEqual(actual, expected, message) { - if (actual !== expected) { - fail(actual, expected, message, '===', assert.strictEqual); - } -}; - -// 10. The strict non-equality assertion tests for strict inequality, as -// determined by !==. assert.notStrictEqual(actual, expected, message_opt); - -assert.notStrictEqual = function notStrictEqual(actual, expected, message) { - if (actual === expected) { - fail(actual, expected, message, '!==', assert.notStrictEqual); - } -}; - -function expectedException(actual, expected) { - if (!actual || !expected) { - return false; - } - - if (expected instanceof RegExp) { - return expected.test(actual); - } else if (actual instanceof expected) { - return true; - } else if (expected.call({}, actual) === true) { - return true; - } - - return false; -} - -function _throws(shouldThrow, block, expected, message) { - var actual; - - if (typeof expected === 'string') { - message = expected; - expected = null; - } - - try { - block(); - } catch (e) { - actual = e; - } - - message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + - (message ? ' ' + message : '.'); - - if (shouldThrow && !actual) { - fail('Missing expected exception' + message); - } - - if (!shouldThrow && expectedException(actual, expected)) { - fail('Got unwanted exception' + message); - } - - if ((shouldThrow && actual && expected && - !expectedException(actual, expected)) || (!shouldThrow && actual)) { - throw actual; - } -} - -// 11. Expected to throw an error: -// assert.throws(block, Error_opt, message_opt); - -assert.throws = function(block, /*optional*/error, /*optional*/message) { - _throws.apply(this, [true].concat(pSlice.call(arguments))); -}; - -// EXTENSION! This is annoying to write outside this module. -assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) { - _throws.apply(this, [false].concat(pSlice.call(arguments))); -}; - -assert.ifError = function(err) { if (err) {throw err;}}; - -})() -},{"util":8,"buffer":13}],11:[function(require,module,exports){ -(function(){// Underscore.js 1.4.4 -// http://underscorejs.org -// (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc. -// Underscore may be freely distributed under the MIT license. - -(function() { - - // Baseline setup - // -------------- - - // Establish the root object, `window` in the browser, or `global` on the server. - var root = this; - - // Save the previous value of the `_` variable. - var previousUnderscore = root._; - - // Establish the object that gets returned to break out of a loop iteration. - var breaker = {}; - - // Save bytes in the minified (but not gzipped) version: - var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; - - // Create quick reference variables for speed access to core prototypes. - var push = ArrayProto.push, - slice = ArrayProto.slice, - concat = ArrayProto.concat, - toString = ObjProto.toString, - hasOwnProperty = ObjProto.hasOwnProperty; - - // All **ECMAScript 5** native function implementations that we hope to use - // are declared here. - var - nativeForEach = ArrayProto.forEach, - nativeMap = ArrayProto.map, - nativeReduce = ArrayProto.reduce, - nativeReduceRight = ArrayProto.reduceRight, - nativeFilter = ArrayProto.filter, - nativeEvery = ArrayProto.every, - nativeSome = ArrayProto.some, - nativeIndexOf = ArrayProto.indexOf, - nativeLastIndexOf = ArrayProto.lastIndexOf, - nativeIsArray = Array.isArray, - nativeKeys = Object.keys, - nativeBind = FuncProto.bind; - - // Create a safe reference to the Underscore object for use below. - var _ = function(obj) { - if (obj instanceof _) return obj; - if (!(this instanceof _)) return new _(obj); - this._wrapped = obj; - }; - - // Export the Underscore object for **Node.js**, with - // backwards-compatibility for the old `require()` API. If we're in - // the browser, add `_` as a global object via a string identifier, - // for Closure Compiler "advanced" mode. - if (typeof exports !== 'undefined') { - if (typeof module !== 'undefined' && module.exports) { - exports = module.exports = _; - } - exports._ = _; - } else { - root._ = _; - } - - // Current version. - _.VERSION = '1.4.4'; - - // Collection Functions - // -------------------- - - // The cornerstone, an `each` implementation, aka `forEach`. - // Handles objects with the built-in `forEach`, arrays, and raw objects. - // Delegates to **ECMAScript 5**'s native `forEach` if available. - var each = _.each = _.forEach = function(obj, iterator, context) { - if (obj == null) return; - if (nativeForEach && obj.forEach === nativeForEach) { - obj.forEach(iterator, context); - } else if (obj.length === +obj.length) { - for (var i = 0, l = obj.length; i < l; i++) { - if (iterator.call(context, obj[i], i, obj) === breaker) return; - } - } else { - for (var key in obj) { - if (_.has(obj, key)) { - if (iterator.call(context, obj[key], key, obj) === breaker) return; - } - } - } - }; - - // Return the results of applying the iterator to each element. - // Delegates to **ECMAScript 5**'s native `map` if available. - _.map = _.collect = function(obj, iterator, context) { - var results = []; - if (obj == null) return results; - if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); - each(obj, function(value, index, list) { - results[results.length] = iterator.call(context, value, index, list); - }); - return results; - }; - - var reduceError = 'Reduce of empty array with no initial value'; - - // **Reduce** builds up a single result from a list of values, aka `inject`, - // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. - _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { - var initial = arguments.length > 2; - if (obj == null) obj = []; - if (nativeReduce && obj.reduce === nativeReduce) { - if (context) iterator = _.bind(iterator, context); - return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); - } - each(obj, function(value, index, list) { - if (!initial) { - memo = value; - initial = true; - } else { - memo = iterator.call(context, memo, value, index, list); - } - }); - if (!initial) throw new TypeError(reduceError); - return memo; - }; - - // The right-associative version of reduce, also known as `foldr`. - // Delegates to **ECMAScript 5**'s native `reduceRight` if available. - _.reduceRight = _.foldr = function(obj, iterator, memo, context) { - var initial = arguments.length > 2; - if (obj == null) obj = []; - if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { - if (context) iterator = _.bind(iterator, context); - return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); - } - var length = obj.length; - if (length !== +length) { - var keys = _.keys(obj); - length = keys.length; - } - each(obj, function(value, index, list) { - index = keys ? keys[--length] : --length; - if (!initial) { - memo = obj[index]; - initial = true; - } else { - memo = iterator.call(context, memo, obj[index], index, list); - } - }); - if (!initial) throw new TypeError(reduceError); - return memo; - }; - - // Return the first value which passes a truth test. Aliased as `detect`. - _.find = _.detect = function(obj, iterator, context) { - var result; - any(obj, function(value, index, list) { - if (iterator.call(context, value, index, list)) { - result = value; - return true; - } - }); - return result; - }; - - // Return all the elements that pass a truth test. - // Delegates to **ECMAScript 5**'s native `filter` if available. - // Aliased as `select`. - _.filter = _.select = function(obj, iterator, context) { - var results = []; - if (obj == null) return results; - if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); - each(obj, function(value, index, list) { - if (iterator.call(context, value, index, list)) results[results.length] = value; - }); - return results; - }; - - // Return all the elements for which a truth test fails. - _.reject = function(obj, iterator, context) { - return _.filter(obj, function(value, index, list) { - return !iterator.call(context, value, index, list); - }, context); - }; - - // Determine whether all of the elements match a truth test. - // Delegates to **ECMAScript 5**'s native `every` if available. - // Aliased as `all`. - _.every = _.all = function(obj, iterator, context) { - iterator || (iterator = _.identity); - var result = true; - if (obj == null) return result; - if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); - each(obj, function(value, index, list) { - if (!(result = result && iterator.call(context, value, index, list))) return breaker; - }); - return !!result; - }; - - // Determine if at least one element in the object matches a truth test. - // Delegates to **ECMAScript 5**'s native `some` if available. - // Aliased as `any`. - var any = _.some = _.any = function(obj, iterator, context) { - iterator || (iterator = _.identity); - var result = false; - if (obj == null) return result; - if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); - each(obj, function(value, index, list) { - if (result || (result = iterator.call(context, value, index, list))) return breaker; - }); - return !!result; - }; - - // Determine if the array or object contains a given value (using `===`). - // Aliased as `include`. - _.contains = _.include = function(obj, target) { - if (obj == null) return false; - if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; - return any(obj, function(value) { - return value === target; - }); - }; - - // Invoke a method (with arguments) on every item in a collection. - _.invoke = function(obj, method) { - var args = slice.call(arguments, 2); - var isFunc = _.isFunction(method); - return _.map(obj, function(value) { - return (isFunc ? method : value[method]).apply(value, args); - }); - }; - - // Convenience version of a common use case of `map`: fetching a property. - _.pluck = function(obj, key) { - return _.map(obj, function(value){ return value[key]; }); - }; - - // Convenience version of a common use case of `filter`: selecting only objects - // containing specific `key:value` pairs. - _.where = function(obj, attrs, first) { - if (_.isEmpty(attrs)) return first ? null : []; - return _[first ? 'find' : 'filter'](obj, function(value) { - for (var key in attrs) { - if (attrs[key] !== value[key]) return false; - } - return true; - }); - }; - - // Convenience version of a common use case of `find`: getting the first object - // containing specific `key:value` pairs. - _.findWhere = function(obj, attrs) { - return _.where(obj, attrs, true); - }; - - // Return the maximum element or (element-based computation). - // Can't optimize arrays of integers longer than 65,535 elements. - // See: https://bugs.webkit.org/show_bug.cgi?id=80797 - _.max = function(obj, iterator, context) { - if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { - return Math.max.apply(Math, obj); - } - if (!iterator && _.isEmpty(obj)) return -Infinity; - var result = {computed : -Infinity, value: -Infinity}; - each(obj, function(value, index, list) { - var computed = iterator ? iterator.call(context, value, index, list) : value; - computed >= result.computed && (result = {value : value, computed : computed}); - }); - return result.value; - }; - - // Return the minimum element (or element-based computation). - _.min = function(obj, iterator, context) { - if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { - return Math.min.apply(Math, obj); - } - if (!iterator && _.isEmpty(obj)) return Infinity; - var result = {computed : Infinity, value: Infinity}; - each(obj, function(value, index, list) { - var computed = iterator ? iterator.call(context, value, index, list) : value; - computed < result.computed && (result = {value : value, computed : computed}); - }); - return result.value; - }; - - // Shuffle an array. - _.shuffle = function(obj) { - var rand; - var index = 0; - var shuffled = []; - each(obj, function(value) { - rand = _.random(index++); - shuffled[index - 1] = shuffled[rand]; - shuffled[rand] = value; - }); - return shuffled; - }; - - // An internal function to generate lookup iterators. - var lookupIterator = function(value) { - return _.isFunction(value) ? value : function(obj){ return obj[value]; }; - }; - - // Sort the object's values by a criterion produced by an iterator. - _.sortBy = function(obj, value, context) { - var iterator = lookupIterator(value); - return _.pluck(_.map(obj, function(value, index, list) { - return { - value : value, - index : index, - criteria : iterator.call(context, value, index, list) - }; - }).sort(function(left, right) { - var a = left.criteria; - var b = right.criteria; - if (a !== b) { - if (a > b || a === void 0) return 1; - if (a < b || b === void 0) return -1; - } - return left.index < right.index ? -1 : 1; - }), 'value'); - }; - - // An internal function used for aggregate "group by" operations. - var group = function(obj, value, context, behavior) { - var result = {}; - var iterator = lookupIterator(value || _.identity); - each(obj, function(value, index) { - var key = iterator.call(context, value, index, obj); - behavior(result, key, value); - }); - return result; - }; - - // Groups the object's values by a criterion. Pass either a string attribute - // to group by, or a function that returns the criterion. - _.groupBy = function(obj, value, context) { - return group(obj, value, context, function(result, key, value) { - (_.has(result, key) ? result[key] : (result[key] = [])).push(value); - }); - }; - - // Counts instances of an object that group by a certain criterion. Pass - // either a string attribute to count by, or a function that returns the - // criterion. - _.countBy = function(obj, value, context) { - return group(obj, value, context, function(result, key) { - if (!_.has(result, key)) result[key] = 0; - result[key]++; - }); - }; - - // Use a comparator function to figure out the smallest index at which - // an object should be inserted so as to maintain order. Uses binary search. - _.sortedIndex = function(array, obj, iterator, context) { - iterator = iterator == null ? _.identity : lookupIterator(iterator); - var value = iterator.call(context, obj); - var low = 0, high = array.length; - while (low < high) { - var mid = (low + high) >>> 1; - iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid; - } - return low; - }; - - // Safely convert anything iterable into a real, live array. - _.toArray = function(obj) { - if (!obj) return []; - if (_.isArray(obj)) return slice.call(obj); - if (obj.length === +obj.length) return _.map(obj, _.identity); - return _.values(obj); - }; - - // Return the number of elements in an object. - _.size = function(obj) { - if (obj == null) return 0; - return (obj.length === +obj.length) ? obj.length : _.keys(obj).length; - }; - - // Array Functions - // --------------- - - // Get the first element of an array. Passing **n** will return the first N - // values in the array. Aliased as `head` and `take`. The **guard** check - // allows it to work with `_.map`. - _.first = _.head = _.take = function(array, n, guard) { - if (array == null) return void 0; - return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; - }; - - // Returns everything but the last entry of the array. Especially useful on - // the arguments object. Passing **n** will return all the values in - // the array, excluding the last N. The **guard** check allows it to work with - // `_.map`. - _.initial = function(array, n, guard) { - return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n)); - }; - - // Get the last element of an array. Passing **n** will return the last N - // values in the array. The **guard** check allows it to work with `_.map`. - _.last = function(array, n, guard) { - if (array == null) return void 0; - if ((n != null) && !guard) { - return slice.call(array, Math.max(array.length - n, 0)); - } else { - return array[array.length - 1]; - } - }; - - // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. - // Especially useful on the arguments object. Passing an **n** will return - // the rest N values in the array. The **guard** - // check allows it to work with `_.map`. - _.rest = _.tail = _.drop = function(array, n, guard) { - return slice.call(array, (n == null) || guard ? 1 : n); - }; - - // Trim out all falsy values from an array. - _.compact = function(array) { - return _.filter(array, _.identity); - }; - - // Internal implementation of a recursive `flatten` function. - var flatten = function(input, shallow, output) { - each(input, function(value) { - if (_.isArray(value)) { - shallow ? push.apply(output, value) : flatten(value, shallow, output); - } else { - output.push(value); - } - }); - return output; - }; - - // Return a completely flattened version of an array. - _.flatten = function(array, shallow) { - return flatten(array, shallow, []); - }; - - // Return a version of the array that does not contain the specified value(s). - _.without = function(array) { - return _.difference(array, slice.call(arguments, 1)); - }; - - // Produce a duplicate-free version of the array. If the array has already - // been sorted, you have the option of using a faster algorithm. - // Aliased as `unique`. - _.uniq = _.unique = function(array, isSorted, iterator, context) { - if (_.isFunction(isSorted)) { - context = iterator; - iterator = isSorted; - isSorted = false; - } - var initial = iterator ? _.map(array, iterator, context) : array; - var results = []; - var seen = []; - each(initial, function(value, index) { - if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) { - seen.push(value); - results.push(array[index]); - } - }); - return results; - }; - - // Produce an array that contains the union: each distinct element from all of - // the passed-in arrays. - _.union = function() { - return _.uniq(concat.apply(ArrayProto, arguments)); - }; - - // Produce an array that contains every item shared between all the - // passed-in arrays. - _.intersection = function(array) { - var rest = slice.call(arguments, 1); - return _.filter(_.uniq(array), function(item) { - return _.every(rest, function(other) { - return _.indexOf(other, item) >= 0; - }); - }); - }; - - // Take the difference between one array and a number of other arrays. - // Only the elements present in just the first array will remain. - _.difference = function(array) { - var rest = concat.apply(ArrayProto, slice.call(arguments, 1)); - return _.filter(array, function(value){ return !_.contains(rest, value); }); - }; - - // Zip together multiple lists into a single array -- elements that share - // an index go together. - _.zip = function() { - var args = slice.call(arguments); - var length = _.max(_.pluck(args, 'length')); - var results = new Array(length); - for (var i = 0; i < length; i++) { - results[i] = _.pluck(args, "" + i); - } - return results; - }; - - // Converts lists into objects. Pass either a single array of `[key, value]` - // pairs, or two parallel arrays of the same length -- one of keys, and one of - // the corresponding values. - _.object = function(list, values) { - if (list == null) return {}; - var result = {}; - for (var i = 0, l = list.length; i < l; i++) { - if (values) { - result[list[i]] = values[i]; - } else { - result[list[i][0]] = list[i][1]; - } - } - return result; - }; - - // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), - // we need this function. Return the position of the first occurrence of an - // item in an array, or -1 if the item is not included in the array. - // Delegates to **ECMAScript 5**'s native `indexOf` if available. - // If the array is large and already in sort order, pass `true` - // for **isSorted** to use binary search. - _.indexOf = function(array, item, isSorted) { - if (array == null) return -1; - var i = 0, l = array.length; - if (isSorted) { - if (typeof isSorted == 'number') { - i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted); - } else { - i = _.sortedIndex(array, item); - return array[i] === item ? i : -1; - } - } - if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted); - for (; i < l; i++) if (array[i] === item) return i; - return -1; - }; - - // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. - _.lastIndexOf = function(array, item, from) { - if (array == null) return -1; - var hasIndex = from != null; - if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) { - return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item); - } - var i = (hasIndex ? from : array.length); - while (i--) if (array[i] === item) return i; - return -1; - }; - - // Generate an integer Array containing an arithmetic progression. A port of - // the native Python `range()` function. See - // [the Python documentation](http://docs.python.org/library/functions.html#range). - _.range = function(start, stop, step) { - if (arguments.length <= 1) { - stop = start || 0; - start = 0; - } - step = arguments[2] || 1; - - var len = Math.max(Math.ceil((stop - start) / step), 0); - var idx = 0; - var range = new Array(len); - - while(idx < len) { - range[idx++] = start; - start += step; - } - - return range; - }; - - // Function (ahem) Functions - // ------------------ - - // Create a function bound to a given object (assigning `this`, and arguments, - // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if - // available. - _.bind = function(func, context) { - if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); - var args = slice.call(arguments, 2); - return function() { - return func.apply(context, args.concat(slice.call(arguments))); - }; - }; - - // Partially apply a function by creating a version that has had some of its - // arguments pre-filled, without changing its dynamic `this` context. - _.partial = function(func) { - var args = slice.call(arguments, 1); - return function() { - return func.apply(this, args.concat(slice.call(arguments))); - }; - }; - - // Bind all of an object's methods to that object. Useful for ensuring that - // all callbacks defined on an object belong to it. - _.bindAll = function(obj) { - var funcs = slice.call(arguments, 1); - if (funcs.length === 0) funcs = _.functions(obj); - each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); - return obj; - }; - - // Memoize an expensive function by storing its results. - _.memoize = function(func, hasher) { - var memo = {}; - hasher || (hasher = _.identity); - return function() { - var key = hasher.apply(this, arguments); - return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); - }; - }; - - // Delays a function for the given number of milliseconds, and then calls - // it with the arguments supplied. - _.delay = function(func, wait) { - var args = slice.call(arguments, 2); - return setTimeout(function(){ return func.apply(null, args); }, wait); - }; - - // Defers a function, scheduling it to run after the current call stack has - // cleared. - _.defer = function(func) { - return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); - }; - - // Returns a function, that, when invoked, will only be triggered at most once - // during a given window of time. - _.throttle = function(func, wait) { - var context, args, timeout, result; - var previous = 0; - var later = function() { - previous = new Date; - timeout = null; - result = func.apply(context, args); - }; - return function() { - var now = new Date; - var remaining = wait - (now - previous); - context = this; - args = arguments; - if (remaining <= 0) { - clearTimeout(timeout); - timeout = null; - previous = now; - result = func.apply(context, args); - } else if (!timeout) { - timeout = setTimeout(later, remaining); - } - return result; - }; - }; - - // Returns a function, that, as long as it continues to be invoked, will not - // be triggered. The function will be called after it stops being called for - // N milliseconds. If `immediate` is passed, trigger the function on the - // leading edge, instead of the trailing. - _.debounce = function(func, wait, immediate) { - var timeout, result; - return function() { - var context = this, args = arguments; - var later = function() { - timeout = null; - if (!immediate) result = func.apply(context, args); - }; - var callNow = immediate && !timeout; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - if (callNow) result = func.apply(context, args); - return result; - }; - }; - - // Returns a function that will be executed at most one time, no matter how - // often you call it. Useful for lazy initialization. - _.once = function(func) { - var ran = false, memo; - return function() { - if (ran) return memo; - ran = true; - memo = func.apply(this, arguments); - func = null; - return memo; - }; - }; - - // Returns the first function passed as an argument to the second, - // allowing you to adjust arguments, run code before and after, and - // conditionally execute the original function. - _.wrap = function(func, wrapper) { - return function() { - var args = [func]; - push.apply(args, arguments); - return wrapper.apply(this, args); - }; - }; - - // Returns a function that is the composition of a list of functions, each - // consuming the return value of the function that follows. - _.compose = function() { - var funcs = arguments; - return function() { - var args = arguments; - for (var i = funcs.length - 1; i >= 0; i--) { - args = [funcs[i].apply(this, args)]; - } - return args[0]; - }; - }; - - // Returns a function that will only be executed after being called N times. - _.after = function(times, func) { - if (times <= 0) return func(); - return function() { - if (--times < 1) { - return func.apply(this, arguments); - } - }; - }; - - // Object Functions - // ---------------- - - // Retrieve the names of an object's properties. - // Delegates to **ECMAScript 5**'s native `Object.keys` - _.keys = nativeKeys || function(obj) { - if (obj !== Object(obj)) throw new TypeError('Invalid object'); - var keys = []; - for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key; - return keys; - }; - - // Retrieve the values of an object's properties. - _.values = function(obj) { - var values = []; - for (var key in obj) if (_.has(obj, key)) values.push(obj[key]); - return values; - }; - - // Convert an object into a list of `[key, value]` pairs. - _.pairs = function(obj) { - var pairs = []; - for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]); - return pairs; - }; - - // Invert the keys and values of an object. The values must be serializable. - _.invert = function(obj) { - var result = {}; - for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key; - return result; - }; - - // Return a sorted list of the function names available on the object. - // Aliased as `methods` - _.functions = _.methods = function(obj) { - var names = []; - for (var key in obj) { - if (_.isFunction(obj[key])) names.push(key); - } - return names.sort(); - }; - - // Extend a given object with all the properties in passed-in object(s). - _.extend = function(obj) { - each(slice.call(arguments, 1), function(source) { - if (source) { - for (var prop in source) { - obj[prop] = source[prop]; - } - } - }); - return obj; - }; - - // Return a copy of the object only containing the whitelisted properties. - _.pick = function(obj) { - var copy = {}; - var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); - each(keys, function(key) { - if (key in obj) copy[key] = obj[key]; - }); - return copy; - }; - - // Return a copy of the object without the blacklisted properties. - _.omit = function(obj) { - var copy = {}; - var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); - for (var key in obj) { - if (!_.contains(keys, key)) copy[key] = obj[key]; - } - return copy; - }; - - // Fill in a given object with default properties. - _.defaults = function(obj) { - each(slice.call(arguments, 1), function(source) { - if (source) { - for (var prop in source) { - if (obj[prop] == null) obj[prop] = source[prop]; - } - } - }); - return obj; - }; - - // Create a (shallow-cloned) duplicate of an object. - _.clone = function(obj) { - if (!_.isObject(obj)) return obj; - return _.isArray(obj) ? obj.slice() : _.extend({}, obj); - }; - - // Invokes interceptor with the obj, and then returns obj. - // The primary purpose of this method is to "tap into" a method chain, in - // order to perform operations on intermediate results within the chain. - _.tap = function(obj, interceptor) { - interceptor(obj); - return obj; - }; - - // Internal recursive comparison function for `isEqual`. - var eq = function(a, b, aStack, bStack) { - // Identical objects are equal. `0 === -0`, but they aren't identical. - // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal. - if (a === b) return a !== 0 || 1 / a == 1 / b; - // A strict comparison is necessary because `null == undefined`. - if (a == null || b == null) return a === b; - // Unwrap any wrapped objects. - if (a instanceof _) a = a._wrapped; - if (b instanceof _) b = b._wrapped; - // Compare `[[Class]]` names. - var className = toString.call(a); - if (className != toString.call(b)) return false; - switch (className) { - // Strings, numbers, dates, and booleans are compared by value. - case '[object String]': - // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is - // equivalent to `new String("5")`. - return a == String(b); - case '[object Number]': - // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for - // other numeric values. - return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b); - case '[object Date]': - case '[object Boolean]': - // Coerce dates and booleans to numeric primitive values. Dates are compared by their - // millisecond representations. Note that invalid dates with millisecond representations - // of `NaN` are not equivalent. - return +a == +b; - // RegExps are compared by their source patterns and flags. - case '[object RegExp]': - return a.source == b.source && - a.global == b.global && - a.multiline == b.multiline && - a.ignoreCase == b.ignoreCase; - } - if (typeof a != 'object' || typeof b != 'object') return false; - // Assume equality for cyclic structures. The algorithm for detecting cyclic - // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. - var length = aStack.length; - while (length--) { - // Linear search. Performance is inversely proportional to the number of - // unique nested structures. - if (aStack[length] == a) return bStack[length] == b; - } - // Add the first object to the stack of traversed objects. - aStack.push(a); - bStack.push(b); - var size = 0, result = true; - // Recursively compare objects and arrays. - if (className == '[object Array]') { - // Compare array lengths to determine if a deep comparison is necessary. - size = a.length; - result = size == b.length; - if (result) { - // Deep compare the contents, ignoring non-numeric properties. - while (size--) { - if (!(result = eq(a[size], b[size], aStack, bStack))) break; - } - } - } else { - // Objects with different constructors are not equivalent, but `Object`s - // from different frames are. - var aCtor = a.constructor, bCtor = b.constructor; - if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) && - _.isFunction(bCtor) && (bCtor instanceof bCtor))) { - return false; - } - // Deep compare objects. - for (var key in a) { - if (_.has(a, key)) { - // Count the expected number of properties. - size++; - // Deep compare each member. - if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break; - } - } - // Ensure that both objects contain the same number of properties. - if (result) { - for (key in b) { - if (_.has(b, key) && !(size--)) break; - } - result = !size; - } - } - // Remove the first object from the stack of traversed objects. - aStack.pop(); - bStack.pop(); - return result; - }; - - // Perform a deep comparison to check if two objects are equal. - _.isEqual = function(a, b) { - return eq(a, b, [], []); - }; - - // Is a given array, string, or object empty? - // An "empty" object has no enumerable own-properties. - _.isEmpty = function(obj) { - if (obj == null) return true; - if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; - for (var key in obj) if (_.has(obj, key)) return false; - return true; - }; - - // Is a given value a DOM element? - _.isElement = function(obj) { - return !!(obj && obj.nodeType === 1); - }; - - // Is a given value an array? - // Delegates to ECMA5's native Array.isArray - _.isArray = nativeIsArray || function(obj) { - return toString.call(obj) == '[object Array]'; - }; - - // Is a given variable an object? - _.isObject = function(obj) { - return obj === Object(obj); - }; - - // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp. - each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) { - _['is' + name] = function(obj) { - return toString.call(obj) == '[object ' + name + ']'; - }; - }); - - // Define a fallback version of the method in browsers (ahem, IE), where - // there isn't any inspectable "Arguments" type. - if (!_.isArguments(arguments)) { - _.isArguments = function(obj) { - return !!(obj && _.has(obj, 'callee')); - }; - } - - // Optimize `isFunction` if appropriate. - if (typeof (/./) !== 'function') { - _.isFunction = function(obj) { - return typeof obj === 'function'; - }; - } - - // Is a given object a finite number? - _.isFinite = function(obj) { - return isFinite(obj) && !isNaN(parseFloat(obj)); - }; - - // Is the given value `NaN`? (NaN is the only number which does not equal itself). - _.isNaN = function(obj) { - return _.isNumber(obj) && obj != +obj; - }; - - // Is a given value a boolean? - _.isBoolean = function(obj) { - return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; - }; - - // Is a given value equal to null? - _.isNull = function(obj) { - return obj === null; - }; - - // Is a given variable undefined? - _.isUndefined = function(obj) { - return obj === void 0; - }; - - // Shortcut function for checking if an object has a given property directly - // on itself (in other words, not on a prototype). - _.has = function(obj, key) { - return hasOwnProperty.call(obj, key); - }; - - // Utility Functions - // ----------------- - - // Run Underscore.js in *noConflict* mode, returning the `_` variable to its - // previous owner. Returns a reference to the Underscore object. - _.noConflict = function() { - root._ = previousUnderscore; - return this; - }; - - // Keep the identity function around for default iterators. - _.identity = function(value) { - return value; - }; - - // Run a function **n** times. - _.times = function(n, iterator, context) { - var accum = Array(n); - for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i); - return accum; - }; - - // Return a random integer between min and max (inclusive). - _.random = function(min, max) { - if (max == null) { - max = min; - min = 0; - } - return min + Math.floor(Math.random() * (max - min + 1)); - }; - - // List of HTML entities for escaping. - var entityMap = { - escape: { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''', - '/': '/' - } - }; - entityMap.unescape = _.invert(entityMap.escape); - - // Regexes containing the keys and values listed immediately above. - var entityRegexes = { - escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'), - unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g') - }; - - // Functions for escaping and unescaping strings to/from HTML interpolation. - _.each(['escape', 'unescape'], function(method) { - _[method] = function(string) { - if (string == null) return ''; - return ('' + string).replace(entityRegexes[method], function(match) { - return entityMap[method][match]; - }); - }; - }); - - // If the value of the named property is a function then invoke it; - // otherwise, return it. - _.result = function(object, property) { - if (object == null) return null; - var value = object[property]; - return _.isFunction(value) ? value.call(object) : value; - }; - - // Add your own custom functions to the Underscore object. - _.mixin = function(obj) { - each(_.functions(obj), function(name){ - var func = _[name] = obj[name]; - _.prototype[name] = function() { - var args = [this._wrapped]; - push.apply(args, arguments); - return result.call(this, func.apply(_, args)); - }; - }); - }; - - // Generate a unique integer id (unique within the entire client session). - // Useful for temporary DOM ids. - var idCounter = 0; - _.uniqueId = function(prefix) { - var id = ++idCounter + ''; - return prefix ? prefix + id : id; - }; - - // By default, Underscore uses ERB-style template delimiters, change the - // following template settings to use alternative delimiters. - _.templateSettings = { - evaluate : /<%([\s\S]+?)%>/g, - interpolate : /<%=([\s\S]+?)%>/g, - escape : /<%-([\s\S]+?)%>/g - }; - - // When customizing `templateSettings`, if you don't want to define an - // interpolation, evaluation or escaping regex, we need one that is - // guaranteed not to match. - var noMatch = /(.)^/; - - // Certain characters need to be escaped so that they can be put into a - // string literal. - var escapes = { - "'": "'", - '\\': '\\', - '\r': 'r', - '\n': 'n', - '\t': 't', - '\u2028': 'u2028', - '\u2029': 'u2029' - }; - - var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; - - // JavaScript micro-templating, similar to John Resig's implementation. - // Underscore templating handles arbitrary delimiters, preserves whitespace, - // and correctly escapes quotes within interpolated code. - _.template = function(text, data, settings) { - var render; - settings = _.defaults({}, settings, _.templateSettings); - - // Combine delimiters into one regular expression via alternation. - var matcher = new RegExp([ - (settings.escape || noMatch).source, - (settings.interpolate || noMatch).source, - (settings.evaluate || noMatch).source - ].join('|') + '|$', 'g'); - - // Compile the template source, escaping string literals appropriately. - var index = 0; - var source = "__p+='"; - text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { - source += text.slice(index, offset) - .replace(escaper, function(match) { return '\\' + escapes[match]; }); - - if (escape) { - source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; - } - if (interpolate) { - source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; - } - if (evaluate) { - source += "';\n" + evaluate + "\n__p+='"; - } - index = offset + match.length; - return match; - }); - source += "';\n"; - - // If a variable is not specified, place data values in local scope. - if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; - - source = "var __t,__p='',__j=Array.prototype.join," + - "print=function(){__p+=__j.call(arguments,'');};\n" + - source + "return __p;\n"; - - try { - render = new Function(settings.variable || 'obj', '_', source); - } catch (e) { - e.source = source; - throw e; - } - - if (data) return render(data, _); - var template = function(data) { - return render.call(this, data, _); - }; - - // Provide the compiled function source as a convenience for precompilation. - template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; - - return template; - }; - - // Add a "chain" function, which will delegate to the wrapper. - _.chain = function(obj) { - return _(obj).chain(); - }; - - // OOP - // --------------- - // If Underscore is called as a function, it returns a wrapped object that - // can be used OO-style. This wrapper holds altered versions of all the - // underscore functions. Wrapped objects may be chained. - - // Helper function to continue chaining intermediate results. - var result = function(obj) { - return this._chain ? _(obj).chain() : obj; - }; - - // Add all of the Underscore functions to the wrapper object. - _.mixin(_); - - // Add all mutator Array functions to the wrapper. - each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { - var method = ArrayProto[name]; - _.prototype[name] = function() { - var obj = this._wrapped; - method.apply(obj, arguments); - if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0]; - return result.call(this, obj); - }; - }); - - // Add all accessor Array functions to the wrapper. - each(['concat', 'join', 'slice'], function(name) { - var method = ArrayProto[name]; - _.prototype[name] = function() { - return result.call(this, method.apply(this._wrapped, arguments)); - }; - }); - - _.extend(_.prototype, { - - // Start chaining a wrapped Underscore object. - chain: function() { - this._chain = true; - return this; - }, - - // Extracts the result from a wrapped and chained object. - value: function() { - return this._wrapped; - } - - }); - -}).call(this); - -})() -},{}],14:[function(require,module,exports){ -exports.readIEEE754 = function(buffer, offset, isBE, mLen, nBytes) { - var e, m, - eLen = nBytes * 8 - mLen - 1, - eMax = (1 << eLen) - 1, - eBias = eMax >> 1, - nBits = -7, - i = isBE ? 0 : (nBytes - 1), - d = isBE ? 1 : -1, - s = buffer[offset + i]; - - i += d; - - e = s & ((1 << (-nBits)) - 1); - s >>= (-nBits); - nBits += eLen; - for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8); - - m = e & ((1 << (-nBits)) - 1); - e >>= (-nBits); - nBits += mLen; - for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8); - - if (e === 0) { - e = 1 - eBias; - } else if (e === eMax) { - return m ? NaN : ((s ? -1 : 1) * Infinity); - } else { - m = m + Math.pow(2, mLen); - e = e - eBias; - } - return (s ? -1 : 1) * m * Math.pow(2, e - mLen); -}; - -exports.writeIEEE754 = function(buffer, value, offset, isBE, mLen, nBytes) { - var e, m, c, - eLen = nBytes * 8 - mLen - 1, - eMax = (1 << eLen) - 1, - eBias = eMax >> 1, - rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0), - i = isBE ? (nBytes - 1) : 0, - d = isBE ? -1 : 1, - s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0; - - value = Math.abs(value); - - if (isNaN(value) || value === Infinity) { - m = isNaN(value) ? 1 : 0; - e = eMax; - } else { - e = Math.floor(Math.log(value) / Math.LN2); - if (value * (c = Math.pow(2, -e)) < 1) { - e--; - c *= 2; - } - if (e + eBias >= 1) { - value += rt / c; - } else { - value += rt * Math.pow(2, 1 - eBias); - } - if (value * c >= 2) { - e++; - c /= 2; - } - - if (e + eBias >= eMax) { - m = 0; - e = eMax; - } else if (e + eBias >= 1) { - m = (value * c - 1) * Math.pow(2, mLen); - e = e + eBias; - } else { - m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen); - e = 0; - } - } - - for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8); - - e = (e << mLen) | m; - eLen += mLen; - for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8); - - buffer[offset + i - d] |= s * 128; -}; - -},{}],13:[function(require,module,exports){ -(function(){function SlowBuffer (size) { - this.length = size; -}; - -var assert = require('assert'); - -exports.INSPECT_MAX_BYTES = 50; - - -function toHex(n) { - if (n < 16) return '0' + n.toString(16); - return n.toString(16); -} - -function utf8ToBytes(str) { - var byteArray = []; - for (var i = 0; i < str.length; i++) - if (str.charCodeAt(i) <= 0x7F) - byteArray.push(str.charCodeAt(i)); - else { - var h = encodeURIComponent(str.charAt(i)).substr(1).split('%'); - for (var j = 0; j < h.length; j++) - byteArray.push(parseInt(h[j], 16)); - } - - return byteArray; -} - -function asciiToBytes(str) { - var byteArray = [] - for (var i = 0; i < str.length; i++ ) - // Node's code seems to be doing this and not & 0x7F.. - byteArray.push( str.charCodeAt(i) & 0xFF ); - - return byteArray; -} - -function base64ToBytes(str) { - return require("base64-js").toByteArray(str); -} - -SlowBuffer.byteLength = function (str, encoding) { - switch (encoding || "utf8") { - case 'hex': - return str.length / 2; - - case 'utf8': - case 'utf-8': - return utf8ToBytes(str).length; - - case 'ascii': - case 'binary': - return str.length; - - case 'base64': - return base64ToBytes(str).length; - - default: - throw new Error('Unknown encoding'); - } -}; - -function blitBuffer(src, dst, offset, length) { - var pos, i = 0; - while (i < length) { - if ((i+offset >= dst.length) || (i >= src.length)) - break; - - dst[i + offset] = src[i]; - i++; - } - return i; -} - -SlowBuffer.prototype.utf8Write = function (string, offset, length) { - var bytes, pos; - return SlowBuffer._charsWritten = blitBuffer(utf8ToBytes(string), this, offset, length); -}; - -SlowBuffer.prototype.asciiWrite = function (string, offset, length) { - var bytes, pos; - return SlowBuffer._charsWritten = blitBuffer(asciiToBytes(string), this, offset, length); -}; - -SlowBuffer.prototype.binaryWrite = SlowBuffer.prototype.asciiWrite; - -SlowBuffer.prototype.base64Write = function (string, offset, length) { - var bytes, pos; - return SlowBuffer._charsWritten = blitBuffer(base64ToBytes(string), this, offset, length); -}; - -SlowBuffer.prototype.base64Slice = function (start, end) { - var bytes = Array.prototype.slice.apply(this, arguments) - return require("base64-js").fromByteArray(bytes); -} - -function decodeUtf8Char(str) { - try { - return decodeURIComponent(str); - } catch (err) { - return String.fromCharCode(0xFFFD); // UTF 8 invalid char - } -} - -SlowBuffer.prototype.utf8Slice = function () { - var bytes = Array.prototype.slice.apply(this, arguments); - var res = ""; - var tmp = ""; - var i = 0; - while (i < bytes.length) { - if (bytes[i] <= 0x7F) { - res += decodeUtf8Char(tmp) + String.fromCharCode(bytes[i]); - tmp = ""; - } else - tmp += "%" + bytes[i].toString(16); - - i++; - } - - return res + decodeUtf8Char(tmp); -} - -SlowBuffer.prototype.asciiSlice = function () { - var bytes = Array.prototype.slice.apply(this, arguments); - var ret = ""; - for (var i = 0; i < bytes.length; i++) - ret += String.fromCharCode(bytes[i]); - return ret; -} - -SlowBuffer.prototype.binarySlice = SlowBuffer.prototype.asciiSlice; - -SlowBuffer.prototype.inspect = function() { - var out = [], - len = this.length; - for (var i = 0; i < len; i++) { - out[i] = toHex(this[i]); - if (i == exports.INSPECT_MAX_BYTES) { - out[i + 1] = '...'; - break; - } - } - return '<SlowBuffer ' + out.join(' ') + '>'; -}; - - -SlowBuffer.prototype.hexSlice = function(start, end) { - var len = this.length; - - if (!start || start < 0) start = 0; - if (!end || end < 0 || end > len) end = len; - - var out = ''; - for (var i = start; i < end; i++) { - out += toHex(this[i]); - } - return out; -}; - - -SlowBuffer.prototype.toString = function(encoding, start, end) { - encoding = String(encoding || 'utf8').toLowerCase(); - start = +start || 0; - if (typeof end == 'undefined') end = this.length; - - // Fastpath empty strings - if (+end == start) { - return ''; - } - - switch (encoding) { - case 'hex': - return this.hexSlice(start, end); - - case 'utf8': - case 'utf-8': - return this.utf8Slice(start, end); - - case 'ascii': - return this.asciiSlice(start, end); - - case 'binary': - return this.binarySlice(start, end); - - case 'base64': - return this.base64Slice(start, end); - - case 'ucs2': - case 'ucs-2': - return this.ucs2Slice(start, end); - - default: - throw new Error('Unknown encoding'); - } -}; - - -SlowBuffer.prototype.hexWrite = function(string, offset, length) { - offset = +offset || 0; - var remaining = this.length - offset; - if (!length) { - length = remaining; - } else { - length = +length; - if (length > remaining) { - length = remaining; - } - } - - // must be an even number of digits - var strLen = string.length; - if (strLen % 2) { - throw new Error('Invalid hex string'); - } - if (length > strLen / 2) { - length = strLen / 2; - } - for (var i = 0; i < length; i++) { - var byte = parseInt(string.substr(i * 2, 2), 16); - if (isNaN(byte)) throw new Error('Invalid hex string'); - this[offset + i] = byte; - } - SlowBuffer._charsWritten = i * 2; - return i; -}; - - -SlowBuffer.prototype.write = function(string, offset, length, encoding) { - // Support both (string, offset, length, encoding) - // and the legacy (string, encoding, offset, length) - if (isFinite(offset)) { - if (!isFinite(length)) { - encoding = length; - length = undefined; - } - } else { // legacy - var swap = encoding; - encoding = offset; - offset = length; - length = swap; - } - - offset = +offset || 0; - var remaining = this.length - offset; - if (!length) { - length = remaining; - } else { - length = +length; - if (length > remaining) { - length = remaining; - } - } - encoding = String(encoding || 'utf8').toLowerCase(); - - switch (encoding) { - case 'hex': - return this.hexWrite(string, offset, length); - - case 'utf8': - case 'utf-8': - return this.utf8Write(string, offset, length); - - case 'ascii': - return this.asciiWrite(string, offset, length); - - case 'binary': - return this.binaryWrite(string, offset, length); - - case 'base64': - return this.base64Write(string, offset, length); - - case 'ucs2': - case 'ucs-2': - return this.ucs2Write(string, offset, length); - - default: - throw new Error('Unknown encoding'); - } -}; - - -// slice(start, end) -SlowBuffer.prototype.slice = function(start, end) { - if (end === undefined) end = this.length; - - if (end > this.length) { - throw new Error('oob'); - } - if (start > end) { - throw new Error('oob'); - } - - return new Buffer(this, end - start, +start); -}; - -SlowBuffer.prototype.copy = function(target, targetstart, sourcestart, sourceend) { - var temp = []; - for (var i=sourcestart; i<sourceend; i++) { - assert.ok(typeof this[i] !== 'undefined', "copying undefined buffer bytes!"); - temp.push(this[i]); - } - - for (var i=targetstart; i<targetstart+temp.length; i++) { - target[i] = temp[i-targetstart]; - } -}; - -SlowBuffer.prototype.fill = function(value, start, end) { - if (end > this.length) { - throw new Error('oob'); - } - if (start > end) { - throw new Error('oob'); - } - - for (var i = start; i < end; i++) { - this[i] = value; - } -} - -function coerce(length) { - // Coerce length to a number (possibly NaN), round up - // in case it's fractional (e.g. 123.456) then do a - // double negate to coerce a NaN to 0. Easy, right? - length = ~~Math.ceil(+length); - return length < 0 ? 0 : length; -} - - -// Buffer - -function Buffer(subject, encoding, offset) { - if (!(this instanceof Buffer)) { - return new Buffer(subject, encoding, offset); - } - - var type; - - // Are we slicing? - if (typeof offset === 'number') { - this.length = coerce(encoding); - this.parent = subject; - this.offset = offset; - } else { - // Find the length - switch (type = typeof subject) { - case 'number': - this.length = coerce(subject); - break; - - case 'string': - this.length = Buffer.byteLength(subject, encoding); - break; - - case 'object': // Assume object is an array - this.length = coerce(subject.length); - break; - - default: - throw new Error('First argument needs to be a number, ' + - 'array or string.'); - } - - if (this.length > Buffer.poolSize) { - // Big buffer, just alloc one. - this.parent = new SlowBuffer(this.length); - this.offset = 0; - - } else { - // Small buffer. - if (!pool || pool.length - pool.used < this.length) allocPool(); - this.parent = pool; - this.offset = pool.used; - pool.used += this.length; - } - - // Treat array-ish objects as a byte array. - if (isArrayIsh(subject)) { - for (var i = 0; i < this.length; i++) { - if (subject instanceof Buffer) { - this.parent[i + this.offset] = subject.readUInt8(i); - } - else { - this.parent[i + this.offset] = subject[i]; - } - } - } else if (type == 'string') { - // We are a string - this.length = this.write(subject, 0, encoding); - } - } - -} - -function isArrayIsh(subject) { - return Array.isArray(subject) || Buffer.isBuffer(subject) || - subject && typeof subject === 'object' && - typeof subject.length === 'number'; -} - -exports.SlowBuffer = SlowBuffer; -exports.Buffer = Buffer; - -Buffer.poolSize = 8 * 1024; -var pool; - -function allocPool() { - pool = new SlowBuffer(Buffer.poolSize); - pool.used = 0; -} - - -// Static methods -Buffer.isBuffer = function isBuffer(b) { - return b instanceof Buffer || b instanceof SlowBuffer; -}; - -Buffer.concat = function (list, totalLength) { - if (!Array.isArray(list)) { - throw new Error("Usage: Buffer.concat(list, [totalLength])\n \ - list should be an Array."); - } - - if (list.length === 0) { - return new Buffer(0); - } else if (list.length === 1) { - return list[0]; - } - - if (typeof totalLength !== 'number') { - totalLength = 0; - for (var i = 0; i < list.length; i++) { - var buf = list[i]; - totalLength += buf.length; - } - } - - var buffer = new Buffer(totalLength); - var pos = 0; - for (var i = 0; i < list.length; i++) { - var buf = list[i]; - buf.copy(buffer, pos); - pos += buf.length; - } - return buffer; -}; - -// Inspect -Buffer.prototype.inspect = function inspect() { - var out = [], - len = this.length; - - for (var i = 0; i < len; i++) { - out[i] = toHex(this.parent[i + this.offset]); - if (i == exports.INSPECT_MAX_BYTES) { - out[i + 1] = '...'; - break; - } - } - - return '<Buffer ' + out.join(' ') + '>'; -}; - - -Buffer.prototype.get = function get(i) { - if (i < 0 || i >= this.length) throw new Error('oob'); - return this.parent[this.offset + i]; -}; - - -Buffer.prototype.set = function set(i, v) { - if (i < 0 || i >= this.length) throw new Error('oob'); - return this.parent[this.offset + i] = v; -}; - - -// write(string, offset = 0, length = buffer.length-offset, encoding = 'utf8') -Buffer.prototype.write = function(string, offset, length, encoding) { - // Support both (string, offset, length, encoding) - // and the legacy (string, encoding, offset, length) - if (isFinite(offset)) { - if (!isFinite(length)) { - encoding = length; - length = undefined; - } - } else { // legacy - var swap = encoding; - encoding = offset; - offset = length; - length = swap; - } - - offset = +offset || 0; - var remaining = this.length - offset; - if (!length) { - length = remaining; - } else { - length = +length; - if (length > remaining) { - length = remaining; - } - } - encoding = String(encoding || 'utf8').toLowerCase(); - - var ret; - switch (encoding) { - case 'hex': - ret = this.parent.hexWrite(string, this.offset + offset, length); - break; - - case 'utf8': - case 'utf-8': - ret = this.parent.utf8Write(string, this.offset + offset, length); - break; - - case 'ascii': - ret = this.parent.asciiWrite(string, this.offset + offset, length); - break; - - case 'binary': - ret = this.parent.binaryWrite(string, this.offset + offset, length); - break; - - case 'base64': - // Warning: maxLength not taken into account in base64Write - ret = this.parent.base64Write(string, this.offset + offset, length); - break; - - case 'ucs2': - case 'ucs-2': - ret = this.parent.ucs2Write(string, this.offset + offset, length); - break; - - default: - throw new Error('Unknown encoding'); - } - - Buffer._charsWritten = SlowBuffer._charsWritten; - - return ret; -}; - - -// toString(encoding, start=0, end=buffer.length) -Buffer.prototype.toString = function(encoding, start, end) { - encoding = String(encoding || 'utf8').toLowerCase(); - - if (typeof start == 'undefined' || start < 0) { - start = 0; - } else if (start > this.length) { - start = this.length; - } - - if (typeof end == 'undefined' || end > this.length) { - end = this.length; - } else if (end < 0) { - end = 0; - } - - start = start + this.offset; - end = end + this.offset; - - switch (encoding) { - case 'hex': - return this.parent.hexSlice(start, end); - - case 'utf8': - case 'utf-8': - return this.parent.utf8Slice(start, end); - - case 'ascii': - return this.parent.asciiSlice(start, end); - - case 'binary': - return this.parent.binarySlice(start, end); - - case 'base64': - return this.parent.base64Slice(start, end); - - case 'ucs2': - case 'ucs-2': - return this.parent.ucs2Slice(start, end); - - default: - throw new Error('Unknown encoding'); - } -}; - - -// byteLength -Buffer.byteLength = SlowBuffer.byteLength; - - -// fill(value, start=0, end=buffer.length) -Buffer.prototype.fill = function fill(value, start, end) { - value || (value = 0); - start || (start = 0); - end || (end = this.length); - - if (typeof value === 'string') { - value = value.charCodeAt(0); - } - if (!(typeof value === 'number') || isNaN(value)) { - throw new Error('value is not a number'); - } - - if (end < start) throw new Error('end < start'); - - // Fill 0 bytes; we're done - if (end === start) return 0; - if (this.length == 0) return 0; - - if (start < 0 || start >= this.length) { - throw new Error('start out of bounds'); - } - - if (end < 0 || end > this.length) { - throw new Error('end out of bounds'); - } - - return this.parent.fill(value, - start + this.offset, - end + this.offset); -}; - - -// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) -Buffer.prototype.copy = function(target, target_start, start, end) { - var source = this; - start || (start = 0); - end || (end = this.length); - target_start || (target_start = 0); - - if (end < start) throw new Error('sourceEnd < sourceStart'); - - // Copy 0 bytes; we're done - if (end === start) return 0; - if (target.length == 0 || source.length == 0) return 0; - - if (target_start < 0 || target_start >= target.length) { - throw new Error('targetStart out of bounds'); - } - - if (start < 0 || start >= source.length) { - throw new Error('sourceStart out of bounds'); - } - - if (end < 0 || end > source.length) { - throw new Error('sourceEnd out of bounds'); - } - - // Are we oob? - if (end > this.length) { - end = this.length; - } - - if (target.length - target_start < end - start) { - end = target.length - target_start + start; - } - - return this.parent.copy(target.parent, - target_start + target.offset, - start + this.offset, - end + this.offset); -}; - - -// slice(start, end) -Buffer.prototype.slice = function(start, end) { - if (end === undefined) end = this.length; - if (end > this.length) throw new Error('oob'); - if (start > end) throw new Error('oob'); - - return new Buffer(this.parent, end - start, +start + this.offset); -}; - - -// Legacy methods for backwards compatibility. - -Buffer.prototype.utf8Slice = function(start, end) { - return this.toString('utf8', start, end); -}; - -Buffer.prototype.binarySlice = function(start, end) { - return this.toString('binary', start, end); -}; - -Buffer.prototype.asciiSlice = function(start, end) { - return this.toString('ascii', start, end); -}; - -Buffer.prototype.utf8Write = function(string, offset) { - return this.write(string, offset, 'utf8'); -}; - -Buffer.prototype.binaryWrite = function(string, offset) { - return this.write(string, offset, 'binary'); -}; - -Buffer.prototype.asciiWrite = function(string, offset) { - return this.write(string, offset, 'ascii'); -}; - -Buffer.prototype.readUInt8 = function(offset, noAssert) { - var buffer = this; - - if (!noAssert) { - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset < buffer.length, - 'Trying to read beyond buffer length'); - } - - if (offset >= buffer.length) return; - - return buffer.parent[buffer.offset + offset]; -}; - -function readUInt16(buffer, offset, isBigEndian, noAssert) { - var val = 0; - - - if (!noAssert) { - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset + 1 < buffer.length, - 'Trying to read beyond buffer length'); - } - - if (offset >= buffer.length) return 0; - - if (isBigEndian) { - val = buffer.parent[buffer.offset + offset] << 8; - if (offset + 1 < buffer.length) { - val |= buffer.parent[buffer.offset + offset + 1]; - } - } else { - val = buffer.parent[buffer.offset + offset]; - if (offset + 1 < buffer.length) { - val |= buffer.parent[buffer.offset + offset + 1] << 8; - } - } - - return val; -} - -Buffer.prototype.readUInt16LE = function(offset, noAssert) { - return readUInt16(this, offset, false, noAssert); -}; - -Buffer.prototype.readUInt16BE = function(offset, noAssert) { - return readUInt16(this, offset, true, noAssert); -}; - -function readUInt32(buffer, offset, isBigEndian, noAssert) { - var val = 0; - - if (!noAssert) { - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset + 3 < buffer.length, - 'Trying to read beyond buffer length'); - } - - if (offset >= buffer.length) return 0; - - if (isBigEndian) { - if (offset + 1 < buffer.length) - val = buffer.parent[buffer.offset + offset + 1] << 16; - if (offset + 2 < buffer.length) - val |= buffer.parent[buffer.offset + offset + 2] << 8; - if (offset + 3 < buffer.length) - val |= buffer.parent[buffer.offset + offset + 3]; - val = val + (buffer.parent[buffer.offset + offset] << 24 >>> 0); - } else { - if (offset + 2 < buffer.length) - val = buffer.parent[buffer.offset + offset + 2] << 16; - if (offset + 1 < buffer.length) - val |= buffer.parent[buffer.offset + offset + 1] << 8; - val |= buffer.parent[buffer.offset + offset]; - if (offset + 3 < buffer.length) - val = val + (buffer.parent[buffer.offset + offset + 3] << 24 >>> 0); - } - - return val; -} - -Buffer.prototype.readUInt32LE = function(offset, noAssert) { - return readUInt32(this, offset, false, noAssert); -}; - -Buffer.prototype.readUInt32BE = function(offset, noAssert) { - return readUInt32(this, offset, true, noAssert); -}; - - -/* - * Signed integer types, yay team! A reminder on how two's complement actually - * works. The first bit is the signed bit, i.e. tells us whether or not the - * number should be positive or negative. If the two's complement value is - * positive, then we're done, as it's equivalent to the unsigned representation. - * - * Now if the number is positive, you're pretty much done, you can just leverage - * the unsigned translations and return those. Unfortunately, negative numbers - * aren't quite that straightforward. - * - * At first glance, one might be inclined to use the traditional formula to - * translate binary numbers between the positive and negative values in two's - * complement. (Though it doesn't quite work for the most negative value) - * Mainly: - * - invert all the bits - * - add one to the result - * - * Of course, this doesn't quite work in Javascript. Take for example the value - * of -128. This could be represented in 16 bits (big-endian) as 0xff80. But of - * course, Javascript will do the following: - * - * > ~0xff80 - * -65409 - * - * Whoh there, Javascript, that's not quite right. But wait, according to - * Javascript that's perfectly correct. When Javascript ends up seeing the - * constant 0xff80, it has no notion that it is actually a signed number. It - * assumes that we've input the unsigned value 0xff80. Thus, when it does the - * binary negation, it casts it into a signed value, (positive 0xff80). Then - * when you perform binary negation on that, it turns it into a negative number. - * - * Instead, we're going to have to use the following general formula, that works - * in a rather Javascript friendly way. I'm glad we don't support this kind of - * weird numbering scheme in the kernel. - * - * (BIT-MAX - (unsigned)val + 1) * -1 - * - * The astute observer, may think that this doesn't make sense for 8-bit numbers - * (really it isn't necessary for them). However, when you get 16-bit numbers, - * you do. Let's go back to our prior example and see how this will look: - * - * (0xffff - 0xff80 + 1) * -1 - * (0x007f + 1) * -1 - * (0x0080) * -1 - */ -Buffer.prototype.readInt8 = function(offset, noAssert) { - var buffer = this; - var neg; - - if (!noAssert) { - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset < buffer.length, - 'Trying to read beyond buffer length'); - } - - if (offset >= buffer.length) return; - - neg = buffer.parent[buffer.offset + offset] & 0x80; - if (!neg) { - return (buffer.parent[buffer.offset + offset]); - } - - return ((0xff - buffer.parent[buffer.offset + offset] + 1) * -1); -}; - -function readInt16(buffer, offset, isBigEndian, noAssert) { - var neg, val; - - if (!noAssert) { - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset + 1 < buffer.length, - 'Trying to read beyond buffer length'); - } - - val = readUInt16(buffer, offset, isBigEndian, noAssert); - neg = val & 0x8000; - if (!neg) { - return val; - } - - return (0xffff - val + 1) * -1; -} - -Buffer.prototype.readInt16LE = function(offset, noAssert) { - return readInt16(this, offset, false, noAssert); -}; - -Buffer.prototype.readInt16BE = function(offset, noAssert) { - return readInt16(this, offset, true, noAssert); -}; - -function readInt32(buffer, offset, isBigEndian, noAssert) { - var neg, val; - - if (!noAssert) { - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset + 3 < buffer.length, - 'Trying to read beyond buffer length'); - } - - val = readUInt32(buffer, offset, isBigEndian, noAssert); - neg = val & 0x80000000; - if (!neg) { - return (val); - } - - return (0xffffffff - val + 1) * -1; -} - -Buffer.prototype.readInt32LE = function(offset, noAssert) { - return readInt32(this, offset, false, noAssert); -}; - -Buffer.prototype.readInt32BE = function(offset, noAssert) { - return readInt32(this, offset, true, noAssert); -}; - -function readFloat(buffer, offset, isBigEndian, noAssert) { - if (!noAssert) { - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset + 3 < buffer.length, - 'Trying to read beyond buffer length'); - } - - return require('./buffer_ieee754').readIEEE754(buffer, offset, isBigEndian, - 23, 4); -} - -Buffer.prototype.readFloatLE = function(offset, noAssert) { - return readFloat(this, offset, false, noAssert); -}; - -Buffer.prototype.readFloatBE = function(offset, noAssert) { - return readFloat(this, offset, true, noAssert); -}; - -function readDouble(buffer, offset, isBigEndian, noAssert) { - if (!noAssert) { - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset + 7 < buffer.length, - 'Trying to read beyond buffer length'); - } - - return require('./buffer_ieee754').readIEEE754(buffer, offset, isBigEndian, - 52, 8); -} - -Buffer.prototype.readDoubleLE = function(offset, noAssert) { - return readDouble(this, offset, false, noAssert); -}; - -Buffer.prototype.readDoubleBE = function(offset, noAssert) { - return readDouble(this, offset, true, noAssert); -}; - - -/* - * We have to make sure that the value is a valid integer. This means that it is - * non-negative. It has no fractional component and that it does not exceed the - * maximum allowed value. - * - * value The number to check for validity - * - * max The maximum value - */ -function verifuint(value, max) { - assert.ok(typeof (value) == 'number', - 'cannot write a non-number as a number'); - - assert.ok(value >= 0, - 'specified a negative value for writing an unsigned value'); - - assert.ok(value <= max, 'value is larger than maximum value for type'); - - assert.ok(Math.floor(value) === value, 'value has a fractional component'); -} - -Buffer.prototype.writeUInt8 = function(value, offset, noAssert) { - var buffer = this; - - if (!noAssert) { - assert.ok(value !== undefined && value !== null, - 'missing value'); - - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset < buffer.length, - 'trying to write beyond buffer length'); - - verifuint(value, 0xff); - } - - if (offset < buffer.length) { - buffer.parent[buffer.offset + offset] = value; - } -}; - -function writeUInt16(buffer, value, offset, isBigEndian, noAssert) { - if (!noAssert) { - assert.ok(value !== undefined && value !== null, - 'missing value'); - - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset + 1 < buffer.length, - 'trying to write beyond buffer length'); - - verifuint(value, 0xffff); - } - - for (var i = 0; i < Math.min(buffer.length - offset, 2); i++) { - buffer.parent[buffer.offset + offset + i] = - (value & (0xff << (8 * (isBigEndian ? 1 - i : i)))) >>> - (isBigEndian ? 1 - i : i) * 8; - } - -} - -Buffer.prototype.writeUInt16LE = function(value, offset, noAssert) { - writeUInt16(this, value, offset, false, noAssert); -}; - -Buffer.prototype.writeUInt16BE = function(value, offset, noAssert) { - writeUInt16(this, value, offset, true, noAssert); -}; - -function writeUInt32(buffer, value, offset, isBigEndian, noAssert) { - if (!noAssert) { - assert.ok(value !== undefined && value !== null, - 'missing value'); - - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset + 3 < buffer.length, - 'trying to write beyond buffer length'); - - verifuint(value, 0xffffffff); - } - - for (var i = 0; i < Math.min(buffer.length - offset, 4); i++) { - buffer.parent[buffer.offset + offset + i] = - (value >>> (isBigEndian ? 3 - i : i) * 8) & 0xff; - } -} - -Buffer.prototype.writeUInt32LE = function(value, offset, noAssert) { - writeUInt32(this, value, offset, false, noAssert); -}; - -Buffer.prototype.writeUInt32BE = function(value, offset, noAssert) { - writeUInt32(this, value, offset, true, noAssert); -}; - - -/* - * We now move onto our friends in the signed number category. Unlike unsigned - * numbers, we're going to have to worry a bit more about how we put values into - * arrays. Since we are only worrying about signed 32-bit values, we're in - * slightly better shape. Unfortunately, we really can't do our favorite binary - * & in this system. It really seems to do the wrong thing. For example: - * - * > -32 & 0xff - * 224 - * - * What's happening above is really: 0xe0 & 0xff = 0xe0. However, the results of - * this aren't treated as a signed number. Ultimately a bad thing. - * - * What we're going to want to do is basically create the unsigned equivalent of - * our representation and pass that off to the wuint* functions. To do that - * we're going to do the following: - * - * - if the value is positive - * we can pass it directly off to the equivalent wuint - * - if the value is negative - * we do the following computation: - * mb + val + 1, where - * mb is the maximum unsigned value in that byte size - * val is the Javascript negative integer - * - * - * As a concrete value, take -128. In signed 16 bits this would be 0xff80. If - * you do out the computations: - * - * 0xffff - 128 + 1 - * 0xffff - 127 - * 0xff80 - * - * You can then encode this value as the signed version. This is really rather - * hacky, but it should work and get the job done which is our goal here. - */ - -/* - * A series of checks to make sure we actually have a signed 32-bit number - */ -function verifsint(value, max, min) { - assert.ok(typeof (value) == 'number', - 'cannot write a non-number as a number'); - - assert.ok(value <= max, 'value larger than maximum allowed value'); - - assert.ok(value >= min, 'value smaller than minimum allowed value'); - - assert.ok(Math.floor(value) === value, 'value has a fractional component'); -} - -function verifIEEE754(value, max, min) { - assert.ok(typeof (value) == 'number', - 'cannot write a non-number as a number'); - - assert.ok(value <= max, 'value larger than maximum allowed value'); - - assert.ok(value >= min, 'value smaller than minimum allowed value'); -} - -Buffer.prototype.writeInt8 = function(value, offset, noAssert) { - var buffer = this; - - if (!noAssert) { - assert.ok(value !== undefined && value !== null, - 'missing value'); - - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset < buffer.length, - 'Trying to write beyond buffer length'); - - verifsint(value, 0x7f, -0x80); - } - - if (value >= 0) { - buffer.writeUInt8(value, offset, noAssert); - } else { - buffer.writeUInt8(0xff + value + 1, offset, noAssert); - } -}; - -function writeInt16(buffer, value, offset, isBigEndian, noAssert) { - if (!noAssert) { - assert.ok(value !== undefined && value !== null, - 'missing value'); - - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset + 1 < buffer.length, - 'Trying to write beyond buffer length'); - - verifsint(value, 0x7fff, -0x8000); - } - - if (value >= 0) { - writeUInt16(buffer, value, offset, isBigEndian, noAssert); - } else { - writeUInt16(buffer, 0xffff + value + 1, offset, isBigEndian, noAssert); - } -} - -Buffer.prototype.writeInt16LE = function(value, offset, noAssert) { - writeInt16(this, value, offset, false, noAssert); -}; - -Buffer.prototype.writeInt16BE = function(value, offset, noAssert) { - writeInt16(this, value, offset, true, noAssert); -}; - -function writeInt32(buffer, value, offset, isBigEndian, noAssert) { - if (!noAssert) { - assert.ok(value !== undefined && value !== null, - 'missing value'); - - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset + 3 < buffer.length, - 'Trying to write beyond buffer length'); - - verifsint(value, 0x7fffffff, -0x80000000); - } - - if (value >= 0) { - writeUInt32(buffer, value, offset, isBigEndian, noAssert); - } else { - writeUInt32(buffer, 0xffffffff + value + 1, offset, isBigEndian, noAssert); - } -} - -Buffer.prototype.writeInt32LE = function(value, offset, noAssert) { - writeInt32(this, value, offset, false, noAssert); -}; - -Buffer.prototype.writeInt32BE = function(value, offset, noAssert) { - writeInt32(this, value, offset, true, noAssert); -}; - -function writeFloat(buffer, value, offset, isBigEndian, noAssert) { - if (!noAssert) { - assert.ok(value !== undefined && value !== null, - 'missing value'); - - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset + 3 < buffer.length, - 'Trying to write beyond buffer length'); - - verifIEEE754(value, 3.4028234663852886e+38, -3.4028234663852886e+38); - } - - require('./buffer_ieee754').writeIEEE754(buffer, value, offset, isBigEndian, - 23, 4); -} - -Buffer.prototype.writeFloatLE = function(value, offset, noAssert) { - writeFloat(this, value, offset, false, noAssert); -}; - -Buffer.prototype.writeFloatBE = function(value, offset, noAssert) { - writeFloat(this, value, offset, true, noAssert); -}; - -function writeDouble(buffer, value, offset, isBigEndian, noAssert) { - if (!noAssert) { - assert.ok(value !== undefined && value !== null, - 'missing value'); - - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset + 7 < buffer.length, - 'Trying to write beyond buffer length'); - - verifIEEE754(value, 1.7976931348623157E+308, -1.7976931348623157E+308); - } - - require('./buffer_ieee754').writeIEEE754(buffer, value, offset, isBigEndian, - 52, 8); -} - -Buffer.prototype.writeDoubleLE = function(value, offset, noAssert) { - writeDouble(this, value, offset, false, noAssert); -}; - -Buffer.prototype.writeDoubleBE = function(value, offset, noAssert) { - writeDouble(this, value, offset, true, noAssert); -}; - -SlowBuffer.prototype.readUInt8 = Buffer.prototype.readUInt8; -SlowBuffer.prototype.readUInt16LE = Buffer.prototype.readUInt16LE; -SlowBuffer.prototype.readUInt16BE = Buffer.prototype.readUInt16BE; -SlowBuffer.prototype.readUInt32LE = Buffer.prototype.readUInt32LE; -SlowBuffer.prototype.readUInt32BE = Buffer.prototype.readUInt32BE; -SlowBuffer.prototype.readInt8 = Buffer.prototype.readInt8; -SlowBuffer.prototype.readInt16LE = Buffer.prototype.readInt16LE; -SlowBuffer.prototype.readInt16BE = Buffer.prototype.readInt16BE; -SlowBuffer.prototype.readInt32LE = Buffer.prototype.readInt32LE; -SlowBuffer.prototype.readInt32BE = Buffer.prototype.readInt32BE; -SlowBuffer.prototype.readFloatLE = Buffer.prototype.readFloatLE; -SlowBuffer.prototype.readFloatBE = Buffer.prototype.readFloatBE; -SlowBuffer.prototype.readDoubleLE = Buffer.prototype.readDoubleLE; -SlowBuffer.prototype.readDoubleBE = Buffer.prototype.readDoubleBE; -SlowBuffer.prototype.writeUInt8 = Buffer.prototype.writeUInt8; -SlowBuffer.prototype.writeUInt16LE = Buffer.prototype.writeUInt16LE; -SlowBuffer.prototype.writeUInt16BE = Buffer.prototype.writeUInt16BE; -SlowBuffer.prototype.writeUInt32LE = Buffer.prototype.writeUInt32LE; -SlowBuffer.prototype.writeUInt32BE = Buffer.prototype.writeUInt32BE; -SlowBuffer.prototype.writeInt8 = Buffer.prototype.writeInt8; -SlowBuffer.prototype.writeInt16LE = Buffer.prototype.writeInt16LE; -SlowBuffer.prototype.writeInt16BE = Buffer.prototype.writeInt16BE; -SlowBuffer.prototype.writeInt32LE = Buffer.prototype.writeInt32LE; -SlowBuffer.prototype.writeInt32BE = Buffer.prototype.writeInt32BE; -SlowBuffer.prototype.writeFloatLE = Buffer.prototype.writeFloatLE; -SlowBuffer.prototype.writeFloatBE = Buffer.prototype.writeFloatBE; -SlowBuffer.prototype.writeDoubleLE = Buffer.prototype.writeDoubleLE; -SlowBuffer.prototype.writeDoubleBE = Buffer.prototype.writeDoubleBE; - -})() -},{"assert":9,"./buffer_ieee754":14,"base64-js":15}],15:[function(require,module,exports){ -(function (exports) { - 'use strict'; - - var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - - function b64ToByteArray(b64) { - var i, j, l, tmp, placeHolders, arr; - - if (b64.length % 4 > 0) { - throw 'Invalid string. Length must be a multiple of 4'; - } - - // the number of equal signs (place holders) - // if there are two placeholders, than the two characters before it - // represent one byte - // if there is only one, then the three characters before it represent 2 bytes - // this is just a cheap hack to not do indexOf twice - placeHolders = b64.indexOf('='); - placeHolders = placeHolders > 0 ? b64.length - placeHolders : 0; - - // base64 is 4/3 + up to two characters of the original data - arr = [];//new Uint8Array(b64.length * 3 / 4 - placeHolders); - - // if there are placeholders, only get up to the last complete 4 chars - l = placeHolders > 0 ? b64.length - 4 : b64.length; - - for (i = 0, j = 0; i < l; i += 4, j += 3) { - tmp = (lookup.indexOf(b64[i]) << 18) | (lookup.indexOf(b64[i + 1]) << 12) | (lookup.indexOf(b64[i + 2]) << 6) | lookup.indexOf(b64[i + 3]); - arr.push((tmp & 0xFF0000) >> 16); - arr.push((tmp & 0xFF00) >> 8); - arr.push(tmp & 0xFF); - } - - if (placeHolders === 2) { - tmp = (lookup.indexOf(b64[i]) << 2) | (lookup.indexOf(b64[i + 1]) >> 4); - arr.push(tmp & 0xFF); - } else if (placeHolders === 1) { - tmp = (lookup.indexOf(b64[i]) << 10) | (lookup.indexOf(b64[i + 1]) << 4) | (lookup.indexOf(b64[i + 2]) >> 2); - arr.push((tmp >> 8) & 0xFF); - arr.push(tmp & 0xFF); - } - - return arr; - } - - function uint8ToBase64(uint8) { - var i, - extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes - output = "", - temp, length; - - function tripletToBase64 (num) { - return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]; - }; - - // go through the array every three bytes, we'll deal with trailing stuff later - for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) { - temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]); - output += tripletToBase64(temp); - } - - // pad the end with zeros, but make sure to not forget the extra bytes - switch (extraBytes) { - case 1: - temp = uint8[uint8.length - 1]; - output += lookup[temp >> 2]; - output += lookup[(temp << 4) & 0x3F]; - output += '=='; - break; - case 2: - temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]); - output += lookup[temp >> 10]; - output += lookup[(temp >> 4) & 0x3F]; - output += lookup[(temp << 2) & 0x3F]; - output += '='; - break; - } - - return output; - } - - module.exports.toByteArray = b64ToByteArray; - module.exports.fromByteArray = uint8ToBase64; -}()); - -},{}]},{},["E/GbHF"]) -; -JSHINT = require('jshint').JSHINT; -}()); diff --git a/dom/system/gonk/tests/marionette/ril_jshint/jshintrc b/dom/system/gonk/tests/marionette/ril_jshint/jshintrc deleted file mode 100644 index 437fe1a6f..000000000 --- a/dom/system/gonk/tests/marionette/ril_jshint/jshintrc +++ /dev/null @@ -1,118 +0,0 @@ -{ - // JSHint Default Configuration File (as on JSHint website) - // See http://jshint.com/docs/ for more details - - // Modify for RIL usage. - - "maxerr" : 10000, // {int} Maximum error before stopping - - // Enforcing - "bitwise" : false, // true: Prohibit bitwise operators (&, |, ^, etc.) - "camelcase" : false, // true: Identifiers must be in camelCase - "curly" : false, // true: Require {} for every new block or scope - "eqeqeq" : false, // true: Require triple equals (===) for comparison - "forin" : false, // true: Require filtering for..in loops with obj.hasOwnProperty() - "immed" : false, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());` - //"indent" : 2, // {int} Number of spaces to use for indentation - "latedef" : false, // true: Require variables/functions to be defined before being used - "newcap" : false, // true: Require capitalization of all constructor functions e.g. `new F()` - "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee` - "noempty" : false, // true: Prohibit use of empty blocks - "nonew" : false, // true: Prohibit use of constructors for side-effects (without assignment) - "plusplus" : false, // true: Prohibit use of `++` & `--` - "quotmark" : false, // Quotation mark consistency: - // false : do nothing (default) - // true : ensure whatever is used is consistent - // "single" : require single quotes - // "double" : require double quotes - "undef" : false, // true: Require all non-global variables to be declared (prevents global leaks) - "unused" : false, // true: Require all defined variables be used - "strict" : false, // true: Requires all functions run in ES5 Strict Mode - "trailing" : false, // true: Prohibit trailing whitespaces - "maxparams" : false, // {int} Max number of formal params allowed per function - "maxdepth" : false, // {int} Max depth of nested blocks (within functions) - "maxstatements" : false, // {int} Max number statements per function - "maxcomplexity" : false, // {int} Max cyclomatic complexity per function - "maxlen" : false, // {int} Max number of characters per line - - // Relaxing - "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons) - "boss" : false, // true: Tolerate assignments where comparisons would be expected - "debug" : false, // true: Allow debugger statements e.g. browser breakpoints. - "eqnull" : true, // true: Tolerate use of `== null` - "es5" : false, // true: Allow ES5 syntax (ex: getters and setters) - "esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`) - "moz" : true, // true: Allow Mozilla specific syntax (extends and overrides esnext features) - // (ex: `for each`, multiple try/catch, function expression…) - "evil" : false, // true: Tolerate use of `eval` and `new Function()` - "expr" : false, // true: Tolerate `ExpressionStatement` as Programs - "funcscope" : false, // true: Tolerate defining variables inside control statements" - "globalstrict" : true, // true: Allow global "use strict" (also enables 'strict') - "iterator" : false, // true: Tolerate using the `__iterator__` property - "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block - "laxbreak" : true, // true: Tolerate possibly unsafe line breakings - "laxcomma" : false, // true: Tolerate comma-first style coding - "loopfunc" : false, // true: Tolerate functions being defined in loops - "multistr" : false, // true: Tolerate multi-line strings - "proto" : true, // true: Tolerate using the `__proto__` property - "scripturl" : false, // true: Tolerate script-targeted URLs - "smarttabs" : false, // true: Tolerate mixed tabs/spaces when used for alignment - "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;` - "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation - "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;` - "validthis" : true, // true: Tolerate using this in a non-constructor function - - // Environments - "browser" : false, // Web Browser (window, document, etc) - "couch" : false, // CouchDB - "devel" : true, // Development/debugging (alert, confirm, etc) - "dojo" : false, // Dojo Toolkit - "jquery" : false, // jQuery - "mootools" : false, // MooTools - "node" : false, // Node.js - "nonstandard" : false, // Widely adopted globals (escape, unescape, etc) - "prototypejs" : false, // Prototype and Scriptaculous - "rhino" : false, // Rhino - "worker" : true, // Web Workers - "wsh" : false, // Windows Scripting Host - "yui" : false, // Yahoo User Interface - - // Legacy - "nomen" : false, // true: Prohibit dangling `_` in variables - "onevar" : false, // true: Allow only one `var` statement per function - "passfail" : false, // true: Stop on first error - "white" : false, // true: Check against strict whitespace and indentation rules - - // Custom Globals - "predef" : [ ], // additional predefined global variables - - "globals": { - "ChromeWorker": false, - "Components": false, - "DOMRequestIpcHelper": false, - "ObjectWrapper": false, - "PhoneNumberUtils": false, - "RILNetworkInterface": false, - "Services": false, - "Uint8Array": false, - "WAP": false, - "XPCOMUtils": false, - "cpmm": false, - "dump": false, - "gAudioManager": false, - "gMessageManager": false, - "gMobileMessageDatabaseService": false, - "gMobileMessageService": false, - "gNetworkManager": false, - "gPowerManagerService": false, - "gSettingsService": false, - "gSmsService": false, - "gSystemMessenger": false, - "gSystemWorkerManager": false, - "gTimeService": false, - "gUUIDGenerator": false, - "ppmm": true, - - "__end_guardian_for_easy_sorting__": false - } -} diff --git a/dom/system/gonk/tests/marionette/test_all_network_info.js b/dom/system/gonk/tests/marionette/test_all_network_info.js deleted file mode 100644 index 5225ab6d6..000000000 --- a/dom/system/gonk/tests/marionette/test_all_network_info.js +++ /dev/null @@ -1,106 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 60000; -MARIONETTE_HEAD_JS = "head.js"; - -var networkManager = - Cc["@mozilla.org/network/manager;1"].getService(Ci.nsINetworkManager); -ok(networkManager, - "networkManager.constructor is " + networkManager.constructor); - -var wifiManager = window.navigator.mozWifiManager; -ok(wifiManager, "wifiManager.constructor is " + wifiManager.constructor); - -function setEmulatorAPN() { - let apn = [ - [{"carrier":"T-Mobile US", - "apn":"epc.tmobile.com", - "mmsc":"http://mms.msg.eng.t-mobile.com/mms/wapenc", - "types":["default","supl","mms","ims","dun", "fota"]}] - ]; - - return setSettings(SETTINGS_KEY_DATA_APN_SETTINGS, apn); -} - -function ensureWifiEnabled(aEnabled) { - if (wifiManager.enabled === aEnabled) { - log('Already ' + (aEnabled ? 'enabled' : 'disabled')); - return Promise.resolve(); - } - return requestWifiEnabled(aEnabled); -} - -function requestWifiEnabled(aEnabled) { - let promises = []; - - promises.push(waitForTargetEvent(wifiManager, aEnabled ? 'enabled' : 'disabled', - function() { - return wifiManager.enabled === aEnabled ? true : false; - })); - promises.push(setSettings(SETTINGS_KEY_WIFI_ENABLED, aEnabled)); - - return Promise.all(promises); -} - -// Test initial State -function verifyInitialState() { - log("= verifyInitialState ="); - - // Data and wifi should be off before starting any test. - return getSettings(SETTINGS_KEY_DATA_ENABLED) - .then(value => { - is(value, false, "Data must be off"); - }) - .then(() => ensureWifiEnabled(false)); -} - -function testAllNetworkInfo(aAnyConnected) { - log("= testAllNetworkInfo = " + aAnyConnected); - - let allNetworkInfo = networkManager.allNetworkInfo; - ok(allNetworkInfo, "NetworkManager.allNetworkInfo"); - - let count = Object.keys(allNetworkInfo).length; - ok(count > 0, "NetworkManager.allNetworkInfo count"); - - let connected = false; - for (let networkId in allNetworkInfo) { - if (allNetworkInfo.hasOwnProperty(networkId)) { - let networkInfo = allNetworkInfo[networkId]; - if (networkInfo.state == Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) { - connected = true; - break; - } - } - } - - is(aAnyConnected, connected, "NetworkManager.allNetworkInfo any connected"); -} - -// Start test -startTestBase(function() { - - let origApnSettings, origWifiEnabled; - return Promise.resolve() - .then(() => { - origWifiEnabled = wifiManager.enabled; - }) - .then(() => verifyInitialState()) - .then(() => getSettings(SETTINGS_KEY_DATA_APN_SETTINGS)) - .then(value => { - origApnSettings = value; - }) - .then(() => setEmulatorAPN()) - .then(() => setDataEnabledAndWait(true)) - .then(() => testAllNetworkInfo(true)) - .then(() => setDataEnabledAndWait(false)) - .then(() => testAllNetworkInfo(false)) - // Restore original apn settings and wifi state. - .then(() => { - if (origApnSettings) { - return setSettings(SETTINGS_KEY_DATA_APN_SETTINGS, origApnSettings); - } - }) - .then(() => ensureWifiEnabled(origWifiEnabled)); -}); diff --git a/dom/system/gonk/tests/marionette/test_data_connection.js b/dom/system/gonk/tests/marionette/test_data_connection.js deleted file mode 100644 index 5a53b1e5f..000000000 --- a/dom/system/gonk/tests/marionette/test_data_connection.js +++ /dev/null @@ -1,70 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 60000; -MARIONETTE_HEAD_JS = "head.js"; - -function setEmulatorAPN() { - let apn = [ - [{"carrier":"T-Mobile US", - "apn":"epc.tmobile.com", - "mmsc":"http://mms.msg.eng.t-mobile.com/mms/wapenc", - "types":["default","supl","mms","ims","dun", "fota"]}] - ]; - - return setSettings(SETTINGS_KEY_DATA_APN_SETTINGS, apn); -} - -// Test initial State -function testInitialState() { - log("= testInitialState ="); - - // Data should be off before starting any test. - return getSettings(SETTINGS_KEY_DATA_ENABLED) - .then(value => { - is(value, false, "Data must be off"); - }); -} - -// Test default data Connection -function testDefaultDataConnection() { - log("= testDefaultDataConnection ="); - - // Enable default data - return setDataEnabledAndWait(true) - // Disable default data - .then(() => setDataEnabledAndWait(false)); -} - -// Test non default data connection -function testNonDefaultDataConnection() { - log("= testNonDefaultDataConnection ="); - - function doTestNonDefaultDataConnection(type) { - log("doTestNonDefaultDataConnection: " + type); - - return setupDataCallAndWait(type) - .then(() => deactivateDataCallAndWait(type)); - } - - let currentApn; - return getSettings(SETTINGS_KEY_DATA_APN_SETTINGS) - .then(value => { - currentApn = value; - }) - .then(setEmulatorAPN) - .then(() => doTestNonDefaultDataConnection(NETWORK_TYPE_MOBILE_MMS)) - .then(() => doTestNonDefaultDataConnection(NETWORK_TYPE_MOBILE_SUPL)) - .then(() => doTestNonDefaultDataConnection(NETWORK_TYPE_MOBILE_IMS)) - .then(() => doTestNonDefaultDataConnection(NETWORK_TYPE_MOBILE_DUN)) - .then(() => doTestNonDefaultDataConnection(NETWORK_TYPE_MOBILE_FOTA)) - // Restore APN settings - .then(() => setSettings(SETTINGS_KEY_DATA_APN_SETTINGS, currentApn)); -} - -// Start test -startTestBase(function() { - return testInitialState() - .then(() => testDefaultDataConnection()) - .then(() => testNonDefaultDataConnection()); -}); diff --git a/dom/system/gonk/tests/marionette/test_data_connection_proxy.js b/dom/system/gonk/tests/marionette/test_data_connection_proxy.js deleted file mode 100644 index a99187538..000000000 --- a/dom/system/gonk/tests/marionette/test_data_connection_proxy.js +++ /dev/null @@ -1,99 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 60000; -MARIONETTE_HEAD_JS = "head.js"; - -const HTTP_PROXY = "10.0.2.200"; -const HTTP_PROXY_PORT = "8080"; -const MANUAL_PROXY_CONFIGURATION = 1; - -// Test initial State -function verifyInitialState() { - log("= verifyInitialState ="); - - // Data should be off before starting any test. - return getSettings(SETTINGS_KEY_DATA_ENABLED) - .then(value => { - is(value, false, "Data must be off"); - }); -} - -function setTestApn() { - let apn = [ - [ {"carrier": "T-Mobile US", - "apn": "epc.tmobile.com", - "proxy": HTTP_PROXY, - "port": HTTP_PROXY_PORT, - "mmsc": "http://mms.msg.eng.t-mobile.com/mms/wapenc", - "types": ["default","supl","mms"]} ] - ]; - - return setSettings(SETTINGS_KEY_DATA_APN_SETTINGS, apn); -} - -function waitForHttpProxyVerified(aShouldBeSet) { - let TIME_OUT_VALUE = 20000; - - return new Promise(function(aResolve, aReject) { - try { - waitFor(aResolve, () => { - let proxyType = SpecialPowers.getIntPref("network.proxy.type"); - let httpProxy = SpecialPowers.getCharPref("network.proxy.http"); - let sslProxy = SpecialPowers.getCharPref("network.proxy.ssl"); - let httpProxyPort = SpecialPowers.getIntPref("network.proxy.http_port"); - let sslProxyPort = SpecialPowers.getIntPref("network.proxy.ssl_port"); - - if ((aShouldBeSet && - proxyType == MANUAL_PROXY_CONFIGURATION && - httpProxy == HTTP_PROXY && - sslProxy == HTTP_PROXY && - httpProxyPort == HTTP_PROXY_PORT && - sslProxyPort == HTTP_PROXY_PORT) || - (!aShouldBeSet && proxyType != MANUAL_PROXY_CONFIGURATION && - !httpProxy && !sslProxy && !httpProxyPort && !sslProxyPort)) { - return true; - } - - return false; - }, TIME_OUT_VALUE); - } catch(aError) { - // Timed out. - aReject(aError); - } - }); -} - -function testDefaultDataHttpProxy() { - log("= testDefaultDataHttpProxy ="); - - return setDataEnabledAndWait(true) - .then(() => waitForHttpProxyVerified(true)) - .then(() => setDataEnabledAndWait(false)) - .then(() => waitForHttpProxyVerified(false)); -} - -function testNonDefaultDataHttpProxy(aType) { - log("= testNonDefaultDataHttpProxy - " + aType + " ="); - - return setupDataCallAndWait(aType) - // Http proxy should not be set for non-default data connections. - .then(() => waitForHttpProxyVerified(false)) - .then(() => deactivateDataCallAndWait(aType)); -} - -// Start test -startTestBase(function() { - let origApnSettings; - return verifyInitialState() - .then(() => getSettings(SETTINGS_KEY_DATA_APN_SETTINGS)) - .then(value => { - origApnSettings = value; - }) - .then(() => setTestApn()) - .then(() => testDefaultDataHttpProxy()) - .then(() => testNonDefaultDataHttpProxy(NETWORK_TYPE_MOBILE_MMS)) - .then(() => testNonDefaultDataHttpProxy(NETWORK_TYPE_MOBILE_SUPL)) - // Restore APN settings - .then(() => setSettings(SETTINGS_KEY_DATA_APN_SETTINGS, origApnSettings)); -}); diff --git a/dom/system/gonk/tests/marionette/test_dsds_numRadioInterfaces.js b/dom/system/gonk/tests/marionette/test_dsds_numRadioInterfaces.js deleted file mode 100644 index e178b8b65..000000000 --- a/dom/system/gonk/tests/marionette/test_dsds_numRadioInterfaces.js +++ /dev/null @@ -1,43 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 60000; -MARIONETTE_CONTEXT = "chrome"; - -Cu.import("resource://gre/modules/Promise.jsm"); -Cu.import("resource://gre/modules/systemlibs.js"); - -const NS_RIL_CONTRACTID = "@mozilla.org/ril;1"; - -const PROP_RO_MOZ_RIL_NUMCLIENTS = "ro.moz.ril.numclients"; - -const PREF_RIL_NUM_RADIO_INTERFACES = "ril.numRadioInterfaces"; - -ok(libcutils, "libcutils is available"); - -var propNum = (function() { - try { - let numString = libcutils.property_get(PROP_RO_MOZ_RIL_NUMCLIENTS, "1"); - let num = parseInt(numString, 10); - if (num >= 0) { - return num; - } - } catch (e) {} -})(); - -log("Retrieved '" + PROP_RO_MOZ_RIL_NUMCLIENTS + "' = " + propNum); -ok(propNum, PROP_RO_MOZ_RIL_NUMCLIENTS); - -var prefNum = Services.prefs.getIntPref(PREF_RIL_NUM_RADIO_INTERFACES); -log("Retrieved '" + PREF_RIL_NUM_RADIO_INTERFACES + "' = " + prefNum); - -var ril = Cc[NS_RIL_CONTRACTID].getService(Ci.nsIRadioInterfaceLayer); -ok(ril, "ril.constructor is " + ril.constructor); - -var ifaceNum = ril.numRadioInterfaces; -log("Retrieved 'nsIRadioInterfaceLayer.numRadioInterfaces' = " + ifaceNum); - -is(propNum, prefNum); -is(propNum, ifaceNum); - -finish(); diff --git a/dom/system/gonk/tests/marionette/test_fakevolume.js b/dom/system/gonk/tests/marionette/test_fakevolume.js deleted file mode 100644 index 173f9ac11..000000000 --- a/dom/system/gonk/tests/marionette/test_fakevolume.js +++ /dev/null @@ -1,25 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 10000; - -var Cc = SpecialPowers.Cc; -var Ci = SpecialPowers.Ci; - -var volumeService = Cc["@mozilla.org/telephony/volume-service;1"].getService(Ci.nsIVolumeService); -ok(volumeService, "Should have volume service"); - -var volName = "fake"; -var mountPoint = "/data/fake/storage"; -volumeService.createFakeVolume(volName, mountPoint); - -var vol = volumeService.getVolumeByName(volName); -ok(vol, "volume shouldn't be null"); - -is(volName, vol.name, "name"); -is(mountPoint, vol.mountPoint, "moutnPoint"); -is(Ci.nsIVolume.STATE_MOUNTED, vol.state, "state"); - -ok(vol.mountGeneration > 0, "mount generation should not be zero"); - -finish(); diff --git a/dom/system/gonk/tests/marionette/test_geolocation.js b/dom/system/gonk/tests/marionette/test_geolocation.js deleted file mode 100644 index 201c8b3e3..000000000 --- a/dom/system/gonk/tests/marionette/test_geolocation.js +++ /dev/null @@ -1,117 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 10000; - -var geolocation = window.navigator.geolocation; -ok(geolocation); - -var sample = []; -var result = []; -var wpid; - -/** - * Grant special power to get the geolocation - */ -SpecialPowers.addPermission("geolocation", true, document); - -/** - * Disable wifi geolocation provider - */ -wifiUri = SpecialPowers.getCharPref("geo.wifi.uri"); -SpecialPowers.setCharPref("geo.wifi.uri", "http://mochi.test:8888/tests/dom/tests/mochitest/geolocation/network_geolocation.sjs?action=stop-responding"); - -/** - * Helper that compares the geolocation against the web API. - */ -function verifyLocation() { - - log("Sample:" + sample.join(',')); - log("Result:" + result.join(',')); - - for (i in sample) { - is(sample.pop(), result.pop()); - } - - window.setTimeout(cleanup, 0); -} - -/** - * Test story begins here. - */ -function setup() { - log("Providing initial setup: set geographic position watcher."); - - - wpid = geolocation.watchPosition(function(position) { - log("Position changes: (" + position.coords.latitude + "/" + position.coords.longitude + ")"); - result.push(""+position.coords.latitude + "/" + position.coords.longitude); - }); - - lat = 0; - lon = 0; - - cmd = "geo fix " + lon + " " + lat; - sample.push(lat+"/"+lon); - - runEmulatorCmd(cmd, function(result) { - window.setTimeout(movePosition_1, 0); - }); -} - -function movePosition_1() { - log("Geolocation changes. Move to Position 1."); - - lat = 25; - lon = 121.56499833333334; - - cmd = "geo fix " + lon + " " + lat; - sample.push(lat+"/"+lon); - - runEmulatorCmd(cmd, function(result) { - window.setTimeout(movePosition_2, 0); - }); -} - -function movePosition_2() { - log("Geolocation changes to a negative longitude. Move to Position 2."); - - lat = 37.393; - lon = -122.08199833333335; - - cmd = "geo fix " + lon + " " + lat; - sample.push(lat+"/"+lon); - - runEmulatorCmd(cmd, function(result) { - window.setTimeout(movePosition_3, 0); - }); -} - -function movePosition_3() { - log("Geolocation changes with WatchPosition. Move to Position 3."); - - lat = -22; - lon = -43; - - cmd = "geo fix " + lon + " " + lat; - sample.push(lat+"/"+lon); - - geolocation.getCurrentPosition(function(position) { - log("getCurrentPosition: Expected location: ("+lat+"/"+lon+"); Current location: (" + position.coords.latitude + "/" + position.coords.longitude + ")"); - is(lat, position.coords.latitude); - is(lon, position.coords.longitude); - }); - - runEmulatorCmd(cmd, function(result) { - window.setTimeout(verifyLocation, 0); - }); -} - -function cleanup() { - geolocation.clearWatch(wpid); - SpecialPowers.removePermission("geolocation", document); - SpecialPowers.setCharPref("geo.wifi.uri", wifiUri); - finish(); -} - -setup(); diff --git a/dom/system/gonk/tests/marionette/test_multiple_data_connection.js b/dom/system/gonk/tests/marionette/test_multiple_data_connection.js deleted file mode 100644 index 24abd4451..000000000 --- a/dom/system/gonk/tests/marionette/test_multiple_data_connection.js +++ /dev/null @@ -1,89 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 60000; -MARIONETTE_HEAD_JS = "head.js"; - -// Must sync with hardware/ril/reference-ril/reference-ril.c -const MAX_DATA_CONTEXTS = 4; - -function setEmulatorAPN() { - // Use different apn for each network type. - let apn = [[ { "carrier":"T-Mobile US", - "apn":"epc1.tmobile.com", - "types":["default"] }, - { "carrier":"T-Mobile US", - "apn":"epc2.tmobile.com", - "mmsc":"http://mms.msg.eng.t-mobile.com/mms/wapenc", - "types":["mms"] }, - { "carrier":"T-Mobile US", - "apn":"epc3.tmobile.com", - "types":["supl"] }, - { "carrier":"T-Mobile US", - "apn":"epc4.tmobile.com", - "types":["ims"] }, - { "carrier":"T-Mobile US", - "apn":"epc5.tmobile.com", - "types":["dun"] }, - { "carrier":"T-Mobile US", - "apn":"epc6.tmobile.com", - "types":["fota"] }]]; - - return setSettings(SETTINGS_KEY_DATA_APN_SETTINGS, apn); -} - -// Test initial State -function testInitialState() { - log("= testInitialState ="); - - // Data should be off before starting any test. - return getSettings(SETTINGS_KEY_DATA_ENABLED) - .then(value => { - is(value, false, "Data must be off"); - }); -} - -function testSetupConcurrentDataCalls() { - log("= testSetupConcurrentDataCalls ="); - - let promise = Promise.resolve(); - // Skip default mobile type. - for (let i = 1; i < MAX_DATA_CONTEXTS; i++) { - let type = networkTypes[i]; - promise = promise.then(() => setupDataCallAndWait(type)); - } - return promise; -} - -function testDeactivateConcurrentDataCalls() { - log("= testDeactivateConcurrentDataCalls ="); - - let promise = Promise.resolve(); - // Skip default mobile type. - for (let i = 1; i < MAX_DATA_CONTEXTS; i++) { - let type = networkTypes[i]; - promise = promise.then(() => deactivateDataCallAndWait(type)); - } - return promise; -} - -// Start test -startTestBase(function() { - - let origApnSettings; - return testInitialState() - .then(() => getSettings(SETTINGS_KEY_DATA_APN_SETTINGS)) - .then(value => { - origApnSettings = value; - }) - .then(() => setEmulatorAPN()) - .then(() => setDataEnabledAndWait(true)) - .then(() => testSetupConcurrentDataCalls()) - .then(() => testDeactivateConcurrentDataCalls()) - .then(() => setDataEnabledAndWait(false)) - .then(() => { - if (origApnSettings) { - return setSettings(SETTINGS_KEY_DATA_APN_SETTINGS, origApnSettings); - } - }); -}); diff --git a/dom/system/gonk/tests/marionette/test_network_active_changed.js b/dom/system/gonk/tests/marionette/test_network_active_changed.js deleted file mode 100644 index 5886f37ed..000000000 --- a/dom/system/gonk/tests/marionette/test_network_active_changed.js +++ /dev/null @@ -1,52 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 60000; -MARIONETTE_HEAD_JS = "head.js"; - -var networkManager = - Cc["@mozilla.org/network/manager;1"].getService(Ci.nsINetworkManager); -ok(networkManager, - "networkManager.constructor is " + networkManager.constructor); - -function testInitialState() { - return getSettings(SETTINGS_KEY_DATA_ENABLED) - .then((enabled) => { - is(enabled, false, "data should be off by default"); - is(networkManager.activeNetworkInfo, null, - "networkManager.activeNetworkInfo should be null by default"); - }); -} - -function testActiveNetworkChangedBySwitchingDataCall(aDataCallEnabled) { - log("Test active network by switching dataCallEnabled to " + aDataCallEnabled); - - let promises = []; - promises.push(waitForObserverEvent(TOPIC_NETWORK_ACTIVE_CHANGED)); - promises.push(setSettings(SETTINGS_KEY_DATA_ENABLED, aDataCallEnabled)); - - return Promise.all(promises).then(function(results) { - let subject = results[0]; - - if (aDataCallEnabled) { - ok(subject instanceof Ci.nsINetworkInfo, - "subject should be an instance of nsINetworkInfo"); - ok(subject instanceof Ci.nsIRilNetworkInfo, - "subject should be an instance of nsIRilNetworkInfo"); - is(subject.type, NETWORK_TYPE_MOBILE, - "subject.type should be NETWORK_TYPE_MOBILE"); - } - - is(subject, networkManager.activeNetworkInfo, - "subject should be equal with networkManager.activeNetworkInfo"); - }); -} - -// Start test -startTestBase(function() { - return testInitialState() - // Test active network changed by enabling data call. - .then(() => testActiveNetworkChangedBySwitchingDataCall(true)) - // Test active network changed by disabling data call. - .then(() => testActiveNetworkChangedBySwitchingDataCall(false)); -}); diff --git a/dom/system/gonk/tests/marionette/test_network_interface_list_service.js b/dom/system/gonk/tests/marionette/test_network_interface_list_service.js deleted file mode 100644 index 549940fa5..000000000 --- a/dom/system/gonk/tests/marionette/test_network_interface_list_service.js +++ /dev/null @@ -1,95 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 60000; -MARIONETTE_HEAD_JS = "head.js"; - -function getNetworkInfo(aType) { - let networkListService = - Cc["@mozilla.org/network/interface-list-service;1"]. - getService(Ci.nsINetworkInterfaceListService); - // Get all available interfaces - let networkList = networkListService.getDataInterfaceList(0); - - // Try to get nsINetworkInterface for aType. - let numberOfInterface = networkList.getNumberOfInterface(); - for (let i = 0; i < numberOfInterface; i++) { - let info = networkList.getInterfaceInfo(i); - if (info.type === aType) { - return info; - } - } - - return null; -} - -// Test getDataInterfaceList by enabling/disabling mobile data. -function testGetDataInterfaceList(aMobileDataEnabled) { - log("Test getDataInterfaceList with mobile data " + - aMobileDataEnabled ? "enabled" : "disabled"); - - return setDataEnabledAndWait(aMobileDataEnabled) - .then(() => getNetworkInfo(NETWORK_TYPE_MOBILE)) - .then((networkInfo) => { - if (!networkInfo) { - ok(false, "Should get an valid nsINetworkInfo for mobile"); - return; - } - - ok(networkInfo instanceof Ci.nsINetworkInfo, - "networkInfo should be an instance of nsINetworkInfo"); - - let ipAddresses = {}; - let prefixs = {}; - let numOfGateways = {}; - let numOfDnses = {}; - let numOfIpAddresses = networkInfo.getAddresses(ipAddresses, prefixs); - let gateways = networkInfo.getGateways(numOfGateways); - let dnses = networkInfo.getDnses(numOfDnses); - - if (aMobileDataEnabled) { - // Mobile data is enabled. - is(networkInfo.state, NETWORK_STATE_CONNECTED, "check state"); - ok(numOfIpAddresses > 0, "check number of ipAddresses"); - ok(ipAddresses.value.length > 0, "check ipAddresses.length"); - ok(prefixs.value.length > 0, "check prefixs.length"); - ok(numOfGateways.value > 0, "check number of gateways"); - ok(prefixs.value.length > 0, "check prefixs.length"); - ok(gateways.length > 0, "check gateways.length"); - ok(numOfDnses.value > 0, "check number of dnses"); - ok(dnses.length > 0, "check dnses.length"); - } else { - // Mobile data is disabled. - is(networkInfo.state, NETWORK_STATE_DISCONNECTED, "check state"); - is(numOfIpAddresses, 0, "check number of ipAddresses"); - is(ipAddresses.value.length, 0, "check ipAddresses.length"); - is(prefixs.value.length, 0, "check prefixs.length"); - is(numOfGateways.value, 0, "check number of gateways"); - is(prefixs.value.length, 0, "check prefixs.length"); - is(gateways.length, 0, "check gateways.length"); - is(numOfDnses.value, 0, "check number of dnses"); - is(dnses.length, 0, "check dnses.length"); - } - }); -} - -// Start test -startTestBase(function() { - return Promise.resolve() - // Test initial State - .then(() => { - log("Test initial state"); - - // Data should be off before starting any test. - return getSettings(SETTINGS_KEY_DATA_ENABLED) - .then(value => { - is(value, false, "Mobile data must be off"); - }); - }) - - // Test getDataInterfaceList with mobile data enabled. - .then(() => testGetDataInterfaceList(true)) - - // Test getDataInterfaceList with mobile data disabled. - .then(() => testGetDataInterfaceList(false)); -}); diff --git a/dom/system/gonk/tests/marionette/test_network_interface_mtu.js b/dom/system/gonk/tests/marionette/test_network_interface_mtu.js deleted file mode 100644 index 679efe2ed..000000000 --- a/dom/system/gonk/tests/marionette/test_network_interface_mtu.js +++ /dev/null @@ -1,100 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 60000; -MARIONETTE_HEAD_JS = "head.js"; - -const TEST_MTU1 = "1410"; -const TEST_MTU2 = "1440"; - -function setEmulatorAPN() { - let apn = [ - [ { "carrier":"T-Mobile US", - "apn":"epc1.tmobile.com", - "types":["default"], - "mtu": TEST_MTU1 }, - { "carrier":"T-Mobile US", - "apn":"epc2.tmobile.com", - "mmsc":"http://mms.msg.eng.t-mobile.com/mms/wapenc", - "types":["supl","mms","ims","dun", "fota"], - "mtu": TEST_MTU2 } ] - ]; - - return setSettings(SETTINGS_KEY_DATA_APN_SETTINGS, apn); -} - -function verifyInitialState() { - // Data should be off before starting any test. - return getSettings(SETTINGS_KEY_DATA_ENABLED) - .then(value => { - is(value, false, "Data must be off"); - }); -} - -function verifyMtu(aInterfaceName, aMtu) { - return runEmulatorShellCmdSafe(['ip', 'link', 'show', 'dev', aInterfaceName]) - .then(aLines => { - // Sample output: - // - // 4: rmnet0: <BROADCAST,MULTICAST> mtu 1410 qdisc pfifo_fast state DOWN mode DEFAULT qlen 1000 - // link/ether 52:54:00:12:34:58 brd ff:ff:ff:ff:ff:ff - // - let mtu; - aLines.some(function (aLine) { - let tokens = aLine.trim().split(/\s+/); - let mtuIndex = tokens.indexOf('mtu'); - if (mtuIndex < 0 || mtuIndex + 1 >= tokens.length) { - return false; - } - - mtu = tokens[mtuIndex + 1]; - return true; - }); - - is(mtu, aMtu, aInterfaceName + "'s mtu."); - }); -} - -function testDefaultDataCallMtu() { - log("= testDefaultDataCallMtu ="); - - return setDataEnabledAndWait(true) - .then(aNetworkInfo => verifyMtu(aNetworkInfo.name, TEST_MTU1)) - .then(() => setDataEnabledAndWait(false)); -} - -function testNonDefaultDataCallMtu() { - log("= testNonDefaultDataCallMtu ="); - - function doTestNonDefaultDataCallMtu(aType) { - log("doTestNonDefaultDataCallMtu: " + aType); - - return setupDataCallAndWait(aType) - .then(aNetworkInfo => verifyMtu(aNetworkInfo.name, TEST_MTU2)) - .then(() => deactivateDataCallAndWait(aType)); - } - - return doTestNonDefaultDataCallMtu(NETWORK_TYPE_MOBILE_MMS) - .then(() => doTestNonDefaultDataCallMtu(NETWORK_TYPE_MOBILE_SUPL)) - .then(() => doTestNonDefaultDataCallMtu(NETWORK_TYPE_MOBILE_IMS)) - .then(() => doTestNonDefaultDataCallMtu(NETWORK_TYPE_MOBILE_DUN)) - .then(() => doTestNonDefaultDataCallMtu(NETWORK_TYPE_MOBILE_FOTA)); -} - -// Start test -startTestBase(function() { - let origApnSettings; - return verifyInitialState() - .then(() => getSettings(SETTINGS_KEY_DATA_APN_SETTINGS)) - .then(value => { - origApnSettings = value; - }) - .then(() => setEmulatorAPN()) - .then(() => testDefaultDataCallMtu()) - .then(() => testNonDefaultDataCallMtu()) - .then(() => { - if (origApnSettings) { - return setSettings(SETTINGS_KEY_DATA_APN_SETTINGS, origApnSettings); - } - }); -}); diff --git a/dom/system/gonk/tests/marionette/test_ril_code_quality.py b/dom/system/gonk/tests/marionette/test_ril_code_quality.py deleted file mode 100644 index d741d8a2e..000000000 --- a/dom/system/gonk/tests/marionette/test_ril_code_quality.py +++ /dev/null @@ -1,371 +0,0 @@ -""" -The test performs the static code analysis check by JSHint. - -Target js files: -- RadioInterfaceLayer.js -- ril_worker.js -- ril_consts.js - -If the js file contains the line of 'importScript()' (Ex: ril_worker.js), the -test will perform a special merge step before excuting JSHint. - -Ex: Script A --------------------------------- -importScripts('Script B') -... --------------------------------- - -We merge these two scripts into one by the following way. - --------------------------------- -[Script B (ex: ril_consts.js)] -(function(){ [Script A (ex: ril_worker.js)] -})(); --------------------------------- - -Script A (ril_worker.js) runs global strict mode. -Script B (ril_consts.js) not. - -The above merge way ensures the correct scope of 'strict mode.' -""" - -import bisect -import inspect -import os -import os.path -import re -import unicodedata - -from marionette_harness import MarionetteTestCase - - -class StringUtility: - - """A collection of some string utilities.""" - - @staticmethod - def find_match_lines(lines, pattern): - """Return a list of lines that contains given pattern.""" - return [line for line in lines if pattern in line] - - @staticmethod - def remove_non_ascii(data): - """Remove non ascii characters in data and return it as new string.""" - if type(data).__name__ == 'unicode': - data = unicodedata.normalize( - 'NFKD', data).encode('ascii', 'ignore') - return data - - @staticmethod - def auto_close(lines): - """Ensure every line ends with '\n'.""" - if lines and not lines[-1].endswith('\n'): - lines[-1] += '\n' - return lines - - @staticmethod - def auto_wrap_strict_mode(lines): - """Wrap by function scope if lines contain 'use strict'.""" - if StringUtility.find_match_lines(lines, 'use strict'): - lines[0] = '(function(){' + lines[0] - lines.append('})();\n') - return lines - - @staticmethod - def get_imported_list(lines): - """Get a list of imported items.""" - return [item - for line in StringUtility.find_match_lines(lines, 'importScripts') - for item in StringUtility._get_imported_list_from_line(line)] - - @staticmethod - def _get_imported_list_from_line(line): - """Extract all items from 'importScripts(...)'. - - importScripts("ril_consts.js", "systemlibs.js") - => ['ril_consts', 'systemlibs.js'] - - """ - pattern = re.compile(r'\s*importScripts\((.*)\)') - m = pattern.match(line) - if not m: - raise Exception('Parse importScripts error.') - return [name.translate(None, '\' "') for name in m.group(1).split(',')] - - -class ResourceUriFileReader: - - """Handle the process of reading the source code from system.""" - - URI_PREFIX = 'resource://gre/' - URI_PATH = { - 'RadioInterfaceLayer.js': 'components/RadioInterfaceLayer.js', - 'ril_worker.js': 'modules/ril_worker.js', - 'ril_consts.js': 'modules/ril_consts.js', - 'systemlibs.js': 'modules/systemlibs.js', - 'worker_buf.js': 'modules/workers/worker_buf.js', - } - - CODE_OPEN_CHANNEL_BY_URI = ''' - var Cc = Components.classes; - var Ci = Components.interfaces; - var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); - var secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager); - global.uri = '%(uri)s'; - global.channel = ios.newChannel2(global.uri, - null, - null, - null, // aLoadingNode - secMan.getSystemPrincipal(), - null, // aTriggeringPrincipal - Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, - Ci.nsIContentPolicy.TYPE_OTHER); - ''' - - CODE_GET_SPEC = ''' - return global.channel.URI.spec; - ''' - - CODE_READ_CONTENT = ''' - var Cc = Components.classes; - var Ci = Components.interfaces; - - var zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].createInstance(Ci.nsIZipReader); - var inputStream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(Ci.nsIScriptableInputStream); - - var jaruri = global.channel.URI.QueryInterface(Ci.nsIJARURI); - var file = jaruri.JARFile.QueryInterface(Ci.nsIFileURL).file; - var entry = jaruri.JAREntry; - zipReader.open(file); - inputStream.init(zipReader.getInputStream(entry)); - var content = inputStream.read(inputStream.available()); - inputStream.close(); - zipReader.close(); - return content; - ''' - - @classmethod - def get_uri(cls, filename): - """Convert filename to URI in system.""" - if filename.startswith(cls.URI_PREFIX): - return filename - else: - return cls.URI_PREFIX + cls.URI_PATH[filename] - - def __init__(self, marionette): - self.runjs = lambda x: marionette.execute_script(x, - new_sandbox=False, - sandbox='system') - - def read_file(self, filename): - """Read file and return the contents as string.""" - content = self._read_uri(self.get_uri(filename)) - content = content.replace('"use strict";', '') - return StringUtility.remove_non_ascii(content) - - def _read_uri(self, uri): - """Read URI in system and return the contents as string.""" - # Open the uri as a channel. - self.runjs(self.CODE_OPEN_CHANNEL_BY_URI % {'uri': uri}) - - # Make sure spec is a jar uri, and not recursive. - # Ex: 'jar:file:///system/b2g/omni.ja!/modules/ril_worker.js' - # - # For simplicity, we don't handle other special cases in this test. - # If B2G build system changes in the future, such as put the jar in - # another jar, the test case will fail. - spec = self.runjs(self.CODE_GET_SPEC) - if (not spec.startswith('jar:file://')) or (spec.count('jar:') != 1): - raise Exception('URI resolve error') - - # Read the content from channel. - content = self.runjs(self.CODE_READ_CONTENT) - return content - - -class JSHintEngine: - - """Invoke jshint script on system.""" - - CODE_INIT_JSHINT = ''' - %(script)s; - global.JSHINT = JSHINT; - global.options = JSON.parse(%(config_string)s); - global.globals = global.options.globals; - delete global.options.globals; - ''' - - CODE_RUN_JSHINT = ''' - global.script = %(code)s; - return global.JSHINT(global.script, global.options, global.globals); - ''' - - CODE_GET_JSHINT_ERROR = ''' - return global.JSHINT.errors; - ''' - - def __init__(self, marionette, script, config): - # Remove single line comment in config. - config = '\n'.join([line.partition('//')[0] - for line in config.splitlines()]) - - # Set global (JSHINT, options, global) in js environment. - self.runjs = lambda x: marionette.execute_script(x, - new_sandbox=False, - sandbox='system') - self.runjs(self.CODE_INIT_JSHINT % - {'script': script, 'config_string': repr(config)}) - - def run(self, code, filename=''): - """Excute JShint check for the given code.""" - check_pass = self.runjs(self.CODE_RUN_JSHINT % {'code': repr(code)}) - errors = self.runjs(self.CODE_GET_JSHINT_ERROR) - return check_pass, self._get_error_messages(errors, filename) - - def _get_error_messages(self, errors, filename=''): - """ - Convert an error object to a list of readable string. - - [{"a": null, "c": null, "code": "W033", "d": null, "character": 6, - "evidence": "var a", "raw": "Missing semicolon.", - "reason": "Missing semicolon.", "b": null, "scope": "(main)", "line": 1, - "id": "(error)"}] - => line 1, col 6, Missing semicolon. - - """ - LINE, COL, REASON = u'line', u'character', u'reason' - return ["%s: line %s, col %s, %s" % - (filename, error[LINE], error[COL], error[REASON]) - for error in errors if error] - - -class Linter: - - """Handle the linting related process.""" - - def __init__(self, code_reader, jshint, reporter=None): - """Set the linter with code_reader, jshint engine, and reporter. - - Should have following functionality. - - code_reader.read_file(filename) - - jshint.run(code, filename) - - reporter([...]) - - """ - self.code_reader = code_reader - self.jshint = jshint - if reporter is None: - self.reporter = lambda x: '\n'.join(x) - else: - self.reporter = reporter - - def lint_file(self, filename): - """Lint the file and return (pass, error_message).""" - # Get code contents. - code = self.code_reader.read_file(filename) - lines = code.splitlines() - import_list = StringUtility.get_imported_list(lines) - if not import_list: - check_pass, error_message = self.jshint.run(code, filename) - else: - newlines, info = self._merge_multiple_codes(filename, import_list) - # Each line of |newlines| contains '\n'. - check_pass, error_message = self.jshint.run(''.join(newlines)) - error_message = self._convert_merged_result(error_message, info) - # Only keep errors for this file. - error_message = [line for line in error_message - if line.startswith(filename)] - check_pass = (len(error_message) == 0) - return check_pass, self.reporter(error_message) - - def _merge_multiple_codes(self, filename, import_list): - """Merge multiple codes from filename and import_list.""" - dirname, filename = os.path.split(filename) - dst_line = 1 - dst_results = [] - info = [] - - # Put the imported script first, and then the original script. - for f in import_list + [filename]: - filepath = os.path.join(dirname, f) - - # Maintain a mapping table. - # New line number after merge => original file and line number. - info.append((dst_line, filepath, 1)) - try: - code = self.code_reader.read_file(filepath) - lines = code.splitlines(True) # Keep '\n'. - src_results = StringUtility.auto_wrap_strict_mode( - StringUtility.auto_close(lines)) - dst_results.extend(src_results) - dst_line += len(src_results) - except: - info.pop() - return dst_results, info - - def _convert_merged_result(self, error_lines, line_info): - pattern = re.compile(r'(.*): line (\d+),(.*)') - start_line = [info[0] for info in line_info] - new_result_lines = [] - for line in error_lines: - m = pattern.match(line) - if not m: - continue - - line_number, remain = int(m.group(2)), m.group(3) - - # [1, 2, 7, 8] - # ^ for 7, pos = 3 - # ^ for 6, pos = 2 - pos = bisect.bisect_right(start_line, line_number) - dst_line, name, src_line = line_info[pos - 1] - real_line_number = line_number - dst_line + src_line - new_result_lines.append( - "%s: line %s,%s" % (name, real_line_number, remain)) - return new_result_lines - - -class TestRILCodeQuality(MarionetteTestCase): - - JSHINT_PATH = 'ril_jshint/jshint.js' - JSHINTRC_PATH = 'ril_jshint/jshintrc' - - def _read_local_file(self, filepath): - """Read file content from local (folder of this test case).""" - test_dir = os.path.dirname(inspect.getfile(TestRILCodeQuality)) - return open(os.path.join(test_dir, filepath)).read() - - def _get_extended_error_message(self, error_message): - return '\n'.join(['See errors below and more information in Bug 880643', - '\n'.join(error_message), - 'See errors above and more information in Bug 880643']) - - def _check(self, filename): - check_pass, error_message = self.linter.lint_file(filename) - self.assertTrue(check_pass, error_message) - - def setUp(self): - MarionetteTestCase.setUp(self) - self.linter = Linter( - ResourceUriFileReader(self.marionette), - JSHintEngine(self.marionette, - self._read_local_file(self.JSHINT_PATH), - self._read_local_file(self.JSHINTRC_PATH)), - self._get_extended_error_message) - - def tearDown(self): - MarionetteTestCase.tearDown(self) - - def test_RadioInterfaceLayer(self): - self._check('RadioInterfaceLayer.js') - - # Bug 936504. Disable the test for 'ril_worker.js'. It sometimes runs very - # slow and causes the timeout fail on try server. - #def test_ril_worker(self): - # self._check('ril_worker.js') - - def test_ril_consts(self): - self._check('ril_consts.js') - - def test_worker_buf(self): - self._check('worker_buf.js') diff --git a/dom/system/gonk/tests/marionette/test_screen_state.js b/dom/system/gonk/tests/marionette/test_screen_state.js deleted file mode 100644 index 2281412d5..000000000 --- a/dom/system/gonk/tests/marionette/test_screen_state.js +++ /dev/null @@ -1,47 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 10000; - -var Services = SpecialPowers.Services; - -function testScreenState(on, expected, msg) { - // send event to RadioInterface - Services.obs.notifyObservers(null, 'screen-state-changed', on); - // maybe rild/qemu needs some time to process the event - window.setTimeout(function() { - runEmulatorCmd('gsm report creg', function(result) { - is(result.pop(), 'OK', '\'gsm report creg\' successful'); - ok(result.indexOf(expected) !== -1, msg); - runNextTest(); - })}, 1000); -} - -function testScreenStateDisabled() { - testScreenState('off', '+CREG: 1', 'screen is disabled'); -} - -function testScreenStateEnabled() { - testScreenState('on', '+CREG: 2', 'screen is enabled'); -} - -var tests = [ - testScreenStateDisabled, - testScreenStateEnabled -]; - -function runNextTest() { - let test = tests.shift(); - if (!test) { - cleanUp(); - return; - } - - test(); -} - -function cleanUp() { - finish(); -} - -runNextTest(); diff --git a/dom/system/gonk/tests/marionette/test_timezone_changes.js b/dom/system/gonk/tests/marionette/test_timezone_changes.js deleted file mode 100644 index 11dbaec5a..000000000 --- a/dom/system/gonk/tests/marionette/test_timezone_changes.js +++ /dev/null @@ -1,135 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 60000; -MARIONETTE_HEAD_JS = 'head.js'; - -function init() { - let promises = []; - - /* - * The initial timezone of the emulator could be anywhere, depends the host - * machine. Ensure resetting it to UTC before testing. - */ - promises.push(runEmulatorCmdSafe('gsm timezone 0')); - promises.push(new Promise((aResolve, aReject) => { - waitFor(aResolve, () => { - return new Date().getTimezoneOffset() === 0; - }); - })); - - return Promise.all(promises); -} - -function paddingZeros(aNumber, aLength) { - let str = '' + aNumber; - while (str.length < aLength) { - str = '0' + str; - } - - return str; -} - -function verifyDate(aTestDate, aUTCOffsetDate) { - // Verify basic properties. - is(aUTCOffsetDate.getUTCFullYear(), aTestDate.getFullYear(), 'year'); - is(aUTCOffsetDate.getUTCMonth(), aTestDate.getMonth(), 'month'); - is(aUTCOffsetDate.getUTCDate(), aTestDate.getDate(), 'date'); - is(aUTCOffsetDate.getUTCHours(), aTestDate.getHours(), 'hours'); - is(aUTCOffsetDate.getUTCMinutes(), aTestDate.getMinutes(), 'minutes'); - is(aUTCOffsetDate.getUTCMilliseconds(), aTestDate.getMilliseconds(), 'milliseconds'); - - // Ensure toLocaleString also uses correct timezone. - // It uses ICU's timezone instead of the offset calculated from gecko prtime. - let expectedDateString = - paddingZeros(aUTCOffsetDate.getUTCMonth() + 1, 2) + '/' + - paddingZeros(aUTCOffsetDate.getUTCDate(), 2); - let dateString = aTestDate.toLocaleString('en-US', { - month: '2-digit', - day: '2-digit', - }); - let expectedTimeString = - paddingZeros(aUTCOffsetDate.getUTCHours(), 2) + ':' + - paddingZeros(aUTCOffsetDate.getUTCMinutes(), 2); - let timeString = aTestDate.toLocaleString('en-US', { - hour12: false, - hour: '2-digit', - minute: '2-digit' - }); - - is(expectedDateString, dateString, 'dateString'); - is(expectedTimeString, timeString, 'timeString'); -} - -function waitForTimezoneUpdate(aTzOffset, - aTestDateInMillis = 86400000, // Use 'UTC 00:00:00, 2nd of Jan, 1970' by default. - aTransTzOffset, aTransTestDateInMillis) { - return new Promise(function(aResolve, aReject) { - window.addEventListener('moztimechange', function onevent(aEvent) { - // Since there could be multiple duplicate moztimechange event, wait until - // timezone is actually changed to expected value before removing the - // listener. - let testDate = new Date(aTestDateInMillis); - if (testDate.getTimezoneOffset() === aTzOffset) { - window.removeEventListener('moztimechange', onevent); - - // The UTC time of offsetDate is the same as the expected local time of - // testDate. We'll use it to verify the values. - let offsetDate = new Date(aTestDateInMillis - aTzOffset * 60 * 1000); - verifyDate(testDate, offsetDate); - - // Verify transition time if given. - if (aTransTzOffset !== undefined) { - testDate = new Date(aTransTestDateInMillis); - is(testDate.getTimezoneOffset(), aTransTzOffset); - - // Verify transition date. - offsetDate = new Date(aTransTestDateInMillis - aTransTzOffset * 60 * 1000); - verifyDate(testDate, offsetDate); - } - - aResolve(aEvent); - } - }); - }); -} - -function testChangeNitzTimezone(aTzDiff) { - let promises = []; - - // aTzOffset should be the expected value for getTimezoneOffset(). - // Note that getTimezoneOffset() is not so straightforward, - // it values (UTC - localtime), so UTC+08:00 returns -480. - promises.push(waitForTimezoneUpdate(-aTzDiff * 15)); - promises.push(runEmulatorCmdSafe('gsm timezone ' + aTzDiff)); - - return Promise.all(promises); -} - -function testChangeOlsonTimezone(aOlsonTz, aTzOffset, aTestDateInMillis, - aTransTzOffset, aTransTestDateInMillis) { - let promises = []; - - promises.push(waitForTimezoneUpdate(aTzOffset, aTestDateInMillis, - aTransTzOffset, aTransTestDateInMillis)); - promises.push(setSettings('time.timezone', aOlsonTz)); - - return Promise.all(promises); -} - -// Start test -startTestBase(function() { - return init() - .then(() => testChangeNitzTimezone(36)) // UTC+09:00 - .then(() => testChangeOlsonTimezone('America/New_York', - 300, 1446357600000, // 2015/11/01 02:00 UTC-04:00 => 01:00 UTC-05:00 (EST) - 240, 1425798000000)) // 2015/03/08 02:00 UTC-05:00 => 03:00 UTC-04:00 (EDT) - .then(() => testChangeNitzTimezone(-22)) // UTC-05:30 - .then(() => testChangeNitzTimezone(51)) // UTC+12:45 - .then(() => testChangeOlsonTimezone('Australia/Adelaide', - -570, 1428165000000, // 2015/04/05 03:00 UTC+10:30 => 02:00 UTC+09:30 (ACST) - -630, 1443889800000)) // 2015/10/04 02:00 UTC+09:30 => 03:00 UTC+10:30 (ACDT) - .then(() => testChangeNitzTimezone(-38)) // UTC-09:30 - .then(() => testChangeNitzTimezone(0)) // UTC - .then(() => runEmulatorCmdSafe('gsm timezone auto')); -}); diff --git a/dom/system/gonk/tests/test_ril_system_messenger.js b/dom/system/gonk/tests/test_ril_system_messenger.js deleted file mode 100644 index a588d0ddb..000000000 --- a/dom/system/gonk/tests/test_ril_system_messenger.js +++ /dev/null @@ -1,1187 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -var RIL = {}; -Cu.import("resource://gre/modules/ril_consts.js", RIL); - -XPCOMUtils.defineLazyServiceGetter(this, "gStkCmdFactory", - "@mozilla.org/icc/stkcmdfactory;1", - "nsIStkCmdFactory"); - -/** - * Name space for RILSystemMessenger.jsm. Only initialized after first call to - * newRILSystemMessenger. - */ -var RSM; - -var gReceivedMsgType = null; -var gReceivedMessage = null; - -/** - * Create a new RILSystemMessenger instance. - * - * @return a RILSystemMessenger instance. - */ -function newRILSystemMessenger() { - if (!RSM) { - RSM = Cu.import("resource://gre/modules/RILSystemMessenger.jsm", {}); - equal(typeof RSM.RILSystemMessenger, "function", "RSM.RILSystemMessenger"); - } - - let rsm = new RSM.RILSystemMessenger(); - rsm.broadcastMessage = (aType, aMessage) => { - gReceivedMsgType = aType; - gReceivedMessage = aMessage; - }; - - rsm.createCommandMessage = (aStkProactiveCmd) => { - return gStkCmdFactory.createCommandMessage(aStkProactiveCmd); - }; - - return rsm; -} - -function equal_received_system_message(aType, aMessage) { - equal(aType, gReceivedMsgType); - deepEqual(aMessage, gReceivedMessage); - gReceivedMsgType = null; - gReceivedMessage = null; -} - -/** - * Verify that each nsIXxxMessenger could be retrieved. - */ -function run_test() { - let telephonyMessenger = Cc["@mozilla.org/ril/system-messenger-helper;1"] - .getService(Ci.nsITelephonyMessenger); - - let smsMessenger = Cc["@mozilla.org/ril/system-messenger-helper;1"] - .getService(Ci.nsISmsMessenger); - - let cellbroadcastMessenger = Cc["@mozilla.org/ril/system-messenger-helper;1"] - .getService(Ci.nsICellbroadcastMessenger); - - let mobileConnectionMessenger = Cc["@mozilla.org/ril/system-messenger-helper;1"] - .getService(Ci.nsIMobileConnectionMessenger); - - let iccMessenger = Cc["@mozilla.org/ril/system-messenger-helper;1"] - .getService(Ci.nsIIccMessenger); - - ok(telephonyMessenger !== null, "Get TelephonyMessenger."); - ok(smsMessenger != null, "Get SmsMessenger."); - ok(cellbroadcastMessenger != null, "Get CellbroadcastMessenger."); - ok(mobileConnectionMessenger != null, "Get MobileConnectionMessenger."); - ok(iccMessenger != null, "Get IccMessenger."); - - run_next_test(); -} - -/** - * Verify RILSystemMessenger.notifyNewCall() - */ -add_test(function test_telephony_messenger_notify_new_call() { - let messenger = newRILSystemMessenger(); - - messenger.notifyNewCall(); - equal_received_system_message("telephony-new-call", {}); - - run_next_test(); -}); - -/** - * Verify RILSystemMessenger.notifyCallEnded() - */ -add_test(function test_telephony_messenger_notify_call_ended() { - let messenger = newRILSystemMessenger(); - - messenger.notifyCallEnded(1, - "+0987654321", - null, - true, - 500, - false, - true); - - equal_received_system_message("telephony-call-ended", { - serviceId: 1, - number: "+0987654321", - emergency: true, - duration: 500, - direction: "incoming", - hangUpLocal: true - }); - - // Verify 'optional' parameter of secondNumber. - messenger.notifyCallEnded(1, - "+0987654321", - "+1234567890", - true, - 500, - true, - false); - - equal_received_system_message("telephony-call-ended", { - serviceId: 1, - number: "+0987654321", - emergency: true, - duration: 500, - direction: "outgoing", - hangUpLocal: false, - secondNumber: "+1234567890" - }); - - run_next_test(); -}); - -/** - * Verify RILSystemMessenger.notifySms() - */ -add_test(function test_sms_messenger_notify_sms() { - let messenger = newRILSystemMessenger(); - let timestamp = Date.now(); - let sentTimestamp = timestamp + 100; - let deliveryTimestamp = sentTimestamp + 100; - - // Verify 'sms-received' system message. - messenger.notifySms(Ci.nsISmsMessenger.NOTIFICATION_TYPE_RECEIVED, - 1, - 2, - "99887766554433221100", - Ci.nsISmsService.DELIVERY_TYPE_RECEIVED, - Ci.nsISmsService.DELIVERY_STATUS_TYPE_SUCCESS, - "+0987654321", - null, - "Incoming message", - Ci.nsISmsService.MESSAGE_CLASS_TYPE_CLASS_2, - timestamp, - sentTimestamp, - 0, - false); - - equal_received_system_message("sms-received", { - iccId: "99887766554433221100", - type: "sms", - id: 1, - threadId: 2, - delivery: "received", - deliveryStatus: "success", - sender: "+0987654321", - receiver: null, - body: "Incoming message", - messageClass: "class-2", - timestamp: timestamp, - sentTimestamp: sentTimestamp, - deliveryTimestamp: 0, - read: false - }); - - // Verify 'sms-sent' system message. - messenger.notifySms(Ci.nsISmsMessenger.NOTIFICATION_TYPE_SENT, - 3, - 4, - "99887766554433221100", - Ci.nsISmsService.DELIVERY_TYPE_SENT, - Ci.nsISmsService.DELIVERY_STATUS_TYPE_PENDING, - null, - "+0987654321", - "Outgoing message", - Ci.nsISmsService.MESSAGE_CLASS_TYPE_NORMAL, - timestamp, - 0, - 0, - true); - - equal_received_system_message("sms-sent", { - iccId: "99887766554433221100", - type: "sms", - id: 3, - threadId: 4, - delivery: "sent", - deliveryStatus: "pending", - sender: null, - receiver: "+0987654321", - body: "Outgoing message", - messageClass: "normal", - timestamp: timestamp, - sentTimestamp: 0, - deliveryTimestamp: 0, - read: true - }); - - // Verify 'sms-delivery-success' system message. - messenger.notifySms(Ci.nsISmsMessenger.NOTIFICATION_TYPE_DELIVERY_SUCCESS, - 5, - 6, - "99887766554433221100", - Ci.nsISmsService.DELIVERY_TYPE_SENT, - Ci.nsISmsService.DELIVERY_STATUS_TYPE_SUCCESS, - null, - "+0987654321", - "Outgoing message", - Ci.nsISmsService.MESSAGE_CLASS_TYPE_NORMAL, - timestamp, - 0, - deliveryTimestamp, - true); - - equal_received_system_message("sms-delivery-success", { - iccId: "99887766554433221100", - type: "sms", - id: 5, - threadId: 6, - delivery: "sent", - deliveryStatus: "success", - sender: null, - receiver: "+0987654321", - body: "Outgoing message", - messageClass: "normal", - timestamp: timestamp, - sentTimestamp: 0, - deliveryTimestamp: deliveryTimestamp, - read: true - }); - - // Verify 'sms-failed' system message. - messenger.notifySms(Ci.nsISmsMessenger.NOTIFICATION_TYPE_SENT_FAILED, - 7, - 8, - "99887766554433221100", - Ci.nsISmsService.DELIVERY_TYPE_ERROR, - Ci.nsISmsService.DELIVERY_STATUS_TYPE_ERROR, - null, - "+0987654321", - "Outgoing message", - Ci.nsISmsService.MESSAGE_CLASS_TYPE_NORMAL, - timestamp, - 0, - 0, - true); - - equal_received_system_message("sms-failed", { - iccId: "99887766554433221100", - type: "sms", - id: 7, - threadId: 8, - delivery: "error", - deliveryStatus: "error", - sender: null, - receiver: "+0987654321", - body: "Outgoing message", - messageClass: "normal", - timestamp: timestamp, - sentTimestamp: 0, - deliveryTimestamp: 0, - read: true - }); - - // Verify 'sms-delivery-error' system message. - messenger.notifySms(Ci.nsISmsMessenger.NOTIFICATION_TYPE_DELIVERY_ERROR, - 9, - 10, - "99887766554433221100", - Ci.nsISmsService.DELIVERY_TYPE_SENT, - Ci.nsISmsService.DELIVERY_STATUS_TYPE_ERROR, - null, - "+0987654321", - "Outgoing message", - Ci.nsISmsService.MESSAGE_CLASS_TYPE_NORMAL, - timestamp, - 0, - 0, - true); - - equal_received_system_message("sms-delivery-error", { - iccId: "99887766554433221100", - type: "sms", - id: 9, - threadId: 10, - delivery: "sent", - deliveryStatus: "error", - sender: null, - receiver: "+0987654321", - body: "Outgoing message", - messageClass: "normal", - timestamp: timestamp, - sentTimestamp: 0, - deliveryTimestamp: 0, - read: true - }); - - // Verify the protection of invalid nsISmsMessenger.NOTIFICATION_TYPEs. - try { - messenger.notifySms(5, - 1, - 2, - "99887766554433221100", - Ci.nsISmsService.DELIVERY_TYPE_RECEIVED, - Ci.nsISmsService.DELIVERY_STATUS_TYPE_SUCCESS, - "+0987654321", - null, - "Incoming message", - Ci.nsISmsService.MESSAGE_CLASS_TYPE_NORMAL, - timestamp, - sentTimestamp, - 0, - false); - ok(false, "Failed to verify the protection of invalid nsISmsMessenger.NOTIFICATION_TYPE!"); - } catch (e) {} - - run_next_test(); -}); - -/** - * Verify RILSystemMessenger.notifyCbMessageReceived() - */ -add_test(function test_cellbroadcast_messenger_notify_cb_message_received() { - let messenger = newRILSystemMessenger(); - let timestamp = Date.now(); - - // Verify ETWS - messenger.notifyCbMessageReceived(0, - Ci.nsICellBroadcastService.GSM_GEOGRAPHICAL_SCOPE_CELL_IMMEDIATE, - 256, - 4352, - null, - null, - Ci.nsICellBroadcastService.GSM_MESSAGE_CLASS_NORMAL, - timestamp, - Ci.nsICellBroadcastService.CDMA_SERVICE_CATEGORY_INVALID, - true, - Ci.nsICellBroadcastService.GSM_ETWS_WARNING_EARTHQUAKE, - false, - true); - equal_received_system_message("cellbroadcast-received", { - serviceId: 0, - gsmGeographicalScope: "cell-immediate", - messageCode: 256, - messageId: 4352, - language: null, - body: null, - messageClass: "normal", - timestamp: timestamp, - cdmaServiceCategory: null, - etws: { - warningType: "earthquake", - emergencyUserAlert: false, - popup: true - } - }); - - // Verify Normal CB Message - messenger.notifyCbMessageReceived(1, - Ci.nsICellBroadcastService.GSM_GEOGRAPHICAL_SCOPE_PLMN, - 0, - 50, - "en", - "The quick brown fox jumps over the lazy dog", - Ci.nsICellBroadcastService.GSM_MESSAGE_CLASS_NORMAL, - timestamp, - Ci.nsICellBroadcastService.CDMA_SERVICE_CATEGORY_INVALID, - false, - Ci.nsICellBroadcastService.GSM_ETWS_WARNING_INVALID, - false, - false); - equal_received_system_message("cellbroadcast-received", { - serviceId: 1, - gsmGeographicalScope: "plmn", - messageCode: 0, - messageId: 50, - language: "en", - body: "The quick brown fox jumps over the lazy dog", - messageClass: "normal", - timestamp: timestamp, - cdmaServiceCategory: null, - etws: null - }); - - // Verify CB Message with ETWS Info - messenger.notifyCbMessageReceived(0, - Ci.nsICellBroadcastService.GSM_GEOGRAPHICAL_SCOPE_LOCATION_AREA, - 0, - 4354, - "en", - "Earthquake & Tsunami Warning!", - Ci.nsICellBroadcastService.GSM_MESSAGE_CLASS_0, - timestamp, - Ci.nsICellBroadcastService.CDMA_SERVICE_CATEGORY_INVALID, - true, - Ci.nsICellBroadcastService.GSM_ETWS_WARNING_EARTHQUAKE_TSUNAMI, - true, - false); - equal_received_system_message("cellbroadcast-received", { - serviceId: 0, - gsmGeographicalScope: "location-area", - messageCode: 0, - messageId: 4354, - language: "en", - body: "Earthquake & Tsunami Warning!", - messageClass: "class-0", - timestamp: timestamp, - cdmaServiceCategory: null, - etws: { - warningType: "earthquake-tsunami", - emergencyUserAlert: true, - popup: false - } - }); - - // Verify CDMA CB Message - messenger.notifyCbMessageReceived(0, - Ci.nsICellBroadcastService.GSM_GEOGRAPHICAL_SCOPE_INVALID, - 0, - 0, - null, - "CDMA CB Message", - Ci.nsICellBroadcastService.GSM_MESSAGE_CLASS_NORMAL, - timestamp, - 512, - false, - Ci.nsICellBroadcastService.GSM_ETWS_WARNING_INVALID, - false, - false); - equal_received_system_message("cellbroadcast-received", { - serviceId: 0, - gsmGeographicalScope: null, - messageCode: 0, - messageId: 0, - language: null, - body: "CDMA CB Message", - messageClass: "normal", - timestamp: timestamp, - cdmaServiceCategory: 512, - etws: null - }); - - run_next_test(); -}); - -/** - * Verify RILSystemMessenger.notifyUssdReceived() - */ -add_test(function test_mobileconnection_notify_ussd_received() { - let messenger = newRILSystemMessenger(); - - messenger.notifyUssdReceived(0, "USSD Message", false); - - equal_received_system_message("ussd-received", { - serviceId: 0, - message: "USSD Message", - sessionEnded: false - }); - - messenger.notifyUssdReceived(1, "USSD Message", true); - - equal_received_system_message("ussd-received", { - serviceId: 1, - message: "USSD Message", - sessionEnded: true - }); - - run_next_test(); -}); - -/** - * Verify RILSystemMessenger.notifyCdmaInfoRecXXX() - */ -add_test(function test_mobileconnection_notify_cdma_info() { - let messenger = newRILSystemMessenger(); - - messenger.notifyCdmaInfoRecDisplay(0, "CDMA Display Info"); - - equal_received_system_message("cdma-info-rec-received", { - clientId: 0, - display: "CDMA Display Info" - }); - - messenger.notifyCdmaInfoRecCalledPartyNumber(1, 1, 2, "+0987654321", 3, 4); - - equal_received_system_message("cdma-info-rec-received", { - clientId: 1, - calledNumber: { - type: 1, - plan: 2, - number: "+0987654321", - pi: 3, - si: 4 - } - }); - - messenger.notifyCdmaInfoRecCallingPartyNumber(0, 5, 6, "+1234567890", 7, 8); - - equal_received_system_message("cdma-info-rec-received", { - clientId: 0, - callingNumber: { - type: 5, - plan: 6, - number: "+1234567890", - pi: 7, - si: 8 - } - }); - - messenger.notifyCdmaInfoRecConnectedPartyNumber(1, 4, 3, "+56473839201", 2, 1); - - equal_received_system_message("cdma-info-rec-received", { - clientId: 1, - connectedNumber: { - type: 4, - plan: 3, - number: "+56473839201", - pi: 2, - si: 1 - } - }); - - messenger.notifyCdmaInfoRecSignal(0, 1, 2, 3); - - equal_received_system_message("cdma-info-rec-received", { - clientId: 0, - signal: { - type: 1, - alertPitch: 2, - signal: 3 - } - }); - - messenger.notifyCdmaInfoRecRedirectingNumber(1, 8, 7, "+1029384756", 6, 5, 4); - - equal_received_system_message("cdma-info-rec-received", { - clientId: 1, - redirect: { - type: 8, - plan: 7, - number: "+1029384756", - pi: 6, - si: 5, - reason: 4 - } - }); - - messenger.notifyCdmaInfoRecLineControl(0, 1, 0, 1, 255); - - equal_received_system_message("cdma-info-rec-received", { - clientId: 0, - lineControl: { - polarityIncluded: 1, - toggle: 0, - reverse: 1, - powerDenial: 255 - } - }); - - messenger.notifyCdmaInfoRecClir(1, 256); - - equal_received_system_message("cdma-info-rec-received", { - clientId: 1, - clirCause: 256 - }); - - messenger.notifyCdmaInfoRecAudioControl(0, 255, -1); - - equal_received_system_message("cdma-info-rec-received", { - clientId: 0, - audioControl: { - upLink: 255, - downLink: -1 - } - }); - - run_next_test(); -}); - -/** - * Verify Error Handling of StkProactiveCmdFactory.createCommand() - */ -add_test(function test_icc_stk_cmd_factory_create_command_error() { - let messenger = newRILSystemMessenger(); - - // Verify the protection of invalid typeOfCommand. - try { - gStkCmdFactory.createCommand({ - commandNumber: 0, - typeOfCommand: RIL.STK_CMD_MORE_TIME, // Invalid TypeOfCommand - commandQualifier: 0x00 - }); - - ok(false, "Failed to verify the protection of createCommand()!"); - } catch (e) { - ok(e.message.indexOf("Unknown Command Type") !== -1, - "Invalid typeOfCommand!"); - } - - run_next_test(); -}); - -/** - * Verify Error Handling of StkProactiveCmdFactory.createCommandMessage() - */ -add_test(function test_icc_stk_cmd_factory_create_system_msg_invalid_cmd_type() { - let messenger = newRILSystemMessenger(); - let iccId = "99887766554433221100"; - - // Verify the protection of invalid typeOfCommand. - try { - gStkCmdFactory.createCommandMessage({ - QueryInterface: XPCOMUtils.generateQI([Ci.nsIStkProactiveCmd]), - - // nsIStkProactiveCmd - commandNumber: 0, - typeOfCommand: RIL.STK_CMD_MORE_TIME, // Invalid TypeOfCommand - commandQualifier: 0 - }); - - ok(false, "Failed to identify invalid typeOfCommand!"); - } catch (e) { - ok(e.message.indexOf("Unknown Command Type") !== -1, - "Invalid typeOfCommand!"); - } - - run_next_test(); -}); - -/** - * Verify Error Handling of StkProactiveCmdFactory.createCommandMessage() - */ -add_test(function test_icc_stk_cmd_factory_create_system_msg_incorrect_cmd_type() { - let messenger = newRILSystemMessenger(); - let iccId = "99887766554433221100"; - - // Verify the protection of invalid typeOfCommand. - try { - gStkCmdFactory.createCommandMessage({ - QueryInterface: XPCOMUtils.generateQI([Ci.nsIStkProactiveCmd, - Ci.nsIStkProvideLocalInfoCmd]), - - // nsIStkProactiveCmd - commandNumber: 0, - typeOfCommand: RIL.STK_CMD_POLL_INTERVAL, // Incorrect typeOfCommand - commandQualifier: 0, - // nsIStkProvideLocalInfoCmd - localInfoType: 0x00, - }); - - ok(false, "Failed to identify incorrect typeOfCommand!"); - } catch (e) { - ok(e.message.indexOf("Failed to convert command into concrete class: ") !== -1); - } - - run_next_test(); -}); - -/** - * Verify RILSystemMessenger.notifyStkProactiveCommand() - */ -add_test(function test_icc_notify_stk_proactive_command() { - let messenger = newRILSystemMessenger(); - let iccId = "99887766554433221100"; - let WHT = 0xFFFFFFFF; - let BLK = 0x000000FF; - let RED = 0xFF0000FF; - let GRN = 0x00FF00FF; - let BLU = 0x0000FFFF; - let TSP = 0; - // Basic Image, see Anex B.1 in TS 31.102. - let basicIcon = { - width: 8, - height: 8, - codingScheme: "basic", - pixels: [WHT, WHT, WHT, WHT, WHT, WHT, WHT, WHT, - BLK, BLK, BLK, BLK, BLK, BLK, WHT, WHT, - WHT, BLK, WHT, BLK, BLK, WHT, BLK, WHT, - WHT, BLK, BLK, WHT, WHT, BLK, BLK, WHT, - WHT, BLK, BLK, WHT, WHT, BLK, BLK, WHT, - WHT, BLK, WHT, BLK, BLK, WHT, BLK, WHT, - WHT, WHT, BLK, BLK, BLK, BLK, WHT, WHT, - WHT, WHT, WHT, WHT, WHT, WHT, WHT, WHT] - }; - // Color Image, see Anex B.2 in TS 31.102. - let colorIcon = { - width: 8, - height: 8, - codingScheme: "color", - pixels: [BLU, BLU, BLU, BLU, BLU, BLU, BLU, BLU, - BLU, RED, RED, RED, RED, RED, RED, BLU, - BLU, RED, GRN, GRN, GRN, RED, RED, BLU, - BLU, RED, RED, GRN, GRN, RED, RED, BLU, - BLU, RED, RED, GRN, GRN, RED, RED, BLU, - BLU, RED, RED, GRN, GRN, GRN, RED, BLU, - BLU, RED, RED, RED, RED, RED, RED, BLU, - BLU, BLU, BLU, BLU, BLU, BLU, BLU, BLU] - }; - // Color Image with Transparency, see Anex B.2 in TS 31.102. - let colorTransparencyIcon = { - width: 8, - height: 8, - codingScheme: "color-transparency", - pixels: [TSP, TSP, TSP, TSP, TSP, TSP, TSP, TSP, - TSP, RED, RED, RED, RED, RED, RED, TSP, - TSP, RED, GRN, GRN, GRN, RED, RED, TSP, - TSP, RED, RED, GRN, GRN, RED, RED, TSP, - TSP, RED, RED, GRN, GRN, RED, RED, TSP, - TSP, RED, RED, GRN, GRN, GRN, RED, TSP, - TSP, RED, RED, RED, RED, RED, RED, TSP, - TSP, TSP, TSP, TSP, TSP, TSP, TSP, TSP] - }; - - let cmdCount = 0; - - // Test Messages: - let messages = [ - // STK_CMD_REFRESH - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_REFRESH, - commandQualifier: 0x04 // UICC Reset - }, - // STK_CMD_POLL_INTERVAL - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_POLL_INTERVAL, - commandQualifier: 0x00, // RFU - options: { - timeUnit: RIL.STK_TIME_UNIT_TENTH_SECOND, - timeInterval: 0x05 - } - }, - // STK_CMD_POLL_OFF - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_POLL_OFF, - commandQualifier: 0x00, // RFU - }, - // STK_CMD_PROVIDE_LOCAL_INFO - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_PROVIDE_LOCAL_INFO, - commandQualifier: 0x01, // IMEI of the terminal - options: { - localInfoType: 0x01 // IMEI of the terminal - } - }, - // STK_CMD_SET_UP_EVENT_LIST with eventList - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SET_UP_EVENT_LIST, - commandQualifier: 0x00, // RFU - options: { - eventList: [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1A, 0x1B, 0x1C ] - } - }, - // STK_CMD_SET_UP_EVENT_LIST without eventList - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SET_UP_EVENT_LIST, - commandQualifier: 0x00, // RFU - options: { - eventList: null - } - }, - // STK_CMD_SET_UP_MENU with mandatory properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SET_UP_MENU, - commandQualifier: 0x80, // bit 8: 1 = help information available - options: { - title: "Toolkit Menu 1", - items: [ - { identifier: 0x01, text: "Menu Item 1" }, - { identifier: 0x02, text: "Menu Item 2" }, - { identifier: 0x03, text: "Menu Item 3" } - ], - isHelpAvailable: true - } - }, - // STK_CMD_SET_UP_MENU with optional properties including: - // iconInfo for this menu, iconInfo for each item and nextActionList. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SET_UP_MENU, - commandQualifier: 0x00, // bit 8: 0 = help information is not available - options: { - title: "Toolkit Menu 2", - items: [ - { identifier: 0x01, - text: "Menu Item 1", - iconSelfExplanatory: true, - icons: [basicIcon] - }, - { identifier: 0x02, - text: "Menu Item 2", - iconSelfExplanatory: false, - icons: [basicIcon, colorIcon] - }, - { identifier: 0x03, - text: "Menu Item 3", - iconSelfExplanatory: true, - icons: [basicIcon, colorIcon, colorTransparencyIcon] - }, - ], - nextActionList: [ - RIL.STK_NEXT_ACTION_END_PROACTIVE_SESSION, - RIL.STK_NEXT_ACTION_NULL, - RIL.STK_NEXT_ACTION_NULL, - RIL.STK_NEXT_ACTION_NULL - ], - iconSelfExplanatory: false, - icons: [basicIcon, colorIcon, colorTransparencyIcon], - isHelpAvailable: false - } - }, - // STK_CMD_SELECT_ITEM with mandatory properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SELECT_ITEM, - commandQualifier: RIL.STK_PRESENTATION_TYPE_NOT_SPECIFIED, - options: { - title: null, - items: [ - { identifier: 0x01, text: "Menu Item 1" }, - { identifier: 0x02, text: "Menu Item 2" }, - { identifier: 0x03, text: "Menu Item 3" } - ], - presentationType: RIL.STK_PRESENTATION_TYPE_NOT_SPECIFIED, - isHelpAvailable: false - } - }, - // STK_CMD_SELECT_ITEM with optional properties including: - // title, iconInfo for this menu, iconInfo for each item and nextActionList. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SELECT_ITEM, - commandQualifier: RIL.STK_PRESENTATION_TYPE_NAVIGATION_OPTIONS, - options: { - title: "Selected Toolkit Menu", - items: [ - { identifier: 0x01, - text: "Menu Item 1", - iconSelfExplanatory: true, - icons: [basicIcon] - }, - { identifier: 0x02, - text: "Menu Item 2", - iconSelfExplanatory: false, - icons: [basicIcon, colorIcon] - }, - { identifier: 0x03, - text: "Menu Item 3", - iconSelfExplanatory: true, - icons: [basicIcon, colorIcon, colorTransparencyIcon] - }, - ], - nextActionList: [ - RIL.STK_NEXT_ACTION_END_PROACTIVE_SESSION, - RIL.STK_NEXT_ACTION_NULL, - RIL.STK_NEXT_ACTION_NULL, - RIL.STK_NEXT_ACTION_NULL - ], - defaultItem: 0x02, - iconSelfExplanatory: false, - icons: [basicIcon, colorIcon, colorTransparencyIcon], - presentationType: RIL.STK_PRESENTATION_TYPE_NAVIGATION_OPTIONS, - isHelpAvailable: false - } - }, - // STK_CMD_DISPLAY_TEXT with mandatory properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_DISPLAY_TEXT, - commandQualifier: 0x01, // bit 1: High Priority - options: { - text: "Display Text 1", - isHighPriority: true, - userClear: false, - responseNeeded: false - } - }, - // STK_CMD_DISPLAY_TEXT with optional properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_DISPLAY_TEXT, - commandQualifier: 0x80, // bit 8: User Clear - options: { - text: "Display Text 2", - isHighPriority: false, - userClear: true, - responseNeeded: true, - duration: { - timeUnit: RIL.STK_TIME_UNIT_TENTH_SECOND, - timeInterval: 0x05 - }, - iconSelfExplanatory: true, - icons: [basicIcon] - } - }, - // STK_CMD_SET_UP_IDLE_MODE_TEXT - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SET_UP_IDLE_MODE_TEXT, - commandQualifier: 0x00, // RFU - options: { - text: "Setup Idle Mode Text" - } - }, - // STK_CMD_SEND_SS - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SEND_SS, - commandQualifier: 0x00, // RFU - options: { - text: "Send SS", - iconSelfExplanatory: true, - icons: [colorIcon] - } - }, - // STK_CMD_SEND_USSD - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SEND_USSD, - commandQualifier: 0x00, // RFU - options: { - text: "Send USSD" - } - }, - // STK_CMD_SEND_SMS - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SEND_SMS, - commandQualifier: 0x00, // RFU - options: { - text: "Send SMS", - iconSelfExplanatory: false, - icons: [colorTransparencyIcon] - } - }, - // STK_CMD_SEND_DTMF - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SEND_DTMF, - commandQualifier: 0x00, // RFU - options: { - text: "Send DTMF", - iconSelfExplanatory: true, - icons: [basicIcon] - } - }, - // STK_CMD_GET_INKEY - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_GET_INKEY, - commandQualifier: 0x84, // bit 3: isYesNoRequested, bit 8: isHelpAvailable - options: { - text: "Get Input Key", - minLength: 1, - maxLength: 1, - duration: { - timeUnit: RIL.STK_TIME_UNIT_SECOND, - timeInterval: 0x0A - }, - isAlphabet: false, - isUCS2: false, - isYesNoRequested: true, - isHelpAvailable: true, - defaultText: null, - iconSelfExplanatory: false, - icons: [colorIcon] - } - }, - // STK_CMD_GET_INPUT - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_GET_INPUT, - commandQualifier: 0x0F, // bit 1-4: isAlphabet, isUCS2, hideInput, isPacked - options: { - text: "Get Input Text", - minLength: 1, - maxLength: 255, - defaultText: "Default Input Text", - isAlphabet: true, - isUCS2: true, - hideInput: true, - isPacked: true, - isHelpAvailable: false, - defaultText: null, - iconSelfExplanatory: true, - icons: [basicIcon] - } - }, - // STK_CMD_SET_UP_CALL with mandatory properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SET_UP_CALL, - commandQualifier: 0x00, // RFU - options: { - address: "+0987654321" - } - }, - // STK_CMD_SET_UP_CALL with optional properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SET_UP_CALL, - commandQualifier: 0x00, // RFU - options: { - address: "+0987654321", - confirmMessage: { - text: "Confirm Message", - iconSelfExplanatory: false, - icons: [colorIcon] - }, - callMessage: { - text: "Call Message", - iconSelfExplanatory: true, - icons: [basicIcon] - }, - duration: { - timeUnit: RIL.STK_TIME_UNIT_SECOND, - timeInterval: 0x0A - } - } - }, - // STK_CMD_LAUNCH_BROWSER with mandatory properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_LAUNCH_BROWSER, - commandQualifier: RIL.STK_BROWSER_MODE_USING_NEW_BROWSER, - options: { - url: "http://www.mozilla.org", - mode: RIL.STK_BROWSER_MODE_USING_NEW_BROWSER - } - }, - // STK_CMD_LAUNCH_BROWSER with optional properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_LAUNCH_BROWSER, - commandQualifier: RIL.STK_BROWSER_MODE_USING_NEW_BROWSER, - options: { - url: "http://www.mozilla.org", - mode: RIL.STK_BROWSER_MODE_USING_NEW_BROWSER, - confirmMessage: { - text: "Confirm Message for Launch Browser", - iconSelfExplanatory: false, - icons: [colorTransparencyIcon] - } - } - }, - // STK_CMD_PLAY_TONE with mandatory properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_PLAY_TONE, - commandQualifier: 0x01, // isVibrate - options: { - text: null, - isVibrate: true - } - }, - // STK_CMD_PLAY_TONE with optional properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_PLAY_TONE, - commandQualifier: 0x00, // isVibrate = false - options: { - text: "Play Tone", - tone: RIL.STK_TONE_TYPE_CONGESTION, - isVibrate: false, - duration: { - timeUnit: RIL.STK_TIME_UNIT_SECOND, - timeInterval: 0x0A - }, - iconSelfExplanatory: true, - icons: [basicIcon] - } - }, - // STK_CMD_TIMER_MANAGEMENT with mandatory properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_TIMER_MANAGEMENT, - commandQualifier: RIL.STK_TIMER_DEACTIVATE, - options: { - timerId: 0x08, - timerAction: RIL.STK_TIMER_DEACTIVATE - } - }, - // STK_CMD_TIMER_MANAGEMENT with optional properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_TIMER_MANAGEMENT, - commandQualifier: RIL.STK_TIMER_START, - options: { - timerId: 0x01, - timerValue: (12 * 60 * 60) + (30 * 60) + (30), // 12:30:30 - timerAction: RIL.STK_TIMER_START - } - }, - // STK_CMD_OPEN_CHANNEL with mandatory properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_OPEN_CHANNEL, - commandQualifier: 0x00, //RFU - options: { - text: null, - } - }, - // STK_CMD_OPEN_CHANNEL with optional properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_OPEN_CHANNEL, - commandQualifier: 0x00, //RFU - options: { - text: "Open Channel", - iconSelfExplanatory: false, - icons: [colorIcon] - } - }, - // STK_CMD_CLOSE_CHANNEL with optional properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_CLOSE_CHANNEL, - commandQualifier: 0x00, //RFU - options: { - text: "Close Channel", - iconSelfExplanatory: true, - icons: [colorTransparencyIcon] - } - }, - // STK_CMD_SEND_DATA with optional properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SEND_DATA, - commandQualifier: 0x00, //RFU - options: { - text: null, - iconSelfExplanatory: false, - icons: [basicIcon] - } - }, - // STK_CMD_RECEIVE_DATA with optional properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_RECEIVE_DATA, - commandQualifier: 0x00, //RFU - options: { - text: "Receive Data" - } - }, - null // Termination condition to run_next_test() - ]; - - messages.forEach(function(aMessage) { - if (!aMessage) { - run_next_test(); - return; - } - - messenger.notifyStkProactiveCommand(iccId, - gStkCmdFactory.createCommand(aMessage)); - - equal_received_system_message("icc-stkcommand", { - iccId: iccId, - command: aMessage - }); - }); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_barring_password.js b/dom/system/gonk/tests/test_ril_worker_barring_password.js deleted file mode 100644 index fcd3e4405..000000000 --- a/dom/system/gonk/tests/test_ril_worker_barring_password.js +++ /dev/null @@ -1,61 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -const PIN = "0000"; -const NEW_PIN = "1234"; - -add_test(function test_change_call_barring_password() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - - function do_test(facility, pin, newPin) { - buf.sendParcel = function fakeSendParcel () { - // Request Type. - equal(this.readInt32(), REQUEST_CHANGE_BARRING_PASSWORD); - - // Token : we don't care. - this.readInt32(); - - let parcel = this.readStringList(); - equal(parcel.length, 3); - equal(parcel[0], facility); - equal(parcel[1], pin); - equal(parcel[2], newPin); - }; - - let options = {facility: facility, pin: pin, newPin: newPin}; - context.RIL.changeCallBarringPassword(options); - } - - do_test(ICC_CB_FACILITY_BA_ALL, PIN, NEW_PIN); - - run_next_test(); -}); - -add_test(function test_check_change_call_barring_password_result() { - let barringPasswordOptions; - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - - let context = worker.ContextPool._contexts[0]; - context.RIL.changeCallBarringPassword = - function fakeChangeCallBarringPassword(options) { - barringPasswordOptions = options; - context.RIL[REQUEST_CHANGE_BARRING_PASSWORD](0, {}); - }; - - context.RIL.changeCallBarringPassword({pin: PIN, newPin: NEW_PIN}); - - let postedMessage = workerHelper.postedMessage; - equal(barringPasswordOptions.pin, PIN); - equal(barringPasswordOptions.newPin, NEW_PIN); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_buf.js b/dom/system/gonk/tests/test_ril_worker_buf.js deleted file mode 100644 index 30054a881..000000000 --- a/dom/system/gonk/tests/test_ril_worker_buf.js +++ /dev/null @@ -1,187 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -function run_test() { - run_next_test(); -} - -/** - * Add test function with specified parcel and request handler. - * - * @param parcel - * Incoming parcel to be tested. - * @param handler - * Handler to be invoked as RIL request handler. - */ -function add_test_incoming_parcel(parcel, handler) { - add_test(function test_incoming_parcel() { - let worker = newWorker({ - postRILMessage: function(data) { - // do nothing - }, - postMessage: function(message) { - // do nothing - } - }); - - if (!parcel) { - parcel = newIncomingParcel(-1, - worker.RESPONSE_TYPE_UNSOLICITED, - worker.REQUEST_VOICE_REGISTRATION_STATE, - [0, 0, 0, 0]); - } - - let context = worker.ContextPool._contexts[0]; - // supports only requests less or equal than UINT8_MAX(255). - let buf = context.Buf; - let request = parcel[buf.PARCEL_SIZE_SIZE + buf.UINT32_SIZE]; - context.RIL[request] = function ril_request_handler() { - handler.apply(this, arguments); - }; - - worker.onRILMessage(0, parcel); - - // end of incoming parcel's trip, let's do next test. - run_next_test(); - }); -} - -// Test normal parcel handling. -add_test_incoming_parcel(null, - function test_normal_parcel_handling() { - let self = this; - try { - // reads exactly the same size, should not throw anything. - self.context.Buf.readInt32(); - } catch (e) { - ok(false, "Got exception: " + e); - } - } -); - -// Test parcel under read. -add_test_incoming_parcel(null, - function test_parcel_under_read() { - let self = this; - try { - // reads less than parcel size, should not throw. - self.context.Buf.readUint16(); - } catch (e) { - ok(false, "Got exception: " + e); - } - } -); - -// Test parcel over read. -add_test_incoming_parcel(null, - function test_parcel_over_read() { - let buf = this.context.Buf; - - // read all data available - while (buf.readAvailable > 0) { - buf.readUint8(); - } - - throws(function over_read_handler() { - // reads more than parcel size, should throw an error. - buf.readUint8(); - },"Trying to read data beyond the parcel end!"); - } -); - -// Test Bug 814761: buffer overwritten -add_test(function test_incoming_parcel_buffer_overwritten() { - let worker = newWorker({ - postRILMessage: function(data) { - // do nothing - }, - postMessage: function(message) { - // do nothing - } - }); - - let context = worker.ContextPool._contexts[0]; - // A convenient alias. - let buf = context.Buf; - - // Allocate an array of specified size and set each of its elements to value. - function calloc(length, value) { - let array = new Array(length); - for (let i = 0; i < length; i++) { - array[i] = value; - } - return array; - } - - // Do nothing in handleParcel(). - let request = worker.REQUEST_VOICE_REGISTRATION_STATE; - context.RIL[request] = null; - - // Prepare two parcels, whose sizes are both smaller than the incoming buffer - // size but larger when combined, to trigger the bug. - let pA_dataLength = buf.incomingBufferLength / 2; - let pA = newIncomingParcel(-1, - worker.RESPONSE_TYPE_UNSOLICITED, - request, - calloc(pA_dataLength, 1)); - let pA_parcelSize = pA.length - buf.PARCEL_SIZE_SIZE; - - let pB_dataLength = buf.incomingBufferLength * 3 / 4; - let pB = newIncomingParcel(-1, - worker.RESPONSE_TYPE_UNSOLICITED, - request, - calloc(pB_dataLength, 1)); - let pB_parcelSize = pB.length - buf.PARCEL_SIZE_SIZE; - - // First, send an incomplete pA and verifies related data pointer: - let p1 = pA.subarray(0, pA.length - 1); - worker.onRILMessage(0, p1); - // The parcel should not have been processed. - equal(buf.readAvailable, 0); - // buf.currentParcelSize should have been set because incoming data has more - // than 4 octets. - equal(buf.currentParcelSize, pA_parcelSize); - // buf.readIncoming should contains remaining unconsumed octets count. - equal(buf.readIncoming, p1.length - buf.PARCEL_SIZE_SIZE); - // buf.incomingWriteIndex should be ready to accept the last octet. - equal(buf.incomingWriteIndex, p1.length); - - // Second, send the last octet of pA and whole pB. The Buf should now expand - // to cover both pA & pB. - let p2 = new Uint8Array(1 + pB.length); - p2.set(pA.subarray(pA.length - 1), 0); - p2.set(pB, 1); - worker.onRILMessage(0, p2); - // The parcels should have been both consumed. - equal(buf.readAvailable, 0); - // No parcel data remains. - equal(buf.currentParcelSize, 0); - // No parcel data remains. - equal(buf.readIncoming, 0); - // The Buf should now expand to cover both pA & pB. - equal(buf.incomingWriteIndex, pA.length + pB.length); - - // end of incoming parcel's trip, let's do next test. - run_next_test(); -}); - -// Test Buf.readUint8Array. -add_test_incoming_parcel(null, - function test_buf_readUint8Array() { - let buf = this.context.Buf; - - let u8array = buf.readUint8Array(1); - equal(u8array instanceof Uint8Array, true); - equal(u8array.length, 1); - equal(buf.readAvailable, 3); - - u8array = buf.readUint8Array(2); - equal(u8array.length, 2); - equal(buf.readAvailable, 1); - - throws(function over_read_handler() { - // reads more than parcel size, should throw an error. - u8array = buf.readUint8Array(2); - }, "Trying to read data beyond the parcel end!"); - } -); diff --git a/dom/system/gonk/tests/test_ril_worker_cdma_info_rec.js b/dom/system/gonk/tests/test_ril_worker_cdma_info_rec.js deleted file mode 100644 index 335c0c403..000000000 --- a/dom/system/gonk/tests/test_ril_worker_cdma_info_rec.js +++ /dev/null @@ -1,234 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Helper function. - */ -function newWorkerWithParcel(parcelBuf) { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - - let index = 0; // index for read - let buf = parcelBuf; - - let context = worker.ContextPool._contexts[0]; - context.Buf.readUint8 = function() { - return buf[index++]; - }; - - context.Buf.readUint16 = function() { - return buf[index++]; - }; - - context.Buf.readInt32 = function() { - return buf[index++]; - }; - - context.Buf.seekIncoming = function(offset) { - index += offset / context.Buf.UINT32_SIZE; - }; - - return worker; -} - -// Test CDMA information record decoder. - -/** - * Verify decoder for type DISPLAY - */ -add_test(function test_display() { - let worker = newWorkerWithParcel([ - 0x01, // one inforemation record - 0x00, // type: display - 0x09, // length: 9 - 0x54, 0x65, 0x73, 0x74, 0x20, 0x49, 0x6E, 0x66, - 0x6F, 0x00]); - let context = worker.ContextPool._contexts[0]; - let helper = context.CdmaPDUHelper; - let records = helper.decodeInformationRecord(); - - equal(records[0].display, "Test Info"); - - run_next_test(); -}); - -/** - * Verify decoder for type EXTENDED DISPLAY - */ -add_test(function test_extended_display() { - let worker = newWorkerWithParcel([ - 0x01, // one inforemation record - 0x07, // type: extended display - 0x12, // length: 18 - 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x78, 0x74, - 0x65, 0x6E, 0x64, 0x65, 0x64, 0x20, 0x49, 0x6E, - 0x66, 0x6F, 0x00, 0x00]); - let context = worker.ContextPool._contexts[0]; - let helper = context.CdmaPDUHelper; - let records = helper.decodeInformationRecord(); - - equal(records[0].display, "Test Extended Info"); - - run_next_test(); -}); - -/** - * Verify decoder for mixed type - */ -add_test(function test_mixed() { - let worker = newWorkerWithParcel([ - 0x02, // two inforemation record - 0x00, // type: display - 0x0B, // length: 11 - 0x54, 0x65, 0x73, 0x74, 0x20, 0x49, 0x6E, 0x66, - 0x6F, 0x20, 0x31, 0x00, - 0x07, // type: extended display - 0x0B, // length: 11 - 0x54, 0x65, 0x73, 0x74, 0x20, 0x49, 0x6E, 0x66, - 0x6F, 0x20, 0x32, 0x00]); - let context = worker.ContextPool._contexts[0]; - let helper = context.CdmaPDUHelper; - let records = helper.decodeInformationRecord(); - - equal(records[0].display, "Test Info 1"); - equal(records[1].display, "Test Info 2"); - - run_next_test(); -}); - -/** - * Verify decoder for multiple types - */ -add_test(function test_multiple() { - let worker = newWorkerWithParcel([ - 0x02, // two inforemation record - 0x00, // type: display - 0x0B, // length: 11 - 0x54, 0x65, 0x73, 0x74, 0x20, 0x49, 0x6E, 0x66, - 0x6F, 0x20, 0x31, 0x00, - 0x00, // type: display - 0x0B, // length: 11 - 0x54, 0x65, 0x73, 0x74, 0x20, 0x49, 0x6E, 0x66, - 0x6F, 0x20, 0x32, 0x00]); - let context = worker.ContextPool._contexts[0]; - let helper = context.CdmaPDUHelper; - let records = helper.decodeInformationRecord(); - - equal(records[0].display, "Test Info 1"); - equal(records[1].display, "Test Info 2"); - - run_next_test(); -}); - -/** - * Verify decoder for Signal Type - */ -add_test(function test_signal() { - let worker = newWorkerWithParcel([ - 0x01, // one inforemation record - 0x04, // type: signal - 0x01, // isPresent: non-zero - 0x00, // signalType: Tone signal (00) - 0x01, // alertPitch: High pitch - 0x03]); // signal: Abbreviated intercept (000011) - let context = worker.ContextPool._contexts[0]; - let helper = context.CdmaPDUHelper; - let records = helper.decodeInformationRecord(); - - equal(records[0].signal.type, 0x00); - equal(records[0].signal.alertPitch, 0x01); - equal(records[0].signal.signal, 0x03); - - run_next_test(); -}); - -/** - * Verify decoder for Signal Type for Not Presented - */ -add_test(function test_signal_not_present() { - let worker = newWorkerWithParcel([ - 0x01, // one inforemation record - 0x04, // type: signal - 0x00, // isPresent: zero - 0x00, // signalType: Tone signal (00) - 0x01, // alertPitch: High pitch - 0x03]); // signal: Abbreviated intercept (000011) - let context = worker.ContextPool._contexts[0]; - let helper = context.CdmaPDUHelper; - let records = helper.decodeInformationRecord(); - - equal(records.length, 0); - - run_next_test(); -}); - -/** - * Verify decoder for Line Control - */ -add_test(function test_line_control() { - let worker = newWorkerWithParcel([ - 0x01, // one inforemation record - 0x06, // type: line control - 0x01, // polarity included - 0x00, // not toggled - 0x01, // reversed - 0xFF]); // Power denial timeout: 255 * 5 ms - let context = worker.ContextPool._contexts[0]; - let helper = context.CdmaPDUHelper; - let records = helper.decodeInformationRecord(); - - equal(records[0].lineControl.polarityIncluded, 1); - equal(records[0].lineControl.toggle, 0); - equal(records[0].lineControl.reverse, 1); - equal(records[0].lineControl.powerDenial, 255); - - run_next_test(); -}); - -/** - * Verify decoder for CLIR Cause - */ -add_test(function test_clir() { - let worker = newWorkerWithParcel([ - 0x01, // one inforemation record - 0x08, // type: clir - 0x01]); // cause: Rejected by user - let context = worker.ContextPool._contexts[0]; - let helper = context.CdmaPDUHelper; - let records = helper.decodeInformationRecord(); - - equal(records[0].clirCause, 1); - - run_next_test(); -}); - -/** - * Verify decoder for Audio Control - */ -add_test(function test_clir() { - let worker = newWorkerWithParcel([ - 0x01, // one inforemation record - 0x0A, // type: audio control - 0x01, // uplink - 0xFF]); // downlink - let context = worker.ContextPool._contexts[0]; - let helper = context.CdmaPDUHelper; - let records = helper.decodeInformationRecord(); - - equal(records[0].audioControl.upLink, 1); - equal(records[0].audioControl.downLink, 255); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_cellbroadcast_config.js b/dom/system/gonk/tests/test_ril_worker_cellbroadcast_config.js deleted file mode 100644 index d5645a3cf..000000000 --- a/dom/system/gonk/tests/test_ril_worker_cellbroadcast_config.js +++ /dev/null @@ -1,470 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -add_test(function test_ril_worker_cellbroadcast_activate() { - let worker = newWorker({ - postRILMessage: function(id, parcel) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - let context = worker.ContextPool._contexts[0]; - - let parcelTypes = []; - let org_newParcel = context.Buf.newParcel; - context.Buf.newParcel = function(type, options) { - parcelTypes.push(type); - org_newParcel.apply(this, arguments); - }; - - function setup(isCdma) { - context.RIL._isCdma = isCdma; - context.RIL.cellBroadcastDisabled = false; - context.RIL.mergedCellBroadcastConfig = [1, 2, 4, 7]; // 1, 4-6 - parcelTypes = []; - } - - function test(isCdma, expectedRequest) { - setup(isCdma); - context.RIL.setCellBroadcastDisabled({disabled: true}); - // Makesure that request parcel is sent out. - notEqual(parcelTypes.indexOf(expectedRequest), -1); - equal(context.RIL.cellBroadcastDisabled, true); - } - - test(false, REQUEST_GSM_SMS_BROADCAST_ACTIVATION); - test(true, REQUEST_CDMA_SMS_BROADCAST_ACTIVATION); - - run_next_test(); -}); - -add_test(function test_ril_worker_cellbroadcast_config() { - let currentParcel; - let worker = newWorker({ - postRILMessage: function(id, parcel) { - currentParcel = parcel; - }, - postMessage: function(message) { - // Do nothing - } - }); - let context = worker.ContextPool._contexts[0]; - - function U32ArrayFromParcelArray(pa) { - do_print(pa); - let out = []; - for (let i = 0; i < pa.length; i += 4) { - let data = pa[i] + (pa[i+1] << 8) + (pa[i+2] << 16) + (pa[i+3] << 24); - out.push(data); - } - return out; - } - - function test(isCdma, configs, expected) { - let parcelType = isCdma ? REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG - : REQUEST_GSM_SET_BROADCAST_SMS_CONFIG; - - let found = false; - worker.postRILMessage = function(id, parcel) { - let u32Parcel = U32ArrayFromParcelArray(Array.slice(parcel)); - if (u32Parcel[1] != parcelType) { - return; - } - - found = true; - // Check parcel. Data start from 4th word (32bit) - equal(u32Parcel.slice(3).toString(), expected); - }; - - context.RIL._isCdma = isCdma; - context.RIL.setSmsBroadcastConfig(configs); - - // Makesure that request parcel is sent out. - ok(found); - } - - // (GSM) RIL writes the following data to outgoing parcel: - // nums [(from, to, 0, 0xFF, 1), ... ] - test(false, - [1, 2, 4, 7] /* 1, 4-6 */, - ["2", "1,1,0,255,1", "4,6,0,255,1"].join()); - - // (CDMA) RIL writes the following data to outgoing parcel: - // nums [(id, 0, 1), ... ] - test(true, - [1, 2, 4, 7] /* 1, 4-6 */, - ["4", "1,0,1", "4,0,1", "5,0,1", "6,0,1"].join()); - - run_next_test(); -}); - -add_test(function test_ril_worker_cellbroadcast_merge_config() { - let worker = newWorker({ - postRILMessage: function(id, parcel) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - let context = worker.ContextPool._contexts[0]; - - function test(isCdma, configs, expected) { - context.RIL._isCdma = isCdma; - context.RIL.cellBroadcastConfigs = configs; - context.RIL._mergeAllCellBroadcastConfigs(); - equal(context.RIL.mergedCellBroadcastConfig.toString(), expected); - } - - let configs = { - MMI: [1, 2, 4, 7], // 1, 4-6 - CBMI: [6, 9], // 6-8 - CBMID: [8, 11], // 8-10 - CBMIR: [10, 13] // 10-12 - }; - - test(false, configs, "1,2,4,13"); - test(true, configs, "1,2,4,7"); - - run_next_test(); -}); - -add_test(function test_ril_worker_cellbroadcast_set_search_list() { - let worker = newWorker({ - postRILMessage: function(id, parcel) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - - let context = worker.ContextPool._contexts[0]; - - function test(aIsCdma, aSearchList, aExpected) { - context.RIL._isCdma = aIsCdma; - - let options = { searchList: aSearchList }; - context.RIL.setCellBroadcastSearchList(options); - // Enforce the MMI result to string for comparison. - equal("" + context.RIL.cellBroadcastConfigs.MMI, aExpected); - do_check_eq(options.errorMsg, undefined); - } - - let searchListStr = "1,2,3,4"; - let searchList = { gsm: "1,2,3,4", cdma: "5,6,7,8" }; - - test(false, searchListStr, "1,2,2,3,3,4,4,5"); - test(true, searchListStr, "1,2,2,3,3,4,4,5"); - test(false, searchList, "1,2,2,3,3,4,4,5"); - test(true, searchList, "5,6,6,7,7,8,8,9"); - test(false, null, "null"); - test(true, null, "null"); - - run_next_test(); -}); - -add_test(function test_ril_worker_mergeCellBroadcastConfigs() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - - function test(olist, from, to, expected) { - let result = ril._mergeCellBroadcastConfigs(olist, from, to); - equal(JSON.stringify(expected), JSON.stringify(result)); - } - - test(null, 0, 1, [0, 1]); - - test([10, 13], 7, 8, [ 7, 8, 10, 13]); - test([10, 13], 7, 9, [ 7, 9, 10, 13]); - test([10, 13], 7, 10, [ 7, 13]); - test([10, 13], 7, 11, [ 7, 13]); - test([10, 13], 7, 12, [ 7, 13]); - test([10, 13], 7, 13, [ 7, 13]); - test([10, 13], 7, 14, [ 7, 14]); - test([10, 13], 7, 15, [ 7, 15]); - test([10, 13], 7, 16, [ 7, 16]); - test([10, 13], 8, 9, [ 8, 9, 10, 13]); - test([10, 13], 8, 10, [ 8, 13]); - test([10, 13], 8, 11, [ 8, 13]); - test([10, 13], 8, 12, [ 8, 13]); - test([10, 13], 8, 13, [ 8, 13]); - test([10, 13], 8, 14, [ 8, 14]); - test([10, 13], 8, 15, [ 8, 15]); - test([10, 13], 8, 16, [ 8, 16]); - test([10, 13], 9, 10, [ 9, 13]); - test([10, 13], 9, 11, [ 9, 13]); - test([10, 13], 9, 12, [ 9, 13]); - test([10, 13], 9, 13, [ 9, 13]); - test([10, 13], 9, 14, [ 9, 14]); - test([10, 13], 9, 15, [ 9, 15]); - test([10, 13], 9, 16, [ 9, 16]); - test([10, 13], 10, 11, [10, 13]); - test([10, 13], 10, 12, [10, 13]); - test([10, 13], 10, 13, [10, 13]); - test([10, 13], 10, 14, [10, 14]); - test([10, 13], 10, 15, [10, 15]); - test([10, 13], 10, 16, [10, 16]); - test([10, 13], 11, 12, [10, 13]); - test([10, 13], 11, 13, [10, 13]); - test([10, 13], 11, 14, [10, 14]); - test([10, 13], 11, 15, [10, 15]); - test([10, 13], 11, 16, [10, 16]); - test([10, 13], 12, 13, [10, 13]); - test([10, 13], 12, 14, [10, 14]); - test([10, 13], 12, 15, [10, 15]); - test([10, 13], 12, 16, [10, 16]); - test([10, 13], 13, 14, [10, 14]); - test([10, 13], 13, 15, [10, 15]); - test([10, 13], 13, 16, [10, 16]); - test([10, 13], 14, 15, [10, 13, 14, 15]); - test([10, 13], 14, 16, [10, 13, 14, 16]); - test([10, 13], 15, 16, [10, 13, 15, 16]); - - test([10, 13, 14, 17], 7, 8, [ 7, 8, 10, 13, 14, 17]); - test([10, 13, 14, 17], 7, 9, [ 7, 9, 10, 13, 14, 17]); - test([10, 13, 14, 17], 7, 10, [ 7, 13, 14, 17]); - test([10, 13, 14, 17], 7, 11, [ 7, 13, 14, 17]); - test([10, 13, 14, 17], 7, 12, [ 7, 13, 14, 17]); - test([10, 13, 14, 17], 7, 13, [ 7, 13, 14, 17]); - test([10, 13, 14, 17], 7, 14, [ 7, 17]); - test([10, 13, 14, 17], 7, 15, [ 7, 17]); - test([10, 13, 14, 17], 7, 16, [ 7, 17]); - test([10, 13, 14, 17], 7, 17, [ 7, 17]); - test([10, 13, 14, 17], 7, 18, [ 7, 18]); - test([10, 13, 14, 17], 7, 19, [ 7, 19]); - test([10, 13, 14, 17], 8, 9, [ 8, 9, 10, 13, 14, 17]); - test([10, 13, 14, 17], 8, 10, [ 8, 13, 14, 17]); - test([10, 13, 14, 17], 8, 11, [ 8, 13, 14, 17]); - test([10, 13, 14, 17], 8, 12, [ 8, 13, 14, 17]); - test([10, 13, 14, 17], 8, 13, [ 8, 13, 14, 17]); - test([10, 13, 14, 17], 8, 14, [ 8, 17]); - test([10, 13, 14, 17], 8, 15, [ 8, 17]); - test([10, 13, 14, 17], 8, 16, [ 8, 17]); - test([10, 13, 14, 17], 8, 17, [ 8, 17]); - test([10, 13, 14, 17], 8, 18, [ 8, 18]); - test([10, 13, 14, 17], 8, 19, [ 8, 19]); - test([10, 13, 14, 17], 9, 10, [ 9, 13, 14, 17]); - test([10, 13, 14, 17], 9, 11, [ 9, 13, 14, 17]); - test([10, 13, 14, 17], 9, 12, [ 9, 13, 14, 17]); - test([10, 13, 14, 17], 9, 13, [ 9, 13, 14, 17]); - test([10, 13, 14, 17], 9, 14, [ 9, 17]); - test([10, 13, 14, 17], 9, 15, [ 9, 17]); - test([10, 13, 14, 17], 9, 16, [ 9, 17]); - test([10, 13, 14, 17], 9, 17, [ 9, 17]); - test([10, 13, 14, 17], 9, 18, [ 9, 18]); - test([10, 13, 14, 17], 9, 19, [ 9, 19]); - test([10, 13, 14, 17], 10, 11, [10, 13, 14, 17]); - test([10, 13, 14, 17], 10, 12, [10, 13, 14, 17]); - test([10, 13, 14, 17], 10, 13, [10, 13, 14, 17]); - test([10, 13, 14, 17], 10, 14, [10, 17]); - test([10, 13, 14, 17], 10, 15, [10, 17]); - test([10, 13, 14, 17], 10, 16, [10, 17]); - test([10, 13, 14, 17], 10, 17, [10, 17]); - test([10, 13, 14, 17], 10, 18, [10, 18]); - test([10, 13, 14, 17], 10, 19, [10, 19]); - test([10, 13, 14, 17], 11, 12, [10, 13, 14, 17]); - test([10, 13, 14, 17], 11, 13, [10, 13, 14, 17]); - test([10, 13, 14, 17], 11, 14, [10, 17]); - test([10, 13, 14, 17], 11, 15, [10, 17]); - test([10, 13, 14, 17], 11, 16, [10, 17]); - test([10, 13, 14, 17], 11, 17, [10, 17]); - test([10, 13, 14, 17], 11, 18, [10, 18]); - test([10, 13, 14, 17], 11, 19, [10, 19]); - test([10, 13, 14, 17], 12, 13, [10, 13, 14, 17]); - test([10, 13, 14, 17], 12, 14, [10, 17]); - test([10, 13, 14, 17], 12, 15, [10, 17]); - test([10, 13, 14, 17], 12, 16, [10, 17]); - test([10, 13, 14, 17], 12, 17, [10, 17]); - test([10, 13, 14, 17], 12, 18, [10, 18]); - test([10, 13, 14, 17], 12, 19, [10, 19]); - test([10, 13, 14, 17], 13, 14, [10, 17]); - test([10, 13, 14, 17], 13, 15, [10, 17]); - test([10, 13, 14, 17], 13, 16, [10, 17]); - test([10, 13, 14, 17], 13, 17, [10, 17]); - test([10, 13, 14, 17], 13, 18, [10, 18]); - test([10, 13, 14, 17], 13, 19, [10, 19]); - test([10, 13, 14, 17], 14, 15, [10, 13, 14, 17]); - test([10, 13, 14, 17], 14, 16, [10, 13, 14, 17]); - test([10, 13, 14, 17], 14, 17, [10, 13, 14, 17]); - test([10, 13, 14, 17], 14, 18, [10, 13, 14, 18]); - test([10, 13, 14, 17], 14, 19, [10, 13, 14, 19]); - test([10, 13, 14, 17], 15, 16, [10, 13, 14, 17]); - test([10, 13, 14, 17], 15, 17, [10, 13, 14, 17]); - test([10, 13, 14, 17], 15, 18, [10, 13, 14, 18]); - test([10, 13, 14, 17], 15, 19, [10, 13, 14, 19]); - test([10, 13, 14, 17], 16, 17, [10, 13, 14, 17]); - test([10, 13, 14, 17], 16, 18, [10, 13, 14, 18]); - test([10, 13, 14, 17], 16, 19, [10, 13, 14, 19]); - test([10, 13, 14, 17], 17, 18, [10, 13, 14, 18]); - test([10, 13, 14, 17], 17, 19, [10, 13, 14, 19]); - test([10, 13, 14, 17], 18, 19, [10, 13, 14, 17, 18, 19]); - - test([10, 13, 16, 19], 7, 14, [ 7, 14, 16, 19]); - test([10, 13, 16, 19], 7, 15, [ 7, 15, 16, 19]); - test([10, 13, 16, 19], 7, 16, [ 7, 19]); - test([10, 13, 16, 19], 8, 14, [ 8, 14, 16, 19]); - test([10, 13, 16, 19], 8, 15, [ 8, 15, 16, 19]); - test([10, 13, 16, 19], 8, 16, [ 8, 19]); - test([10, 13, 16, 19], 9, 14, [ 9, 14, 16, 19]); - test([10, 13, 16, 19], 9, 15, [ 9, 15, 16, 19]); - test([10, 13, 16, 19], 9, 16, [ 9, 19]); - test([10, 13, 16, 19], 10, 14, [10, 14, 16, 19]); - test([10, 13, 16, 19], 10, 15, [10, 15, 16, 19]); - test([10, 13, 16, 19], 10, 16, [10, 19]); - test([10, 13, 16, 19], 11, 14, [10, 14, 16, 19]); - test([10, 13, 16, 19], 11, 15, [10, 15, 16, 19]); - test([10, 13, 16, 19], 11, 16, [10, 19]); - test([10, 13, 16, 19], 12, 14, [10, 14, 16, 19]); - test([10, 13, 16, 19], 12, 15, [10, 15, 16, 19]); - test([10, 13, 16, 19], 12, 16, [10, 19]); - test([10, 13, 16, 19], 13, 14, [10, 14, 16, 19]); - test([10, 13, 16, 19], 13, 15, [10, 15, 16, 19]); - test([10, 13, 16, 19], 13, 16, [10, 19]); - test([10, 13, 16, 19], 14, 15, [10, 13, 14, 15, 16, 19]); - test([10, 13, 16, 19], 14, 16, [10, 13, 14, 19]); - test([10, 13, 16, 19], 15, 16, [10, 13, 15, 19]); - - run_next_test(); -}); - -add_test(function test_ril_consts_cellbroadcast_misc() { - // Must be 16 for indexing. - equal(CB_DCS_LANG_GROUP_1.length, 16); - equal(CB_DCS_LANG_GROUP_2.length, 16); - - // Array length must be even. - equal(CB_NON_MMI_SETTABLE_RANGES.length & 0x01, 0); - for (let i = 0; i < CB_NON_MMI_SETTABLE_RANGES.length;) { - let from = CB_NON_MMI_SETTABLE_RANGES[i++]; - let to = CB_NON_MMI_SETTABLE_RANGES[i++]; - equal(from < to, true); - } - - run_next_test(); -}); - -add_test(function test_ril_worker_checkCellBroadcastMMISettable() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - - function test(from, to, expected) { - equal(expected, ril._checkCellBroadcastMMISettable(from, to)); - } - - test(-2, -1, false); - test(-1, 0, false); - test(0, 1, true); - test(1, 1, false); - test(2, 1, false); - test(65536, 65537, false); - - // We have both [4096, 4224), [4224, 4352), so it's actually [4096, 4352), - // and [61440, 65536), [65535, 65536), so it's actually [61440, 65536). - for (let i = 0; i < CB_NON_MMI_SETTABLE_RANGES.length;) { - let from = CB_NON_MMI_SETTABLE_RANGES[i++]; - let to = CB_NON_MMI_SETTABLE_RANGES[i++]; - if ((from != 4224) && (from != 65535)) { - test(from - 1, from, true); - } - test(from - 1, from + 1, false); - test(from - 1, to, false); - test(from - 1, to + 1, false); - test(from, from + 1, false); - test(from, to, false); - test(from, to + 1, false); - if ((from + 1) < to) { - test(from + 1, to, false); - test(from + 1, to + 1, false); - } - if ((to != 4224) && (to < 65535)) { - test(to, to + 1, true); - test(to + 1, to + 2, true); - } - } - - run_next_test(); -}); - -add_test(function test_ril_worker_CellBroadcastDisabled() { - let count = 0; - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - if (message.rilMessageType == "cellbroadcast-received") { - ok(true, "cellbroadcast-received: " + JSON.stringify(message)); - count++; - } - } - }); - - function buildPdu(aMessageId) { - return "C002" + aMessageId + "011154741914AFA7C76B9058" + - "FEBEBB41E6371EA4AEB7E173D0DB5E96" + - "83E8E832881DD6E741E4F7B9D168341A" + - "8D46A3D168341A8D46A3D168341A8D46" + - "A3D168341A8D46A3D168341A8D46A3D1" + - "68341A8D46A3D100"; - } - - worker.ContextPool._contexts[0].RIL.cellBroadcastDisabled = true; - - let networkAlertIds = [ - "1100", "1107", // ETWS - "1112", "112F", // CMAS - "1130", "18FF", // PWS - ]; - networkAlertIds.forEach(aMessageId => { - worker.onRILMessage( - 0, - newIncomingParcel( - -1, - RESPONSE_TYPE_UNSOLICITED, - UNSOLICITED_RESPONSE_NEW_BROADCAST_SMS, - hexStringToParcelByteArrayData(buildPdu(aMessageId)))); - }); - equal(count, networkAlertIds.length, "Alerts shall not be ignored."); - - count = 0; - let normalMsgIds = [ "0000", "03E7", "1108", "1901" ]; - normalMsgIds.forEach(aMessageId => { - worker.onRILMessage( - 0, - newIncomingParcel( - -1, - RESPONSE_TYPE_UNSOLICITED, - UNSOLICITED_RESPONSE_NEW_BROADCAST_SMS, - hexStringToParcelByteArrayData(buildPdu(aMessageId)))); - }); - equal(count, 0, "Normal messages shall be ignored."); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_cellbroadcast_gsm.js b/dom/system/gonk/tests/test_ril_worker_cellbroadcast_gsm.js deleted file mode 100644 index b08b64135..000000000 --- a/dom/system/gonk/tests/test_ril_worker_cellbroadcast_gsm.js +++ /dev/null @@ -1,230 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -add_test(function test_ril_worker_GsmPDUHelper_readCbDataCodingScheme() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - - let context = worker.ContextPool._contexts[0]; - function test_dcs(dcs, encoding, language, hasLanguageIndicator, messageClass) { - context.Buf.readUint8 = function() { - return dcs; - }; - - let msg = {}; - context.GsmPDUHelper.readCbDataCodingScheme(msg); - - equal(msg.dcs, dcs); - equal(msg.encoding, encoding); - equal(msg.language, language); - equal(msg.hasLanguageIndicator, hasLanguageIndicator); - equal(msg.messageClass, messageClass); - } - - function test_dcs_throws(dcs) { - context.Buf.readUint8 = function() { - return dcs; - }; - - throws(function() { - context.GsmPDUHelper.readCbDataCodingScheme({}); - }, "Unsupported CBS data coding scheme: " + dcs); - } - - // Group 0000 - for (let i = 0; i < 16; i++) { - test_dcs(i, PDU_DCS_MSG_CODING_7BITS_ALPHABET, CB_DCS_LANG_GROUP_1[i], - false, GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - } - - // Group 0001 - // 0000 GSM 7 bit default alphabet; message preceded by language indication. - test_dcs(0x10, PDU_DCS_MSG_CODING_7BITS_ALPHABET, null, true, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - // 0001 UCS2; message preceded by language indication. - test_dcs(0x11, PDU_DCS_MSG_CODING_16BITS_ALPHABET, null, true, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - - // Group 0010 - // 0000..0100 - for (let i = 0; i < 5; i++) { - test_dcs(0x20 + i, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - CB_DCS_LANG_GROUP_2[i], false, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - } - // 0101..1111 Reserved - for (let i = 5; i < 16; i++) { - test_dcs(0x20 + i, PDU_DCS_MSG_CODING_7BITS_ALPHABET, null, false, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - } - - // Group 0100, 0101, 1001 - for (let group of [0x40, 0x50, 0x90]) { - for (let i = 0; i < 16; i++) { - let encoding = i & 0x0C; - if (encoding == 0x0C) { - encoding = PDU_DCS_MSG_CODING_7BITS_ALPHABET; - } - let messageClass = GECKO_SMS_MESSAGE_CLASSES[i & PDU_DCS_MSG_CLASS_BITS]; - test_dcs(group + i, encoding, null, false, messageClass); - } - } - - // Group 1111 - for (let i = 0; i < 16; i ++) { - let encoding = i & 0x04 ? PDU_DCS_MSG_CODING_8BITS_ALPHABET - : PDU_DCS_MSG_CODING_7BITS_ALPHABET; - let messageClass; - switch(i & PDU_DCS_MSG_CLASS_BITS) { - case 0x01: messageClass = PDU_DCS_MSG_CLASS_USER_1; break; - case 0x02: messageClass = PDU_DCS_MSG_CLASS_USER_2; break; - case 0x03: messageClass = PDU_DCS_MSG_CLASS_3; break; - default: messageClass = PDU_DCS_MSG_CLASS_NORMAL; break; - } - test_dcs(0xF0 + i, encoding, null, false, - GECKO_SMS_MESSAGE_CLASSES[messageClass]); - } - - // Group 0011, 1000, 1010, 1011, 1100 - // 0000..1111 Reserved - for (let group of [0x30, 0x80, 0xA0, 0xB0, 0xC0]) { - for (let i = 0; i < 16; i++) { - test_dcs(group + i, PDU_DCS_MSG_CODING_7BITS_ALPHABET, null, false, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - } - } - - // Group 0110, 0111, 1101, 1110 - // TODO: unsupported - for (let group of [0x60, 0x70, 0xD0, 0xE0]) { - for (let i = 0; i < 16; i++) { - test_dcs_throws(group + i); - } - } - - run_next_test(); -}); - -add_test(function test_ril_worker_GsmPDUHelper_readGsmCbData() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - - let context = worker.ContextPool._contexts[0]; - function test_data(options, expected) { - let readIndex = 0; - context.Buf.readUint8 = function() { - return options[3][readIndex++]; - }; - context.Buf.readUint8Array = function(length) { - let array = new Uint8Array(length); - for (let i = 0; i < length; i++) { - array[i] = this.readUint8(); - } - return array; - }; - - let msg = { - encoding: options[0], - language: options[1], - hasLanguageIndicator: options[2] - }; - context.GsmPDUHelper.readGsmCbData(msg, options[3].length); - - equal(msg.body, expected[0]); - equal(msg.data == null, expected[1] == null); - if (expected[1] != null) { - equal(msg.data.length, expected[1].length); - for (let i = 0; i < expected[1].length; i++) { - equal(msg.data[i], expected[1][i]); - } - } - equal(msg.language, expected[2]); - } - - // We're testing Cell Broadcast message body with all zeros octet stream. As - // shown in 3GPP TS 23.038, septet 0x00 will be decoded as '@' when both - // langTableIndex and langShiftTableIndex equal to - // PDU_DCS_MSG_CODING_7BITS_ALPHABET. - - // PDU_DCS_MSG_CODING_7BITS_ALPHABET - test_data([PDU_DCS_MSG_CODING_7BITS_ALPHABET, null, false, - [0]], - ["@", null, null]); - test_data([PDU_DCS_MSG_CODING_7BITS_ALPHABET, null, true, - [0, 0, 0, 0]], - ["@", null, "@@"]); - test_data([PDU_DCS_MSG_CODING_7BITS_ALPHABET, "@@", false, - [0]], - ["@", null, "@@"]); - - // PDU_DCS_MSG_CODING_8BITS_ALPHABET - test_data([PDU_DCS_MSG_CODING_8BITS_ALPHABET, null, false, - [0]], - [null, [0], null]); - - // PDU_DCS_MSG_CODING_16BITS_ALPHABET - test_data([PDU_DCS_MSG_CODING_16BITS_ALPHABET, null, false, - [0x00, 0x40]], - ["@", null, null]); - test_data([PDU_DCS_MSG_CODING_16BITS_ALPHABET, null, true, - [0x00, 0x00, 0x00, 0x40]], - ["@", null, "@@"]); - test_data([PDU_DCS_MSG_CODING_16BITS_ALPHABET, "@@", false, - [0x00, 0x40]], - ["@", null, "@@"]); - - run_next_test(); -}); - -add_test(function test_ril_worker_Sim_Download_Message() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - ok(message.rilMessageType !== "cellbroadcast-received", - "Data-Download message shall be ignored."); - } - }); - - function buildPdu(aMessageId) { - return "C002" + aMessageId + "011154741914AFA7C76B9058" + - "FEBEBB41E6371EA4AEB7E173D0DB5E96" + - "83E8E832881DD6E741E4F7B9D168341A" + - "8D46A3D168341A8D46A3D168341A8D46" + - "A3D168341A8D46A3D168341A8D46A3D1" + - "68341A8D46A3D100"; - } - - ["1000", "107F", "1080", "10FF"].forEach(aMessageId => { - worker.onRILMessage( - 0, - newIncomingParcel( - -1, - RESPONSE_TYPE_UNSOLICITED, - UNSOLICITED_RESPONSE_NEW_BROADCAST_SMS, - hexStringToParcelByteArrayData(buildPdu(aMessageId)))); - }); - - ok(true, "All Data-Download Messages are ingored."); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_cellbroadcast_umts.js b/dom/system/gonk/tests/test_ril_worker_cellbroadcast_umts.js deleted file mode 100644 index 0380c4122..000000000 --- a/dom/system/gonk/tests/test_ril_worker_cellbroadcast_umts.js +++ /dev/null @@ -1,105 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -function buildHexStr(aNum, aNumSemiOctets) { - let str = aNum.toString(16); - while (str.length < aNumSemiOctets) { - str = "0" + str; - } - return str; -} - -/** - * Verify GsmPDUHelper#readUmtsCbMessage with numOfPages from 1 to 15. - */ -add_test(function test_GsmPDUHelper_readUmtsCbMessage_MultiParts() { - let CB_UMTS_MESSAGE_PAGE_SIZE = 82; - let CB_MAX_CONTENT_PER_PAGE_7BIT = 93; - let workerHelper = newInterceptWorker(), - worker = workerHelper.worker, - context = worker.ContextPool._contexts[0], - GsmPDUHelper = context.GsmPDUHelper; - - function test_MultiParts(aNumOfPages) { - let pdu = buildHexStr(CB_UMTS_MESSAGE_TYPE_CBS, 2) // msg_type - + buildHexStr(0, 4) // skip msg_id - + buildHexStr(0, 4) // skip SN - + buildHexStr(0, 2) // skip dcs - + buildHexStr(aNumOfPages, 2); // set num_of_pages - for (let i = 1; i <= aNumOfPages; i++) { - pdu = pdu + buildHexStr(0, CB_UMTS_MESSAGE_PAGE_SIZE * 2) - + buildHexStr(CB_UMTS_MESSAGE_PAGE_SIZE, 2); // msg_info_length - } - - worker.onRILMessage(0, newIncomingParcel(-1, - RESPONSE_TYPE_UNSOLICITED, - UNSOLICITED_RESPONSE_NEW_BROADCAST_SMS, - hexStringToParcelByteArrayData(pdu))); - - let postedMessage = workerHelper.postedMessage; - equal("cellbroadcast-received", postedMessage.rilMessageType); - equal(postedMessage.fullBody.length, - aNumOfPages * CB_MAX_CONTENT_PER_PAGE_7BIT); - } - - [1, 5, 15].forEach(function(i) { - test_MultiParts(i); - }); - - run_next_test(); -}); - -/** - * Verify GsmPDUHelper#readUmtsCbMessage with 8bit encoded. - */ -add_test(function test_GsmPDUHelper_readUmtsCbMessage_Binary() { - let CB_UMTS_MESSAGE_PAGE_SIZE = 82; - let CB_MAX_CONTENT_PER_PAGE_7BIT = 93; - let TEXT_BINARY = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - + "FFFF"; - let workerHelper = newInterceptWorker(), - worker = workerHelper.worker, - context = worker.ContextPool._contexts[0], - GsmPDUHelper = context.GsmPDUHelper; - - function test_MultiPartsBinary(aNumOfPages) { - let pdu = buildHexStr(CB_UMTS_MESSAGE_TYPE_CBS, 2) // msg_type - + buildHexStr(0, 4) // skip msg_id - + buildHexStr(0, 4) // skip SN - + buildHexStr(68, 2) // set DCS to 8bit data - + buildHexStr(aNumOfPages, 2); // set num_of_pages - for (let i = 1; i <= aNumOfPages; i++) { - pdu = pdu + TEXT_BINARY - + buildHexStr(CB_UMTS_MESSAGE_PAGE_SIZE, 2); // msg_info_length - } - - worker.onRILMessage(0, newIncomingParcel(-1, - RESPONSE_TYPE_UNSOLICITED, - UNSOLICITED_RESPONSE_NEW_BROADCAST_SMS, - hexStringToParcelByteArrayData(pdu))); - - let postedMessage = workerHelper.postedMessage; - equal("cellbroadcast-received", postedMessage.rilMessageType); - equal(postedMessage.fullData.length, - aNumOfPages * CB_UMTS_MESSAGE_PAGE_SIZE); - for (let i = 0; i < postedMessage.fullData.length; i++) { - equal(postedMessage.fullData[i], 255); - } - } - - [1, 5, 15].forEach(function(i) { - test_MultiPartsBinary(i); - }); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_cf.js b/dom/system/gonk/tests/test_ril_worker_cf.js deleted file mode 100644 index b8db716b7..000000000 --- a/dom/system/gonk/tests/test_ril_worker_cf.js +++ /dev/null @@ -1,126 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -function toaFromString(number) { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - let context = worker.ContextPool._contexts[0]; - return context.RIL._toaFromString(number); -} - -add_test(function test_toaFromString_empty() { - let retval = toaFromString(""); - - equal(retval, TOA_UNKNOWN); - - run_next_test(); -}); - -add_test(function test_toaFromString_undefined() { - let retval = toaFromString(); - - equal(retval, TOA_UNKNOWN); - - run_next_test(); -}); - -add_test(function test_toaFromString_unknown() { - let retval = toaFromString("666222333"); - - equal(retval, TOA_UNKNOWN); - - run_next_test(); -}); - -add_test(function test_toaFromString_international() { - let retval = toaFromString("+34666222333"); - - equal(retval, TOA_INTERNATIONAL); - - run_next_test(); -}); - -add_test(function test_setCallForward_unconditional() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.RIL.setCallForward = function fakeSetCallForward(options) { - context.RIL[REQUEST_SET_CALL_FORWARD](0, {}); - }; - - context.RIL.setCallForward({ - action: CALL_FORWARD_ACTION_REGISTRATION, - reason: CALL_FORWARD_REASON_UNCONDITIONAL, - serviceClass: ICC_SERVICE_CLASS_VOICE, - number: "666222333", - timeSeconds: 10 - }); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, undefined); - - run_next_test(); -}); - -add_test(function test_queryCallForwardStatus_unconditional() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.RIL.setCallForward = function fakeSetCallForward(options) { - context.RIL[REQUEST_SET_CALL_FORWARD](0, {}); - }; - - context.Buf.readInt32 = function fakeReadUint32() { - return context.Buf.int32Array.pop(); - }; - - context.Buf.readString = function fakeReadString() { - return "+34666222333"; - }; - - context.RIL.queryCallForwardStatus = function fakeQueryCallForward(options) { - context.Buf.int32Array = [ - 0, // rules.timeSeconds - 145, // rules.toa - 49, // rules.serviceClass - CALL_FORWARD_REASON_UNCONDITIONAL, // rules.reason - 1, // rules.active - 1 // rulesLength - ]; - context.RIL[REQUEST_QUERY_CALL_FORWARD_STATUS](1, {}); - }; - - context.RIL.queryCallForwardStatus({ - action: CALL_FORWARD_ACTION_QUERY_STATUS, - reason: CALL_FORWARD_REASON_UNCONDITIONAL, - serviceClass: ICC_SERVICE_CLASS_VOICE, - number: "666222333", - timeSeconds: 10 - }); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, undefined); - ok(Array.isArray(postedMessage.rules)); - do_print(postedMessage.rules.length); - equal(postedMessage.rules.length, 1); - ok(postedMessage.rules[0].active); - equal(postedMessage.rules[0].reason, CALL_FORWARD_REASON_UNCONDITIONAL); - equal(postedMessage.rules[0].number, "+34666222333"); - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_clip.js b/dom/system/gonk/tests/test_ril_worker_clip.js deleted file mode 100644 index d1ce5f617..000000000 --- a/dom/system/gonk/tests/test_ril_worker_clip.js +++ /dev/null @@ -1,59 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -add_test(function test_queryCLIP_provisioned() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.Buf.readInt32 = function fakeReadUint32() { - return context.Buf.int32Array.pop(); - }; - - context.RIL.queryCLIP = function fakeQueryCLIP(options) { - context.Buf.int32Array = [ - 1, // CLIP provisioned. - 1 // Length. - ]; - context.RIL[REQUEST_QUERY_CLIP](1, {}); - }; - - context.RIL.queryCLIP({}); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, undefined); - equal(postedMessage.provisioned, 1); - run_next_test(); -}); - -add_test(function test_getCLIP_error_generic_failure_invalid_length() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.Buf.readInt32 = function fakeReadUint32() { - return context.Buf.int32Array.pop(); - }; - - context.RIL.queryCLIP = function fakeQueryCLIP(options) { - context.Buf.int32Array = [ - 1, // CLIP provisioned. - 0 // Length. - ]; - context.RIL[REQUEST_QUERY_CLIP](1, {}); - }; - - context.RIL.queryCLIP({}); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, GECKO_ERROR_GENERIC_FAILURE); - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_clir.js b/dom/system/gonk/tests/test_ril_worker_clir.js deleted file mode 100644 index 5882a3c4c..000000000 --- a/dom/system/gonk/tests/test_ril_worker_clir.js +++ /dev/null @@ -1,122 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -// Calling line identification restriction constants. - -// Uses subscription default value. -const CLIR_DEFAULT = 0; -// Restricts CLI presentation. -const CLIR_INVOCATION = 1; -// Allows CLI presentation. -const CLIR_SUPPRESSION = 2; - -function run_test() { - run_next_test(); -} - -add_test(function test_setCLIR_success() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.RIL.setCLIR = function fakeSetCLIR(options) { - context.RIL[REQUEST_SET_CLIR](0, { - rilMessageType: "setCLIR" - }); - }; - - context.RIL.setCLIR({ - clirMode: CLIR_DEFAULT - }); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, undefined); - - run_next_test(); -}); - -add_test(function test_setCLIR_generic_failure() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.RIL.setCLIR = function fakeSetCLIR(options) { - context.RIL[REQUEST_SET_CLIR](0, { - rilMessageType: "setCLIR", - errorMsg: GECKO_ERROR_GENERIC_FAILURE - }); - }; - - context.RIL.setCLIR({ - clirMode: CLIR_DEFAULT - }); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, GECKO_ERROR_GENERIC_FAILURE); - - run_next_test(); -}); - -add_test(function test_getCLIR_n0_m1() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.Buf.readInt32 = function fakeReadUint32() { - return context.Buf.int32Array.pop(); - }; - - context.RIL.getCLIR = function fakeGetCLIR(options) { - context.Buf.int32Array = [ - 1, // Presentation indicator is used according to the subscription - // of the CLIR service. - 0, // CLIR provisioned in permanent mode. - 2 // Length. - ]; - context.RIL[REQUEST_GET_CLIR](1, { - rilMessageType: "setCLIR" - }); - }; - - context.RIL.getCLIR({}); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, undefined); - equal(postedMessage.n, 0); - equal(postedMessage.m, 1); - run_next_test(); -}); - -add_test(function test_getCLIR_error_generic_failure_invalid_length() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.Buf.readInt32 = function fakeReadUint32() { - return context.Buf.int32Array.pop(); - }; - - context.RIL.getCLIR = function fakeGetCLIR(options) { - context.Buf.int32Array = [ - 1, // Presentation indicator is used according to the subscription - // of the CLIR service. - 0, // CLIR provisioned in permanent mode. - 0 // Length (invalid one). - ]; - context.RIL[REQUEST_GET_CLIR](1, { - rilMessageType: "setCLIR" - }); - }; - - context.RIL.getCLIR({}); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, GECKO_ERROR_GENERIC_FAILURE); - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_cw.js b/dom/system/gonk/tests/test_ril_worker_cw.js deleted file mode 100644 index efa8b5c21..000000000 --- a/dom/system/gonk/tests/test_ril_worker_cw.js +++ /dev/null @@ -1,104 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -add_test(function test_setCallWaiting_success() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.RIL.setCallWaiting = function fakeSetCallWaiting(options) { - context.RIL[REQUEST_SET_CALL_WAITING](0, {}); - }; - - context.RIL.setCallWaiting({ - enabled: true - }); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, undefined); - - run_next_test(); -}); - -add_test(function test_setCallWaiting_generic_failure() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.RIL.setCallWaiting = function fakeSetCallWaiting(options) { - context.RIL[REQUEST_SET_CALL_WAITING](0, { - errorMsg: GECKO_ERROR_GENERIC_FAILURE - }); - }; - - context.RIL.setCallWaiting({ - enabled: true - }); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, GECKO_ERROR_GENERIC_FAILURE); - - run_next_test(); -}); - -add_test(function test_queryCallWaiting_success_enabled_true() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.Buf.readInt32 = function fakeReadUint32() { - return context.Buf.int32Array.pop(); - }; - - context.RIL.queryCallWaiting = function fakeQueryCallWaiting(options) { - context.Buf.int32Array = [ - 1, // serviceClass - 1, // enabled - 2 // length - ]; - context.RIL[REQUEST_QUERY_CALL_WAITING](1, {}); - }; - - context.RIL.queryCallWaiting({}); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, undefined); - equal(postedMessage.serviceClass, 1); - run_next_test(); -}); - -add_test(function test_queryCallWaiting_success_enabled_false() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.Buf.readInt32 = function fakeReadUint32() { - return context.Buf.int32Array.pop(); - }; - - context.RIL.queryCallWaiting = function fakeQueryCallWaiting(options) { - context.Buf.int32Array = [ - 1, // serviceClass - 0, // enabled - 2 // length - ]; - context.RIL[REQUEST_QUERY_CALL_WAITING](1, {}); - }; - - context.RIL.queryCallWaiting({}); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, undefined); - equal(postedMessage.serviceClass, ICC_SERVICE_CLASS_NONE); - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_ecm.js b/dom/system/gonk/tests/test_ril_worker_ecm.js deleted file mode 100644 index d10cba9ec..000000000 --- a/dom/system/gonk/tests/test_ril_worker_ecm.js +++ /dev/null @@ -1,168 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -var timeoutCallback = null; -var timeoutDelayMs = 0; -const TIMER_ID = 1234; -const TIMEOUT_VALUE = 300000; // 5 mins. - -// No window in xpcshell-test. Create our own timer mechanism. - -function setTimeout(callback, timeoutMs) { - timeoutCallback = callback; - timeoutDelayMs = timeoutMs; - equal(timeoutMs, TIMEOUT_VALUE); - return TIMER_ID; -} - -function clearTimeout(timeoutId) { - equal(timeoutId, TIMER_ID); - timeoutCallback = null; -} - -function fireTimeout() { - notEqual(timeoutCallback, null); - if (timeoutCallback) { - timeoutCallback(); - timeoutCallback = null; - } -} - -add_test(function test_enter_emergencyCbMode() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - // Do it twice. Should always send the event. - for (let i = 0; i < 2; ++i) { - context.RIL[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE](); - let postedMessage = workerHelper.postedMessage; - - // Should store the mode. - equal(context.RIL._isInEmergencyCbMode, true); - - // Should notify change. - equal(postedMessage.rilMessageType, "emergencyCbModeChange"); - equal(postedMessage.active, true); - equal(postedMessage.timeoutMs, TIMEOUT_VALUE); - - // Should start timer. - equal(context.RIL._exitEmergencyCbModeTimeoutID, TIMER_ID); - } - - run_next_test(); -}); - -add_test(function test_exit_emergencyCbMode() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.RIL[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE](); - context.RIL[UNSOLICITED_EXIT_EMERGENCY_CALLBACK_MODE](); - let postedMessage = workerHelper.postedMessage; - - // Should store the mode. - equal(context.RIL._isInEmergencyCbMode, false); - - // Should notify change. - equal(postedMessage.rilMessageType, "emergencyCbModeChange"); - equal(postedMessage.active, false); - - // Should clear timer. - equal(context.RIL._exitEmergencyCbModeTimeoutID, null); - - run_next_test(); -}); - -add_test(function test_request_exit_emergencyCbMode_when_timeout() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.RIL[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE](); - equal(context.RIL._isInEmergencyCbMode, true); - equal(context.RIL._exitEmergencyCbModeTimeoutID, TIMER_ID); - - let parcelTypes = []; - context.Buf.newParcel = function(type, options) { - parcelTypes.push(type); - }; - - // Timeout. - fireTimeout(); - - // Should clear timeout event. - equal(context.RIL._exitEmergencyCbModeTimeoutID, null); - - // Check indeed sent out REQUEST_EXIT_EMERGENCY_CALLBACK_MODE. - notEqual(parcelTypes.indexOf(REQUEST_EXIT_EMERGENCY_CALLBACK_MODE), -1); - - run_next_test(); -}); - -add_test(function test_request_exit_emergencyCbMode_when_dial() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.RIL[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE](); - equal(context.RIL._isInEmergencyCbMode, true); - equal(context.RIL._exitEmergencyCbModeTimeoutID, TIMER_ID); - - let parcelTypes = []; - context.Buf.newParcel = function(type, options) { - parcelTypes.push(type); - }; - - // Dial non-emergency call. - context.RIL.dial({number: "0912345678", - isEmergency: false, - isDialEmergency: false}); - - // Should clear timeout event. - equal(context.RIL._exitEmergencyCbModeTimeoutID, null); - - // Check indeed sent out REQUEST_EXIT_EMERGENCY_CALLBACK_MODE. - notEqual(parcelTypes.indexOf(REQUEST_EXIT_EMERGENCY_CALLBACK_MODE), -1); - - run_next_test(); -}); - -add_test(function test_request_exit_emergencyCbMode_explicitly() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.RIL[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE](); - equal(context.RIL._isInEmergencyCbMode, true); - equal(context.RIL._exitEmergencyCbModeTimeoutID, TIMER_ID); - - let parcelTypes = []; - context.Buf.newParcel = function(type, options) { - parcelTypes.push(type); - }; - - context.RIL.handleChromeMessage({rilMessageType: "exitEmergencyCbMode"}); - context.RIL[REQUEST_EXIT_EMERGENCY_CALLBACK_MODE](1, { - rilMessageType: "exitEmergencyCbMode" - }); - let postedMessage = workerHelper.postedMessage; - - // Should clear timeout event. - equal(context.RIL._exitEmergencyCbModeTimeoutID, null); - - // Check indeed sent out REQUEST_EXIT_EMERGENCY_CALLBACK_MODE. - notEqual(parcelTypes.indexOf(REQUEST_EXIT_EMERGENCY_CALLBACK_MODE), -1); - - // Send back the response. - equal(postedMessage.rilMessageType, "exitEmergencyCbMode"); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_icc_BerTlvHelper.js b/dom/system/gonk/tests/test_ril_worker_icc_BerTlvHelper.js deleted file mode 100644 index 89fcd874d..000000000 --- a/dom/system/gonk/tests/test_ril_worker_icc_BerTlvHelper.js +++ /dev/null @@ -1,87 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -// Test ICC_COMMAND_GET_RESPONSE with FCP template format. -/** - * Verify transparent structure with FCP template format. - */ -add_test(function test_fcp_template_for_transparent_structure() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let berHelper = context.BerTlvHelper; - - let tag_test = [ - 0x62, - 0x22, - 0x82, 0x02, 0x41, 0x21, - 0x83, 0x02, 0x2F, 0xE2, - 0xA5, 0x09, 0xC1, 0x04, 0x40, 0x0F, 0xF5, 0x55, 0x92, 0x01, 0x00, - 0x8A, 0x01, 0x05, - 0x8B, 0x03, 0x2F, 0x06, 0x0B, - 0x80, 0x02, 0x00, 0x0A, - 0x88, 0x01, 0x10]; - - for (let i = 0; i < tag_test.length; i++) { - pduHelper.writeHexOctet(tag_test[i]); - } - - let berTlv = berHelper.decode(tag_test.length); - let iter = berTlv.value.values(); - let tlv = berHelper.searchForNextTag(BER_FCP_FILE_DESCRIPTOR_TAG, iter); - equal(tlv.value.fileStructure, UICC_EF_STRUCTURE[EF_STRUCTURE_TRANSPARENT]); - - tlv = berHelper.searchForNextTag(BER_FCP_FILE_IDENTIFIER_TAG, iter); - equal(tlv.value.fileId, 0x2FE2); - - tlv = berHelper.searchForNextTag(BER_FCP_FILE_SIZE_DATA_TAG, iter); - equal(tlv.value.fileSizeData, 0x0A); - - run_next_test(); -}); - -/** - * Verify linear fixed structure with FCP template format. - */ -add_test(function test_fcp_template_for_linear_fixed_structure() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let berHelper = context.BerTlvHelper; - - let tag_test = [ - 0x62, - 0x1E, - 0x82, 0x05, 0x42, 0x21, 0x00, 0x1A, 0x01, - 0x83, 0x02, 0x6F, 0x40, - 0xA5, 0x03, 0x92, 0x01, 0x00, - 0x8A, 0x01, 0x07, - 0x8B, 0x03, 0x6F, 0x06, 0x02, - 0x80, 0x02, 0x00, 0x1A, - 0x88, 0x00]; - - for (let i = 0; i < tag_test.length; i++) { - pduHelper.writeHexOctet(tag_test[i]); - } - - let berTlv = berHelper.decode(tag_test.length); - let iter = berTlv.value.values(); - let tlv = berHelper.searchForNextTag(BER_FCP_FILE_DESCRIPTOR_TAG, iter); - equal(tlv.value.fileStructure, UICC_EF_STRUCTURE[EF_STRUCTURE_LINEAR_FIXED]); - equal(tlv.value.recordLength, 0x1A); - equal(tlv.value.numOfRecords, 0x01); - - tlv = berHelper.searchForNextTag(BER_FCP_FILE_IDENTIFIER_TAG, iter); - equal(tlv.value.fileId, 0x6F40); - - tlv = berHelper.searchForNextTag(BER_FCP_FILE_SIZE_DATA_TAG, iter); - equal(tlv.value.fileSizeData, 0x1A); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_icc_CardLock.js b/dom/system/gonk/tests/test_ril_worker_icc_CardLock.js deleted file mode 100644 index dc7eb93b9..000000000 --- a/dom/system/gonk/tests/test_ril_worker_icc_CardLock.js +++ /dev/null @@ -1,282 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Verify RIL.iccGetCardLockEnabled - */ -add_test(function test_icc_get_card_lock_enabled() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let ril = context.RIL; - ril.aid = "123456789"; - - function do_test(aLock) { - const serviceClass = ICC_SERVICE_CLASS_VOICE | - ICC_SERVICE_CLASS_DATA | - ICC_SERVICE_CLASS_FAX; - - buf.sendParcel = function fakeSendParcel() { - // Request Type. - equal(this.readInt32(), REQUEST_QUERY_FACILITY_LOCK) - - // Token : we don't care. - this.readInt32(); - - // Data - let parcel = this.readStringList(); - equal(parcel.length, 4); - equal(parcel[0], GECKO_CARDLOCK_TO_FACILITY[aLock]); - equal(parcel[1], ""); - equal(parcel[2], serviceClass.toString()); - equal(parcel[3], ril.aid); - }; - - ril.iccGetCardLockEnabled({lockType: aLock}); - } - - do_test(GECKO_CARDLOCK_PIN) - do_test(GECKO_CARDLOCK_FDN) - - run_next_test(); -}); - -add_test(function test_path_id_for_spid_and_spn() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - }}); - let context = worker.ContextPool._contexts[0]; - let RIL = context.RIL; - let ICCFileHelper = context.ICCFileHelper; - - // Test SIM - RIL.appType = CARD_APPTYPE_SIM; - equal(ICCFileHelper.getEFPath(ICC_EF_SPDI), - EF_PATH_MF_SIM + EF_PATH_DF_GSM); - equal(ICCFileHelper.getEFPath(ICC_EF_SPN), - EF_PATH_MF_SIM + EF_PATH_DF_GSM); - - // Test USIM - RIL.appType = CARD_APPTYPE_USIM; - equal(ICCFileHelper.getEFPath(ICC_EF_SPDI), - EF_PATH_MF_SIM + EF_PATH_ADF_USIM); - equal(ICCFileHelper.getEFPath(ICC_EF_SPDI), - EF_PATH_MF_SIM + EF_PATH_ADF_USIM); - run_next_test(); -}); - -/** - * Verify RIL.iccSetCardLockEnabled - */ -add_test(function test_icc_set_card_lock_enabled() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let ril = context.RIL; - ril.aid = "123456789"; - - function do_test(aLock, aPassword, aEnabled) { - const serviceClass = ICC_SERVICE_CLASS_VOICE | - ICC_SERVICE_CLASS_DATA | - ICC_SERVICE_CLASS_FAX; - - buf.sendParcel = function fakeSendParcel() { - // Request Type. - equal(this.readInt32(), REQUEST_SET_FACILITY_LOCK); - - // Token : we don't care - this.readInt32(); - - // Data - let parcel = this.readStringList(); - equal(parcel.length, 5); - equal(parcel[0], GECKO_CARDLOCK_TO_FACILITY[aLock]); - equal(parcel[1], aEnabled ? "1" : "0"); - equal(parcel[2], aPassword); - equal(parcel[3], serviceClass.toString()); - equal(parcel[4], ril.aid); - }; - - ril.iccSetCardLockEnabled({ - lockType: aLock, - enabled: aEnabled, - password: aPassword}); - } - - do_test(GECKO_CARDLOCK_PIN, "1234", true); - do_test(GECKO_CARDLOCK_PIN, "1234", false); - do_test(GECKO_CARDLOCK_FDN, "4321", true); - do_test(GECKO_CARDLOCK_FDN, "4321", false); - - run_next_test(); -}); - -/** - * Verify RIL.iccChangeCardLockPassword - */ -add_test(function test_icc_change_card_lock_password() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let ril = context.RIL; - - - function do_test(aLock, aPassword, aNewPassword) { - let GECKO_CARDLOCK_TO_REQUEST = {}; - GECKO_CARDLOCK_TO_REQUEST[GECKO_CARDLOCK_PIN] = REQUEST_CHANGE_SIM_PIN; - GECKO_CARDLOCK_TO_REQUEST[GECKO_CARDLOCK_PIN2] = REQUEST_CHANGE_SIM_PIN2; - - buf.sendParcel = function fakeSendParcel() { - // Request Type. - equal(this.readInt32(), GECKO_CARDLOCK_TO_REQUEST[aLock]); - - // Token : we don't care - this.readInt32(); - - // Data - let parcel = this.readStringList(); - equal(parcel.length, 3); - equal(parcel[0], aPassword); - equal(parcel[1], aNewPassword); - equal(parcel[2], ril.aid); - }; - - ril.iccChangeCardLockPassword({ - lockType: aLock, - password: aPassword, - newPassword: aNewPassword}); - } - - do_test(GECKO_CARDLOCK_PIN, "1234", "4321"); - do_test(GECKO_CARDLOCK_PIN2, "1234", "4321"); - - run_next_test(); -}); - -/** - * Verify RIL.iccUnlockCardLock - PIN - */ -add_test(function test_icc_unlock_card_lock_pin() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - let buf = context.Buf; - ril.aid = "123456789"; - - function do_test(aLock, aPassword) { - let GECKO_CARDLOCK_TO_REQUEST = {}; - GECKO_CARDLOCK_TO_REQUEST[GECKO_CARDLOCK_PIN] = REQUEST_ENTER_SIM_PIN; - GECKO_CARDLOCK_TO_REQUEST[GECKO_CARDLOCK_PIN2] = REQUEST_ENTER_SIM_PIN2; - - buf.sendParcel = function fakeSendParcel() { - // Request Type. - equal(this.readInt32(), GECKO_CARDLOCK_TO_REQUEST[aLock]); - - // Token : we don't care - this.readInt32(); - - // Data - let parcel = this.readStringList(); - equal(parcel.length, 2); - equal(parcel[0], aPassword); - equal(parcel[1], ril.aid); - }; - - ril.iccUnlockCardLock({ - lockType: aLock, - password: aPassword - }); - } - - do_test(GECKO_CARDLOCK_PIN, "1234"); - do_test(GECKO_CARDLOCK_PIN2, "1234"); - - run_next_test(); -}); - -/** - * Verify RIL.iccUnlockCardLock - PUK - */ -add_test(function test_icc_unlock_card_lock_puk() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - let buf = context.Buf; - ril.aid = "123456789"; - - function do_test(aLock, aPassword, aNewPin) { - let GECKO_CARDLOCK_TO_REQUEST = {}; - GECKO_CARDLOCK_TO_REQUEST[GECKO_CARDLOCK_PUK] = REQUEST_ENTER_SIM_PUK; - GECKO_CARDLOCK_TO_REQUEST[GECKO_CARDLOCK_PUK2] = REQUEST_ENTER_SIM_PUK2; - - buf.sendParcel = function fakeSendParcel() { - // Request Type. - equal(this.readInt32(), GECKO_CARDLOCK_TO_REQUEST[aLock]); - - // Token : we don't care - this.readInt32(); - - // Data - let parcel = this.readStringList(); - equal(parcel.length, 3); - equal(parcel[0], aPassword); - equal(parcel[1], aNewPin); - equal(parcel[2], ril.aid); - }; - - ril.iccUnlockCardLock({ - lockType: aLock, - password: aPassword, - newPin: aNewPin - }); - } - - do_test(GECKO_CARDLOCK_PUK, "12345678", "1234"); - do_test(GECKO_CARDLOCK_PUK2, "12345678", "1234"); - - run_next_test(); -}); - -/** - * Verify RIL.iccUnlockCardLock - Depersonalization - */ -add_test(function test_icc_unlock_card_lock_depersonalization() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - let buf = context.Buf; - - function do_test(aPassword) { - buf.sendParcel = function fakeSendParcel() { - // Request Type. - equal(this.readInt32(), REQUEST_ENTER_NETWORK_DEPERSONALIZATION_CODE); - - // Token : we don't care - this.readInt32(); - - // Data - let parcel = this.readStringList(); - equal(parcel.length, 1); - equal(parcel[0], aPassword); - }; - - ril.iccUnlockCardLock({ - lockType: GECKO_CARDLOCK_NCK, - password: aPassword - }); - } - - do_test("12345678"); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_icc_CardState.js b/dom/system/gonk/tests/test_ril_worker_icc_CardState.js deleted file mode 100644 index 788df5073..000000000 --- a/dom/system/gonk/tests/test_ril_worker_icc_CardState.js +++ /dev/null @@ -1,210 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -add_test(function test_personalization_state() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - - context.ICCRecordHelper.readICCID = function fakeReadICCID() {}; - - function testPersonalization(isCdma, cardPersoState, geckoCardState) { - let iccStatus = { - cardState: CARD_STATE_PRESENT, - gsmUmtsSubscriptionAppIndex: (!isCdma) ? 0 : -1, - cdmaSubscriptionAppIndex: (isCdma) ? 0 : -1, - apps: [ - { - app_state: CARD_APPSTATE_SUBSCRIPTION_PERSO, - perso_substate: cardPersoState - }], - }; - - ril._isCdma = isCdma; - ril._processICCStatus(iccStatus); - equal(ril.cardState, geckoCardState); - } - - // Test GSM personalization state. - testPersonalization(false, CARD_PERSOSUBSTATE_SIM_NETWORK, - Ci.nsIIcc.CARD_STATE_NETWORK_LOCKED); - testPersonalization(false, CARD_PERSOSUBSTATE_SIM_NETWORK_SUBSET, - Ci.nsIIcc.CARD_STATE_NETWORK_SUBSET_LOCKED); - testPersonalization(false, CARD_PERSOSUBSTATE_SIM_CORPORATE, - Ci.nsIIcc.CARD_STATE_CORPORATE_LOCKED); - testPersonalization(false, CARD_PERSOSUBSTATE_SIM_SERVICE_PROVIDER, - Ci.nsIIcc.CARD_STATE_SERVICE_PROVIDER_LOCKED); - testPersonalization(false, CARD_PERSOSUBSTATE_SIM_SIM, - Ci.nsIIcc.CARD_STATE_SIM_LOCKED); - testPersonalization(false, CARD_PERSOSUBSTATE_SIM_NETWORK_PUK, - Ci.nsIIcc.CARD_STATE_NETWORK_PUK_REQUIRED); - testPersonalization(false, CARD_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK, - Ci.nsIIcc.CARD_STATE_NETWORK_SUBSET_PUK_REQUIRED); - testPersonalization(false, CARD_PERSOSUBSTATE_SIM_CORPORATE_PUK, - Ci.nsIIcc.CARD_STATE_CORPORATE_PUK_REQUIRED); - testPersonalization(false, CARD_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK, - Ci.nsIIcc.CARD_STATE_SERVICE_PROVIDER_PUK_REQUIRED); - testPersonalization(false, CARD_PERSOSUBSTATE_SIM_SIM_PUK, - Ci.nsIIcc.CARD_STATE_SIM_PUK_REQUIRED); - - testPersonalization(false, CARD_PERSOSUBSTATE_UNKNOWN, - Ci.nsIIcc.CARD_STATE_UNKNOWN); - testPersonalization(false, CARD_PERSOSUBSTATE_IN_PROGRESS, - Ci.nsIIcc.CARD_STATE_PERSONALIZATION_IN_PROGRESS); - testPersonalization(false, CARD_PERSOSUBSTATE_READY, - Ci.nsIIcc.CARD_STATE_PERSONALIZATION_READY); - - // Test CDMA personalization state. - testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_NETWORK1, - Ci.nsIIcc.CARD_STATE_NETWORK1_LOCKED); - testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_NETWORK2, - Ci.nsIIcc.CARD_STATE_NETWORK2_LOCKED); - testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_HRPD, - Ci.nsIIcc.CARD_STATE_HRPD_NETWORK_LOCKED); - testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_CORPORATE, - Ci.nsIIcc.CARD_STATE_RUIM_CORPORATE_LOCKED); - testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER, - Ci.nsIIcc.CARD_STATE_RUIM_SERVICE_PROVIDER_LOCKED); - testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_RUIM, - Ci.nsIIcc.CARD_STATE_RUIM_LOCKED); - testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_NETWORK1_PUK, - Ci.nsIIcc.CARD_STATE_NETWORK1_PUK_REQUIRED); - testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_NETWORK2_PUK, - Ci.nsIIcc.CARD_STATE_NETWORK2_PUK_REQUIRED); - testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_HRPD_PUK, - Ci.nsIIcc.CARD_STATE_HRPD_NETWORK_PUK_REQUIRED); - testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_CORPORATE_PUK, - Ci.nsIIcc.CARD_STATE_RUIM_CORPORATE_PUK_REQUIRED); - testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK, - Ci.nsIIcc.CARD_STATE_RUIM_SERVICE_PROVIDER_PUK_REQUIRED); - testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_RUIM_PUK, - Ci.nsIIcc.CARD_STATE_RUIM_PUK_REQUIRED); - - testPersonalization(true, CARD_PERSOSUBSTATE_UNKNOWN, - Ci.nsIIcc.CARD_STATE_UNKNOWN); - testPersonalization(true, CARD_PERSOSUBSTATE_IN_PROGRESS, - Ci.nsIIcc.CARD_STATE_PERSONALIZATION_IN_PROGRESS); - testPersonalization(true, CARD_PERSOSUBSTATE_READY, - Ci.nsIIcc.CARD_STATE_PERSONALIZATION_READY); - - run_next_test(); -}); - -/** - * Verify SIM app_state in _processICCStatus - */ -add_test(function test_card_app_state() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - - context.ICCRecordHelper.readICCID = function fakeReadICCID() {}; - - function testCardAppState(cardAppState, geckoCardState) { - let iccStatus = { - cardState: CARD_STATE_PRESENT, - gsmUmtsSubscriptionAppIndex: 0, - apps: [ - { - app_state: cardAppState - }], - }; - - ril._processICCStatus(iccStatus); - equal(ril.cardState, geckoCardState); - } - - testCardAppState(CARD_APPSTATE_ILLEGAL, - Ci.nsIIcc.CARD_STATE_ILLEGAL); - testCardAppState(CARD_APPSTATE_PIN, - Ci.nsIIcc.CARD_STATE_PIN_REQUIRED); - testCardAppState(CARD_APPSTATE_PUK, - Ci.nsIIcc.CARD_STATE_PUK_REQUIRED); - testCardAppState(CARD_APPSTATE_READY, - Ci.nsIIcc.CARD_STATE_READY); - testCardAppState(CARD_APPSTATE_UNKNOWN, - Ci.nsIIcc.CARD_STATE_UNKNOWN); - testCardAppState(CARD_APPSTATE_DETECTED, - Ci.nsIIcc.CARD_STATE_UNKNOWN); - - run_next_test(); -}); - -/** - * Verify permanent blocked for ICC. - */ -add_test(function test_icc_permanent_blocked() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - - context.ICCRecordHelper.readICCID = function fakeReadICCID() {}; - - function testPermanentBlocked(pin1_replaced, universalPINState, pin1) { - let iccStatus = { - cardState: CARD_STATE_PRESENT, - gsmUmtsSubscriptionAppIndex: 0, - universalPINState: universalPINState, - apps: [ - { - pin1_replaced: pin1_replaced, - pin1: pin1 - }] - }; - - ril._processICCStatus(iccStatus); - equal(ril.cardState, Ci.nsIIcc.CARD_STATE_PERMANENT_BLOCKED); - } - - testPermanentBlocked(1, - CARD_PINSTATE_ENABLED_PERM_BLOCKED, - CARD_PINSTATE_UNKNOWN); - testPermanentBlocked(1, - CARD_PINSTATE_ENABLED_PERM_BLOCKED, - CARD_PINSTATE_ENABLED_PERM_BLOCKED); - testPermanentBlocked(0, - CARD_PINSTATE_UNKNOWN, - CARD_PINSTATE_ENABLED_PERM_BLOCKED); - - run_next_test(); -}); - -/** - * Verify ICC without app index. - */ -add_test(function test_icc_without_app_index() { - const ICCID = "123456789"; - - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - - let iccStatus = { - cardState: CARD_STATE_PRESENT, - gsmUmtsSubscriptionAppIndex: -1, - universalPINState: CARD_PINSTATE_DISABLED, - apps: [ - { - app_state: CARD_APPSTATE_READY - }] - }; - - context.ICCRecordHelper.readICCID = function fakeReadICCID() { - ril.iccInfo.iccid = ICCID; - }; - - ril._processICCStatus(iccStatus); - - // Should read icc id event if the app index is -1. - equal(ril.iccInfo.iccid, ICCID); - // cardState is "unknown" if the app index is -1. - equal(ril.cardState, GECKO_CARDSTATE_UNKNOWN); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_icc_GsmPDUHelper.js b/dom/system/gonk/tests/test_ril_worker_icc_GsmPDUHelper.js deleted file mode 100644 index 0d074da79..000000000 --- a/dom/system/gonk/tests/test_ril_worker_icc_GsmPDUHelper.js +++ /dev/null @@ -1,79 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Verify GsmPDUHelper.writeTimestamp - */ -add_test(function test_write_timestamp() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - - // current date - let dateInput = new Date(); - let dateOutput = new Date(); - helper.writeTimestamp(dateInput); - dateOutput.setTime(helper.readTimestamp()); - - equal(dateInput.getFullYear(), dateOutput.getFullYear()); - equal(dateInput.getMonth(), dateOutput.getMonth()); - equal(dateInput.getDate(), dateOutput.getDate()); - equal(dateInput.getHours(), dateOutput.getHours()); - equal(dateInput.getMinutes(), dateOutput.getMinutes()); - equal(dateInput.getSeconds(), dateOutput.getSeconds()); - equal(dateInput.getTimezoneOffset(), dateOutput.getTimezoneOffset()); - - // 2034-01-23 12:34:56 -0800 GMT - let time = Date.UTC(2034, 1, 23, 12, 34, 56); - time = time - (8 * 60 * 60 * 1000); - dateInput.setTime(time); - helper.writeTimestamp(dateInput); - dateOutput.setTime(helper.readTimestamp()); - - equal(dateInput.getFullYear(), dateOutput.getFullYear()); - equal(dateInput.getMonth(), dateOutput.getMonth()); - equal(dateInput.getDate(), dateOutput.getDate()); - equal(dateInput.getHours(), dateOutput.getHours()); - equal(dateInput.getMinutes(), dateOutput.getMinutes()); - equal(dateInput.getSeconds(), dateOutput.getSeconds()); - equal(dateInput.getTimezoneOffset(), dateOutput.getTimezoneOffset()); - - run_next_test(); -}); - -/** - * Verify GsmPDUHelper.octectToBCD and GsmPDUHelper.BCDToOctet - */ -add_test(function test_octect_BCD() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - - // 23 - let number = 23; - let octet = helper.BCDToOctet(number); - equal(helper.octetToBCD(octet), number); - - // 56 - number = 56; - octet = helper.BCDToOctet(number); - equal(helper.octetToBCD(octet), number); - - // 0x23 - octet = 0x23; - number = helper.octetToBCD(octet); - equal(helper.BCDToOctet(number), octet); - - // 0x56 - octet = 0x56; - number = helper.octetToBCD(octet); - equal(helper.BCDToOctet(number), octet); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_icc_ICCContactHelper.js b/dom/system/gonk/tests/test_ril_worker_icc_ICCContactHelper.js deleted file mode 100644 index 29b83b76a..000000000 --- a/dom/system/gonk/tests/test_ril_worker_icc_ICCContactHelper.js +++ /dev/null @@ -1,1042 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Test error message returned in onerror for readICCContacts. - */ -add_test(function test_error_message_read_icc_contact () { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - - function do_test(options, expectedErrorMsg) { - ril.sendChromeMessage = function(message) { - equal(message.errorMsg, expectedErrorMsg); - } - ril.readICCContacts(options); - } - - // Error 1, didn't specify correct contactType. - do_test({}, CONTACT_ERR_REQUEST_NOT_SUPPORTED); - - // Error 2, specifying a non-supported contactType. - ril.appType = CARD_APPTYPE_USIM; - do_test({contactType: "foo"}, CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED); - - // Error 3, suppose we update the supported PBR fields in USIM_PBR_FIELDS, - // but forget to add implemenetations for it. - USIM_PBR_FIELDS.push("pbc"); - do_test({contactType: GECKO_CARDCONTACT_TYPE_ADN}, - CONTACT_ERR_FIELD_NOT_SUPPORTED); - - run_next_test(); -}); - -/** - * Test error message returned in onerror for updateICCContact. - */ -add_test(function test_error_message_update_icc_contact() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - - const ICCID = "123456789"; - ril.iccInfo.iccid = ICCID; - - function do_test(options, expectedErrorMsg) { - ril.sendChromeMessage = function(message) { - equal(message.errorMsg, expectedErrorMsg); - } - ril.updateICCContact(options); - } - - // Error 1, didn't specify correct contactType. - do_test({}, CONTACT_ERR_REQUEST_NOT_SUPPORTED); - - // Error 2, specifying a correct contactType, but without providing 'contact'. - do_test({contactType: GECKO_CARDCONTACT_TYPE_ADN}, - CONTACT_ERR_REQUEST_NOT_SUPPORTED); - - // Error 3, specifying a non-supported contactType. - ril.appType = CARD_APPTYPE_USIM; - do_test({contactType: GECKO_CARDCONTACT_TYPE_SDN, contact: {}}, - CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED); - - // Error 4, without supplying pin2. - do_test({contactType: GECKO_CARDCONTACT_TYPE_FDN, - contact: {contactId: ICCID + "1"}}, - GECKO_ERROR_SIM_PIN2); - - // Error 5, No free record found in EF_ADN. - let record = context.ICCRecordHelper; - record.readPBR = function(onsuccess, onerror) { - onsuccess([{adn: {fileId: 0x4f3a}}]); - }; - - let io = context.ICCIOHelper; - io.loadLinearFixedEF = function(options) { - options.totalRecords = 1; - options.p1 = 1; - options.callback(options); - }; - - do_test({contactType: GECKO_CARDCONTACT_TYPE_ADN, contact: {}}, - CONTACT_ERR_NO_FREE_RECORD_FOUND); - - // Error 6, ICC IO Error. - io.loadLinearFixedEF = function(options) { - ril[REQUEST_SIM_IO](0, { - errorMsg: GECKO_ERROR_GENERIC_FAILURE - }); - }; - do_test({contactType: GECKO_CARDCONTACT_TYPE_ADN, - contact: {contactId: ICCID + "1"}}, - GECKO_ERROR_GENERIC_FAILURE); - - // Error 7, suppose we update the supported PBR fields in USIM_PBR_FIELDS, - // but forget to add implemenetations for it. - USIM_PBR_FIELDS.push("pbc"); - do_test({contactType: GECKO_CARDCONTACT_TYPE_ADN, - contact: {contactId: ICCID + "1"}}, - CONTACT_ERR_FIELD_NOT_SUPPORTED); - - // Error 8, EF_PBR doesn't exist. - record.readPBR = function(onsuccess, onerror) { - onsuccess([]); - }; - - do_test({contactType: GECKO_CARDCONTACT_TYPE_ADN, - contact: {contactId: ICCID + "1"}}, - CONTACT_ERR_CANNOT_ACCESS_PHONEBOOK); - - run_next_test(); -}); - -/** - * Verify ICCContactHelper.readICCContacts - */ -add_test(function test_read_icc_contacts() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.ICCRecordHelper; - let contactHelper = context.ICCContactHelper; - let ril = context.RIL; - let test_data = [ - //Record 1. - { - comment: "Test read SIM adn contact", - rawData: { - simType: CARD_APPTYPE_SIM, - contactType: GECKO_CARDCONTACT_TYPE_ADN, - adnLike: [{recordId: 1, alphaId: "name", number: "111111"}], - }, - expectedContact: [{ - recordId: 1, - alphaId: "name", - number: "111111" - }], - }, - //Record 2. - { - comment: "Test read SIM fdn contact", - rawData: { - simType: CARD_APPTYPE_SIM, - contactType: GECKO_CARDCONTACT_TYPE_FDN, - adnLike: [{recordId: 1, alphaId: "name", number: "111111"}], - }, - expectedContact: [{ - recordId: 1, - alphaId: "name", - number: "111111" - }], - }, - //Record 3. - { - comment: "Test read USIM adn contact", - rawData: { - simType: CARD_APPTYPE_USIM, - contactType: GECKO_CARDCONTACT_TYPE_ADN, - pbrs: [{adn:{fileId: 0x6f3a}, email: {}, anr0: {}}], - adnLike: [{recordId: 1, alphaId: "name", number: "111111"}], - email: "hello@mail.com", - anr: "123456", - }, - expectedContact: [{ - pbrIndex: 0, - recordId: 1, - alphaId: "name", - number: "111111", - email: "hello@mail.com", - anr: ["123456"] - }], - }, - //Record 4. - { - comment: "Test read USIM adn contacts", - rawData: { - simType: CARD_APPTYPE_USIM, - contactType: GECKO_CARDCONTACT_TYPE_ADN, - pbrs: [{adn:{fileId: 0x6f3a}, email: {}, anr0: {}}, - {adn:{fileId: 0x6f3b}, email: {}, anr0: {}}], - adnLike: [{recordId: 1, alphaId: "name1", number: "111111"}, - {recordId: 2, alphaId: "name2", number: "222222"}], - email: "hello@mail.com", - anr: "123456", - }, - expectedContact: [ - { - pbrIndex: 0, - recordId: 1, - alphaId: "name1", - number: "111111", - email: "hello@mail.com", - anr: ["123456"] - }, { - pbrIndex: 0, - recordId: 2, - alphaId: "name2", - number: "222222", - email: "hello@mail.com", - anr: ["123456"] - }, { - pbrIndex: 1, - recordId: 1, - alphaId: "name1", - number: "111111", - email: "hello@mail.com", - anr: ["123456"] - }, { - pbrIndex: 1, - recordId: 2, - alphaId: "name2", - number: "222222", - email: "hello@mail.com", - anr: ["123456"] - } - ], - }, - //Record 5. - { - comment: "Test read USIM fdn contact", - rawData: { - simType: CARD_APPTYPE_USIM, - contactType: GECKO_CARDCONTACT_TYPE_FDN, - adnLike: [{recordId: 1, alphaId: "name", number: "111111"}], - }, - expectedContact: [{ - recordId: 1, - alphaId: "name", - number: "111111" - }], - }, - //Record 6. - { - comment: "Test read RUIM adn contact", - rawData: { - simType: CARD_APPTYPE_RUIM, - contactType: GECKO_CARDCONTACT_TYPE_ADN, - adnLike: [{recordId: 1, alphaId: "name", number: "111111"}], - }, - expectedContact: [{ - recordId: 1, - alphaId: "name", - number: "111111" - }], - }, - //Record 7. - { - comment: "Test read RUIM fdn contact", - rawData: { - simType: CARD_APPTYPE_RUIM, - contactType: GECKO_CARDCONTACT_TYPE_FDN, - adnLike: [{recordId: 1, alphaId: "name", number: "111111"}], - }, - expectedContact: [{ - recordId: 1, - alphaId: "name", - number: "111111" - }], - }, - //Record 8. - { - comment: "Test read RUIM adn contact with enhanced phone book", - rawData: { - simType: CARD_APPTYPE_RUIM, - contactType: GECKO_CARDCONTACT_TYPE_ADN, - pbrs: [{adn:{fileId: 0x6f3a}, email: {}, anr0: {}}], - adnLike: [{recordId: 1, alphaId: "name", number: "111111"}], - email: "hello@mail.com", - anr: "123456", - enhancedPhoneBook: true, - }, - expectedContact: [{ - pbrIndex: 0, - recordId: 1, - alphaId: "name", - number: "111111", - email: "hello@mail.com", - anr: ["123456"] - }], - }, - //Record 9. - { - comment: "Test read RUIM adn contacts with enhanced phone book", - rawData: { - simType: CARD_APPTYPE_RUIM, - contactType: GECKO_CARDCONTACT_TYPE_ADN, - pbrs: [{adn:{fileId: 0x6f3a}, email: {}, anr0: {}}, - {adn:{fileId: 0x6f3b}, email: {}, anr0: {}}], - adnLike: [{recordId: 1, alphaId: "name1", number: "111111"}, - {recordId: 2, alphaId: "name2", number: "222222"}], - email: "hello@mail.com", - anr: "123456", - enhancedPhoneBook: true, - }, - expectedContact: [ - { - pbrIndex: 0, - recordId: 1, - alphaId: "name1", - number: "111111", - email: "hello@mail.com", - anr: ["123456"] - }, { - pbrIndex: 0, - recordId: 2, - alphaId: "name2", - number: "222222", - email: "hello@mail.com", - anr: ["123456"] - }, { - pbrIndex: 1, - recordId: 1, - alphaId: "name1", - number: "111111", - email: "hello@mail.com", - anr: ["123456"] - }, { - pbrIndex: 1, - recordId: 2, - alphaId: "name2", - number: "222222", - email: "hello@mail.com", - anr: ["123456"] - } - ], - }, - ]; - - function do_test(aTestData, aExpectedContact) { - ril.appType = aTestData.simType; - ril._isCdma = (aTestData.simType === CARD_APPTYPE_RUIM); - ril.iccInfoPrivate.cst = (aTestData.enhancedPhoneBook) ? - [0x20, 0x0C, 0x0, 0x0, 0x0]: - [0x20, 0x00, 0x0, 0x0, 0x0]; - - ril.iccInfoPrivate.sst = (aTestData.simType === CARD_APPTYPE_SIM)? - [0x20, 0x0, 0x0, 0x0, 0x0]: - [0x2, 0x0, 0x0, 0x0, 0x0]; - - // Override some functions to test. - contactHelper.getContactFieldRecordId = function(pbr, contact, field, onsuccess, onerror) { - onsuccess(1); - }; - - record.readPBR = function readPBR(onsuccess, onerror) { - onsuccess(JSON.parse(JSON.stringify(aTestData.pbrs))); - }; - - record.readADNLike = function readADNLike(fileId, extFileId, onsuccess, onerror) { - onsuccess(JSON.parse(JSON.stringify(aTestData.adnLike))); - }; - - record.readEmail = function readEmail(fileId, fileType, recordNumber, onsuccess, onerror) { - onsuccess(aTestData.email); - }; - - record.readANR = function readANR(fileId, fileType, recordNumber, onsuccess, onerror) { - onsuccess(aTestData.anr); - }; - - let onsuccess = function onsuccess(contacts) { - for (let i = 0; i < contacts.length; i++) { - do_print("check contacts[" + i + "]:" + JSON.stringify(contacts[i])); - deepEqual(contacts[i], aExpectedContact[i]); - } - }; - - let onerror = function onerror(errorMsg) { - do_print("readICCContacts failed: " + errorMsg); - ok(false); - }; - - contactHelper.readICCContacts(aTestData.simType, aTestData.contactType, onsuccess, onerror); - } - - for (let i = 0; i < test_data.length; i++) { - do_print(test_data[i].comment); - do_test(test_data[i].rawData, test_data[i].expectedContact); - } - - run_next_test(); -}); - -/** - * Verify ICCContactHelper.updateICCContact with appType is CARD_APPTYPE_USIM. - */ -add_test(function test_update_icc_contact() { - const ADN_RECORD_ID = 100; - const ADN_SFI = 1; - const IAP_FILE_ID = 0x4f17; - const EMAIL_FILE_ID = 0x4f50; - const EMAIL_RECORD_ID = 20; - const ANR0_FILE_ID = 0x4f11; - const ANR0_RECORD_ID = 30; - const EXT_RECORD_ID = 0x01; - - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let recordHelper = context.ICCRecordHelper; - let contactHelper = context.ICCContactHelper; - let ril = context.RIL; - - function do_test(aSimType, aContactType, aContact, aPin2, aFileType, aHaveIapIndex, aEnhancedPhoneBook) { - ril.appType = aSimType; - ril._isCdma = (aSimType === CARD_APPTYPE_RUIM); - ril.iccInfoPrivate.cst = (aEnhancedPhoneBook) ? [0x20, 0x0C, 0x28, 0x0, 0x20] - : [0x20, 0x0, 0x28, 0x0, 0x20]; - ril.iccInfoPrivate.sst = (aSimType === CARD_APPTYPE_SIM)? - [0x20, 0x0, 0x28, 0x0, 0x20]: - [0x16, 0x0, 0x0, 0x0, 0x0]; - - recordHelper.readPBR = function(onsuccess, onerror) { - if (aFileType === ICC_USIM_TYPE1_TAG) { - onsuccess([{ - adn: {fileId: ICC_EF_ADN}, - email: {fileId: EMAIL_FILE_ID, - fileType: ICC_USIM_TYPE1_TAG}, - anr0: {fileId: ANR0_FILE_ID, - fileType: ICC_USIM_TYPE1_TAG}, - ext1: {fileId: ICC_EF_EXT1} - - }]); - } else if (aFileType === ICC_USIM_TYPE2_TAG) { - onsuccess([{ - adn: {fileId: ICC_EF_ADN, - sfi: ADN_SFI}, - iap: {fileId: IAP_FILE_ID}, - email: {fileId: EMAIL_FILE_ID, - fileType: ICC_USIM_TYPE2_TAG, - indexInIAP: 0}, - anr0: {fileId: ANR0_FILE_ID, - fileType: ICC_USIM_TYPE2_TAG, - indexInIAP: 1}, - ext1: {fileId: ICC_EF_EXT1} - }]); - } - }; - - recordHelper.updateADNLike = function(fileId, extRecordNumber, contact, pin2, onsuccess, onerror) { - if (aContactType === GECKO_CARDCONTACT_TYPE_FDN) { - equal(fileId, ICC_EF_FDN); - } else if (aContactType === GECKO_CARDCONTACT_TYPE_ADN) { - equal(fileId, ICC_EF_ADN); - } - - if (aContact.number.length > ADN_MAX_NUMBER_DIGITS) { - equal(extRecordNumber, EXT_RECORD_ID); - } else { - equal(extRecordNumber, 0xff); - } - - equal(pin2, aPin2); - equal(contact.alphaId, aContact.alphaId); - equal(contact.number, aContact.number); - onsuccess({alphaId: contact.alphaId, - number: contact.number.substring(0, ADN_MAX_NUMBER_DIGITS)}); - }; - - recordHelper.getADNLikeExtensionRecordNumber = function(fileId, recordNumber, onsuccess, onerror) { - onsuccess(EXT_RECORD_ID); - }; - - recordHelper.updateExtension = function(fileId, recordNumber, number, onsuccess, onerror) { - onsuccess(); - }; - - recordHelper.findFreeRecordId = function(fileId, onsuccess, onerror) { - onsuccess(EXT_RECORD_ID); - }; - - recordHelper.cleanEFRecord = function(fileId, recordNumber, onsuccess, onerror) { - onsuccess(); - } - - recordHelper.readIAP = function(fileId, recordNumber, onsuccess, onerror) { - equal(fileId, IAP_FILE_ID); - equal(recordNumber, ADN_RECORD_ID); - onsuccess((aHaveIapIndex) ? [EMAIL_RECORD_ID, ANR0_RECORD_ID] - : [0xff, 0xff]); - }; - - recordHelper.updateIAP = function(fileId, recordNumber, iap, onsuccess, onerror) { - equal(fileId, IAP_FILE_ID); - equal(recordNumber, ADN_RECORD_ID); - onsuccess(); - }; - - recordHelper.updateEmail = function(pbr, recordNumber, email, adnRecordId, onsuccess, onerror) { - equal(pbr.email.fileId, EMAIL_FILE_ID); - if (pbr.email.fileType === ICC_USIM_TYPE1_TAG) { - equal(recordNumber, ADN_RECORD_ID); - } else if (pbr.email.fileType === ICC_USIM_TYPE2_TAG) { - equal(recordNumber, EMAIL_RECORD_ID); - } - equal(email, aContact.email); - onsuccess(email); - }; - - recordHelper.updateANR = function(pbr, recordNumber, number, adnRecordId, onsuccess, onerror) { - equal(pbr.anr0.fileId, ANR0_FILE_ID); - if (pbr.anr0.fileType === ICC_USIM_TYPE1_TAG) { - equal(recordNumber, ADN_RECORD_ID); - } else if (pbr.anr0.fileType === ICC_USIM_TYPE2_TAG) { - equal(recordNumber, ANR0_RECORD_ID); - } - if (Array.isArray(aContact.anr)) { - equal(number, aContact.anr[0]); - } - onsuccess(number); - }; - - recordHelper.findFreeRecordId = function(fileId, onsuccess, onerror) { - let recordId = 0; - if (fileId === EMAIL_FILE_ID) { - recordId = EMAIL_RECORD_ID; - } else if (fileId === ANR0_FILE_ID) { - recordId = ANR0_RECORD_ID; - } - onsuccess(recordId); - }; - - let isSuccess = false; - let onsuccess = function onsuccess(updatedContact) { - equal(ADN_RECORD_ID, updatedContact.recordId); - equal(aContact.alphaId, updatedContact.alphaId); - equal(aContact.number.substring(0, ADN_MAX_NUMBER_DIGITS + EXT_MAX_NUMBER_DIGITS), - updatedContact.number); - if ((aSimType == CARD_APPTYPE_USIM || aSimType == CARD_APPTYPE_RUIM) && - (aFileType == ICC_USIM_TYPE1_TAG || aFileType == ICC_USIM_TYPE2_TAG)) { - if (aContact.hasOwnProperty('email')) { - equal(aContact.email, updatedContact.email); - } - - if (aContact.hasOwnProperty('anr')) { - equal(aContact.anr[0], updatedContact.anr[0]); - } - } else { - equal(updatedContact.email, null); - equal(updatedContact.anr, null); - } - - do_print("updateICCContact success"); - isSuccess = true; - }; - - let onerror = function onerror(errorMsg) { - do_print("updateICCContact failed: " + errorMsg); - }; - - contactHelper.updateICCContact(aSimType, aContactType, aContact, aPin2, onsuccess, onerror); - ok(isSuccess); - } - - let contacts = [ - { - pbrIndex: 0, - recordId: ADN_RECORD_ID, - alphaId: "test", - number: "123456", - email: "test@mail.com", - anr: ["+654321"] - }, - // a contact without email and anr. - { - pbrIndex: 0, - recordId: ADN_RECORD_ID, - alphaId: "test2", - number: "123456", - }, - // a contact with email but no anr. - { - pbrIndex: 0, - recordId: ADN_RECORD_ID, - alphaId: "test3", - number: "123456", - email: "test@mail.com" - }, - // a contact with anr but no email. - { - pbrIndex: 0, - recordId: ADN_RECORD_ID, - alphaId: "test4", - number: "123456", - anr: ["+654321"] - }, - // a contact number over 20 digits. - { - pbrIndex: 0, - recordId: ADN_RECORD_ID, - alphaId: "test4", - number: "0123456789012345678901234567890123456789", - anr: ["+654321"] - }, - // a contact number over 40 digits. - { - pbrIndex: 0, - recordId: ADN_RECORD_ID, - alphaId: "test5", - number: "01234567890123456789012345678901234567890123456789", - anr: ["+654321"] - }]; - - for (let i = 0; i < contacts.length; i++) { - let contact = contacts[i]; - // SIM - do_print("Test update SIM adn contacts"); - do_test(CARD_APPTYPE_SIM, GECKO_CARDCONTACT_TYPE_ADN, contact); - - do_print("Test update SIM fdn contacts"); - do_test(CARD_APPTYPE_SIM, GECKO_CARDCONTACT_TYPE_FDN, contact, "1234"); - - // USIM - do_print("Test update USIM adn contacts"); - do_test(CARD_APPTYPE_USIM, GECKO_CARDCONTACT_TYPE_ADN, contact, null, - ICC_USIM_TYPE1_TAG); - do_test(CARD_APPTYPE_USIM, GECKO_CARDCONTACT_TYPE_ADN, contact, null, - ICC_USIM_TYPE2_TAG, true); - do_test(CARD_APPTYPE_USIM, GECKO_CARDCONTACT_TYPE_ADN, contact, null, - ICC_USIM_TYPE2_TAG, false); - - do_print("Test update USIM fdn contacts"); - do_test(CARD_APPTYPE_USIM, GECKO_CARDCONTACT_TYPE_FDN, contact, "1234"); - - // RUIM - do_print("Test update RUIM adn contacts"); - do_test(CARD_APPTYPE_RUIM, GECKO_CARDCONTACT_TYPE_ADN, contact); - - do_print("Test update RUIM fdn contacts"); - do_test(CARD_APPTYPE_RUIM, GECKO_CARDCONTACT_TYPE_FDN, contact, "1234"); - - // RUIM with enhanced phone book - do_print("Test update RUIM adn contacts with enhanced phone book"); - do_test(CARD_APPTYPE_RUIM, GECKO_CARDCONTACT_TYPE_ADN, contact, null, - ICC_USIM_TYPE1_TAG, null,true); - do_test(CARD_APPTYPE_RUIM, GECKO_CARDCONTACT_TYPE_ADN, contact, null, - ICC_USIM_TYPE2_TAG, true, true); - do_test(CARD_APPTYPE_RUIM, GECKO_CARDCONTACT_TYPE_ADN, contact, null, - ICC_USIM_TYPE2_TAG, false, true); - - do_print("Test update RUIM fdn contacts with enhanced phone book"); - do_test(CARD_APPTYPE_RUIM, GECKO_CARDCONTACT_TYPE_FDN, contact, "1234", - null, true); - } - - run_next_test(); -}); - -/** - * Verify ICCContactHelper.updateICCContact with appType is CARD_APPTYPE_USIM and - * insufficient space to store Type 2 USIM contact fields. - */ -add_test(function test_update_icc_contact_full_email_and_anr_field() { - const ADN_RECORD_ID = 100; - const ADN_SFI = 1; - const IAP_FILE_ID = 0x4f17; - const EMAIL_FILE_ID = 0x4f50; - const EMAIL_RECORD_ID = 20; - const ANR0_FILE_ID = 0x4f11; - const ANR0_RECORD_ID = 30; - - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let recordHelper = context.ICCRecordHelper; - let contactHelper = context.ICCContactHelper; - let ril = context.RIL; - - function do_test(aSimType, aContactType, aContact, aPin2) { - ril.appType = CARD_APPTYPE_USIM; - ril.iccInfoPrivate.sst = [0x2, 0x0, 0x0, 0x0, 0x0]; - - recordHelper.readPBR = function(onsuccess, onerror) { - onsuccess([{ - adn: {fileId: ICC_EF_ADN, - sfi: ADN_SFI}, - iap: {fileId: IAP_FILE_ID}, - email: {fileId: EMAIL_FILE_ID, - fileType: ICC_USIM_TYPE2_TAG, - indexInIAP: 0}, - anr0: {fileId: ANR0_FILE_ID, - fileType: ICC_USIM_TYPE2_TAG, - indexInIAP: 1} - }]); - }; - - recordHelper.updateADNLike = function(fileId, extRecordNumber, contact, pin2, onsuccess, onerror) { - if (aContactType === GECKO_CARDCONTACT_TYPE_ADN) { - equal(fileId, ICC_EF_ADN); - } - equal(pin2, aPin2); - equal(contact.alphaId, aContact.alphaId); - equal(contact.number, aContact.number); - onsuccess({alphaId: contact.alphaId, - number: contact.number}); - }; - - recordHelper.readIAP = function(fileId, recordNumber, onsuccess, onerror) { - equal(fileId, IAP_FILE_ID); - equal(recordNumber, ADN_RECORD_ID); - onsuccess([0xff, 0xff]); - }; - - recordHelper.updateIAP = function(fileId, recordNumber, iap, onsuccess, onerror) { - equal(fileId, IAP_FILE_ID); - equal(recordNumber, ADN_RECORD_ID); - onsuccess(); - }; - - recordHelper.findFreeRecordId = function(fileId, onsuccess, onerror) { - let recordId = 0; - // emulate email and anr don't have free record. - if (fileId === EMAIL_FILE_ID || fileId === ANR0_FILE_ID) { - onerror(CONTACT_ERR_NO_FREE_RECORD_FOUND); - } else { - onsuccess(recordId); - } - }; - - let isSuccess = false; - let onsuccess = function onsuccess(updatedContact) { - equal(ADN_RECORD_ID, updatedContact.recordId); - equal(aContact.alphaId, updatedContact.alphaId); - equal(updatedContact.email, null); - equal(updatedContact.anr, null); - - do_print("updateICCContact success"); - isSuccess = true; - }; - - let onerror = function onerror(errorMsg) { - do_print("updateICCContact failed: " + errorMsg); - }; - - contactHelper.updateICCContact(aSimType, aContactType, aContact, aPin2, onsuccess, onerror); - ok(isSuccess); - } - - let contact = { - pbrIndex: 0, - recordId: ADN_RECORD_ID, - alphaId: "test", - number: "123456", - email: "test@mail.com", - anr: ["+654321"] - }; - - // USIM - do_print("Test update USIM adn contacts"); - do_test(CARD_APPTYPE_USIM, GECKO_CARDCONTACT_TYPE_ADN, contact, null); - - run_next_test(); -}); - -/** - * Verify updateICCContact with removal of anr and email with File Type 1. - */ -add_test(function test_update_icc_contact_with_remove_type1_attr() { - const ADN_RECORD_ID = 100; - const IAP_FILE_ID = 0x4f17; - const EMAIL_FILE_ID = 0x4f50; - const EMAIL_RECORD_ID = 20; - const ANR0_FILE_ID = 0x4f11; - const ANR0_RECORD_ID = 30; - - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let recordHelper = context.ICCRecordHelper; - let contactHelper = context.ICCContactHelper; - - recordHelper.updateADNLike = function(fileId, extRecordNumber, contact, pin2, onsuccess, onerror) { - onsuccess({alphaId: contact.alphaId, - number: contact.number}); - }; - - let contact = { - pbrIndex: 0, - recordId: ADN_RECORD_ID, - alphaId: "test2", - number: "123456", - }; - - recordHelper.readIAP = function(fileId, recordNumber, onsuccess, onerror) { - onsuccess([EMAIL_RECORD_ID, ANR0_RECORD_ID]); - }; - - recordHelper.updateEmail = function(pbr, recordNumber, email, adnRecordId, onsuccess, onerror) { - ok(email == null); - onsuccess(email); - }; - - recordHelper.updateANR = function(pbr, recordNumber, number, adnRecordId, onsuccess, onerror) { - ok(number == null); - onsuccess(number); - }; - - function do_test(type) { - recordHelper.readPBR = function(onsuccess, onerror) { - if (type == ICC_USIM_TYPE1_TAG) { - onsuccess([{ - adn: {fileId: ICC_EF_ADN}, - email: {fileId: EMAIL_FILE_ID, - fileType: ICC_USIM_TYPE1_TAG}, - anr0: {fileId: ANR0_FILE_ID, - fileType: ICC_USIM_TYPE1_TAG}}]); - } else { - onsuccess([{ - adn: {fileId: ICC_EF_ADN}, - iap: {fileId: IAP_FILE_ID}, - email: {fileId: EMAIL_FILE_ID, - fileType: ICC_USIM_TYPE2_TAG, - indexInIAP: 0}, - anr0: {fileId: ANR0_FILE_ID, - fileType: ICC_USIM_TYPE2_TAG, - indexInIAP: 1}}]); - } - }; - - let successCb = function(updatedContact) { - equal(updatedContact.email, null); - equal(updatedContact.anr, null); - ok(true); - }; - - let errorCb = function(errorMsg) { - do_print(errorMsg); - ok(false); - }; - - contactHelper.updateICCContact(CARD_APPTYPE_USIM, - GECKO_CARDCONTACT_TYPE_ADN, - contact, null, successCb, errorCb); - } - - do_test(ICC_USIM_TYPE1_TAG); - do_test(ICC_USIM_TYPE2_TAG); - - run_next_test(); -}); - -/** - * Verify ICCContactHelper.findFreeICCContact in SIM - */ -add_test(function test_find_free_icc_contact_sim() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let recordHelper = context.ICCRecordHelper; - let contactHelper = context.ICCContactHelper; - // Correct record Id starts with 1, so put a null element at index 0. - let records = [null]; - const MAX_RECORDS = 3; - const PBR_INDEX = 0; - - recordHelper.findFreeRecordId = function(fileId, onsuccess, onerror) { - if (records.length > MAX_RECORDS) { - onerror("No free record found."); - return; - } - - onsuccess(records.length); - }; - - let successCb = function(pbrIndex, recordId) { - equal(pbrIndex, PBR_INDEX); - records[recordId] = {}; - }; - - let errorCb = function(errorMsg) { - do_print(errorMsg); - ok(false); - }; - - for (let i = 0; i < MAX_RECORDS; i++) { - contactHelper.findFreeICCContact(CARD_APPTYPE_SIM, - GECKO_CARDCONTACT_TYPE_ADN, - successCb, errorCb); - } - // The 1st element, records[0], is null. - equal(records.length - 1, MAX_RECORDS); - - // Now the EF is full, so finding a free one should result failure. - successCb = function(pbrIndex, recordId) { - ok(false); - }; - - errorCb = function(errorMsg) { - ok(errorMsg === "No free record found."); - }; - contactHelper.findFreeICCContact(CARD_APPTYPE_SIM, GECKO_CARDCONTACT_TYPE_ADN, - successCb, errorCb); - - run_next_test(); -}); - -/** - * Verify ICCContactHelper.findFreeICCContact in USIM - */ -add_test(function test_find_free_icc_contact_usim() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let recordHelper = context.ICCRecordHelper; - let contactHelper = context.ICCContactHelper; - const ADN1_FILE_ID = 0x6f3a; - const ADN2_FILE_ID = 0x6f3b; - const MAX_RECORDS = 3; - - // The adn in the first phonebook set has already two records, which means - // only 1 free record remained. - let pbrs = [{adn: {fileId: ADN1_FILE_ID, records: [null, {}, {}]}}, - {adn: {fileId: ADN2_FILE_ID, records: [null]}}]; - - recordHelper.readPBR = function readPBR(onsuccess, onerror) { - onsuccess(pbrs); - }; - - recordHelper.findFreeRecordId = function(fileId, onsuccess, onerror) { - let pbr = (fileId == ADN1_FILE_ID ? pbrs[0]: pbrs[1]); - if (pbr.adn.records.length > MAX_RECORDS) { - onerror("No free record found."); - return; - } - - onsuccess(pbr.adn.records.length); - }; - - let successCb = function(pbrIndex, recordId) { - equal(pbrIndex, 0); - pbrs[pbrIndex].adn.records[recordId] = {}; - }; - - let errorCb = function(errorMsg) { - ok(false); - }; - - contactHelper.findFreeICCContact(CARD_APPTYPE_USIM, - GECKO_CARDCONTACT_TYPE_ADN, - successCb, errorCb); - - // Now the EF_ADN in the 1st phonebook set is full, so the next free contact - // will come from the 2nd phonebook set. - successCb = function(pbrIndex, recordId) { - equal(pbrIndex, 1); - equal(recordId, 1); - } - contactHelper.findFreeICCContact(CARD_APPTYPE_USIM, - GECKO_CARDCONTACT_TYPE_ADN, - successCb, errorCb); - - run_next_test(); -}); - -/** - * Verify ICCContactHelper.updateADNLikeWithExtension - */ -add_test(function test_update_adn_like_with_extension() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - let record = context.ICCRecordHelper; - let contactHelper = context.ICCContactHelper; - ril.appType = CARD_APPTYPE_SIM; - // Correct record Id starts from 1, so put a null element at index 0. - // ext_records contains data at index 1, and it only has 1 free record at index 2. - let notFree = 0x01; - let ext_records = [null, notFree, null]; - - function do_test(contact, extRecordNumber, expectedExtRecordNumber, expectedNumber, expectedCleanEFRecord) { - // Override some functions to test. - record.getADNLikeExtensionRecordNumber = function(fileId, recordNumber, onsuccess, onerror) { - onsuccess(extRecordNumber); - } - - record.updateADNLike = function(fileId, extRecordNumber, contact, pin2, onsuccess, onerror) { - equal(extRecordNumber, expectedExtRecordNumber); - onsuccess({alphaId: contact.alphaId, - number: contact.number.substring(0, ADN_MAX_NUMBER_DIGITS)}); - } - - record.updateExtension = function(fileId, recordNumber, number, onsuccess, onerror) { - if (recordNumber > ext_records.length) { - onerror("updateExtension failed."); - return; - } - ext_records[recordNumber] = number; - onsuccess(); - } - - record.findFreeRecordId = function(fileId, onsuccess, onerror) { - for (let i = 1; i < ext_records.length; i++) { - if (!ext_records[i]) { - onsuccess(i); - return; - } - } - - onerror("No free record found."); - } - - let isCleanEFRecord = false; - record.cleanEFRecord = function(fileId, recordNumber, onsuccess, onerror) { - if (recordNumber > ext_records.length) { - onerror("cleanEFRecord failed."); - return; - } - ext_records[recordNumber] = null; - isCleanEFRecord = true; - onsuccess(); - } - - let successCb = function successCb(updatedContact) { - equal(updatedContact.number, expectedNumber); - }; - - let errorCb = function errorCb(errorMsg) { - do_print("updateADNLikeWithExtension failed, msg = " + errorMsg); - ok(false); - }; - - contactHelper.updateADNLikeWithExtension(ICC_EF_ADN, ICC_EF_EXT1, contact, null, successCb, errorCb); - - if (expectedCleanEFRecord) { - ok(isCleanEFRecord); - } - } - - // Update extension record with previous extension record number. - do_test({recordId: 1, alphaId: "test", number: "001122334455667788991234"}, 0x01, 0x01, "001122334455667788991234"); - // Update extension record and find a free record. - do_test({recordId: 1, alphaId: "test", number: "001122334455667788995678"}, 0xff, 0x02, "001122334455667788995678"); - // Update extension record with no free extension record. - do_test({recordId: 1, alphaId: "test", number: "001122334455667788994321"}, 0xff, 0xff, "00112233445566778899"); - // Update extension record with clean previous extension record. - do_test({recordId: 1, alphaId: "test", number: "00112233445566778899"}, 0x01, 0xff, "00112233445566778899", true); - // Update extension record with no extension record and previous extension record. - do_test({recordId: 1, alphaId: "test", number: "00112233445566778899"}, 0xff, 0xff, "00112233445566778899"); - - run_next_test(); -});
\ No newline at end of file diff --git a/dom/system/gonk/tests/test_ril_worker_icc_ICCIOHelper.js b/dom/system/gonk/tests/test_ril_worker_icc_ICCIOHelper.js deleted file mode 100644 index e690b1206..000000000 --- a/dom/system/gonk/tests/test_ril_worker_icc_ICCIOHelper.js +++ /dev/null @@ -1,173 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Verify ICCIOHelper.loadLinearFixedEF with recordSize. - */ -add_test(function test_load_linear_fixed_ef() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - let io = context.ICCIOHelper; - - io.getResponse = function fakeGetResponse(options) { - // When recordSize is provided, loadLinearFixedEF should call iccIO directly. - ok(false); - run_next_test(); - }; - - ril.iccIO = function fakeIccIO(options) { - ok(true); - run_next_test(); - }; - - io.loadLinearFixedEF({recordSize: 0x20}); -}); - -/** - * Verify ICCIOHelper.loadLinearFixedEF without recordSize. - */ -add_test(function test_load_linear_fixed_ef() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - let io = context.ICCIOHelper; - - io.getResponse = function fakeGetResponse(options) { - ok(true); - run_next_test(); - }; - - ril.iccIO = function fakeIccIO(options) { - // When recordSize is not provided, loadLinearFixedEF should call getResponse. - ok(false); - run_next_test(); - }; - - io.loadLinearFixedEF({}); -}); - -/** - * Verify ICC IO Error. - */ -add_test(function test_process_icc_io_error() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - - function do_test(sw1, sw2, expectedErrorMsg) { - let called = false; - function errorCb(errorMsg) { - called = true; - equal(errorMsg, expectedErrorMsg); - } - - // Write sw1 and sw2 to buffer. - buf.writeInt32(sw1); - buf.writeInt32(sw2); - - context.RIL[REQUEST_SIM_IO](0, {fileId: 0xffff, - command: 0xff, - onerror: errorCb}); - - // onerror callback should be triggered. - ok(called); - } - - let TEST_DATA = [ - // [sw1, sw2, expectError] - [ICC_STATUS_ERROR_COMMAND_NOT_ALLOWED, 0xff, GECKO_ERROR_GENERIC_FAILURE], - [ICC_STATUS_ERROR_WRONG_PARAMETERS, 0xff, GECKO_ERROR_GENERIC_FAILURE], - ]; - - for (let i = 0; i < TEST_DATA.length; i++) { - do_test.apply(null, TEST_DATA[i]); - } - - run_next_test(); -}); - -/** - * Verify ICCIOHelper.processICCIOGetResponse for EF_TYPE_TRANSPARENT. - */ -add_test(function test_icc_io_get_response_for_transparent_structure() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let iccioHelper = context.ICCIOHelper; - let pduHelper = context.GsmPDUHelper; - - let responseArray = [ - // SIM response. - [0x00, 0x00, 0x00, 0x0A, 0x2F, 0xE2, 0x04, 0x00, 0x0A, 0xA0, 0xAA, 0x00, - 0x02, 0x00, 0x00], - // USIM response. - [0x62, 0x22, 0x82, 0x02, 0x41, 0x21, 0x83, 0x02, 0x2F, 0xE2, 0xA5, 0x09, - 0xC1, 0x04, 0x40, 0x0F, 0xF5, 0x55, 0x92, 0x01, 0x00, 0x8A, 0x01, 0x05, - 0x8B, 0x03, 0x2F, 0x06, 0x0B, 0x80, 0x02, 0x00, 0x0A, 0x88, 0x01, 0x10] - ]; - - for (let i = 0; i < responseArray.length; i++) { - let strLen = responseArray[i].length * 2; - buf.writeInt32(strLen); - for (let j = 0; j < responseArray[i].length; j++) { - pduHelper.writeHexOctet(responseArray[i][j]); - } - buf.writeStringDelimiter(strLen); - - let options = {fileId: ICC_EF_ICCID, - structure: EF_STRUCTURE_TRANSPARENT}; - iccioHelper.processICCIOGetResponse(options); - - equal(options.fileSize, 0x0A); - } - - run_next_test(); -}); - -/** - * Verify ICCIOHelper.processICCIOGetResponse for EF_TYPE_LINEAR_FIXED. - */ -add_test(function test_icc_io_get_response_for_linear_fixed_structure() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let iccioHelper = context.ICCIOHelper; - let pduHelper = context.GsmPDUHelper; - - let responseArray = [ - // SIM response. - [0x00, 0x00, 0x00, 0x1A, 0x6F, 0x40, 0x04, 0x00, 0x11, 0xA0, 0xAA, 0x00, - 0x02, 0x01, 0x1A], - // USIM response. - [0x62, 0x1E, 0x82, 0x05, 0x42, 0x21, 0x00, 0x1A, 0x01, 0x83, 0x02, 0x6F, - 0x40, 0xA5, 0x03, 0x92, 0x01, 0x00, 0x8A, 0x01, 0x07, 0x8B, 0x03, 0x6F, - 0x06, 0x02, 0x80, 0x02, 0x00, 0x1A, 0x88, 0x00] - ]; - - for (let i = 0; i < responseArray.length; i++) { - let strLen = responseArray[i].length * 2; - buf.writeInt32(strLen); - for (let j = 0; j < responseArray[i].length; j++) { - pduHelper.writeHexOctet(responseArray[i][j]); - } - buf.writeStringDelimiter(strLen); - - let options = {fileId: ICC_EF_MSISDN, - structure: EF_STRUCTURE_LINEAR_FIXED}; - iccioHelper.processICCIOGetResponse(options); - - equal(options.fileSize, 0x1A); - equal(options.recordSize, 0x1A); - equal(options.totalRecords, 0x01); - } - - run_next_test(); -}); - diff --git a/dom/system/gonk/tests/test_ril_worker_icc_ICCPDUHelper.js b/dom/system/gonk/tests/test_ril_worker_icc_ICCPDUHelper.js deleted file mode 100644 index 91495b1b7..000000000 --- a/dom/system/gonk/tests/test_ril_worker_icc_ICCPDUHelper.js +++ /dev/null @@ -1,652 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Verify ICCPDUHelper#readICCUCS2String() - */ -add_test(function test_read_icc_ucs2_string() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - - // 0x80 - let text = "TEST"; - helper.writeUCS2String(text); - // Also write two unused octets. - let ffLen = 2; - for (let i = 0; i < ffLen; i++) { - helper.writeHexOctet(0xff); - } - equal(iccHelper.readICCUCS2String(0x80, (2 * text.length) + ffLen), text); - - // 0x81 - let array = [0x08, 0xd2, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0xca, - 0xff, 0xff]; - let len = array.length; - for (let i = 0; i < len; i++) { - helper.writeHexOctet(array[i]); - } - equal(iccHelper.readICCUCS2String(0x81, len), "Mozilla\u694a"); - - // 0x82 - let array2 = [0x08, 0x69, 0x00, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, - 0xca, 0xff, 0xff]; - let len2 = array2.length; - for (let i = 0; i < len2; i++) { - helper.writeHexOctet(array2[i]); - } - equal(iccHelper.readICCUCS2String(0x82, len2), "Mozilla\u694a"); - - run_next_test(); -}); - -/** - * Verify ICCPDUHelper#writeICCUCS2String() - */ -add_test(function test_write_icc_ucs2_string() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - let alphaLen = 18; - let test_data = [ - { - encode: 0x80, - // string only contain one character. - data: "\u82b3" - }, { - encode: 0x80, - // 2 UCS2 character not located in the same half-page. - data: "Fire \u82b3\u8233" - }, { - encode: 0x80, - // 2 UCS2 character not located in the same half-page. - data: "\u694a\u704a" - }, { - encode: 0x81, - // 2 UCS2 character within same half-page. - data: "Fire \u6901\u697f" - }, { - encode: 0x81, - // 2 UCS2 character within same half-page. - data: "Fire \u6980\u69ff" - }, { - encode: 0x82, - // 2 UCS2 character within same half-page, but bit 8 is different. - data: "Fire \u0514\u0593" - }, { - encode: 0x82, - // 2 UCS2 character over 0x81 can encode range. - data: "Fire \u8000\u8001" - }, { - encode: 0x82, - // 2 UCS2 character over 0x81 can encode range. - data: "Fire \ufffd\ufffe" - }]; - - for (let i = 0; i < test_data.length; i++) { - let test = test_data[i]; - let writtenStr = iccHelper.writeICCUCS2String(alphaLen, test.data); - equal(writtenStr, test.data); - equal(helper.readHexOctet(), test.encode); - equal(iccHelper.readICCUCS2String(test.encode, alphaLen - 1), test.data); - } - - // This string use 0x80 encoded and the maximum capacity is 17 octets. - // Each alphabet takes 2 octets, thus the first 8 alphabets can be written. - let str = "Mozilla \u82b3\u8233 On Fire"; - let writtenStr = iccHelper.writeICCUCS2String(alphaLen, str); - equal(writtenStr, str.substring(0, 8)); - equal(helper.readHexOctet(), 0x80); - equal(iccHelper.readICCUCS2String(0x80, alphaLen - 1), str.substring(0, 8)); - - // This string use 0x81 encoded and the maximum capacity is 15 octets. - // Each alphabet takes 1 octets, thus the first 15 alphabets can be written. - str = "Mozilla \u6901\u697f On Fire"; - writtenStr = iccHelper.writeICCUCS2String(alphaLen, str); - equal(writtenStr, str.substring(0, 15)); - equal(helper.readHexOctet(), 0x81); - equal(iccHelper.readICCUCS2String(0x81, alphaLen - 1), str.substring(0, 15)); - - // This string use 0x82 encoded and the maximum capacity is 14 octets. - // Each alphabet takes 1 octets, thus the first 14 alphabets can be written. - str = "Mozilla \u0514\u0593 On Fire"; - writtenStr = iccHelper.writeICCUCS2String(alphaLen, str); - equal(writtenStr, str.substring(0, 14)); - equal(helper.readHexOctet(), 0x82); - equal(iccHelper.readICCUCS2String(0x82, alphaLen - 1), str.substring(0, 14)); - - run_next_test(); -}); -/** - * Verify ICCPDUHelper#readDiallingNumber - */ -add_test(function test_read_dialling_number() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - let str = "123456789"; - - helper.readHexOctet = function() { - return 0x81; - }; - - helper.readSwappedNibbleExtendedBcdString = function(len) { - return str.substring(0, len); - }; - - for (let i = 0; i < str.length; i++) { - equal(str.substring(0, i - 1), // -1 for the TON - iccHelper.readDiallingNumber(i)); - } - - run_next_test(); -}); - -/** - * Verify ICCPDUHelper#read8BitUnpackedToString - */ -add_test(function test_read_8bit_unpacked_to_string() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - - // Test 1: Read GSM alphabets. - // Write alphabets before ESCAPE. - for (let i = 0; i < PDU_NL_EXTENDED_ESCAPE; i++) { - helper.writeHexOctet(i); - } - - // Write two ESCAPEs to make it become ' '. - helper.writeHexOctet(PDU_NL_EXTENDED_ESCAPE); - helper.writeHexOctet(PDU_NL_EXTENDED_ESCAPE); - - for (let i = PDU_NL_EXTENDED_ESCAPE + 1; i < langTable.length; i++) { - helper.writeHexOctet(i); - } - - // Also write two unused fields. - let ffLen = 2; - for (let i = 0; i < ffLen; i++) { - helper.writeHexOctet(0xff); - } - - equal(iccHelper.read8BitUnpackedToString(PDU_NL_EXTENDED_ESCAPE), - langTable.substring(0, PDU_NL_EXTENDED_ESCAPE)); - equal(iccHelper.read8BitUnpackedToString(2), " "); - equal(iccHelper.read8BitUnpackedToString(langTable.length - - PDU_NL_EXTENDED_ESCAPE - 1 + ffLen), - langTable.substring(PDU_NL_EXTENDED_ESCAPE + 1)); - - // Test 2: Read GSM extended alphabets. - for (let i = 0; i < langShiftTable.length; i++) { - helper.writeHexOctet(PDU_NL_EXTENDED_ESCAPE); - helper.writeHexOctet(i); - } - - // Read string before RESERVED_CONTROL. - equal(iccHelper.read8BitUnpackedToString(PDU_NL_RESERVED_CONTROL * 2), - langShiftTable.substring(0, PDU_NL_RESERVED_CONTROL)); - // ESCAPE + RESERVED_CONTROL will become ' '. - equal(iccHelper.read8BitUnpackedToString(2), " "); - // Read string between RESERVED_CONTROL and EXTENDED_ESCAPE. - equal(iccHelper.read8BitUnpackedToString( - (PDU_NL_EXTENDED_ESCAPE - PDU_NL_RESERVED_CONTROL - 1) * 2), - langShiftTable.substring(PDU_NL_RESERVED_CONTROL + 1, - PDU_NL_EXTENDED_ESCAPE)); - // ESCAPE + ESCAPE will become ' '. - equal(iccHelper.read8BitUnpackedToString(2), " "); - // Read remaining string. - equal(iccHelper.read8BitUnpackedToString( - (langShiftTable.length - PDU_NL_EXTENDED_ESCAPE - 1) * 2), - langShiftTable.substring(PDU_NL_EXTENDED_ESCAPE + 1)); - - run_next_test(); -}); - -/** - * Verify ICCPDUHelper#writeStringTo8BitUnpacked. - * - * Test writing GSM 8 bit alphabets. - */ -add_test(function test_write_string_to_8bit_unpacked() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - // Length of trailing 0xff. - let ffLen = 2; - let str; - - // Test 1, write GSM alphabets. - let writtenStr = iccHelper.writeStringTo8BitUnpacked(langTable.length + ffLen, langTable); - equal(writtenStr, langTable); - - for (let i = 0; i < langTable.length; i++) { - equal(helper.readHexOctet(), i); - } - - for (let i = 0; i < ffLen; i++) { - equal(helper.readHexOctet(), 0xff); - } - - // Test 2, write GSM extended alphabets. - str = "\u000c\u20ac"; - writtenStr = iccHelper.writeStringTo8BitUnpacked(4, str); - equal(writtenStr, str); - equal(iccHelper.read8BitUnpackedToString(4), str); - - // Test 3, write GSM and GSM extended alphabets. - // \u000c, \u20ac are from gsm extended alphabets. - // \u00a3 is from gsm alphabet. - str = "\u000c\u20ac\u00a3"; - - // 2 octets * 2 = 4 octets for 2 gsm extended alphabets, - // 1 octet for 1 gsm alphabet, - // 2 octes for trailing 0xff. - // "Totally 7 octets are to be written." - writtenStr = iccHelper.writeStringTo8BitUnpacked(7, str); - equal(writtenStr, str); - equal(iccHelper.read8BitUnpackedToString(7), str); - - run_next_test(); -}); - -/** - * Verify ICCPDUHelper#writeStringTo8BitUnpacked with maximum octets written. - */ -add_test(function test_write_string_to_8bit_unpacked_with_max_octets_written() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - - // The maximum of the number of octets that can be written is 3. - // Only 3 characters shall be written even the length of the string is 4. - let writtenStr = iccHelper.writeStringTo8BitUnpacked(3, langTable.substring(0, 4)); - equal(writtenStr, langTable.substring(0, 3)); - helper.writeHexOctet(0xff); // dummy octet. - for (let i = 0; i < 3; i++) { - equal(helper.readHexOctet(), i); - } - ok(helper.readHexOctet() != 4); - - // \u000c is GSM extended alphabet, 2 octets. - // \u00a3 is GSM alphabet, 1 octet. - let str = "\u000c\u00a3"; - writtenStr = iccHelper.writeStringTo8BitUnpacked(3, str); - equal(writtenStr, str.substring(0, 2)); - equal(iccHelper.read8BitUnpackedToString(3), str); - - str = "\u00a3\u000c"; - writtenStr = iccHelper.writeStringTo8BitUnpacked(3, str); - equal(writtenStr, str.substring(0, 2)); - equal(iccHelper.read8BitUnpackedToString(3), str); - - // 2 GSM extended alphabets cost 4 octets, but maximum is 3, so only the 1st - // alphabet can be written. - str = "\u000c\u000c"; - writtenStr = iccHelper.writeStringTo8BitUnpacked(3, str); - helper.writeHexOctet(0xff); // dummy octet. - equal(writtenStr, str.substring(0, 1)); - equal(iccHelper.read8BitUnpackedToString(4), str.substring(0, 1)); - - run_next_test(); -}); - -/** - * Verify ICCPDUHelper.readAlphaIdentifier - */ -add_test(function test_read_alpha_identifier() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - - // UCS2: 0x80 - let text = "TEST"; - helper.writeHexOctet(0x80); - helper.writeUCS2String(text); - // Also write two unused octets. - let ffLen = 2; - for (let i = 0; i < ffLen; i++) { - helper.writeHexOctet(0xff); - } - equal(iccHelper.readAlphaIdentifier(1 + (2 * text.length) + ffLen), text); - - // UCS2: 0x81 - let array = [0x81, 0x08, 0xd2, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0xca, 0xff, 0xff]; - for (let i = 0; i < array.length; i++) { - helper.writeHexOctet(array[i]); - } - equal(iccHelper.readAlphaIdentifier(array.length), "Mozilla\u694a"); - - // UCS2: 0x82 - let array2 = [0x82, 0x08, 0x69, 0x00, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0xca, 0xff, 0xff]; - for (let i = 0; i < array2.length; i++) { - helper.writeHexOctet(array2[i]); - } - equal(iccHelper.readAlphaIdentifier(array2.length), "Mozilla\u694a"); - - // GSM 8 Bit Unpacked - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - for (let i = 0; i < PDU_NL_EXTENDED_ESCAPE; i++) { - helper.writeHexOctet(i); - } - equal(iccHelper.readAlphaIdentifier(PDU_NL_EXTENDED_ESCAPE), - langTable.substring(0, PDU_NL_EXTENDED_ESCAPE)); - - run_next_test(); -}); - -/** - * Verify ICCPDUHelper.writeAlphaIdentifier - */ -add_test(function test_write_alpha_identifier() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - // Length of trailing 0xff. - let ffLen = 2; - - // Removal - let writenAlphaId = iccHelper.writeAlphaIdentifier(10, null); - equal(writenAlphaId, ""); - equal(iccHelper.readAlphaIdentifier(10), ""); - - // GSM 8 bit - let str = "Mozilla"; - writenAlphaId = iccHelper.writeAlphaIdentifier(str.length + ffLen, str); - equal(writenAlphaId , str); - equal(iccHelper.readAlphaIdentifier(str.length + ffLen), str); - - // UCS2 - str = "Mozilla\u8000"; - writenAlphaId = iccHelper.writeAlphaIdentifier(str.length * 2 + ffLen, str); - equal(writenAlphaId , str); - // * 2 for each character will be encoded to UCS2 alphabets. - equal(iccHelper.readAlphaIdentifier(str.length * 2 + ffLen), str); - - // Test with maximum octets written. - // 1 coding scheme (0x80) and 1 UCS2 character, total 3 octets. - str = "\u694a"; - writenAlphaId = iccHelper.writeAlphaIdentifier(3, str); - equal(writenAlphaId , str); - equal(iccHelper.readAlphaIdentifier(3), str); - - // 1 coding scheme (0x80) and 2 UCS2 characters, total 5 octets. - // numOctets is limited to 4, so only 1 UCS2 character can be written. - str = "\u694a\u69ca"; - writenAlphaId = iccHelper.writeAlphaIdentifier(4, str); - helper.writeHexOctet(0xff); // dummy octet. - equal(writenAlphaId , str.substring(0, 1)); - equal(iccHelper.readAlphaIdentifier(5), str.substring(0, 1)); - - // Write 0 octet. - writenAlphaId = iccHelper.writeAlphaIdentifier(0, "1"); - helper.writeHexOctet(0xff); // dummy octet. - equal(writenAlphaId, ""); - equal(iccHelper.readAlphaIdentifier(1), ""); - - run_next_test(); -}); - -/** - * Verify ICCPDUHelper.readAlphaIdDiallingNumber - */ -add_test(function test_read_alpha_id_dialling_number() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - let buf = context.Buf; - const recordSize = 32; - - function testReadAlphaIdDiallingNumber(contact) { - iccHelper.readAlphaIdentifier = function() { - return contact.alphaId; - }; - - iccHelper.readNumberWithLength = function() { - return contact.number; - }; - - let strLen = recordSize * 2; - buf.writeInt32(strLen); // fake length - helper.writeHexOctet(0xff); // fake CCP - helper.writeHexOctet(0xff); // fake EXT1 - buf.writeStringDelimiter(strLen); - - let contactR = iccHelper.readAlphaIdDiallingNumber(recordSize); - if (contact.alphaId == "" && contact.number == "") { - equal(contactR, null); - } else { - equal(contactR.alphaId, contact.alphaId); - equal(contactR.number, contact.number); - } - } - - testReadAlphaIdDiallingNumber({alphaId: "AlphaId", number: "0987654321"}); - testReadAlphaIdDiallingNumber({alphaId: "", number: ""}); - - run_next_test(); -}); - -/** - * Verify ICCPDUHelper.writeAlphaIdDiallingNumber - */ -add_test(function test_write_alpha_id_dialling_number() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.ICCPDUHelper; - const recordSize = 32; - - // Write a normal contact. - let contactW = { - alphaId: "Mozilla", - number: "1234567890" - }; - - let writtenContact = helper.writeAlphaIdDiallingNumber(recordSize, - contactW.alphaId, - contactW.number, 0xff); - - let contactR = helper.readAlphaIdDiallingNumber(recordSize); - equal(writtenContact.alphaId, contactR.alphaId); - equal(writtenContact.number, contactR.number); - equal(0xff, contactR.extRecordNumber); - - // Write a contact with alphaId encoded in UCS2 and number has '+'. - let contactUCS2 = { - alphaId: "火狐", - number: "+1234567890" - }; - - writtenContact = helper.writeAlphaIdDiallingNumber(recordSize, - contactUCS2.alphaId, - contactUCS2.number, 0xff); - contactR = helper.readAlphaIdDiallingNumber(recordSize); - equal(writtenContact.alphaId, contactR.alphaId); - equal(writtenContact.number, contactR.number); - equal(0xff, contactR.extRecordNumber); - - // Write a null contact (Removal). - writtenContact = helper.writeAlphaIdDiallingNumber(recordSize); - contactR = helper.readAlphaIdDiallingNumber(recordSize); - equal(contactR, null); - equal(writtenContact.alphaId, ""); - equal(writtenContact.number, ""); - - // Write a longer alphaId/dialling number - // Dialling Number : Maximum 20 digits(10 octets). - // Alpha Identifier: 32(recordSize) - 14 (10 octets for Dialling Number, 1 - // octet for TON/NPI, 1 for number length octet, and 2 for - // Ext) = Maximum 18 octets. - let longContact = { - alphaId: "AAAAAAAAABBBBBBBBBCCCCCCCCC", - number: "123456789012345678901234567890", - }; - - writtenContact = helper.writeAlphaIdDiallingNumber(recordSize, - longContact.alphaId, - longContact.number, 0xff); - contactR = helper.readAlphaIdDiallingNumber(recordSize); - equal(writtenContact.alphaId, contactR.alphaId); - equal(writtenContact.number, contactR.number); - equal(0xff, contactR.extRecordNumber); - - // Add '+' to number and test again. - longContact.number = "+123456789012345678901234567890"; - writtenContact = helper.writeAlphaIdDiallingNumber(recordSize, - longContact.alphaId, - longContact.number, 0xff); - contactR = helper.readAlphaIdDiallingNumber(recordSize); - equal(writtenContact.alphaId, contactR.alphaId); - equal(writtenContact.number, contactR.number); - equal(0xff, contactR.extRecordNumber); - - run_next_test(); -}); - -/** - * Verify ICCPDUHelper.writeDiallingNumber - */ -add_test(function test_write_dialling_number() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.ICCPDUHelper; - - // with + - let number = "+123456"; - let len = 4; - helper.writeDiallingNumber(number); - equal(helper.readDiallingNumber(len), number); - - // without + - number = "987654"; - len = 4; - helper.writeDiallingNumber(number); - equal(helper.readDiallingNumber(len), number); - - number = "9876543"; - len = 5; - helper.writeDiallingNumber(number); - equal(helper.readDiallingNumber(len), number); - - run_next_test(); -}); - -/** - * Verify ICCPDUHelper.readNumberWithLength - */ -add_test(function test_read_number_with_length() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - - let numbers = [ - { - number: "123456789", - expectedNumber: "123456789" - }, - { - number: "", - expectedNumber: "" - }, - // Invalid length of BCD number/SSC contents - { - number: "12345678901234567890123", - expectedNumber: "" - }, - ]; - - // To avoid obtaining wrong buffer content. - context.Buf.seekIncoming = function(offset) { - }; - - function do_test(aNumber, aExpectedNumber) { - iccHelper.readDiallingNumber = function(numLen) { - return aNumber.substring(0, numLen); - }; - - if (aNumber) { - helper.writeHexOctet(aNumber.length + 1); - } else { - helper.writeHexOctet(0xff); - } - - equal(iccHelper.readNumberWithLength(), aExpectedNumber); - } - - for (let i = 0; i < numbers.length; i++) { - do_test(numbers[i].number, numbers[i].expectedNumber); - } - - run_next_test(); -}); - -/** - * Verify ICCPDUHelper.writeNumberWithLength - */ -add_test(function test_write_number_with_length() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - - function test(number, expectedNumber) { - expectedNumber = expectedNumber || number; - let writeNumber = iccHelper.writeNumberWithLength(number); - equal(writeNumber, expectedNumber); - let numLen = helper.readHexOctet(); - equal(expectedNumber, iccHelper.readDiallingNumber(numLen)); - for (let i = 0; i < (ADN_MAX_BCD_NUMBER_BYTES - numLen); i++) { - equal(0xff, helper.readHexOctet()); - } - } - - // without + - test("123456789"); - - // with + - test("+987654321"); - - // extended BCD coding - test("1*2#3,4*5#6,"); - - // with + and extended BCD coding - test("+1*2#3,4*5#6,"); - - // non-supported characters should not be written. - test("(1)23-456+789", "123456789"); - - test("++(01)2*3-4#5,6+7(8)9*0#1,", "+012*34#5,6789*0#1,"); - - // over maximum 20 digits should be truncated. - test("012345678901234567890123456789", "01234567890123456789"); - - // null - iccHelper.writeNumberWithLength(null); - for (let i = 0; i < (ADN_MAX_BCD_NUMBER_BYTES + 1); i++) { - equal(0xff, helper.readHexOctet()); - } - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_icc_ICCRecordHelper.js b/dom/system/gonk/tests/test_ril_worker_icc_ICCRecordHelper.js deleted file mode 100644 index 00c55873d..000000000 --- a/dom/system/gonk/tests/test_ril_worker_icc_ICCRecordHelper.js +++ /dev/null @@ -1,1080 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Verify ICCRecordHelper.readPBR - */ -add_test(function test_read_pbr() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let record = context.ICCRecordHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - let pbr_1 = [ - 0xa8, 0x05, 0xc0, 0x03, 0x4f, 0x3a, 0x01 - ]; - - // Write data size - buf.writeInt32(pbr_1.length * 2); - - // Write pbr - for (let i = 0; i < pbr_1.length; i++) { - helper.writeHexOctet(pbr_1[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(pbr_1.length * 2); - - options.totalRecords = 2; - if (options.callback) { - options.callback(options); - } - }; - - io.loadNextRecord = function fakeLoadNextRecord(options) { - let pbr_2 = [ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff - ]; - - options.p1++; - if (options.callback) { - options.callback(options); - } - }; - - let successCb = function successCb(pbrs) { - equal(pbrs[0].adn.fileId, 0x4f3a); - equal(pbrs.length, 1); - }; - - let errorCb = function errorCb(errorMsg) { - do_print("Reading EF_PBR failed, msg = " + errorMsg); - ok(false); - }; - - record.readPBR(successCb, errorCb); - - // Check cache pbrs when 2nd call - let ifLoadEF = false; - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - ifLoadEF = true; - } - record.readPBR(successCb, errorCb); - ok(!ifLoadEF); - - run_next_test(); -}); - -/** - * Verify ICCRecordHelper.readEmail - */ -add_test(function test_read_email() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let record = context.ICCRecordHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - let recordSize; - - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - let email_1 = [ - 0x65, 0x6D, 0x61, 0x69, 0x6C, - 0x00, 0x6D, 0x6F, 0x7A, 0x69, - 0x6C, 0x6C, 0x61, 0x2E, 0x63, - 0x6F, 0x6D, 0x02, 0x23]; - - // Write data size - buf.writeInt32(email_1.length * 2); - - // Write email - for (let i = 0; i < email_1.length; i++) { - helper.writeHexOctet(email_1[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(email_1.length * 2); - - recordSize = email_1.length; - options.recordSize = recordSize; - if (options.callback) { - options.callback(options); - } - }; - - function doTestReadEmail(type, expectedResult) { - let fileId = 0x6a75; - let recordNumber = 1; - - // fileId and recordNumber are dummy arguments. - record.readEmail(fileId, type, recordNumber, function(email) { - equal(email, expectedResult); - }); - }; - - doTestReadEmail(ICC_USIM_TYPE1_TAG, "email@mozilla.com$#"); - doTestReadEmail(ICC_USIM_TYPE2_TAG, "email@mozilla.com"); - equal(record._emailRecordSize, recordSize); - - run_next_test(); -}); - -/** - * Verify ICCRecordHelper.updateEmail - */ -add_test(function test_update_email() { - const recordSize = 0x20; - const recordNumber = 1; - const fileId = 0x4f50; - const NUM_TESTS = 2; - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - let ril = context.RIL; - ril.appType = CARD_APPTYPE_USIM; - let recordHelper = context.ICCRecordHelper; - let buf = context.Buf; - let ioHelper = context.ICCIOHelper; - let pbr = {email: {fileId: fileId, fileType: ICC_USIM_TYPE1_TAG}, - adn: {sfi: 1}}; - let count = 0; - - // Override. - ioHelper.updateLinearFixedEF = function(options) { - options.pathId = context.ICCFileHelper.getEFPath(options.fileId); - options.command = ICC_COMMAND_UPDATE_RECORD; - options.p1 = options.recordNumber; - options.p2 = READ_RECORD_ABSOLUTE_MODE; - options.p3 = recordSize; - ril.iccIO(options); - }; - - function do_test(pbr, expectedEmail, expectedAdnRecordId) { - buf.sendParcel = function() { - count++; - - // Request Type. - equal(this.readInt32(), REQUEST_SIM_IO); - - // Token : we don't care - this.readInt32(); - - // command. - equal(this.readInt32(), ICC_COMMAND_UPDATE_RECORD); - - // fileId. - equal(this.readInt32(), fileId); - - // pathId. - equal(this.readString(), - EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_DF_PHONEBOOK); - - // p1. - equal(this.readInt32(), recordNumber); - - // p2. - equal(this.readInt32(), READ_RECORD_ABSOLUTE_MODE); - - // p3. - equal(this.readInt32(), recordSize); - - // data. - let strLen = this.readInt32(); - let email; - if (pbr.email.fileType === ICC_USIM_TYPE1_TAG) { - email = iccHelper.read8BitUnpackedToString(recordSize); - } else { - email = iccHelper.read8BitUnpackedToString(recordSize - 2); - equal(pduHelper.readHexOctet(), pbr.adn.sfi); - equal(pduHelper.readHexOctet(), expectedAdnRecordId); - } - this.readStringDelimiter(strLen); - equal(email, expectedEmail); - - // pin2. - equal(this.readString(), null); - - // AID. Ignore because it's from modem. - this.readInt32(); - - if (count == NUM_TESTS) { - run_next_test(); - } - }; - recordHelper.updateEmail(pbr, recordNumber, expectedEmail, expectedAdnRecordId); - } - - do_test(pbr, "test@mail.com"); - pbr.email.fileType = ICC_USIM_TYPE2_TAG; - do_test(pbr, "test@mail.com", 1); -}); - -/** - * Verify ICCRecordHelper.readANR - */ -add_test(function test_read_anr() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let record = context.ICCRecordHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - let recordSize; - - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - let anr_1 = [ - 0x01, 0x05, 0x81, 0x10, 0x32, - 0x54, 0xF6, 0xFF, 0xFF]; - - // Write data size - buf.writeInt32(anr_1.length * 2); - - // Write anr - for (let i = 0; i < anr_1.length; i++) { - helper.writeHexOctet(anr_1[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(anr_1.length * 2); - - recordSize = anr_1.length; - options.recordSize = recordSize; - if (options.callback) { - options.callback(options); - } - }; - - function doTestReadAnr(fileType, expectedResult) { - let fileId = 0x4f11; - let recordNumber = 1; - - // fileId and recordNumber are dummy arguments. - record.readANR(fileId, fileType, recordNumber, function(anr) { - equal(anr, expectedResult); - }); - }; - - doTestReadAnr(ICC_USIM_TYPE1_TAG, "0123456"); - equal(record._anrRecordSize, recordSize); - - run_next_test(); -}); - -/** - * Verify ICCRecordHelper.updateANR - */ -add_test(function test_update_anr() { - const recordSize = 0x20; - const recordNumber = 1; - const fileId = 0x4f11; - const NUM_TESTS = 2; - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - let ril = context.RIL; - ril.appType = CARD_APPTYPE_USIM; - let recordHelper = context.ICCRecordHelper; - let buf = context.Buf; - let ioHelper = context.ICCIOHelper; - let pbr = {anr0: {fileId: fileId, fileType: ICC_USIM_TYPE1_TAG}, - adn: {sfi: 1}}; - let count = 0; - - // Override. - ioHelper.updateLinearFixedEF = function(options) { - options.pathId = context.ICCFileHelper.getEFPath(options.fileId); - options.command = ICC_COMMAND_UPDATE_RECORD; - options.p1 = options.recordNumber; - options.p2 = READ_RECORD_ABSOLUTE_MODE; - options.p3 = recordSize; - ril.iccIO(options); - }; - - function do_test(pbr, expectedANR, expectedAdnRecordId) { - buf.sendParcel = function() { - count++; - - // Request Type. - equal(this.readInt32(), REQUEST_SIM_IO); - - // Token : we don't care - this.readInt32(); - - // command. - equal(this.readInt32(), ICC_COMMAND_UPDATE_RECORD); - - // fileId. - equal(this.readInt32(), fileId); - - // pathId. - equal(this.readString(), - EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_DF_PHONEBOOK); - - // p1. - equal(this.readInt32(), recordNumber); - - // p2. - equal(this.readInt32(), READ_RECORD_ABSOLUTE_MODE); - - // p3. - equal(this.readInt32(), recordSize); - - // data. - let strLen = this.readInt32(); - // EF_AAS, ignore. - pduHelper.readHexOctet(); - equal(iccHelper.readNumberWithLength(), expectedANR); - // EF_CCP, ignore. - pduHelper.readHexOctet(); - // EF_EXT1, ignore. - pduHelper.readHexOctet(); - if (pbr.anr0.fileType === ICC_USIM_TYPE2_TAG) { - equal(pduHelper.readHexOctet(), pbr.adn.sfi); - equal(pduHelper.readHexOctet(), expectedAdnRecordId); - } - this.readStringDelimiter(strLen); - - // pin2. - equal(this.readString(), null); - - // AID. Ignore because it's from modem. - this.readInt32(); - - if (count == NUM_TESTS) { - run_next_test(); - } - }; - recordHelper.updateANR(pbr, recordNumber, expectedANR, expectedAdnRecordId); - } - - do_test(pbr, "+123456789"); - pbr.anr0.fileType = ICC_USIM_TYPE2_TAG; - do_test(pbr, "123456789", 1); -}); - -/** - * Verify ICCRecordHelper.readIAP - */ -add_test(function test_read_iap() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let record = context.ICCRecordHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - let recordSize; - - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - let iap_1 = [0x01, 0x02]; - - // Write data size/ - buf.writeInt32(iap_1.length * 2); - - // Write iap. - for (let i = 0; i < iap_1.length; i++) { - helper.writeHexOctet(iap_1[i]); - } - - // Write string delimiter. - buf.writeStringDelimiter(iap_1.length * 2); - - recordSize = iap_1.length; - options.recordSize = recordSize; - if (options.callback) { - options.callback(options); - } - }; - - function doTestReadIAP(expectedIAP) { - const fileId = 0x4f17; - const recordNumber = 1; - - let successCb = function successCb(iap) { - for (let i = 0; i < iap.length; i++) { - equal(expectedIAP[i], iap[i]); - } - run_next_test(); - }.bind(this); - - let errorCb = function errorCb(errorMsg) { - do_print(errorMsg); - ok(false); - run_next_test(); - }.bind(this); - - record.readIAP(fileId, recordNumber, successCb, errorCb); - }; - - doTestReadIAP([1, 2]); -}); - -/** - * Verify ICCRecordHelper.updateIAP - */ -add_test(function test_update_iap() { - const recordSize = 2; - const recordNumber = 1; - const fileId = 0x4f17; - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let ril = context.RIL; - ril.appType = CARD_APPTYPE_USIM; - let recordHelper = context.ICCRecordHelper; - let buf = context.Buf; - let ioHelper = context.ICCIOHelper; - let count = 0; - - // Override. - ioHelper.updateLinearFixedEF = function(options) { - options.pathId = context.ICCFileHelper.getEFPath(options.fileId); - options.command = ICC_COMMAND_UPDATE_RECORD; - options.p1 = options.recordNumber; - options.p2 = READ_RECORD_ABSOLUTE_MODE; - options.p3 = recordSize; - ril.iccIO(options); - }; - - function do_test(expectedIAP) { - buf.sendParcel = function() { - // Request Type. - equal(this.readInt32(), REQUEST_SIM_IO); - - // Token : we don't care - this.readInt32(); - - // command. - equal(this.readInt32(), ICC_COMMAND_UPDATE_RECORD); - - // fileId. - equal(this.readInt32(), fileId); - - // pathId. - equal(this.readString(), - EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_DF_PHONEBOOK); - - // p1. - equal(this.readInt32(), recordNumber); - - // p2. - equal(this.readInt32(), READ_RECORD_ABSOLUTE_MODE); - - // p3. - equal(this.readInt32(), recordSize); - - // data. - let strLen = this.readInt32(); - for (let i = 0; i < recordSize; i++) { - equal(expectedIAP[i], pduHelper.readHexOctet()); - } - this.readStringDelimiter(strLen); - - // pin2. - equal(this.readString(), null); - - // AID. Ignore because it's from modem. - this.readInt32(); - - run_next_test(); - }; - recordHelper.updateIAP(fileId, recordNumber, expectedIAP); - } - - do_test([1, 2]); -}); - -/** - * Verify ICCRecordHelper.readADNLike. - */ -add_test(function test_read_adn_like() { - const RECORD_SIZE = 0x20; - - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let record = context.ICCRecordHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - let ril = context.RIL; - - function do_test(extFileId, rawEF, expectedExtRecordNumber, expectedNumber) { - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - // Write data size - buf.writeInt32(rawEF.length * 2); - - // Write adn - for (let i = 0; i < rawEF.length; i += 2) { - helper.writeHexOctet(parseInt(rawEF.substr(i, 2), 16)); - } - - // Write string delimiter - buf.writeStringDelimiter(rawEF.length * 2); - - options.p1 = 1; - options.recordSize = RECORD_SIZE; - options.totalRecords = 1; - if (options.callback) { - options.callback(options); - } - }; - - record.readExtension = function(fileId, recordNumber, onsuccess, onerror) { - onsuccess("1234"); - } - - let successCb = function successCb(contacts) { - ok(contacts[0].number == expectedNumber); - }; - - let errorCb = function errorCb(errorMsg) { - do_print("Reading ADNLike failed, msg = " + errorMsg); - ok(false); - }; - - record.readADNLike(ICC_EF_ADN, extFileId, successCb, errorCb); - } - - ril.appType = CARD_APPTYPE_SIM; - // Valid extension - do_test(ICC_EF_EXT1,"436f6e74616374303031ffffffffffffffff0b8199887766554433221100ff01", - 0x01,"998877665544332211001234"); - // Empty extension - do_test(ICC_EF_EXT1,"436f6e74616374303031ffffffffffffffff0b8199887766554433221100ffff", - 0xff, "99887766554433221100"); - // Unsupport extension - do_test(null,"436f6e74616374303031ffffffffffffffff0b8199887766554433221100ffff", - 0xff, "99887766554433221100"); - // Empty dialling number contact - do_test(null,"436f6e74616374303031ffffffffffffffffffffffffffffffffffffffffffff", - 0xff, ""); - - run_next_test(); -}); - -/** - * Verify ICCRecordHelper.updateADNLike. - */ -add_test(function test_update_adn_like() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - let record = context.ICCRecordHelper; - let io = context.ICCIOHelper; - let pdu = context.ICCPDUHelper; - let buf = context.Buf; - - ril.appType = CARD_APPTYPE_SIM; - const recordSize = 0x20; - let fileId; - - // Override. - io.updateLinearFixedEF = function(options) { - options.pathId = context.ICCFileHelper.getEFPath(options.fileId); - options.command = ICC_COMMAND_UPDATE_RECORD; - options.p1 = options.recordNumber; - options.p2 = READ_RECORD_ABSOLUTE_MODE; - options.p3 = recordSize; - ril.iccIO(options); - }; - - buf.sendParcel = function() { - // Request Type. - equal(this.readInt32(), REQUEST_SIM_IO); - - // Token : we don't care - this.readInt32(); - - // command. - equal(this.readInt32(), ICC_COMMAND_UPDATE_RECORD); - - // fileId. - equal(this.readInt32(), fileId); - - // pathId. - equal(this.readString(), EF_PATH_MF_SIM + EF_PATH_DF_TELECOM); - - // p1. - equal(this.readInt32(), 1); - - // p2. - equal(this.readInt32(), READ_RECORD_ABSOLUTE_MODE); - - // p3. - equal(this.readInt32(), 0x20); - - // data. - let contact = pdu.readAlphaIdDiallingNumber(0x20); - equal(contact.alphaId, "test"); - equal(contact.number, "123456"); - equal(contact.extRecordNumber, "0xff"); - - // pin2. - if (fileId == ICC_EF_ADN) { - equal(this.readString(), null); - } else { - equal(this.readString(), "1111"); - } - - // AID. Ignore because it's from modem. - this.readInt32(); - - if (fileId == ICC_EF_FDN) { - run_next_test(); - } - }; - - fileId = ICC_EF_ADN; - record.updateADNLike(fileId, 0xff, - {recordId: 1, alphaId: "test", number: "123456"}); - - fileId = ICC_EF_FDN; - record.updateADNLike(fileId, 0xff, - {recordId: 1, alphaId: "test", number: "123456"}, - "1111"); -}); - -/** - * Verify ICCRecordHelper.findFreeRecordId. - */ -add_test(function test_find_free_record_id() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let recordHelper = context.ICCRecordHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - let ril = context.RIL; - - function writeRecord(record) { - // Write data size - buf.writeInt32(record.length * 2); - - for (let i = 0; i < record.length; i++) { - pduHelper.writeHexOctet(record[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(record.length * 2); - } - - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - // Some random data. - let record = [0x12, 0x34, 0x56, 0x78, 0x90]; - options.p1 = 1; - options.totalRecords = 2; - writeRecord(record); - if (options.callback) { - options.callback(options); - } - }; - - ril.iccIO = function fakeIccIO(options) { - // Unused bytes. - let record = [0xff, 0xff, 0xff, 0xff, 0xff]; - writeRecord(record); - if (options.callback) { - options.callback(options); - } - }; - - let fileId = 0x0000; // Dummy. - recordHelper.findFreeRecordId( - fileId, - function(recordId) { - equal(recordId, 2); - run_next_test(); - }.bind(this), - function(errorMsg) { - do_print(errorMsg); - ok(false); - run_next_test(); - }.bind(this)); -}); - -/** - * Verify ICCRecordHelper.fetchICCRecords. - */ -add_test(function test_fetch_icc_recodes() { - let worker = newWorker(); - let context = worker.ContextPool._contexts[0]; - let RIL = context.RIL; - let iccRecord = context.ICCRecordHelper; - let simRecord = context.SimRecordHelper; - let ruimRecord = context.RuimRecordHelper; - let fetchTag = 0x00; - - simRecord.fetchSimRecords = function() { - fetchTag = 0x01; - }; - - ruimRecord.fetchRuimRecords = function() { - fetchTag = 0x02; - }; - - RIL.appType = CARD_APPTYPE_SIM; - iccRecord.fetchICCRecords(); - equal(fetchTag, 0x01); - - RIL.appType = CARD_APPTYPE_RUIM; - iccRecord.fetchICCRecords(); - equal(fetchTag, 0x02); - - RIL.appType = CARD_APPTYPE_USIM; - iccRecord.fetchICCRecords(); - equal(fetchTag, 0x01); - - run_next_test(); -}); - -/** - * Verify reading EF_ICCID. - */ -add_test(function test_handling_iccid() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.ICCRecordHelper; - let helper = context.GsmPDUHelper; - let ril = context.RIL; - let buf = context.Buf; - let io = context.ICCIOHelper; - - ril.reportStkServiceIsRunning = function fakeReportStkServiceIsRunning() { - }; - - function do_test(rawICCID, expectedICCID) { - io.loadTransparentEF = function fakeLoadTransparentEF(options) { - // Write data size - buf.writeInt32(rawICCID.length); - - // Write data - for (let i = 0; i < rawICCID.length; i += 2) { - helper.writeHexOctet(parseInt(rawICCID.substr(i, 2), 16)); - } - - // Write string delimiter - buf.writeStringDelimiter(rawICCID.length); - - if (options.callback) { - options.callback(options); - } - }; - - record.readICCID(); - - equal(ril.iccInfo.iccid, expectedICCID); - } - - // Invalid value 0xE at high nibbile + low nibbile contains 0xF. - do_test("9868002E90909F001519", "89860020909"); - // Invalid value 0xD at low nibbile. - do_test("986800D2909090001519", "8986002090909005191"); - // Invalid value 0xC at low nibbile. - do_test("986800C2909090001519", "8986002090909005191"); - // Invalid value 0xB at low nibbile. - do_test("986800B2909090001519", "8986002090909005191"); - // Invalid value 0xA at low nibbile. - do_test("986800A2909090001519", "8986002090909005191"); - // Valid ICCID. - do_test("98101430121181157002", "89014103211118510720"); - - run_next_test(); -}); - -/** - * Verify ICCRecordHelper.readExtension - */ -add_test(function test_read_extension() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let record = context.ICCRecordHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - - function do_test(rawExtension, expectedExtensionNumber) { - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - // Write data size - buf.writeInt32(rawExtension.length * 2); - - // Write ext - for (let i = 0; i < rawExtension.length; i += 2) { - helper.writeHexOctet(parseInt(rawExtension.substr(i, 2), 16)); - } - - // Write string delimiter - buf.writeStringDelimiter(rawExtension.length); - - if (options.callback) { - options.callback(options); - } - }; - - let successCb = function successCb(number) { - do_print("extension number:" + number); - equal(number, expectedExtensionNumber); - }; - - let errorCb = function errorCb() { - ok(expectedExtensionNumber == null); - }; - - record.readExtension(0x6f4a, 1, successCb, errorCb); - } - - // Test unsupported record type 0x01 - do_test("010a10325476981032547698ff", ""); - // Test invalid length 0xc1 - do_test("020c10325476981032547698ff", null); - // Test extension chain which we don't support - do_test("020a1032547698103254769802", "01234567890123456789"); - // Test valid Extension - do_test("020a10325476981032547698ff", "01234567890123456789"); - // Test valid Extension - do_test("0209103254769810325476ffff", "012345678901234567"); - // Test empty Extension - do_test("02ffffffffffffffffffffffff", ""); - - run_next_test(); -}); - -/** - * Verify ICCRecordHelper.updateExtension - */ -add_test(function test_update_extension() { - const RECORD_SIZE = 13; - const RECORD_NUMBER = 1; - - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let ril = context.RIL; - let recordHelper = context.ICCRecordHelper; - let buf = context.Buf; - let ioHelper = context.ICCIOHelper; - - // Override. - ioHelper.updateLinearFixedEF = function(options) { - options.pathId = context.ICCFileHelper.getEFPath(options.fileId); - options.command = ICC_COMMAND_UPDATE_RECORD; - options.p1 = options.recordNumber; - options.p2 = READ_RECORD_ABSOLUTE_MODE; - options.p3 = RECORD_SIZE; - ril.iccIO(options); - }; - - function do_test(fileId, number, expectedNumber) { - buf.sendParcel = function() { - // Request Type. - equal(this.readInt32(), REQUEST_SIM_IO); - - // Token : we don't care - this.readInt32(); - - // command. - equal(this.readInt32(), ICC_COMMAND_UPDATE_RECORD); - - // fileId. - equal(this.readInt32(), fileId); - - // pathId. - if (ril.appType == CARD_APPTYPE_SIM || ril.appType == CARD_APPTYPE_RUIM) { - equal(this.readString(), - EF_PATH_MF_SIM + EF_PATH_DF_TELECOM); - } else{ - equal(this.readString(), - EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_DF_PHONEBOOK); - } - - // p1. - equal(this.readInt32(), RECORD_NUMBER); - - // p2. - equal(this.readInt32(), READ_RECORD_ABSOLUTE_MODE); - - // p3. - equal(this.readInt32(), RECORD_SIZE); - - // data. - let strLen = this.readInt32(); - // Extension record - let recordType = pduHelper.readHexOctet(); - - equal(recordType, 0x02); - equal(pduHelper.readHexOctet(), 10); - equal( - pduHelper.readSwappedNibbleExtendedBcdString(EXT_MAX_NUMBER_DIGITS - 1), - expectedNumber); - - this.readStringDelimiter(strLen); - - // pin2. - equal(this.readString(), null); - - // AID. Ignore because it's from modem. - this.readInt32(); - }; - - recordHelper.updateExtension(fileId, RECORD_NUMBER, number); - } - - ril.appType = CARD_APPTYPE_SIM; - do_test(ICC_EF_EXT1, "01234567890123456789", "01234567890123456789"); - // We don't support extension chain. - do_test(ICC_EF_EXT1, "012345678901234567891234", "01234567890123456789"); - - ril.appType = CARD_APPTYPE_USIM; - do_test(ICC_EF_EXT1, "01234567890123456789", "01234567890123456789"); - - ril.appType = CARD_APPTYPE_RUIM; - do_test(ICC_EF_EXT1, "01234567890123456789", "01234567890123456789"); - - run_next_test(); -}); - -/** - * Verify ICCRecordHelper.cleanEFRecord - */ -add_test(function test_clean_ef_record() { - const RECORD_SIZE = 13; - const RECORD_NUMBER = 1; - - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let ril = context.RIL; - let recordHelper = context.ICCRecordHelper; - let buf = context.Buf; - let ioHelper = context.ICCIOHelper; - - // Override. - ioHelper.updateLinearFixedEF = function(options) { - options.pathId = context.ICCFileHelper.getEFPath(options.fileId); - options.command = ICC_COMMAND_UPDATE_RECORD; - options.p1 = options.recordNumber; - options.p2 = READ_RECORD_ABSOLUTE_MODE; - options.p3 = RECORD_SIZE; - ril.iccIO(options); - }; - - function do_test(fileId) { - buf.sendParcel = function() { - // Request Type. - equal(this.readInt32(), REQUEST_SIM_IO); - - // Token : we don't care - this.readInt32(); - - // command. - equal(this.readInt32(), ICC_COMMAND_UPDATE_RECORD); - - // fileId. - equal(this.readInt32(), fileId); - - // pathId. - if (ril.appType == CARD_APPTYPE_SIM || ril.appType == CARD_APPTYPE_RUIM) { - equal(this.readString(), - EF_PATH_MF_SIM + EF_PATH_DF_TELECOM); - } else{ - equal(this.readString(), - EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_DF_PHONEBOOK); - } - - // p1. - equal(this.readInt32(), RECORD_NUMBER); - - // p2. - equal(this.readInt32(), READ_RECORD_ABSOLUTE_MODE); - - // p3. - equal(this.readInt32(), RECORD_SIZE); - - // data. - let strLen = this.readInt32(); - // Extension record - for (let i = 0; i < RECORD_SIZE; i++) { - equal(pduHelper.readHexOctet(), 0xff); - } - - this.readStringDelimiter(strLen); - - // pin2. - equal(this.readString(), null); - - // AID. Ignore because it's from modem. - this.readInt32(); - }; - - recordHelper.cleanEFRecord(fileId, RECORD_NUMBER); - } - - ril.appType = CARD_APPTYPE_SIM; - do_test(ICC_EF_EXT1); - - run_next_test(); -}); - -/** - * Verify ICCRecordHelper.getADNLikeExtensionRecordNumber - */ -add_test(function test_get_adn_like_extension_record_number() { - const RECORD_SIZE = 0x20; - - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let record = context.ICCRecordHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - - function do_test(rawEF, expectedRecordNumber) { - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - // Write data size - buf.writeInt32(rawEF.length * 2); - - // Write ext - for (let i = 0; i < rawEF.length; i += 2) { - helper.writeHexOctet(parseInt(rawEF.substr(i, 2), 16)); - } - - // Write string delimiter - buf.writeStringDelimiter(rawEF.length); - options.recordSize = RECORD_SIZE; - if (options.callback) { - options.callback(options); - } - }; - - let isSuccess = false; - let successCb = function successCb(number) { - equal(number, expectedRecordNumber); - isSuccess = true; - }; - - let errorCb = function errorCb(errorMsg) { - do_print("Reading ADNLike failed, msg = " + errorMsg); - ok(false); - }; - - record.getADNLikeExtensionRecordNumber(ICC_EF_ADN, 1, successCb, errorCb); - ok(isSuccess); - } - - // Valid Extension, Alpha Id(Encoded with GSM 8 bit): "Contact001", - // Dialling Number: 99887766554433221100, Ext1: 0x01 - do_test("436f6e74616374303031ffffffffffffffff0b8199887766554433221100ff01", 0x01); - // Empty Extension, Alpha Id(Encoded with GSM 8 bit): "Contact001", Ext1: 0xff - do_test("436f6e74616374303031ffffffffffffffffffffffffffffffffffffffffffff", 0xff); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_icc_ICCUtilsHelper.js b/dom/system/gonk/tests/test_ril_worker_icc_ICCUtilsHelper.js deleted file mode 100644 index b23d0b598..000000000 --- a/dom/system/gonk/tests/test_ril_worker_icc_ICCUtilsHelper.js +++ /dev/null @@ -1,326 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Verify ICCUtilsHelper.isICCServiceAvailable. - */ -add_test(function test_is_icc_service_available() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ICCUtilsHelper = context.ICCUtilsHelper; - let RIL = context.RIL; - - function test_table(sst, geckoService, simEnabled, usimEnabled) { - RIL.iccInfoPrivate.sst = sst; - RIL.appType = CARD_APPTYPE_SIM; - equal(ICCUtilsHelper.isICCServiceAvailable(geckoService), simEnabled); - RIL.appType = CARD_APPTYPE_USIM; - equal(ICCUtilsHelper.isICCServiceAvailable(geckoService), usimEnabled); - } - - test_table([0x08], "ADN", true, false); - test_table([0x08], "FDN", false, false); - test_table([0x08], "SDN", false, true); - - run_next_test(); -}); - -/** - * Verify ICCUtilsHelper.isGsm8BitAlphabet - */ -add_test(function test_is_gsm_8bit_alphabet() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ICCUtilsHelper = context.ICCUtilsHelper; - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - - equal(ICCUtilsHelper.isGsm8BitAlphabet(langTable), true); - equal(ICCUtilsHelper.isGsm8BitAlphabet(langShiftTable), true); - equal(ICCUtilsHelper.isGsm8BitAlphabet("\uaaaa"), false); - - run_next_test(); -}); - -/** - * Verify ICCUtilsHelper.parsePbrTlvs - */ -add_test(function test_parse_pbr_tlvs() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - - let pbrTlvs = [ - {tag: ICC_USIM_TYPE1_TAG, - length: 0x0F, - value: [{tag: ICC_USIM_EFADN_TAG, - length: 0x03, - value: [0x4F, 0x3A, 0x02]}, - {tag: ICC_USIM_EFIAP_TAG, - length: 0x03, - value: [0x4F, 0x25, 0x01]}, - {tag: ICC_USIM_EFPBC_TAG, - length: 0x03, - value: [0x4F, 0x09, 0x04]}] - }, - {tag: ICC_USIM_TYPE2_TAG, - length: 0x05, - value: [{tag: ICC_USIM_EFEMAIL_TAG, - length: 0x03, - value: [0x4F, 0x50, 0x0B]}, - {tag: ICC_USIM_EFANR_TAG, - length: 0x03, - value: [0x4F, 0x11, 0x02]}, - {tag: ICC_USIM_EFANR_TAG, - length: 0x03, - value: [0x4F, 0x12, 0x03]}] - }, - {tag: ICC_USIM_TYPE3_TAG, - length: 0x0A, - value: [{tag: ICC_USIM_EFCCP1_TAG, - length: 0x03, - value: [0x4F, 0x3D, 0x0A]}, - {tag: ICC_USIM_EFEXT1_TAG, - length: 0x03, - value: [0x4F, 0x4A, 0x03]}] - }, - ]; - - let pbr = context.ICCUtilsHelper.parsePbrTlvs(pbrTlvs); - equal(pbr.adn.fileId, 0x4F3a); - equal(pbr.iap.fileId, 0x4F25); - equal(pbr.pbc.fileId, 0x4F09); - equal(pbr.email.fileId, 0x4F50); - equal(pbr.anr0.fileId, 0x4f11); - equal(pbr.anr1.fileId, 0x4f12); - equal(pbr.ccp1.fileId, 0x4F3D); - equal(pbr.ext1.fileId, 0x4F4A); - - run_next_test(); -}); - -/** - * Verify MCC and MNC parsing - */ -add_test(function test_mcc_mnc_parsing() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.ICCUtilsHelper; - - function do_test(imsi, mncLength, expectedMcc, expectedMnc) { - let result = helper.parseMccMncFromImsi(imsi, mncLength); - - if (!imsi) { - equal(result, null); - return; - } - - equal(result.mcc, expectedMcc); - equal(result.mnc, expectedMnc); - } - - // Test the imsi is null. - do_test(null, null, null, null); - - // Test MCC is Taiwan - do_test("466923202422409", 0x02, "466", "92"); - do_test("466923202422409", 0x03, "466", "923"); - do_test("466923202422409", null, "466", "92"); - - // Test MCC is US - do_test("310260542718417", 0x02, "310", "26"); - do_test("310260542718417", 0x03, "310", "260"); - do_test("310260542718417", null, "310", "260"); - - run_next_test(); -}); - -add_test(function test_get_network_name_from_icc() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let RIL = context.RIL; - let ICCUtilsHelper = context.ICCUtilsHelper; - - function testGetNetworkNameFromICC(operatorData, expectedResult) { - let result = ICCUtilsHelper.getNetworkNameFromICC(operatorData.mcc, - operatorData.mnc, - operatorData.lac); - - if (expectedResult == null) { - equal(result, expectedResult); - } else { - equal(result.fullName, expectedResult.longName); - equal(result.shortName, expectedResult.shortName); - } - } - - // Before EF_OPL and EF_PNN have been loaded. - testGetNetworkNameFromICC({mcc: "123", mnc: "456", lac: 0x1000}, null); - testGetNetworkNameFromICC({mcc: "321", mnc: "654", lac: 0x2000}, null); - - // Set HPLMN - RIL.iccInfo.mcc = "123"; - RIL.iccInfo.mnc = "456"; - - RIL.voiceRegistrationState = { - cell: { - gsmLocationAreaCode: 0x1000 - } - }; - RIL.operator = {}; - - // Set EF_PNN - RIL.iccInfoPrivate = { - PNN: [ - {"fullName": "PNN1Long", "shortName": "PNN1Short"}, - {"fullName": "PNN2Long", "shortName": "PNN2Short"}, - {"fullName": "PNN3Long", "shortName": "PNN3Short"}, - {"fullName": "PNN4Long", "shortName": "PNN4Short"}, - {"fullName": "PNN5Long", "shortName": "PNN5Short"}, - {"fullName": "PNN6Long", "shortName": "PNN6Short"}, - {"fullName": "PNN7Long", "shortName": "PNN7Short"}, - {"fullName": "PNN8Long", "shortName": "PNN8Short"} - ] - }; - - // EF_OPL isn't available - ICCUtilsHelper.isICCServiceAvailable = function fakeIsICCServiceAvailable(service) { - return false; - }; - - // EF_OPL isn't available and current isn't in HPLMN, - testGetNetworkNameFromICC({mcc: "321", mnc: "654", lac: 0x1000}, null); - - // EF_OPL isn't available and current is in HPLMN, - // the first record of PNN should be returned. - testGetNetworkNameFromICC({mcc: "123", mnc: "456", lac: 0x1000}, - {longName: "PNN1Long", shortName: "PNN1Short"}); - - // EF_OPL is available - ICCUtilsHelper.isICCServiceAvailable = function fakeIsICCServiceAvailable(service) { - return service === "OPL"; - }; - - // Set EF_OPL - RIL.iccInfoPrivate.OPL = [ - { - "mcc": "123", - "mnc": "456", - "lacTacStart": 0, - "lacTacEnd": 0xFFFE, - "pnnRecordId": 4 - }, - { - "mcc": "321", - "mnc": "654", - "lacTacStart": 0, - "lacTacEnd": 0x0010, - "pnnRecordId": 3 - }, - { - "mcc": "321", - "mnc": "654", - "lacTacStart": 0x0100, - "lacTacEnd": 0x1010, - "pnnRecordId": 2 - }, - { - "mcc": ";;;", - "mnc": "01", - "lacTacStart": 0, - "lacTacEnd": 0xFFFE, - "pnnRecordId": 5 - }, - { - "mcc": "00;", - "mnc": "02", - "lacTacStart": 0, - "lacTacEnd": 0xFFFE, - "pnnRecordId": 6 - }, - { - "mcc": "001", - "mnc": ";;", - "lacTacStart": 0, - "lacTacEnd": 0xFFFE, - "pnnRecordId": 7 - }, - { - "mcc": "002", - "mnc": "0;", - "lacTacStart": 0, - "lacTacEnd": 0xFFFE, - "pnnRecordId": 8 - } - ]; - - // Both EF_PNN and EF_OPL are presented, and current PLMN is HPLMN, - testGetNetworkNameFromICC({mcc: "123", mnc: "456", lac: 0x1000}, - {longName: "PNN4Long", shortName: "PNN4Short"}); - - // Current PLMN is not HPLMN, and according to LAC, we should get - // the second PNN record. - testGetNetworkNameFromICC({mcc: "321", mnc: "654", lac: 0x1000}, - {longName: "PNN2Long", shortName: "PNN2Short"}); - - // Current PLMN is not HPLMN, and according to LAC, we should get - // the thrid PNN record. - testGetNetworkNameFromICC({mcc: "321", mnc: "654", lac: 0x0001}, - {longName: "PNN3Long", shortName: "PNN3Short"}); - - // Current PLMN is not HPLMN, and according to LAC, we should get - // the 5th PNN record after wild char (ie: ';') handling. - testGetNetworkNameFromICC({mcc: "001", mnc: "01", lac: 0x0001}, - {longName: "PNN5Long", shortName: "PNN5Short"}); - - // Current PLMN is not HPLMN, and according to LAC, we should get - // the 6th PNN record after wild char (ie: ';') handling. - testGetNetworkNameFromICC({mcc: "001", mnc: "02", lac: 0x0001}, - {longName: "PNN6Long", shortName: "PNN6Short"}); - - // Current PLMN is not HPLMN, and according to LAC, we should get - // the 7th PNN record after wild char (ie: ';') handling. - testGetNetworkNameFromICC({mcc: "001", mnc: "03", lac: 0x0001}, - {longName: "PNN7Long", shortName: "PNN7Short"}); - - // Current PLMN is not HPLMN, and according to LAC, we should get - // the 8th PNN record after wild char (ie: ';') handling. - testGetNetworkNameFromICC({mcc: "002", mnc: "03", lac: 0x0001}, - {longName: "PNN8Long", shortName: "PNN8Short"}); - - run_next_test(); -}); - -/** - * Verify ICCUtilsHelper.isCphsServiceAvailable. - */ -add_test(function test_is_cphs_service_available() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ICCUtilsHelper = context.ICCUtilsHelper; - let RIL = context.RIL; - RIL.iccInfoPrivate.cphsSt = new Uint8Array(2); - - function test_table(cphsSt, geckoService) { - RIL.iccInfoPrivate.cphsSt.set(cphsSt); - - for (let service in GECKO_ICC_SERVICES.cphs) { - equal(ICCUtilsHelper.isCphsServiceAvailable(service), - geckoService == service); - } - } - - test_table([0x03, 0x00], "CSP"); - test_table([0x0C, 0x00], "SST"); - test_table([0x30, 0x00], "MBN"); - test_table([0xC0, 0x00], "ONSF"); - test_table([0x00, 0x03], "INFO_NUM"); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_icc_IconLoader.js b/dom/system/gonk/tests/test_ril_worker_icc_IconLoader.js deleted file mode 100644 index 8bcd26ffe..000000000 --- a/dom/system/gonk/tests/test_ril_worker_icc_IconLoader.js +++ /dev/null @@ -1,771 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Verify IconLoader.loadIcons with recordNumbers array length being 1. - * Query images of one record at a time. - */ -add_test(function test_load_icon_basic() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - let iconLoader = context.IconLoader; - let simRecordHelper = context.SimRecordHelper; - - let test_data = [ - {rawData: [ - {codingScheme: ICC_IMG_CODING_SCHEME_BASIC, - width: 0x10, - height: 0x10, - body: [0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x00, 0x9d, 0xe9, 0xa1, 0x2d, 0xa1, 0x2d, 0xa1, 0x2b, - 0xa1, 0x2b, 0x9d, 0xe9, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff]}], - expected: [ - {width: 0x10, - height: 0x10, - pixels: [/* 1st byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 2nd byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 3rd byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 4th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 5th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 6th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 7th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 8th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 9th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 10th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 11th byte of body: 0x9d */ - 0xffffffff, 0x000000ff, 0x000000ff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 12th byte of body: 0xe9 */ - 0xffffffff, 0xffffffff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 13th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 14th byte of body: 0x2d */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 15th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 16th byte of body: 0x2d */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 17th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 18th byte of body: 0x2b */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0xffffffff, 0xffffffff, - /* 19th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 20th byte of body: 0x2b */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0xffffffff, 0xffffffff, - /* 21th byte of body: 0x9d */ - 0xffffffff, 0x000000ff, 0x000000ff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 22th byte of body: 0xe9 */ - 0xffffffff, 0xffffffff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 23th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 24th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 25th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 26th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 27th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 28th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 29th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 30th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 31th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 32th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff]}]}, - {rawData: [ - {codingScheme: ICC_IMG_CODING_SCHEME_COLOR, - width: 0x10, - height: 0x10, - bitsPerImgPoint: 0x04, - numOfClutEntries: 0x10, - body: [0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xcf, 0xfc, 0xcc, 0xfc, 0xcc, - 0xcf, 0xcf, 0xfc, 0xcf, 0xcf, 0xff, 0xfc, 0xff, 0xcf, - 0xcc, 0xfc, 0xcf, 0xcf, 0xff, 0xfc, 0xff, 0xcf, 0xcc, - 0xfc, 0xcf, 0xcf, 0xff, 0xfc, 0xff, 0xcf, 0xcf, 0xcc, - 0xcf, 0xcf, 0xff, 0xfc, 0xff, 0xcf, 0xcf, 0xcc, 0xcf, - 0xfc, 0xcc, 0xfc, 0xcc, 0xcf, 0xcf, 0xfc, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99], - clut: [0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x80, - 0x00, 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x80, - 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff]}], - expected: [ - {width: 0x10, - height: 0x10, - pixels: [0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, - 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, - 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, - 0xff0000ff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0x0000ffff, 0xffffffff, 0xffffffff, 0x0000ffff, 0x0000ffff, - 0x0000ffff, 0xffffffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, - 0x0000ffff, 0xffffffff, 0x0000ffff, 0xffffffff, 0xffffffff, - 0x0000ffff, 0x0000ffff, 0xffffffff, 0x0000ffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0x0000ffff, 0xffffffff, - 0xffffffff, 0x0000ffff, 0xffffffff, 0x0000ffff, 0x0000ffff, - 0xffffffff, 0x0000ffff, 0x0000ffff, 0xffffffff, 0x0000ffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0000ffff, - 0xffffffff, 0xffffffff, 0x0000ffff, 0xffffffff, 0x0000ffff, - 0x0000ffff, 0xffffffff, 0x0000ffff, 0x0000ffff, 0xffffffff, - 0x0000ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0x0000ffff, 0xffffffff, 0xffffffff, 0x0000ffff, 0xffffffff, - 0x0000ffff, 0xffffffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, - 0xffffffff, 0x0000ffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x0000ffff, 0xffffffff, 0xffffffff, 0x0000ffff, - 0xffffffff, 0x0000ffff, 0xffffffff, 0x0000ffff, 0x0000ffff, - 0x0000ffff, 0xffffffff, 0xffffffff, 0x0000ffff, 0x0000ffff, - 0x0000ffff, 0xffffffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, - 0x0000ffff, 0xffffffff, 0x0000ffff, 0xffffffff, 0xffffffff, - 0x0000ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, - 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, - 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, - 0xff0000ff]}]}, - {rawData: [ - {codingScheme: ICC_IMG_CODING_SCHEME_COLOR, - width: 0x03, - height: 0x03, - bitsPerImgPoint: 0x05, - numOfClutEntries: 0x20, - body: [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88], - clut: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, - 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, - 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, - 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, - 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, - 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, - 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, - 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f]}, - {codingScheme: ICC_IMG_CODING_SCHEME_BASIC, - width: 0x10, - height: 0x10, - body: [0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x00, 0x9d, 0xe9, 0xa1, 0x2d, 0xa1, 0x2d, 0xa1, 0x2b, - 0xa1, 0x2b, 0x9d, 0xe9, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff]}], - expected: [ - {width: 0x03, - height: 0x03, - pixels: [0x000102ff, 0x060708ff, 0x0c0d0eff, 0x121314ff, 0x18191aff, - 0x1e1f20ff, 0x242526ff, 0x2a2b2cff, 0x333435ff]}, - {width: 0x10, - height: 0x10, - pixels: [/* 1st byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 2nd byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 3rd byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 4th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 5th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 6th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 7th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 8th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 9th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 10th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 11th byte of body: 0x9d */ - 0xffffffff, 0x000000ff, 0x000000ff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 12th byte of body: 0xe9 */ - 0xffffffff, 0xffffffff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 13th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 14th byte of body: 0x2d */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 15th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 16th byte of body: 0x2d */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 17th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 18th byte of body: 0x2b */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0xffffffff, 0xffffffff, - /* 19th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 20th byte of body: 0x2b */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0xffffffff, 0xffffffff, - /* 21th byte of body: 0x9d */ - 0xffffffff, 0x000000ff, 0x000000ff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 22th byte of body: 0xe9 */ - 0xffffffff, 0xffffffff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 23th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 24th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 25th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 26th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 27th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 28th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 29th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 30th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 31th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 32th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff]}]}, - {rawData: [ - {codingScheme: ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY, - width: 0x04, - height: 0x04, - bitsPerImgPoint: 0x04, - numOfClutEntries: 0x10, - body: [0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88], - clut: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, - 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, - 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, - 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, - 0x2d, 0x2e, 0x2f]}], - expected: [ - {width: 0x04, - height: 0x04, - pixels: [0x00000000, 0x00000000, 0x2a2b2cff, 0x2a2b2cff, 0x272829ff, - 0x272829ff, 0x242526ff, 0x242526ff, 0x212223ff, 0x212223ff, - 0x1e1f20ff, 0x1e1f20ff, 0x1b1c1dff, 0x1b1c1dff, 0x18191aff, - 0x18191aff]}]}]; - - function do_test(test_data, expected) { - simRecordHelper.readIMG = function fakeReadIMG(recordNumber, onsuccess, onerror) { - onsuccess(test_data); - }; - - let onsuccess = function(icons) { - // Query one record at a time. - equal(icons.length, 1); - equal(icons[0].length, expected.length); - for (let i = 0; i < icons[0].length; i++) { - // Read the i_th image of the record. - let icon = icons[0][i]; - let exp = expected[i]; - equal(icon.width, exp.width); - equal(icon.height, exp.height); - equal(icon.pixels.length, exp.pixels.length); - for (let j = 0; j < icon.pixels.length; j++) { - equal(icon.pixels[j], exp.pixels[j]); - } - } - }; - - iconLoader.loadIcons([0], onsuccess); - } - - for (let i = 0; i < test_data.length; i++) { - do_test(test_data[i].rawData, test_data[i].expected); - } - - run_next_test(); -}); - -/** - * Verify IconLoader.loadIcons. - */ -add_test(function test_load_icons() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - let iconLoader = context.IconLoader; - let simRecordHelper = context.SimRecordHelper; - - let test_data = { - rawData: [ - // Record 1. - [{codingScheme: ICC_IMG_CODING_SCHEME_BASIC, - width: 0x10, - height: 0x10, - body: [0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x00, 0x9d, 0xe9, 0xa1, 0x2d, 0xa1, 0x2d, 0xa1, 0x2b, - 0xa1, 0x2b, 0x9d, 0xe9, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff]}], - // Record 2. - [{codingScheme: ICC_IMG_CODING_SCHEME_COLOR, - width: 0x10, - height: 0x10, - bitsPerImgPoint: 0x04, - numOfClutEntries: 0x10, - body: [0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xcf, 0xfc, 0xcc, 0xfc, 0xcc, - 0xcf, 0xcf, 0xfc, 0xcf, 0xcf, 0xff, 0xfc, 0xff, 0xcf, - 0xcc, 0xfc, 0xcf, 0xcf, 0xff, 0xfc, 0xff, 0xcf, 0xcc, - 0xfc, 0xcf, 0xcf, 0xff, 0xfc, 0xff, 0xcf, 0xcf, 0xcc, - 0xcf, 0xcf, 0xff, 0xfc, 0xff, 0xcf, 0xcf, 0xcc, 0xcf, - 0xfc, 0xcc, 0xfc, 0xcc, 0xcf, 0xcf, 0xfc, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99], - clut: [0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x80, - 0x00, 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x80, - 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff]}], - // Record 3. - [{codingScheme: ICC_IMG_CODING_SCHEME_COLOR, - width: 0x03, - height: 0x03, - bitsPerImgPoint: 0x05, - numOfClutEntries: 0x20, - body: [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88], - clut: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, - 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, - 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, - 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, - 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, - 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, - 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, - 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f]}, - {codingScheme: ICC_IMG_CODING_SCHEME_BASIC, - width: 0x10, - height: 0x10, - body: [0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x00, 0x9d, 0xe9, 0xa1, 0x2d, 0xa1, 0x2d, 0xa1, 0x2b, - 0xa1, 0x2b, 0x9d, 0xe9, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff]}], - // Record 4. - [{codingScheme: ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY, - width: 0x04, - height: 0x04, - bitsPerImgPoint: 0x04, - numOfClutEntries: 0x10, - body: [0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88], - clut: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, - 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, - 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, - 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, - 0x2d, 0x2e, 0x2f]}]], - expected: [ - // Record 1. - [{width: 0x10, - height: 0x10, - pixels: [/* 1st byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 2nd byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 3rd byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 4th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 5th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 6th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 7th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 8th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 9th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 10th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 11th byte of body: 0x9d */ - 0xffffffff, 0x000000ff, 0x000000ff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 12th byte of body: 0xe9 */ - 0xffffffff, 0xffffffff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 13th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 14th byte of body: 0x2d */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 15th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 16th byte of body: 0x2d */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 17th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 18th byte of body: 0x2b */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0xffffffff, 0xffffffff, - /* 19th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 20th byte of body: 0x2b */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0xffffffff, 0xffffffff, - /* 21th byte of body: 0x9d */ - 0xffffffff, 0x000000ff, 0x000000ff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 22th byte of body: 0xe9 */ - 0xffffffff, 0xffffffff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 23th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 24th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 25th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 26th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 27th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 28th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 29th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 30th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 31th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 32th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff]}], - // Record 2. - [{width: 0x10, - height: 0x10, - pixels: [0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, - 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, - 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, - 0xff0000ff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0x0000ffff, 0xffffffff, 0xffffffff, 0x0000ffff, 0x0000ffff, - 0x0000ffff, 0xffffffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, - 0x0000ffff, 0xffffffff, 0x0000ffff, 0xffffffff, 0xffffffff, - 0x0000ffff, 0x0000ffff, 0xffffffff, 0x0000ffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0x0000ffff, 0xffffffff, - 0xffffffff, 0x0000ffff, 0xffffffff, 0x0000ffff, 0x0000ffff, - 0xffffffff, 0x0000ffff, 0x0000ffff, 0xffffffff, 0x0000ffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0000ffff, - 0xffffffff, 0xffffffff, 0x0000ffff, 0xffffffff, 0x0000ffff, - 0x0000ffff, 0xffffffff, 0x0000ffff, 0x0000ffff, 0xffffffff, - 0x0000ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0x0000ffff, 0xffffffff, 0xffffffff, 0x0000ffff, 0xffffffff, - 0x0000ffff, 0xffffffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, - 0xffffffff, 0x0000ffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x0000ffff, 0xffffffff, 0xffffffff, 0x0000ffff, - 0xffffffff, 0x0000ffff, 0xffffffff, 0x0000ffff, 0x0000ffff, - 0x0000ffff, 0xffffffff, 0xffffffff, 0x0000ffff, 0x0000ffff, - 0x0000ffff, 0xffffffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, - 0x0000ffff, 0xffffffff, 0x0000ffff, 0xffffffff, 0xffffffff, - 0x0000ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, - 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, - 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, - 0xff0000ff]}], - // Record 3. - [{width: 0x03, - height: 0x03, - pixels: [0x000102ff, 0x060708ff, 0x0c0d0eff, 0x121314ff, 0x18191aff, - 0x1e1f20ff, 0x242526ff, 0x2a2b2cff, 0x333435ff]}, - {width: 0x10, - height: 0x10, - pixels: [/* 1st byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 2nd byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 3rd byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 4th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 5th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 6th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 7th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 8th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 9th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 10th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 11th byte of body: 0x9d */ - 0xffffffff, 0x000000ff, 0x000000ff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 12th byte of body: 0xe9 */ - 0xffffffff, 0xffffffff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 13th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 14th byte of body: 0x2d */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 15th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 16th byte of body: 0x2d */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 17th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 18th byte of body: 0x2b */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0xffffffff, 0xffffffff, - /* 19th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 20th byte of body: 0x2b */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0xffffffff, 0xffffffff, - /* 21th byte of body: 0x9d */ - 0xffffffff, 0x000000ff, 0x000000ff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 22th byte of body: 0xe9 */ - 0xffffffff, 0xffffffff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 23th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 24th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 25th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 26th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 27th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 28th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 29th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 30th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 31th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 32th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff]}], - // Record 4. - [{width: 0x04, - height: 0x04, - pixels: [0x00000000, 0x00000000, 0x2a2b2cff, 0x2a2b2cff, 0x272829ff, - 0x272829ff, 0x242526ff, 0x242526ff, 0x212223ff, 0x212223ff, - 0x1e1f20ff, 0x1e1f20ff, 0x1b1c1dff, 0x1b1c1dff, 0x18191aff, - 0x18191aff]}]]}; - - function do_test() { - simRecordHelper.readIMG = function fakeReadIMG(recordNumber, onsuccess, onerror) { - onsuccess(test_data.rawData[recordNumber]); - }; - - let onsuccess = function(icons) { - equal(icons.length, test_data.expected.length); - for (let i = 0; i < icons.length; i++) { - for (let j = 0; j < icons[i].length; j++) { - // Read the j_th image from the i_th record. - let icon = icons[i][j]; - let expected = test_data.expected[i][j]; - equal(icon.width, expected.width); - equal(icon.height, expected.height); - equal(icon.pixels.length, expected.pixels.length); - for (let k = 0; k < icon.pixels.length; k++) { - equal(icon.pixels[k], expected.pixels[k]); - } - } - } - }; - - let recordNumbers = [0, 1, 2, 3]; - iconLoader.loadIcons(recordNumbers, onsuccess); - } - - do_test(); - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_icc_SimRecordHelper.js b/dom/system/gonk/tests/test_ril_worker_icc_SimRecordHelper.js deleted file mode 100644 index 6500cc663..000000000 --- a/dom/system/gonk/tests/test_ril_worker_icc_SimRecordHelper.js +++ /dev/null @@ -1,1648 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Verify reading EF_AD and parsing MCC/MNC - */ -add_test(function test_reading_ad_and_parsing_mcc_mnc() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.SimRecordHelper; - let helper = context.GsmPDUHelper; - let ril = context.RIL; - let buf = context.Buf; - let io = context.ICCIOHelper; - - function do_test(mncLengthInEf, imsi, expectedMcc, expectedMnc) { - ril.iccInfoPrivate.imsi = imsi; - - io.loadTransparentEF = function fakeLoadTransparentEF(options) { - let ad = [0x00, 0x00, 0x00]; - if (typeof mncLengthInEf === 'number') { - ad.push(mncLengthInEf); - } - - // Write data size - buf.writeInt32(ad.length * 2); - - // Write data - for (let i = 0; i < ad.length; i++) { - helper.writeHexOctet(ad[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(ad.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - record.readAD(); - - equal(ril.iccInfo.mcc, expectedMcc); - equal(ril.iccInfo.mnc, expectedMnc); - } - - do_test(undefined, "466923202422409", "466", "92" ); - do_test(0x00, "466923202422409", "466", "92" ); - do_test(0x01, "466923202422409", "466", "92" ); - do_test(0x02, "466923202422409", "466", "92" ); - do_test(0x03, "466923202422409", "466", "923"); - do_test(0x04, "466923202422409", "466", "92" ); - do_test(0xff, "466923202422409", "466", "92" ); - - do_test(undefined, "310260542718417", "310", "260"); - do_test(0x00, "310260542718417", "310", "260"); - do_test(0x01, "310260542718417", "310", "260"); - do_test(0x02, "310260542718417", "310", "26" ); - do_test(0x03, "310260542718417", "310", "260"); - do_test(0x04, "310260542718417", "310", "260"); - do_test(0xff, "310260542718417", "310", "260"); - - run_next_test(); -}); - -add_test(function test_reading_optional_efs() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.SimRecordHelper; - let gsmPdu = context.GsmPDUHelper; - let ril = context.RIL; - let buf = context.Buf; - let io = context.ICCIOHelper; - - function buildSST(supportedEf) { - let sst = []; - let len = supportedEf.length; - for (let i = 0; i < len; i++) { - let index, bitmask, iccService; - if (ril.appType === CARD_APPTYPE_SIM) { - iccService = GECKO_ICC_SERVICES.sim[supportedEf[i]]; - iccService -= 1; - index = Math.floor(iccService / 4); - bitmask = 2 << ((iccService % 4) << 1); - } else if (ril.appType === CARD_APPTYPE_USIM){ - iccService = GECKO_ICC_SERVICES.usim[supportedEf[i]]; - iccService -= 1; - index = Math.floor(iccService / 8); - bitmask = 1 << ((iccService % 8) << 0); - } - - if (sst) { - sst[index] |= bitmask; - } - } - return sst; - } - - ril.updateCellBroadcastConfig = function fakeUpdateCellBroadcastConfig() { - // Ignore updateCellBroadcastConfig after reading SST - }; - - function do_test(sst, supportedEf) { - // Clone supportedEf to local array for testing - let testEf = supportedEf.slice(0); - - record.readMSISDN = function fakeReadMSISDN() { - testEf.splice(testEf.indexOf("MSISDN"), 1); - }; - - record.readMBDN = function fakeReadMBDN() { - testEf.splice(testEf.indexOf("MDN"), 1); - }; - - record.readMWIS = function fakeReadMWIS() { - testEf.splice(testEf.indexOf("MWIS"), 1); - }; - - io.loadTransparentEF = function fakeLoadTransparentEF(options) { - // Write data size - buf.writeInt32(sst.length * 2); - - // Write data - for (let i = 0; i < sst.length; i++) { - gsmPdu.writeHexOctet(sst[i] || 0); - } - - // Write string delimiter - buf.writeStringDelimiter(sst.length * 2); - - if (options.callback) { - options.callback(options); - } - - if (testEf.length !== 0) { - do_print("Un-handled EF: " + JSON.stringify(testEf)); - ok(false); - } - }; - - record.readSST(); - } - - // TODO: Add all necessary optional EFs eventually - let supportedEf = ["MSISDN", "MDN", "MWIS"]; - ril.appType = CARD_APPTYPE_SIM; - do_test(buildSST(supportedEf), supportedEf); - ril.appType = CARD_APPTYPE_USIM; - do_test(buildSST(supportedEf), supportedEf); - - run_next_test(); -}); - -/** - * Verify fetchSimRecords. - */ -add_test(function test_fetch_sim_records() { - let worker = newWorker(); - let context = worker.ContextPool._contexts[0]; - let RIL = context.RIL; - let iccRecord = context.ICCRecordHelper; - let simRecord = context.SimRecordHelper; - - function testFetchSimRecordes(expectCalled, expectCphsSuccess) { - let ifCalled = []; - - RIL.getIMSI = function() { - ifCalled.push("getIMSI"); - }; - - simRecord.readAD = function() { - ifCalled.push("readAD"); - }; - - simRecord.readCphsInfo = function(onsuccess, onerror) { - ifCalled.push("readCphsInfo"); - if (expectCphsSuccess) { - onsuccess(); - } else { - onerror(); - } - }; - - simRecord.readSST = function() { - ifCalled.push("readSST"); - }; - - simRecord.fetchSimRecords(); - - for (let i = 0; i < expectCalled.length; i++ ) { - if (ifCalled[i] != expectCalled[i]) { - do_print(expectCalled[i] + " is not called."); - ok(false); - } - } - } - - let expectCalled = ["getIMSI", "readAD", "readCphsInfo", "readSST"]; - testFetchSimRecordes(expectCalled, true); - testFetchSimRecordes(expectCalled, false); - - run_next_test(); -}); - -/** - * Verify SimRecordHelper.readMWIS - */ -add_test(function test_read_mwis() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let recordHelper = context.SimRecordHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - let mwisData; - let postedMessage; - - worker.postMessage = function fakePostMessage(message) { - postedMessage = message; - }; - - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - if (mwisData) { - // Write data size - buf.writeInt32(mwisData.length * 2); - - // Write MWIS - for (let i = 0; i < mwisData.length; i++) { - helper.writeHexOctet(mwisData[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(mwisData.length * 2); - - options.recordSize = mwisData.length; - if (options.callback) { - options.callback(options); - } - } else { - do_print("mwisData[] is not set."); - } - }; - - function buildMwisData(isActive, msgCount) { - if (msgCount < 0 || msgCount === GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN) { - msgCount = 0; - } else if (msgCount > 255) { - msgCount = 255; - } - - mwisData = [ (isActive) ? 0x01 : 0x00, - msgCount, - 0xFF, 0xFF, 0xFF ]; - } - - function do_test(isActive, msgCount) { - buildMwisData(isActive, msgCount); - recordHelper.readMWIS(); - - equal("iccmwis", postedMessage.rilMessageType); - equal(isActive, postedMessage.mwi.active); - equal((isActive) ? msgCount : 0, postedMessage.mwi.msgCount); - } - - do_test(true, GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN); - do_test(true, 1); - do_test(true, 255); - - do_test(false, 0); - do_test(false, 255); // Test the corner case when mwi is disable with incorrect msgCount. - - run_next_test(); -}); - -/** - * Verify SimRecordHelper.updateMWIS - */ -add_test(function test_update_mwis() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let ril = context.RIL; - ril.appType = CARD_APPTYPE_USIM; - ril.iccInfoPrivate.mwis = [0x00, 0x00, 0x00, 0x00, 0x00]; - let recordHelper = context.SimRecordHelper; - let buf = context.Buf; - let ioHelper = context.ICCIOHelper; - let recordSize = ril.iccInfoPrivate.mwis.length; - let recordNum = 1; - - ioHelper.updateLinearFixedEF = function(options) { - options.pathId = context.ICCFileHelper.getEFPath(options.fileId); - options.command = ICC_COMMAND_UPDATE_RECORD; - options.p1 = options.recordNumber; - options.p2 = READ_RECORD_ABSOLUTE_MODE; - options.p3 = recordSize; - ril.iccIO(options); - }; - - function do_test(isActive, count) { - let mwis = ril.iccInfoPrivate.mwis; - let isUpdated = false; - - function buildMwisData() { - let result = mwis.slice(0); - result[0] = isActive? (mwis[0] | 0x01) : (mwis[0] & 0xFE); - result[1] = (count === GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN) ? 0 : count; - - return result; - } - - buf.sendParcel = function() { - isUpdated = true; - - // Request Type. - equal(this.readInt32(), REQUEST_SIM_IO); - - // Token : we don't care - this.readInt32(); - - // command. - equal(this.readInt32(), ICC_COMMAND_UPDATE_RECORD); - - // fileId. - equal(this.readInt32(), ICC_EF_MWIS); - - // pathId. - equal(this.readString(), - EF_PATH_MF_SIM + ((ril.appType === CARD_APPTYPE_USIM) ? EF_PATH_ADF_USIM : EF_PATH_DF_GSM)); - - // p1. - equal(this.readInt32(), recordNum); - - // p2. - equal(this.readInt32(), READ_RECORD_ABSOLUTE_MODE); - - // p3. - equal(this.readInt32(), recordSize); - - // data. - let strLen = this.readInt32(); - equal(recordSize * 2, strLen); - let expectedMwis = buildMwisData(); - for (let i = 0; i < recordSize; i++) { - equal(expectedMwis[i], pduHelper.readHexOctet()); - } - this.readStringDelimiter(strLen); - - // pin2. - equal(this.readString(), null); - - // AID. Ignore because it's from modem. - this.readInt32(); - }; - - ok(!isUpdated); - - recordHelper.updateMWIS({ active: isActive, - msgCount: count }); - - ok((ril.iccInfoPrivate.mwis) ? isUpdated : !isUpdated); - } - - do_test(true, GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN); - do_test(true, 1); - do_test(true, 255); - - do_test(false, 0); - - // Test if Path ID is correct for SIM. - ril.appType = CARD_APPTYPE_SIM; - do_test(false, 0); - - // Test if loadLinearFixedEF() is not invoked in updateMWIS() when - // EF_MWIS is not loaded/available. - delete ril.iccInfoPrivate.mwis; - do_test(false, 0); - - run_next_test(); -}); - -/** - * Verify the call flow of receiving Class 2 SMS stored in SIM: - * 1. UNSOLICITED_RESPONSE_NEW_SMS_ON_SIM. - * 2. SimRecordHelper.readSMS(). - * 3. sendChromeMessage() with rilMessageType == "sms-received". - */ -add_test(function test_read_new_sms_on_sim() { - // Instead of reusing newUint8Worker defined in this file, - // we define our own worker to fake the methods in WorkerBuffer dynamically. - function newSmsOnSimWorkerHelper() { - let _postedMessage; - let _worker = newWorker({ - postRILMessage: function(data) { - }, - postMessage: function(message) { - _postedMessage = message; - } - }); - - _worker.debug = do_print; - - return { - get postedMessage() { - return _postedMessage; - }, - get worker() { - return _worker; - }, - fakeWokerBuffer: function() { - let context = _worker.ContextPool._contexts[0]; - let index = 0; // index for read - let buf = []; - context.Buf.writeUint8 = function(value) { - buf.push(value); - }; - context.Buf.readUint8 = function() { - return buf[index++]; - }; - context.Buf.seekIncoming = function(offset) { - index += offset; - }; - context.Buf.getReadAvailable = function() { - return buf.length - index; - }; - } - }; - } - - let workerHelper = newSmsOnSimWorkerHelper(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.ICCIOHelper.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - // SimStatus: Unread, SMSC:+0123456789, Sender: +9876543210, Text: How are you? - let SimSmsPduHex = "0306911032547698040A9189674523010000208062917314080CC8F71D14969741F977FD07" - // In 4.2.25 EF_SMS Short Messages of 3GPP TS 31.102: - // 1. Record length == 176 bytes. - // 2. Any bytes in the record following the TPDU shall be filled with 'FF'. - + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"; - - workerHelper.fakeWokerBuffer(); - - context.Buf.writeString(SimSmsPduHex); - - options.recordSize = 176; // Record length is fixed to 176 bytes. - if (options.callback) { - options.callback(options); - } - }; - - function newSmsOnSimParcel() { - let data = new Uint8Array(4 + 4); // Int32List with 1 element. - let offset = 0; - - function writeInt(value) { - data[offset++] = value & 0xFF; - data[offset++] = (value >> 8) & 0xFF; - data[offset++] = (value >> 16) & 0xFF; - data[offset++] = (value >> 24) & 0xFF; - } - - writeInt(1); // Length of Int32List - writeInt(1); // RecordNum = 1. - - return newIncomingParcel(-1, - RESPONSE_TYPE_UNSOLICITED, - UNSOLICITED_RESPONSE_NEW_SMS_ON_SIM, - data); - } - - function do_test() { - worker.onRILMessage(0, newSmsOnSimParcel()); - - let postedMessage = workerHelper.postedMessage; - - equal("sms-received", postedMessage.rilMessageType); - equal("+0123456789", postedMessage.SMSC); - equal("+9876543210", postedMessage.sender); - equal("How are you?", postedMessage.body); - } - - do_test(); - - run_next_test(); -}); - -/** - * Verify the result of updateDisplayCondition after reading EF_SPDI | EF_SPN. - */ -add_test(function test_update_display_condition() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.SimRecordHelper; - let helper = context.GsmPDUHelper; - let ril = context.RIL; - let buf = context.Buf; - let io = context.ICCIOHelper; - - function do_test_spdi() { - // No EF_SPN, but having EF_SPDI. - // It implies "ril.iccInfoPrivate.spnDisplayCondition = undefined;". - io.loadTransparentEF = function fakeLoadTransparentEF(options) { - // PLMN lists are : 234-136 and 466-92. - let spdi = [0xA3, 0x0B, 0x80, 0x09, 0x32, 0x64, 0x31, 0x64, 0x26, 0x9F, - 0xFF, 0xFF, 0xFF]; - - // Write data size. - buf.writeInt32(spdi.length * 2); - - // Write data. - for (let i = 0; i < spdi.length; i++) { - helper.writeHexOctet(spdi[i]); - } - - // Write string delimiter. - buf.writeStringDelimiter(spdi.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - record.readSPDI(); - - equal(ril.iccInfo.isDisplayNetworkNameRequired, true); - equal(ril.iccInfo.isDisplaySpnRequired, false); - } - - function do_test_spn(displayCondition, - expectedPlmnNameDisplay, - expectedSpnDisplay) { - io.loadTransparentEF = function fakeLoadTransparentEF(options) { - // "Android" as Service Provider Name. - let spn = [0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64]; - if (typeof displayCondition === 'number') { - spn.unshift(displayCondition); - } - - // Write data size. - buf.writeInt32(spn.length * 2); - - // Write data. - for (let i = 0; i < spn.length; i++) { - helper.writeHexOctet(spn[i]); - } - - // Write string delimiter. - buf.writeStringDelimiter(spn.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - record.readSPN(); - - equal(ril.iccInfo.isDisplayNetworkNameRequired, expectedPlmnNameDisplay); - equal(ril.iccInfo.isDisplaySpnRequired, expectedSpnDisplay); - } - - // Create empty operator object. - ril.operator = {}; - // Setup SIM MCC-MNC to 310-260 as home network. - ril.iccInfo.mcc = 310; - ril.iccInfo.mnc = 260; - - do_test_spdi(); - - // No network. - do_test_spn(0x00, true, true); - do_test_spn(0x01, true, true); - do_test_spn(0x02, true, false); - do_test_spn(0x03, true, false); - - // Home network. - ril.operator.mcc = 310; - ril.operator.mnc = 260; - do_test_spn(0x00, false, true); - do_test_spn(0x01, true, true); - do_test_spn(0x02, false, true); - do_test_spn(0x03, true, true); - - // Not HPLMN but in PLMN list. - ril.iccInfoPrivate.SPDI = [{"mcc":"234","mnc":"136"},{"mcc":"466","mnc":"92"}]; - ril.operator.mcc = 466; - ril.operator.mnc = 92; - do_test_spn(0x00, false, true); - do_test_spn(0x01, true, true); - do_test_spn(0x02, false, true); - do_test_spn(0x03, true, true); - ril.iccInfoPrivate.SPDI = null; // reset SPDI to null; - - // Non-Home network. - ril.operator.mcc = 466; - ril.operator.mnc = 01; - do_test_spn(0x00, true, true); - do_test_spn(0x01, true, true); - do_test_spn(0x02, true, false); - do_test_spn(0x03, true, false); - - run_next_test(); -}); - -/** - * Verify reading EF_IMG and EF_IIDF with ICC_IMG_CODING_SCHEME_BASIC - */ -add_test(function test_reading_img_basic() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.SimRecordHelper; - let helper = context.GsmPDUHelper; - let ril = context.RIL; - let buf = context.Buf; - let io = context.ICCIOHelper; - - let test_data = [ - {img: [0x01, 0x05, 0x05, 0x11, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x06], - iidf: [ - [/* Header */ - 0x05, 0x05, - /* Image body */ - 0x11, 0x33, 0x55, 0xfe]], - expected: [ - {width: 0x05, - height: 0x05, - codingScheme: ICC_IMG_CODING_SCHEME_BASIC, - body: [0x11, 0x33, 0x55, 0xfe]}]}, - {img: [0x01, 0x05, 0x05, 0x11, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x06, - /* Padding */ - 0xff, 0xff], - iidf: [ - [/* Header */ - 0x05, 0x05, - /* Image body */ - 0x11, 0x33, 0x55, 0xfe]], - expected: [ - {width: 0x05, - height: 0x05, - codingScheme: ICC_IMG_CODING_SCHEME_BASIC, - body: [0x11, 0x33, 0x55, 0xfe]}]}, - {img: [0x02, 0x10, 0x01, 0x11, 0x4f, 0x04, 0x00, 0x05, 0x00, 0x04, 0x10, - 0x01, 0x11, 0x4f, 0x05, 0x00, 0x05, 0x00, 0x04], - iidf: [ - [/* Data offset */ - 0xff, 0xff, 0xff, 0xff, 0xff, - /* Header */ - 0x10, 0x01, - /* Image body */ - 0x11, 0x99, - /* Trailing data */ - 0xff, 0xff, 0xff], - [/* Data offset */ - 0xff, 0xff, 0xff, 0xff, 0xff, - /* Header */ - 0x10, 0x01, - /* Image body */ - 0x99, 0x11]], - expected: [ - {width: 0x10, - height: 0x01, - codingScheme: ICC_IMG_CODING_SCHEME_BASIC, - body: [0x11, 0x99]}, - {width: 0x10, - height: 0x01, - codingScheme: ICC_IMG_CODING_SCHEME_BASIC, - body: [0x99, 0x11]}]}, - {img: [0x01, 0x28, 0x20, 0x11, 0x4f, 0xac, 0x00, 0x0b, 0x00, 0xa2], - iidf: [ - [/* Data offset */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* Header */ - 0x28, 0x20, - /* Image body */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, - 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, - 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, - 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, - 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, - 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, - 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x00, 0x01, 0x02, - 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, - 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, - 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, - 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, - 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f]], - expected: [ - {width: 0x28, - height: 0x20, - codingScheme: ICC_IMG_CODING_SCHEME_BASIC, - body: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, - 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, - 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, - 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, - 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, - 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, - 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, - 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, - 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, - 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f]}]}]; - - function do_test(img, iidf, expected) { - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - // Write data size - buf.writeInt32(img.length * 2); - - // Write data - for (let i = 0; i < img.length; i++) { - helper.writeHexOctet(img[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(img.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - let instanceIndex = 0; - io.loadTransparentEF = function fakeLoadTransparentEF(options) { - // Write data size - buf.writeInt32(iidf[instanceIndex].length * 2); - - // Write data - for (let i = 0; i < iidf[instanceIndex].length; i++) { - helper.writeHexOctet(iidf[instanceIndex][i]); - } - - // Write string delimiter - buf.writeStringDelimiter(iidf[instanceIndex].length * 2); - - instanceIndex++; - - if (options.callback) { - options.callback(options); - } - }; - - let onsuccess = function(icons) { - equal(icons.length, expected.length); - for (let i = 0; i < icons.length; i++) { - let icon = icons[i]; - let exp = expected[i]; - equal(icon.width, exp.width); - equal(icon.height, exp.height); - equal(icon.codingScheme, exp.codingScheme); - - equal(icon.body.length, exp.body.length); - for (let j = 0; j < icon.body.length; j++) { - equal(icon.body[j], exp.body[j]); - } - } - }; - record.readIMG(0, onsuccess); - } - - for (let i = 0; i< test_data.length; i++) { - do_test(test_data[i].img, test_data[i].iidf, test_data[i].expected); - } - run_next_test(); -}); - -/** - * Verify reading EF_IMG and EF_IIDF with the case data length is not enough - */ -add_test(function test_reading_img_length_error() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.SimRecordHelper; - let helper = context.GsmPDUHelper; - let ril = context.RIL; - let buf = context.Buf; - let io = context.ICCIOHelper; - - let test_data = [ - {/* Offset length not enough, should be 4. */ - img: [0x01, 0x05, 0x05, 0x11, 0x4f, 0x00, 0x00, 0x04, 0x00, 0x06], - iidf: [0xff, 0xff, 0xff, // Offset. - 0x05, 0x05, 0x11, 0x22, 0x33, 0xfe]}, - {/* iidf data length not enough, should be 6. */ - img: [0x01, 0x05, 0x05, 0x11, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x06], - iidf: [0x05, 0x05, 0x11, 0x22, 0x33]}]; - - function do_test(img, iidf) { - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - // Write data size - buf.writeInt32(img.length * 2); - - // Write data - for (let i = 0; i < img.length; i++) { - helper.writeHexOctet(img[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(img.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - io.loadTransparentEF = function fakeLoadTransparentEF(options) { - // Write data size - buf.writeInt32(iidf.length * 2); - - // Write data - for (let i = 0; i < iidf.length; i++) { - helper.writeHexOctet(iidf[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(iidf.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - let onsuccess = function() { - do_print("onsuccess shouldn't be called."); - ok(false); - }; - - let onerror = function() { - do_print("onerror called as expected."); - ok(true); - }; - - record.readIMG(0, onsuccess, onerror); - } - - for (let i = 0; i < test_data.length; i++) { - do_test(test_data[i].img, test_data[i].iidf); - } - run_next_test(); -}); - -/** - * Verify reading EF_IMG and EF_IIDF with an invalid fileId - */ -add_test(function test_reading_img_invalid_fileId() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.SimRecordHelper; - let helper = context.GsmPDUHelper; - let ril = context.RIL; - let buf = context.Buf; - let io = context.ICCIOHelper; - - // Test invalid fileId: 0x5f00. - let img_test = [0x01, 0x05, 0x05, 0x11, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x06]; - let iidf_test = [0x05, 0x05, 0x11, 0x22, 0x33, 0xfe]; - - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - // Write data size - buf.writeInt32(img_test.length * 2); - - // Write data - for (let i = 0; i < img_test.length; i++) { - helper.writeHexOctet(img_test[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(img_test.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - io.loadTransparentEF = function fakeLoadTransparentEF(options) { - // Write data size - buf.writeInt32(iidf_test.length * 2); - - // Write data - for (let i = 0; i < iidf_test.length; i++) { - helper.writeHexOctet(iidf_test[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(iidf_test.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - let onsuccess = function() { - do_print("onsuccess shouldn't be called."); - ok(false); - }; - - let onerror = function() { - do_print("onerror called as expected."); - ok(true); - }; - - record.readIMG(0, onsuccess, onerror); - - run_next_test(); -}); - -/** - * Verify reading EF_IMG with a wrong record length - */ -add_test(function test_reading_img_wrong_record_length() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.SimRecordHelper; - let helper = context.GsmPDUHelper; - let ril = context.RIL; - let buf = context.Buf; - let io = context.ICCIOHelper; - - let test_data = [ - [0x01, 0x05, 0x05, 0x11, 0x4f, 0x00, 0x00, 0x00], - [0x02, 0x05, 0x05, 0x11, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x06]]; - - function do_test(img) { - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - // Write data size - buf.writeInt32(img.length * 2); - - // Write data - for (let i = 0; i < img.length; i++) { - helper.writeHexOctet(img[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(img.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - let onsuccess = function() { - do_print("onsuccess shouldn't be called."); - ok(false); - }; - - let onerror = function() { - do_print("onerror called as expected."); - ok(true); - }; - - record.readIMG(0, onsuccess, onerror); - } - - for (let i = 0; i < test_data.length; i++) { - do_test(test_data[i]); - } - run_next_test(); -}); - -/** - * Verify reading EF_IMG and EF_IIDF with ICC_IMG_CODING_SCHEME_COLOR - */ -add_test(function test_reading_img_color() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.SimRecordHelper; - let helper = context.GsmPDUHelper; - let ril = context.RIL; - let buf = context.Buf; - let io = context.ICCIOHelper; - - let test_data = [ - {img: [0x01, 0x05, 0x05, 0x21, 0x4f, 0x11, 0x00, 0x00, 0x00, 0x13], - iidf: [ - [/* Header */ - 0x05, 0x05, 0x03, 0x08, 0x00, 0x13, - /* Image body */ - 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, - 0xb0, 0xc0, 0xd0, - /* Clut entries */ - 0x00, 0x01, 0x02, - 0x10, 0x11, 0x12, - 0x20, 0x21, 0x22, - 0x30, 0x31, 0x32, - 0x40, 0x41, 0x42, - 0x50, 0x51, 0x52, - 0x60, 0x61, 0x62, - 0x70, 0x71, 0x72]], - expected: [ - {width: 0x05, - height: 0x05, - codingScheme: ICC_IMG_CODING_SCHEME_COLOR, - bitsPerImgPoint: 0x03, - numOfClutEntries: 0x08, - body: [0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0, - 0xc0, 0xd0], - clut: [0x00, 0x01, 0x02, - 0x10, 0x11, 0x12, - 0x20, 0x21, 0x22, - 0x30, 0x31, 0x32, - 0x40, 0x41, 0x42, - 0x50, 0x51, 0x52, - 0x60, 0x61, 0x62, - 0x70, 0x71, 0x72]}]}, - {img: [0x02, 0x01, 0x06, 0x21, 0x4f, 0x33, 0x00, 0x02, 0x00, 0x08, 0x01, - 0x06, 0x21, 0x4f, 0x44, 0x00, 0x02, 0x00, 0x08], - iidf: [ - [/* Data offset */ - 0xff, 0xff, - /* Header */ - 0x01, 0x06, 0x02, 0x04, 0x00, 0x0d, - /* Image body */ - 0x40, 0x50, - /* Clut offset */ - 0xaa, 0xbb, 0xcc, - /* Clut entries */ - 0x01, 0x03, 0x05, - 0x21, 0x23, 0x25, - 0x41, 0x43, 0x45, - 0x61, 0x63, 0x65], - [/* Data offset */ - 0xff, 0xff, - /* Header */ - 0x01, 0x06, 0x02, 0x04, 0x00, 0x0d, - /* Image body */ - 0x4f, 0x5f, - /* Clut offset */ - 0xaa, 0xbb, 0xcc, - /* Clut entries */ - 0x11, 0x13, 0x15, - 0x21, 0x23, 0x25, - 0x41, 0x43, 0x45, - 0x61, 0x63, 0x65]], - expected: [ - {width: 0x01, - height: 0x06, - codingScheme: ICC_IMG_CODING_SCHEME_COLOR, - bitsPerImgPoint: 0x02, - numOfClutEntries: 0x04, - body: [0x40, 0x50], - clut: [0x01, 0x03, 0x05, - 0x21, 0x23, 0x25, - 0x41, 0x43, 0x45, - 0x61, 0x63, 0x65]}, - {width: 0x01, - height: 0x06, - codingScheme: ICC_IMG_CODING_SCHEME_COLOR, - bitsPerImgPoint: 0x02, - numOfClutEntries: 0x04, - body: [0x4f, 0x5f], - clut: [0x11, 0x13, 0x15, - 0x21, 0x23, 0x25, - 0x41, 0x43, 0x45, - 0x61, 0x63, 0x65]}]}]; - - function do_test(img, iidf, expected) { - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - // Write data size - buf.writeInt32(img.length * 2); - - // Write data - for (let i = 0; i < img.length; i++) { - helper.writeHexOctet(img[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(img.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - let instanceIndex = 0; - io.loadTransparentEF = function fakeLoadTransparentEF(options) { - // Write data size - buf.writeInt32(iidf[instanceIndex].length * 2); - - // Write data - for (let i = 0; i < iidf[instanceIndex].length; i++) { - helper.writeHexOctet(iidf[instanceIndex][i]); - } - - // Write string delimiter - buf.writeStringDelimiter(iidf[instanceIndex].length * 2); - - instanceIndex++; - - if (options.callback) { - options.callback(options); - } - }; - - let onsuccess = function(icons) { - equal(icons.length, expected.length); - for (let i = 0; i < icons.length; i++) { - let icon = icons[i]; - let exp = expected[i]; - equal(icon.width, exp.width); - equal(icon.height, exp.height); - equal(icon.codingScheme, exp.codingScheme); - - equal(icon.body.length, exp.body.length); - for (let j = 0; j < icon.body.length; j++) { - equal(icon.body[j], exp.body[j]); - } - - equal(icon.clut.length, exp.clut.length); - for (let j = 0; j < icon.clut.length; j++) { - equal(icon.clut[j], exp.clut[j]); - } - } - }; - - record.readIMG(0, onsuccess); - } - - for (let i = 0; i< test_data.length; i++) { - do_test(test_data[i].img, test_data[i].iidf, test_data[i].expected); - } - run_next_test(); -}); - -/** - * Verify reading EF_IMG and EF_IIDF with - * ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY - */ -add_test(function test_reading_img_color() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.SimRecordHelper; - let helper = context.GsmPDUHelper; - let ril = context.RIL; - let buf = context.Buf; - let io = context.ICCIOHelper; - - let test_data = [ - {img: [0x01, 0x05, 0x05, 0x22, 0x4f, 0x11, 0x00, 0x00, 0x00, 0x13], - iidf: [ - [/* Header */ - 0x05, 0x05, 0x03, 0x08, 0x00, 0x13, - /* Image body */ - 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, - 0xb0, 0xc0, 0xd0, - /* Clut entries */ - 0x00, 0x01, 0x02, - 0x10, 0x11, 0x12, - 0x20, 0x21, 0x22, - 0x30, 0x31, 0x32, - 0x40, 0x41, 0x42, - 0x50, 0x51, 0x52, - 0x60, 0x61, 0x62, - 0x70, 0x71, 0x72]], - expected: [ - {width: 0x05, - height: 0x05, - codingScheme: ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY, - bitsPerImgPoint: 0x03, - numOfClutEntries: 0x08, - body: [0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, - 0xa0, 0xb0, 0xc0, 0xd0], - clut: [0x00, 0x01, 0x02, - 0x10, 0x11, 0x12, - 0x20, 0x21, 0x22, - 0x30, 0x31, 0x32, - 0x40, 0x41, 0x42, - 0x50, 0x51, 0x52, - 0x60, 0x61, 0x62, - 0x70, 0x71, 0x72]}]}, - {img: [0x02, 0x01, 0x06, 0x22, 0x4f, 0x33, 0x00, 0x02, 0x00, 0x08, 0x01, - 0x06, 0x22, 0x4f, 0x33, 0x00, 0x02, 0x00, 0x08], - iidf: [ - [/* Data offset */ - 0xff, 0xff, - /* Header */ - 0x01, 0x06, 0x02, 0x04, 0x00, 0x0d, - /* Image body */ - 0x40, 0x50, - /* Clut offset */ - 0x0a, 0x0b, 0x0c, - /* Clut entries */ - 0x01, 0x03, 0x05, - 0x21, 0x23, 0x25, - 0x41, 0x43, 0x45, - 0x61, 0x63, 0x65], - [/* Data offset */ - 0xff, 0xff, - /* Header */ - 0x01, 0x06, 0x02, 0x04, 0x00, 0x0d, - /* Image body */ - 0x4f, 0x5f, - /* Clut offset */ - 0x0a, 0x0b, 0x0c, - /* Clut entries */ - 0x11, 0x13, 0x15, - 0x21, 0x23, 0x25, - 0x41, 0x43, 0x45, - 0x61, 0x63, 0x65]], - expected: [ - {width: 0x01, - height: 0x06, - codingScheme: ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY, - bitsPerImgPoint: 0x02, - numOfClutEntries: 0x04, - body: [0x40, 0x50], - clut: [0x01, 0x03, 0x05, - 0x21, 0x23, 0x25, - 0x41, 0x43, 0x45, - 0x61, 0x63, 0x65]}, - {width: 0x01, - height: 0x06, - codingScheme: ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY, - bitsPerImgPoint: 0x02, - numOfClutEntries: 0x04, - body: [0x4f, 0x5f], - clut: [0x11, 0x13, 0x15, - 0x21, 0x23, 0x25, - 0x41, 0x43, 0x45, - 0x61, 0x63, 0x65]}]}]; - - function do_test(img, iidf, expected) { - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - // Write data size - buf.writeInt32(img.length * 2); - - // Write data - for (let i = 0; i < img.length; i++) { - helper.writeHexOctet(img[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(img.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - let instanceIndex = 0; - io.loadTransparentEF = function fakeLoadTransparentEF(options) { - // Write data size - buf.writeInt32(iidf[instanceIndex].length * 2); - - // Write data - for (let i = 0; i < iidf[instanceIndex].length; i++) { - helper.writeHexOctet(iidf[instanceIndex][i]); - } - - // Write string delimiter - buf.writeStringDelimiter(iidf[instanceIndex].length * 2); - - instanceIndex++; - - if (options.callback) { - options.callback(options); - } - }; - - let onsuccess = function(icons) { - equal(icons.length, expected.length); - for (let i = 0; i < icons.length; i++) { - let icon = icons[i]; - let exp = expected[i]; - equal(icon.width, exp.width); - equal(icon.height, exp.height); - equal(icon.codingScheme, exp.codingScheme); - - equal(icon.body.length, exp.body.length); - for (let j = 0; j < icon.body.length; j++) { - equal(icon.body[j], exp.body[j]); - } - - equal(icon.clut.length, exp.clut.length); - for (let j = 0; j < icon.clut.length; j++) { - equal(icon.clut[j], exp.clut[j]); - } - } - }; - - record.readIMG(0, onsuccess); - } - - for (let i = 0; i< test_data.length; i++) { - do_test(test_data[i].img, test_data[i].iidf, test_data[i].expected); - } - run_next_test(); -}); - -/** - * Verify SimRecordHelper.readCphsInfo - */ -add_test(function test_read_cphs_info() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let RIL = context.RIL; - let pduHelper = context.GsmPDUHelper; - let recordHelper = context.SimRecordHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - let cphsPDU = new Uint8Array(3); - - io.loadTransparentEF = function(options) { - if (cphsPDU) { - // Write data size - buf.writeInt32(cphsPDU.length * 2); - - // Write CPHS INFO - for (let i = 0; i < cphsPDU.length; i++) { - pduHelper.writeHexOctet(cphsPDU[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(cphsPDU.length * 2); - - if (options.callback) { - options.callback(options); - } - } else { - do_print("cphsPDU[] is not set."); - } - }; - - function do_test(cphsInfo, cphsSt) { - let onsuccess = false; - let onerror = false; - - delete RIL.iccInfoPrivate.cphsSt; - cphsPDU.set(cphsInfo); - recordHelper.readCphsInfo(() => { onsuccess = true; }, - () => { onerror = true; }); - - ok((cphsSt) ? onsuccess : onerror); - ok(!((cphsSt) ? onerror : onsuccess)); - if (cphsSt) { - equal(RIL.iccInfoPrivate.cphsSt.length, cphsSt.length); - for (let i = 0; i < cphsSt.length; i++) { - equal(RIL.iccInfoPrivate.cphsSt[i], cphsSt[i]); - } - } else { - equal(RIL.iccInfoPrivate.cphsSt, cphsSt); - } - } - - do_test([ - 0x01, // Phase 1 - 0xFF, // All available & activated - 0x03 // All available & activated - ], - [ - 0x3F, // All services except ONSF(bit 8-7) are available and activated. - 0x00 // INFO_NUM shall not be available & activated. - ]); - - do_test([ - 0x02, // Phase 2 - 0xFF, // All available & activated - 0x03 // All available & activated - ], - [ - 0xF3, // All services except ONSF are available and activated. - 0x03 // INFO_NUM shall not be available & activated. - ]); - - do_test([ - 0x03, // Phase 3 - 0xFF, // All available & activated - 0x03 // All available & activated - ], - undefined); // RIL.iccInfoPrivate.cphsSt shall be remained as 'undefined'. - - run_next_test(); -}); - -/** - * Verify SimRecordHelper.readMBDN/SimRecordHelper.readCphsMBN - */ -add_test(function test_read_voicemail_number() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let RIL = context.RIL; - let pduHelper = context.GsmPDUHelper; - let recordHelper = context.SimRecordHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - let postedMessage; - - worker.postMessage = function(message) { - postedMessage = message; - }; - - io.loadLinearFixedEF = function(options) { - let mbnData = [ - 0x56, 0x6F, 0x69, 0x63, 0x65, 0x6D, 0x61, 0x69, - 0x6C, 0xFF, // Alpha Identifier: Voicemail - 0x03, // Length of BCD number: 3 - 0x80, // TOA: Unknown - 0x11, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, // Dialing Number: 111 - 0xFF, // Capability/Configuration Record Identifier - 0xFF // Extension Record Identifier - ]; - - // Write data size - buf.writeInt32(mbnData.length * 2); - - // Write MBN - for (let i = 0; i < mbnData.length; i++) { - pduHelper.writeHexOctet(mbnData[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(mbnData.length * 2); - - options.recordSize = mbnData.length; - if (options.callback) { - options.callback(options); - } - }; - - function do_test(funcName, msgCount) { - postedMessage = null; - delete RIL.iccInfoPrivate.mbdn; - recordHelper[funcName](); - - equal("iccmbdn", postedMessage.rilMessageType); - equal("Voicemail", postedMessage.alphaId); - equal("111", postedMessage.number); - } - - do_test("readMBDN"); - do_test("readCphsMBN"); - - run_next_test(); -}); - -/** - * Verify the recovery from SimRecordHelper.readCphsMBN() if MBDN is not valid - * or is empty after SimRecordHelper.readMBDN(). - */ -add_test(function test_read_mbdn_recovered_from_cphs_mbn() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let RIL = context.RIL; - let pduHelper = context.GsmPDUHelper; - let recordHelper = context.SimRecordHelper; - let iccUtilsHelper = context.ICCUtilsHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - - io.loadLinearFixedEF = function(options) { - let mbnData = [ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF - ]; - - // Write data size - buf.writeInt32(mbnData.length * 2); - - // Write MBN - for (let i = 0; i < mbnData.length; i++) { - pduHelper.writeHexOctet(mbnData[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(mbnData.length * 2); - - options.recordSize = mbnData.length; - if (options.callback) { - options.callback(options); - } - }; - - iccUtilsHelper.isCphsServiceAvailable = function(geckoService) { - return geckoService == "MBN"; - }; - - let isRecovered = false; - recordHelper.readCphsMBN = function(onComplete) { - isRecovered = true; - }; - - recordHelper.readMBDN(); - - equal(RIL.iccInfoPrivate.mbdn, undefined); - ok(isRecovered); - - run_next_test(); -}); - -/** - * Verify reading EF_PNN with different coding scheme. - */ -add_test(function test_pnn_with_different_coding_scheme() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.SimRecordHelper; - let pduHelper = context.GsmPDUHelper; - let ril = context.RIL; - let buf = context.Buf; - let io = context.ICCIOHelper; - - let test_data = [{ - // Cell Broadcast data coding scheme - "Test1" - pnn: [0x43, 0x06, 0x85, 0xD4, 0xF2, 0x9C, 0x1E, 0x03], - expectedResult: "Test1" - },{ - // UCS2 with 0x80 - "Test1" - pnn: [0x43, 0x0C, 0x90, 0x80, 0x00, 0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x31], - expectedResult: "Test1" - },{ - // UCS2 with 0x81 - "Mozilla\u694a" - pnn: [0x43, 0x0E, 0x90, 0x81, 0x08, 0xd2, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0xca, 0xff, 0xff], - expectedResult: "Mozilla\u694a" - },{ - // UCS2 with 0x82 - "Mozilla\u694a" - pnn: [0x43, 0x0F, 0x90, 0x82, 0x08, 0x69, 0x00, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0xca, 0xff, 0xff], - expectedResult: "Mozilla\u694a" - }]; - - function do_test_pnn(pnn, expectedResult) { - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - // Write data size. - buf.writeInt32(pnn.length * 2); - - // Write data. - for (let i = 0; i < pnn.length; i++) { - pduHelper.writeHexOctet(pnn[i]); - } - - // Write string delimiter. - buf.writeStringDelimiter(pnn.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - record.readPNN(); - - equal(ril.iccInfoPrivate.PNN[0].fullName, expectedResult); - // Reset PNN info for next test - ril.iccInfoPrivate.PNN = null; - } - - ril.appType = CARD_APPTYPE_SIM; - for (let i = 0; i < test_data.length; i++) { - do_test_pnn(test_data[i].pnn, test_data[i].expectedResult); - } - - run_next_test(); -}); - -/** - * Verify reading EF_PNN with different content. - */ -add_test(function test_pnn_with_different_content() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.SimRecordHelper; - let pduHelper = context.GsmPDUHelper; - let ril = context.RIL; - let buf = context.Buf; - let io = context.ICCIOHelper; - - let test_data = [{ - // [0]: {"fullName":"Test1","shortName":"Test1"} - pnn: [0x43, 0x06, 0x85, 0xD4, 0xF2, 0x9C, 0x1E, 0x03, - 0x45, 0x06, 0x85, 0xD4, 0xF2, 0x9C, 0x1E, 0x03], - expectedResult: {"fullName": "Test1","shortName": "Test1"} - },{ - // [1]: {"fullName":"Test2"} - pnn: [0x43, 0x06, 0x85, 0xD4, 0xF2, 0x9C, 0x2E, 0x03], - expectedResult: {"fullName": "Test2"} - },{ - // [2]: undefined - pnn: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], - },{ - // [3]: {"fullName": "Test4"} - pnn: [0x43, 0x06, 0x85, 0xD4, 0xF2, 0x9C, 0x4E, 0x03], - expectedResult: {"fullName": "Test4"} - },{ - // [4]: undefined - pnn: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], - }]; - - function do_test_pnn() { - ril.iccIO = function fakeIccIO(options) { - let index = options.p1 - 1; - let pnn = test_data[index].pnn; - - // Write data size. - buf.writeInt32(pnn.length * 2); - - // Write data. - for (let i = 0; i < pnn.length; i++) { - pduHelper.writeHexOctet(pnn[i]); - } - - // Write string delimiter. - buf.writeStringDelimiter(pnn.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - options.p1 = 1; - options.totalRecords = test_data.length; - - ril.iccIO(options); - }; - - record.readPNN(); - - equal(test_data.length, ril.iccInfoPrivate.PNN.length); - for (let i = 0; i < test_data.length; i++) { - if (test_data[i].expectedResult) { - equal(test_data[i].expectedResult.fullName, - ril.iccInfoPrivate.PNN[i].fullName); - equal(test_data[i].expectedResult.shortName, - ril.iccInfoPrivate.PNN[i].shortName); - } else { - equal(test_data[i].expectedResult, ril.iccInfoPrivate.PNN[i]); - } - } - } - - ril.appType = CARD_APPTYPE_SIM; - do_test_pnn(); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_ruim.js b/dom/system/gonk/tests/test_ril_worker_ruim.js deleted file mode 100644 index 0ddc10f29..000000000 --- a/dom/system/gonk/tests/test_ril_worker_ruim.js +++ /dev/null @@ -1,328 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Verify RUIM Service. - */ -add_test(function test_is_ruim_service_available() { - let worker = newWorker(); - let context = worker.ContextPool._contexts[0]; - context.RIL._isCdma = true; - context.RIL.appType = CARD_APPTYPE_RUIM; - - function test_table(cst, geckoService, enabled) { - context.RIL.iccInfoPrivate.cst = cst; - equal(context.ICCUtilsHelper.isICCServiceAvailable(geckoService), - enabled); - } - - test_table([0x0, 0x0, 0x0, 0x0, 0x03], "SPN", true); - test_table([0x0, 0x0, 0x0, 0x03, 0x0], "SPN", false); - test_table([0x0, 0x0C, 0x0, 0x0, 0x0], "ENHANCED_PHONEBOOK", true); - test_table([0x0, 0x0, 0x0, 0x0, 0x0], "ENHANCED_PHONEBOOK", false); - - run_next_test(); -}); - -/** - * Verify EF_PATH for RUIM file. - */ -add_test(function test_ruim_file_path_id() { - let worker = newWorker(); - let context = worker.ContextPool._contexts[0]; - let RIL = context.RIL; - let ICCFileHelper = context.ICCFileHelper; - - RIL.appType = CARD_APPTYPE_RUIM; - equal(ICCFileHelper.getEFPath(ICC_EF_CSIM_CST), - EF_PATH_MF_SIM + EF_PATH_DF_CDMA); - - run_next_test(); -}); - -add_test(function test_fetch_ruim_recodes() { - let worker = newWorker(); - let context = worker.ContextPool._contexts[0]; - let RIL = context.RIL; - let ruimHelper = context.RuimRecordHelper; - - function testFetchRuimRecordes(expectCalled) { - let ifCalled = []; - - ruimHelper.getIMSI_M = function() { - ifCalled.push("getIMSI_M"); - }; - - ruimHelper.readCST = function() { - ifCalled.push("readCST"); - }; - - ruimHelper.readCDMAHome = function() { - ifCalled.push("readCDMAHome"); - }; - - RIL.getCdmaSubscription = function() { - ifCalled.push("getCdmaSubscription"); - }; - - ruimHelper.fetchRuimRecords(); - - for (let i = 0; i < expectCalled.length; i++ ) { - if (ifCalled[i] != expectCalled[i]) { - do_print(expectCalled[i] + " is not called."); - ok(false); - } - } - } - - let expectCalled = ["getIMSI_M", "readCST", "readCDMAHome", - "getCdmaSubscription"]; - testFetchRuimRecordes(expectCalled); - - run_next_test(); -}); - -/** - * Verify RuimRecordHelper.decodeIMSIValue - */ -add_test(function test_decode_imsi_value() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - - function testDecodeImsiValue(encoded, length, expect) { - let decoded = context.RuimRecordHelper.decodeIMSIValue(encoded, length); - - equal(expect, decoded); - } - - testDecodeImsiValue( 99, 2, "00"); - testDecodeImsiValue( 90, 2, "01"); - testDecodeImsiValue( 19, 2, "20"); - testDecodeImsiValue( 23, 2, "34"); - testDecodeImsiValue(999, 3, "000"); - testDecodeImsiValue(990, 3, "001"); - testDecodeImsiValue(909, 3, "010"); - testDecodeImsiValue( 99, 3, "100"); - testDecodeImsiValue(901, 3, "012"); - testDecodeImsiValue( 19, 3, "120"); - testDecodeImsiValue( 91, 3, "102"); - testDecodeImsiValue(199, 3, "200"); - testDecodeImsiValue(123, 3, "234"); - testDecodeImsiValue(578, 3, "689"); - - run_next_test(); -}); - -/** - * Verify RuimRecordHelper.getIMSI_M - */ -add_test(function test_get_imsi_m() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - - function testDecodeImsi(encodedImsi, expectedImsi) { - io.loadTransparentEF = function fakeLoadTransparentEF(options) { - // Write data size - buf.writeInt32(encodedImsi.length * 2); - - // Write imsi - for (let i = 0; i < encodedImsi.length; i++) { - helper.writeHexOctet(encodedImsi[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(encodedImsi.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - context.RuimRecordHelper.getIMSI_M(); - let imsi = context.RIL.iccInfoPrivate.imsi; - - equal(expectedImsi, imsi) - } - - let imsi_1 = "466050081062861"; - testDecodeImsi([0x0, 0xe5, 0x03, 0xee, 0xca, 0x17, 0x5e, 0x80, 0x63, 0x01], imsi_1); - - let imsi_2 = "460038351175976"; - testDecodeImsi([0x0, 0xd4, 0x02, 0x61, 0x97, 0x01, 0x5c, 0x80, 0x67, 0x01], imsi_2); - - run_next_test(); -}); - -/** - * Verify RuimRecordHelper.readCDMAHome - */ -add_test(function test_read_cdmahome() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - let cdmaHome = [0xc1, 0x34, 0xff, 0xff, 0x00]; - - // Write data size - buf.writeInt32(cdmaHome.length * 2); - - // Write cdma home file. - for (let i = 0; i < cdmaHome.length; i++) { - helper.writeHexOctet(cdmaHome[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(cdmaHome.length * 2); - - // We just have 1 test record. - - options.totalRecords = 1; - if (options.callback) { - options.callback(options); - } - }; - - function testCdmaHome(expectedSystemIds, expectedNetworkIds) { - context.RuimRecordHelper.readCDMAHome(); - let cdmaHome = context.RIL.cdmaHome; - for (let i = 0; i < expectedSystemIds.length; i++) { - equal(cdmaHome.systemId[i], expectedSystemIds[i]); - equal(cdmaHome.networkId[i], expectedNetworkIds[i]); - } - equal(cdmaHome.systemId.length, expectedSystemIds.length); - equal(cdmaHome.networkId.length, expectedNetworkIds.length); - } - - testCdmaHome([13505], [65535]); - - run_next_test(); -}); - -/** - * Verify reading CDMA EF_SPN - */ -add_test(function test_read_cdmaspn() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - - function testReadSpn(file, expectedSpn, expectedDisplayCondition) { - io.loadTransparentEF = function fakeLoadTransparentEF(options) { - // Write data size - buf.writeInt32(file.length * 2); - - // Write file. - for (let i = 0; i < file.length; i++) { - helper.writeHexOctet(file[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(file.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - context.RuimRecordHelper.readSPN(); - equal(context.RIL.iccInfo.spn, expectedSpn); - equal(context.RIL.iccInfoPrivate.spnDisplayCondition, - expectedDisplayCondition); - } - - testReadSpn([0x01, 0x04, 0x06, 0x4e, 0x9e, 0x59, 0x2a, 0x96, - 0xfb, 0x4f, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff], - String.fromCharCode(0x4e9e) + - String.fromCharCode(0x592a) + - String.fromCharCode(0x96fb) + - String.fromCharCode(0x4fe1), - 0x1); - - // Test when there's no tailing 0xff in spn string. - testReadSpn([0x01, 0x04, 0x06, 0x4e, 0x9e, 0x59, 0x2a, 0x96, - 0xfb, 0x4f, 0xe1], - String.fromCharCode(0x4e9e) + - String.fromCharCode(0x592a) + - String.fromCharCode(0x96fb) + - String.fromCharCode(0x4fe1), - 0x1); - - run_next_test(); -}); - -/** - * Verify display condition for CDMA. - */ -add_test(function test_cdma_spn_display_condition() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - let context = worker.ContextPool._contexts[0]; - let RIL = context.RIL; - let ICCUtilsHelper = context.ICCUtilsHelper; - - // Set cdma. - RIL._isCdma = true; - - // Test updateDisplayCondition runs before any of SIM file is ready. - equal(ICCUtilsHelper.updateDisplayCondition(), true); - equal(RIL.iccInfo.isDisplayNetworkNameRequired, true); - equal(RIL.iccInfo.isDisplaySpnRequired, false); - - // Test with value. - function testDisplayCondition(ruimDisplayCondition, - homeSystemIds, homeNetworkIds, - currentSystemId, currentNetworkId, - expectUpdateDisplayCondition, - expectIsDisplaySPNRequired) { - RIL.iccInfoPrivate.spnDisplayCondition = ruimDisplayCondition; - RIL.cdmaHome = { - systemId: homeSystemIds, - networkId: homeNetworkIds - }; - RIL.voiceRegistrationState.cell = { - cdmaSystemId: currentSystemId, - cdmaNetworkId: currentNetworkId - }; - - equal(ICCUtilsHelper.updateDisplayCondition(), expectUpdateDisplayCondition); - equal(RIL.iccInfo.isDisplayNetworkNameRequired, false); - equal(RIL.iccInfo.isDisplaySpnRequired, expectIsDisplaySPNRequired); - }; - - // SPN is not required when ruimDisplayCondition is false. - testDisplayCondition(0x0, [123], [345], 123, 345, true, false); - - // System id and network id are all match. - testDisplayCondition(0x1, [123], [345], 123, 345, true, true); - - // Network is 65535, we should only need to match system id. - testDisplayCondition(0x1, [123], [65535], 123, 345, false, true); - - // Not match. - testDisplayCondition(0x1, [123], [456], 123, 345, true, false); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_sms.js b/dom/system/gonk/tests/test_ril_worker_sms.js deleted file mode 100644 index 7c1b972a7..000000000 --- a/dom/system/gonk/tests/test_ril_worker_sms.js +++ /dev/null @@ -1,273 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -XPCOMUtils.defineLazyGetter(this, "gSmsSegmentHelper", function() { - let ns = {}; - Cu.import("resource://gre/modules/SmsSegmentHelper.jsm", ns); - return ns.SmsSegmentHelper; -}); - -const ESCAPE = "\uffff"; -const RESCTL = "\ufffe"; - -function run_test() { - run_next_test(); -} - -/** - * Verify receiving SMS-DELIVERY messages - */ - -function hexToNibble(nibble) { - nibble &= 0x0f; - if (nibble < 10) { - nibble += 48; // ASCII '0' - } else { - nibble += 55; // ASCII 'A' - } - return nibble; -} - -function pduToParcelData(pdu) { - let dataLength = 4 + pdu.length * 4 + 4; - let data = new Uint8Array(dataLength); - let offset = 0; - - // String length - data[offset++] = pdu.length & 0xFF; - data[offset++] = (pdu.length >> 8) & 0xFF; - data[offset++] = (pdu.length >> 16) & 0xFF; - data[offset++] = (pdu.length >> 24) & 0xFF; - - // PDU data - for (let i = 0; i < pdu.length; i++) { - let hi = (pdu[i] >>> 4) & 0x0F; - let lo = pdu[i] & 0x0F; - - data[offset++] = hexToNibble(hi); - data[offset++] = 0; - data[offset++] = hexToNibble(lo); - data[offset++] = 0; - } - - // String delimitor - data[offset++] = 0; - data[offset++] = 0; - data[offset++] = 0; - data[offset++] = 0; - - return data; -} - -function compose7bitPdu(lst, sst, data, septets) { - if ((lst == 0) && (sst == 0)) { - return [0x00, // SMSC - PDU_MTI_SMS_DELIVER, // firstOctet - 1, 0x00, 0, // senderAddress - 0x00, // protocolIdentifier - PDU_DCS_MSG_CODING_7BITS_ALPHABET, // dataCodingScheme - 0, 0, 0, 0, 0, 0, 0, // y m d h m s tz - septets] // userDataLength - .concat(data); - } - - return [0x00, // SMSC - PDU_MTI_SMS_DELIVER | PDU_UDHI, // firstOctet - 1, 0x00, 0, // senderAddress - 0x00, // protocolIdentifier - PDU_DCS_MSG_CODING_7BITS_ALPHABET, // dataCodingScheme - 0, 0, 0, 0, 0, 0, 0, // y m d h m s tz - 8 + septets, // userDataLength - 6, // user data header length - PDU_IEI_NATIONAL_LANGUAGE_LOCKING_SHIFT, 1, lst, // PDU_IEI_NATIONAL_LANGUAGE_LOCKING_SHIFT - PDU_IEI_NATIONAL_LANGUAGE_SINGLE_SHIFT, 1, sst] // PDU_IEI_NATIONAL_LANGUAGE_SINGLE_SHIFT - .concat(data); -} - -function composeUcs2Pdu(rawBytes) { - return [0x00, // SMSC - PDU_MTI_SMS_DELIVER, // firstOctet - 1, 0x00, 0, // senderAddress - 0x00, // protocolIdentifier - PDU_DCS_MSG_CODING_16BITS_ALPHABET, // dataCodingScheme - 0, 0, 0, 0, 0, 0, 0, // y m d h m s tz - rawBytes.length] // userDataLength - .concat(rawBytes); -} - -function newSmsParcel(pdu) { - return newIncomingParcel(-1, - RESPONSE_TYPE_UNSOLICITED, - UNSOLICITED_RESPONSE_NEW_SMS, - pduToParcelData(pdu)); -} - -function removeSpecialChar(str, needle) { - for (let i = 0; i < needle.length; i++) { - let pos; - while ((pos = str.indexOf(needle[i])) >= 0) { - str = str.substring(0, pos) + str.substring(pos + 1); - } - } - return str; -} - -function newWriteHexOctetAsUint8Worker() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - - let context = worker.ContextPool._contexts[0]; - context.GsmPDUHelper.writeHexOctet = function(value) { - context.Buf.writeUint8(value); - }; - - return worker; -} - -function add_test_receiving_sms(expected, pdu) { - add_test(function test_receiving_sms() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - do_print("fullBody: " + message.fullBody); - equal(expected, message.fullBody) - } - }); - - do_print("expect: " + expected); - do_print("pdu: " + pdu); - worker.onRILMessage(0, newSmsParcel(pdu)); - - run_next_test(); - }); -} - -var test_receiving_7bit_alphabets__worker; -function test_receiving_7bit_alphabets(lst, sst) { - if (!test_receiving_7bit_alphabets__worker) { - test_receiving_7bit_alphabets__worker = newWriteHexOctetAsUint8Worker(); - } - let worker = test_receiving_7bit_alphabets__worker; - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let buf = context.Buf; - - function get7bitRawBytes(expected) { - buf.outgoingIndex = 0; - helper.writeStringAsSeptets(expected, 0, lst, sst); - - let subArray = buf.outgoingBytes.subarray(0, buf.outgoingIndex); - return Array.slice(subArray); - } - - let langTable = PDU_NL_LOCKING_SHIFT_TABLES[lst]; - let langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[sst]; - - let text = removeSpecialChar(langTable + langShiftTable, ESCAPE + RESCTL); - for (let i = 0; i < text.length;) { - let len = Math.min(70, text.length - i); - let expected = text.substring(i, i + len); - let septets = - gSmsSegmentHelper.countGsm7BitSeptets(expected, langTable, langShiftTable); - let rawBytes = get7bitRawBytes(expected); - let pdu = compose7bitPdu(lst, sst, rawBytes, septets); - add_test_receiving_sms(expected, pdu); - - i += len; - } -} - -function test_receiving_ucs2_alphabets(text) { - let worker = test_receiving_7bit_alphabets__worker; - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - - function getUCS2RawBytes(expected) { - buf.outgoingIndex = 0; - context.GsmPDUHelper.writeUCS2String(expected); - - let subArray = buf.outgoingBytes.subarray(0, buf.outgoingIndex); - return Array.slice(subArray); - } - - for (let i = 0; i < text.length;) { - let len = Math.min(70, text.length - i); - let expected = text.substring(i, i + len); - let rawBytes = getUCS2RawBytes(expected); - let pdu = composeUcs2Pdu(rawBytes); - add_test_receiving_sms(expected, pdu); - - i += len; - } -} - -var ucs2str = ""; -for (let lst = 0; lst < PDU_NL_LOCKING_SHIFT_TABLES.length; lst++) { - ucs2str += PDU_NL_LOCKING_SHIFT_TABLES[lst]; - for (let sst = 0; sst < PDU_NL_SINGLE_SHIFT_TABLES.length; sst++) { - test_receiving_7bit_alphabets(lst, sst); - - if (lst == 0) { - ucs2str += PDU_NL_SINGLE_SHIFT_TABLES[sst]; - } - } -} -test_receiving_ucs2_alphabets(ucs2str); - -// Bug 820220: B2G SMS: wrong order and truncated content in multi-part messages -add_test(function test_sendSMS_UCS2_without_langIndex_langShiftIndex_defined() { - let worker = newWriteHexOctetAsUint8Worker(); - let context = worker.ContextPool._contexts[0]; - - context.Buf.sendParcel = function() { - // Each sendParcel() call represents one outgoing segment of a multipart - // SMS message. Here, we have the first segment send, so it's "Hello " - // only. - // - // 4(parcel size) + 4(request type) + 4(token) - // + 4(two messages) + 4(null SMSC) + 4(message string length) - // + 1(first octet) + 1(message reference) - // + 2(DA len, TOA) + 4(addr) - // + 1(pid) + 1(dcs) - // + 1(UDL) + 6(UDHL, type, len, ref, max, seq) - // + 12(2 * strlen("Hello ")) - // + 4(two delimitors) = 57 - // - // If we have additional 6(type, len, langIndex, type len, langShiftIndex) - // octets here, then bug 809553 is not fixed. - equal(this.outgoingIndex, 57); - - run_next_test(); - }; - - context.RIL.sendSMS({ - number: "1", - segmentMaxSeq: 2, - fullBody: "Hello World!", - dcs: PDU_DCS_MSG_CODING_16BITS_ALPHABET, - segmentRef16Bit: false, - userDataHeaderLength: 5, - requestStatusReport: true, - segments: [ - { - body: "Hello ", - encodedBodyLength: 12, - }, { - body: "World!", - encodedBodyLength: 12, - } - ], - }); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_sms_cdma.js b/dom/system/gonk/tests/test_ril_worker_sms_cdma.js deleted file mode 100644 index 85d0b6e0c..000000000 --- a/dom/system/gonk/tests/test_ril_worker_sms_cdma.js +++ /dev/null @@ -1,298 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/* - * Helper function to covert a HEX string to a byte array. - * - * @param hexString - * A hexadecimal string of which the length is even. - */ -function hexStringToBytes(hexString) { - let bytes = []; - - let length = hexString.length; - - for (let i = 0; i < length; i += 2) { - bytes.push(Number.parseInt(hexString.substr(i, 2), 16)); - } - - return bytes; -} - -/* - * Helper function to covert a byte array to a HEX string. - * - * @param bytes - * Could be a regular byte array or Uint8Array. - */ -function bytesToHexString(bytes) { - let hexString = ""; - let hex; - - for (let i = 0; i < bytes.length; i++) { - hex = bytes[i].toString(16).toUpperCase(); - if (hex.length === 1) { - hexString += "0"; - } - hexString += hex; - } - - return hexString; -} - -/* - * Helper function to ecode Opaque UserData - * - * @param msg_type - * PDU_CDMA_MSG_TYPE_SUBMIT or PDU_CDMA_MSG_TYPE_DELIVER - * @param data - * The byte array of opaque data to be encoded. - */ -function encodeOpaqueUserData(bitBufferHelper, options) { - let bearerDataBuffer = []; - bitBufferHelper.startWrite(bearerDataBuffer); - - // Msg-Id - bitBufferHelper.writeBits(PDU_CDMA_MSG_USERDATA_MSG_ID, 8); - bitBufferHelper.writeBits(3, 8); - bitBufferHelper.writeBits(options.msg_type, 4); // MSG_TYPE - bitBufferHelper.writeBits(1, 16); // MSG_ID - bitBufferHelper.flushWithPadding(); // HEADER_IND (1) + RESERVED (3) - - // User Data - bitBufferHelper.writeBits(PDU_CDMA_MSG_USERDATA_BODY, 8); - let dataLength = options.data.length; - bitBufferHelper.writeBits(2 + dataLength, 8); // 2 bytes for MSG_ENCODING, NUM_FIELDS - bitBufferHelper.writeBits(PDU_CDMA_MSG_CODING_OCTET, 5); //MSG_ENCODING - // MSG_TYPE is omitted if MSG_ENCODING is CODING_OCTET - bitBufferHelper.writeBits(dataLength, 8); // NUM_FIELDS - for (let i = 0; i < dataLength; i++) { // CHARi - bitBufferHelper.writeBits(options.data[i], 8); - } - bitBufferHelper.flushWithPadding(); // RESERVED (3 filling bits) - - return bearerDataBuffer; -} - -function newSmsParcel(cdmaPduHelper, pdu) { - return newIncomingParcel(-1, - RESPONSE_TYPE_UNSOLICITED, - UNSOLICITED_RESPONSE_CDMA_NEW_SMS, - pduToParcelData(cdmaPduHelper, pdu)); -} - -/* - * Helper function to encode PDU into Parcel. - * See ril_cdma_sms.h for the structure definition of RIL_CDMA_SMS_Message - * - * @param teleservice - * The Teleservice-Id of this PDU. - * See PDU_CDMA_MSG_TELESERIVCIE_ID_XXX in ril_const.js. - * @param address - * The Orginating or Destinating address. - * @param bearerData - * The byte array of the encoded bearer data. - */ -function pduToParcelData(cdmaPduHelper, pdu) { - - let addrInfo = cdmaPduHelper.encodeAddr(pdu.address); - // Teleservice, isServicePresent, ServiceCategory, - // addrInfo {digitMode, numberMode, numberType, numberPlan, address.length, address} - // Sub Address - // bearerData length, bearerData. - let dataLength = 4 + 4 + 4 - + (5 + addrInfo.address.length) * 4 - + 3 * 4 - + 4 + pdu.bearerData.length * 4; - - let data = new Uint8Array(dataLength); - let offset = 0; - - function writeInt(value) { - data[offset++] = value & 0xFF; - data[offset++] = (value >> 8) & 0xFF; - data[offset++] = (value >> 16) & 0xFF; - data[offset++] = (value >> 24) & 0xFF; - } - - function writeByte(value) { - data[offset++] = value & 0xFF; - data[offset++] = 0; - data[offset++] = 0; - data[offset++] = 0; - } - - // Teleservice - writeInt(pdu.teleservice); - - // isServicePresent - writeByte(0); - - // ServiceCategory - writeInt(PDU_CDMA_MSG_CATEGORY_UNSPEC); - - // AddrInfo - writeByte(addrInfo.digitMode); - writeByte(addrInfo.numberMode); - writeByte(addrInfo.numberType); - writeByte(addrInfo.numberPlan); - let addressLength = addrInfo.address.length; - writeByte(addressLength); - for (let i = 0; i < addressLength; i++) { - writeByte(addrInfo.address[i]); - } - - // Subaddress - writeByte(0); - writeByte(0); - writeByte(0); - - // Bearer Data Length - dataLength = pdu.bearerData.length; - writeByte(dataLength); - - // Bearer Data - for (let i = 0; i < dataLength; i++) { - writeByte(pdu.bearerData[i]); - } - - return data; -} - -/** - * Verify CDMA SMS Delivery ACK Message. - */ -add_test(function test_processCdmaSmsStatusReport() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - function test_StatusReport(errorClass, msgStatus) { - let msgId = 0; - let sentSmsMap = context.RIL._pendingSentSmsMap; - - sentSmsMap[msgId] = {}; - - let message = { - SMSC: "", - mti: 0, - udhi: 0, - sender: "0987654321", - recipient: null, - pid: PDU_PID_DEFAULT, - epid: PDU_PID_DEFAULT, - dcs: 0, - mwi: null, - replace: false, - header: null, - body: "Status: Sent, Dest: 0987654321", - data: null, - timestamp: new Date().valueOf(), - language: null, - status: null, - scts: null, - dt: null, - encoding: PDU_CDMA_MSG_CODING_7BITS_ASCII, - messageClass: GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], - messageType: PDU_CDMA_MSG_TYPE_P2P, - serviceCategory: 0, - subMsgType: PDU_CDMA_MSG_TYPE_DELIVER_ACK, - msgId: msgId, - errorClass: errorClass, - msgStatus: msgStatus - }; - - context.RIL._processCdmaSmsStatusReport(message); - - let postedMessage = workerHelper.postedMessage; - - // Check if pending token is removed. - ok((errorClass === 2) ? !!sentSmsMap[msgId] : !sentSmsMap[msgId]); - - // Check the response message accordingly. - if (errorClass === -1) { - // Check if the report is treated as normal incoming SMS - equal("sms-received", postedMessage.rilMessageType); - } else if (errorClass === 2) { - // Do nothing. - } else { - // Check Delivery Status - if (errorClass === 0) { - equal(postedMessage.deliveryStatus, GECKO_SMS_DELIVERY_STATUS_SUCCESS); - } else { - equal(postedMessage.deliveryStatus, GECKO_SMS_DELIVERY_STATUS_ERROR); - } - } - } - - test_StatusReport(-1, -1); // Message Status Sub-parameter is absent. - test_StatusReport(0, 0); // 00|000000: no error|Message accepted - test_StatusReport(2, 4); // 10|000100: temporary condition|Network congestion - test_StatusReport(3, 5); // 11|000101: permanent condition|Network error - - run_next_test(); -}); - -/** - * Verify WAP Push over CDMA SMS Message. - */ -add_test(function test_processCdmaSmsWapPush() { - let workerHelper = newInterceptWorker(), - worker = workerHelper.worker, - context = worker.ContextPool._contexts[0], - bitBufferHelper = context.BitBufferHelper, - cdmaPduHelper = context.CdmaPDUHelper; - - function test_CdmaSmsWapPdu(wdpData, reversed) { - let orig_address = "0987654321", - hexString, - fullDataHexString = ""; - - for (let i = 0; i < wdpData.length; i++) { - let dataIndex = (reversed) ? (wdpData.length - i - 1) : i; - hexString = "00"; // MSG_TYPE - hexString += bytesToHexString([wdpData.length]); // TOTAL_SEG - hexString += bytesToHexString([dataIndex]); // SEG_NUM (zero-based) - if ((dataIndex === 0)) { - hexString += "23F00B84"; // SOURCE_PORT, DEST_PORT for 1st segment - } - hexString += wdpData[dataIndex]; // WDP DATA - - do_print("hexString: " + hexString); - - fullDataHexString += wdpData[i]; - - let pdu = { - teleservice: PDU_CDMA_MSG_TELESERIVCIE_ID_WAP, - address: orig_address, - bearerData: encodeOpaqueUserData(bitBufferHelper, - { msg_type: PDU_CDMA_MSG_TYPE_DELIVER, - data: hexStringToBytes(hexString) }) - }; - - worker.onRILMessage(0, newSmsParcel(cdmaPduHelper, pdu)); - } - - let postedMessage = workerHelper.postedMessage; - - do_print("fullDataHexString: " + fullDataHexString); - - equal("sms-received", postedMessage.rilMessageType); - equal(PDU_CDMA_MSG_TELESERIVCIE_ID_WAP, postedMessage.teleservice); - equal(orig_address, postedMessage.sender); - equal(0x23F0, postedMessage.header.originatorPort); - equal(0x0B84, postedMessage.header.destinationPort); - equal(fullDataHexString, bytesToHexString(postedMessage.data)); - } - - // Verify Single WAP PDU - test_CdmaSmsWapPdu(["000102030405060708090A0B0C0D0E0F"]); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_sms_cdmapduhelper.js b/dom/system/gonk/tests/test_ril_worker_sms_cdmapduhelper.js deleted file mode 100644 index 276728f2f..000000000 --- a/dom/system/gonk/tests/test_ril_worker_sms_cdmapduhelper.js +++ /dev/null @@ -1,210 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Verify CdmaPDUHelper#encodeUserDataReplyOption. - */ -add_test(function test_CdmaPDUHelper_encodeUserDataReplyOption() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - let context = worker.ContextPool._contexts[0]; - - let testDataBuffer = []; - context.BitBufferHelper.startWrite(testDataBuffer); - - let helper = context.CdmaPDUHelper; - helper.encodeUserDataReplyOption({requestStatusReport: true}); - - let expectedDataBuffer = [PDU_CDMA_MSG_USERDATA_REPLY_OPTION, 0x01, 0x40]; - - equal(testDataBuffer.length, expectedDataBuffer.length); - - for (let i = 0; i < expectedDataBuffer.length; i++) { - equal(testDataBuffer[i], expectedDataBuffer[i]); - } - - run_next_test(); -}); - -/** - * Verify CdmaPDUHelper#cdma_decodeUserDataMsgStatus. - */ -add_test(function test_CdmaPDUHelper_decodeUserDataMsgStatus() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - let context = worker.ContextPool._contexts[0]; - - let helper = context.CdmaPDUHelper; - function test_MsgStatus(octet) { - let testDataBuffer = [octet]; - context.BitBufferHelper.startRead(testDataBuffer); - let result = helper.decodeUserDataMsgStatus(); - - equal(result.errorClass, octet >>> 6); - equal(result.msgStatus, octet & 0x3F); - } - - // 00|000000: no error|Message accepted - test_MsgStatus(0x00); - - // 10|000100: temporary condition|Network congestion - test_MsgStatus(0x84); - - // 11|000101: permanent condition|Network error - test_MsgStatus(0xC5); - - run_next_test(); -}); - -/** - * Verify CdmaPDUHelper#decodeCdmaPDUMsg. - * - encoding by shift-jis - */ -add_test(function test_CdmaPDUHelper_decodeCdmaPDUMsg_Shift_jis() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - let context = worker.ContextPool._contexts[0]; - - let helper = context.CdmaPDUHelper; - function test_decodePDUMsg(testDataBuffer, expected, encoding, msgType, msgBodySize) { - context.BitBufferHelper.startRead(testDataBuffer); - let result = helper.decodeCdmaPDUMsg(encoding, msgType, msgBodySize); - equal(result, expected); - } - - // Shift-JIS has 1 byte and 2 byte code for one character and has some types of characters: - // Hiragana, Kanji, Katakana(fullwidth, halfwidth)... - // This test is a combination of 1 byte and 2 byte code and types of characters. - - // test case 1 - let testDataBuffer1 = [0x82, 0x58, 0x33, 0x41, 0x61, 0x33, 0x82, 0x60, - 0x82, 0x81, 0x33, 0xB1, 0xAF, 0x33, 0x83, 0x41, - 0x83, 0x96, 0x33, 0x82, 0xA0, 0x33, 0x93, 0xFA, - 0x33, 0x3A, 0x3C, 0x33, 0x81, 0x80, 0x81, 0x8E, - 0x33, 0x31, 0x82, 0x51, 0x41, 0x61, 0x82, 0x51, - 0x82, 0x60, 0x82, 0x81, 0x82, 0x51, 0xB1, 0xAF, - 0x82, 0x51, 0x83, 0x41, 0x83, 0x96, 0x82, 0x51, - 0x82, 0xA0, 0x82, 0x51, 0x93, 0xFA, 0x82, 0x51, - 0x3A, 0x3C, 0x82, 0x51, 0x81, 0x80, 0x81, 0x8E, - 0x82, 0x51]; - - test_decodePDUMsg( - testDataBuffer1, - "\uFF19\u0033\u0041\u0061\u0033\uFF21\uFF41\u0033\uFF71\uFF6F\u0033\u30A2\u30F6\u0033\u3042\u0033\u65E5\u0033\u003A\u003C\u0033\u00F7\u2103\u0033\u0031\uFF12\u0041\u0061\uFF12\uFF21\uFF41\uFF12\uFF71\uFF6F\uFF12\u30A2\u30F6\uFF12\u3042\uFF12\u65E5\uFF12\u003A\u003C\uFF12\u00F7\u2103\uFF12", - PDU_CDMA_MSG_CODING_SHIFT_JIS, - undefined, - testDataBuffer1.length - ); - - // test case 2 - let testDataBuffer2 = [0x31, 0x51, 0x63, 0x82, 0x58, 0x51, 0x63, 0x82, - 0x60, 0x82, 0x81, 0x51, 0x63, 0xB1, 0xAF, 0x51, - 0x63, 0x83, 0x41, 0x83, 0x96, 0x51, 0x63, 0x82, - 0xA0, 0x51, 0x63, 0x93, 0xFA, 0x51, 0x63, 0x3A, - 0x3C, 0x51, 0x63, 0x81, 0x80, 0x81, 0x8E, 0x51, - 0x63, 0x31, 0x82, 0x70, 0x82, 0x85, 0x82, 0x58, - 0x82, 0x70, 0x82, 0x85, 0x41, 0x61, 0x82, 0x70, - 0x82, 0x85, 0xB1, 0xAF, 0x82, 0x70, 0x82, 0x85, - 0x83, 0x41, 0x83, 0x96, 0x82, 0x70, 0x82, 0x85, - 0x82, 0xA0, 0x82, 0x70, 0x82, 0x85, 0x93, 0xFA, - 0x82, 0x70, 0x82, 0x85, 0x3A, 0x3C, 0x82, 0x70, - 0x82, 0x85, 0x81, 0x80, 0x81, 0x8E, 0x82, 0x70, - 0x82, 0x85]; - - test_decodePDUMsg( - testDataBuffer2, - "\u0031\u0051\u0063\uFF19\u0051\u0063\uFF21\uFF41\u0051\u0063\uFF71\uFF6F\u0051\u0063\u30A2\u30F6\u0051\u0063\u3042\u0051\u0063\u65E5\u0051\u0063\u003A\u003C\u0051\u0063\u00F7\u2103\u0051\u0063\u0031\uFF31\uFF45\uFF19\uFF31\uFF45\u0041\u0061\uFF31\uFF45\uFF71\uFF6F\uFF31\uFF45\u30A2\u30F6\uFF31\uFF45\u3042\uFF31\uFF45\u65E5\uFF31\uFF45\u003A\u003C\uFF31\uFF45\u00F7\u2103\uFF31\uFF45", - PDU_CDMA_MSG_CODING_SHIFT_JIS, - undefined, - testDataBuffer2.length - ); - - // test case 3 - let testDataBuffer3 = [0x31, 0xC2, 0xDF, 0x82, 0x58, 0xC2, 0xDF, 0x41, - 0x61, 0xC2, 0xDF, 0x82, 0x60, 0x82, 0x81, 0xC2, - 0xDF, 0x83, 0x41, 0x83, 0x96, 0xC2, 0xDF, 0x82, - 0xA0, 0xC2, 0xDF, 0x93, 0xFA, 0xC2, 0xDF, 0x3A, - 0x3C, 0xC2, 0xDF, 0x81, 0x80, 0x81, 0x8E, 0xC2, - 0xDF, 0x31, 0x83, 0x51, 0x83, 0x87, 0x82, 0x58, - 0x83, 0x51, 0x83, 0x87, 0x41, 0x61, 0x83, 0x51, - 0x83, 0x87, 0x82, 0x60, 0x82, 0x81, 0x83, 0x51, - 0x83, 0x87, 0xB1, 0xAF, 0x83, 0x51, 0x83, 0x87, - 0x82, 0xA0, 0x83, 0x51, 0x83, 0x87, 0x93, 0xFA, - 0x83, 0x51, 0x83, 0x87, 0x3A, 0x3C, 0x83, 0x51, - 0x83, 0x87, 0x81, 0x80, 0x81, 0x8E, 0x83, 0x51, - 0x83, 0x87]; - - test_decodePDUMsg( - testDataBuffer3, - "\u0031\uFF82\uFF9F\uFF19\uFF82\uFF9F\u0041\u0061\uFF82\uFF9F\uFF21\uFF41\uFF82\uFF9F\u30A2\u30F6\uFF82\uFF9F\u3042\uFF82\uFF9F\u65E5\uFF82\uFF9F\u003A\u003C\uFF82\uFF9F\u00F7\u2103\uFF82\uFF9F\u0031\u30B2\u30E7\uFF19\u30B2\u30E7\u0041\u0061\u30B2\u30E7\uFF21\uFF41\u30B2\u30E7\uFF71\uFF6F\u30B2\u30E7\u3042\u30B2\u30E7\u65E5\u30B2\u30E7\u003A\u003C\u30B2\u30E7\u00F7\u2103\u30B2\u30E7", - PDU_CDMA_MSG_CODING_SHIFT_JIS, - undefined, - testDataBuffer3.length - ); - - // test case 4 - let testDataBuffer4 = [0x31, 0x82, 0xB0, 0x82, 0x58, 0x82, 0xB0, 0x41, - 0x61, 0x82, 0xB0, 0x82, 0x60, 0x82, 0x81, 0x82, - 0xB0, 0xB1, 0xAF, 0x82, 0xB0, 0x83, 0x41, 0x83, - 0x96, 0x82, 0xB0, 0x93, 0xFA, 0x82, 0xB0, 0x3A, - 0x3C, 0x82, 0xB0, 0x81, 0x80, 0x81, 0x8E, 0x82, - 0xB0, 0x31, 0x88, 0xA4, 0x82, 0x58, 0x88, 0xA4, - 0x41, 0x61, 0x88, 0xA4, 0x82, 0x60, 0x82, 0x81, - 0x88, 0xA4, 0xB1, 0xAF, 0x88, 0xA4, 0x83, 0x41, - 0x83, 0x96, 0x88, 0xA4, 0x82, 0xA0, 0x88, 0xA4, - 0x3A, 0x3C, 0x88, 0xA4, 0x81, 0x80, 0x81, 0x8E, - 0x88, 0xA4]; - - test_decodePDUMsg( - testDataBuffer4, - "\u0031\u3052\uFF19\u3052\u0041\u0061\u3052\uFF21\uFF41\u3052\uFF71\uFF6F\u3052\u30A2\u30F6\u3052\u65E5\u3052\u003A\u003C\u3052\u00F7\u2103\u3052\u0031\u611B\uFF19\u611B\u0041\u0061\u611B\uFF21\uFF41\u611B\uFF71\uFF6F\u611B\u30A2\u30F6\u611B\u3042\u611B\u003A\u003C\u611B\u00F7\u2103\u611B", - PDU_CDMA_MSG_CODING_SHIFT_JIS, - undefined, - testDataBuffer4.length - ); - - // test case 5 - let testDataBuffer5 = [0x31, 0x40, 0x82, 0x58, 0x40, 0x41, 0x61, 0x40, - 0x82, 0x60, 0x82, 0x81, 0x40, 0xB1, 0xAF, 0x40, - 0x83, 0x41, 0x83, 0x96, 0x40, 0x82, 0xA0, 0x40, - 0x93, 0xFA, 0x40, 0x81, 0x80, 0x81, 0x8E, 0x40, - 0x31, 0x81, 0x9B, 0x82, 0x58, 0x81, 0x9B, 0x41, - 0x61, 0x81, 0x9B, 0x82, 0x60, 0x82, 0x81, 0x81, - 0x9B, 0xB1, 0xAF, 0x81, 0x9B, 0x83, 0x41, 0x83, - 0x96, 0x81, 0x9B, 0x82, 0xA0, 0x81, 0x9B, 0x93, - 0xFA, 0x81, 0x9B, 0x3A, 0x3C, 0x81, 0x9B]; - - test_decodePDUMsg( - testDataBuffer5, - "\u0031\u0040\uFF19\u0040\u0041\u0061\u0040\uFF21\uFF41\u0040\uFF71\uFF6F\u0040\u30A2\u30F6\u0040\u3042\u0040\u65E5\u0040\u00F7\u2103\u0040\u0031\u25CB\uFF19\u25CB\u0041\u0061\u25CB\uFF21\uFF41\u25CB\uFF71\uFF6F\u25CB\u30A2\u30F6\u25CB\u3042\u25CB\u65E5\u25CB\u003A\u003C\u25CB", - PDU_CDMA_MSG_CODING_SHIFT_JIS, - undefined, - testDataBuffer5.length - ); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_sms_gsmpduhelper.js b/dom/system/gonk/tests/test_ril_worker_sms_gsmpduhelper.js deleted file mode 100644 index f52c64cf8..000000000 --- a/dom/system/gonk/tests/test_ril_worker_sms_gsmpduhelper.js +++ /dev/null @@ -1,282 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Verify GsmPDUHelper#readDataCodingScheme. - */ -add_test(function test_GsmPDUHelper_readDataCodingScheme() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - function test_dcs(dcs, encoding, messageClass, mwi) { - helper.readHexOctet = function() { - return dcs; - } - - let msg = {}; - helper.readDataCodingScheme(msg); - - equal(msg.dcs, dcs); - equal(msg.encoding, encoding); - equal(msg.messageClass, messageClass); - equal(msg.mwi == null, mwi == null); - if (mwi != null) { - equal(msg.mwi.active, mwi.active); - equal(msg.mwi.discard, mwi.discard); - equal(msg.mwi.msgCount, mwi.msgCount); - } - } - - // Group 00xx - // Bit 3 and 2 indicate the character set being used. - test_dcs(0x00, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - test_dcs(0x04, PDU_DCS_MSG_CODING_8BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - test_dcs(0x08, PDU_DCS_MSG_CODING_16BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - test_dcs(0x0C, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - // Bit 4, if set to 0, indicates that bits 1 to 0 are reserved and have no - // message class meaning. - test_dcs(0x01, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - test_dcs(0x02, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - test_dcs(0x03, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - // Bit 4, if set to 1, indicates that bits 1 to 0 have a message class meaning. - test_dcs(0x10, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]); - test_dcs(0x11, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_1]); - test_dcs(0x12, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]); - test_dcs(0x13, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_3]); - - // Group 01xx - test_dcs(0x50, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]); - - // Group 1000..1011: reserved - test_dcs(0x8F, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - test_dcs(0x9F, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - test_dcs(0xAF, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - test_dcs(0xBF, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - - // Group 1100: Message Waiting Indication Group: Discard Message - // Bit 3 indicates Indication Sense: - test_dcs(0xC0, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], - {active: false, discard: true, msgCount: 0}); - test_dcs(0xC8, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], - {active: true, discard: true, msgCount: -1}); - // Bit 2 is reserved, and set to 0: - test_dcs(0xCC, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], - {active: true, discard: true, msgCount: -1}); - - // Group 1101: Message Waiting Indication Group: Store Message - // Bit 3 indicates Indication Sense: - test_dcs(0xD0, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], - {active: false, discard: false, msgCount: 0}); - test_dcs(0xD8, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], - {active: true, discard: false, msgCount: -1}); - // Bit 2 is reserved, and set to 0: - test_dcs(0xDC, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], - {active: true, discard: false, msgCount: -1}); - - // Group 1110: Message Waiting Indication Group: Store Message, UCS2 - // Bit 3 indicates Indication Sense: - test_dcs(0xE0, PDU_DCS_MSG_CODING_16BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], - {active: false, discard: false, msgCount: 0}); - test_dcs(0xE8, PDU_DCS_MSG_CODING_16BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], - {active: true, discard: false, msgCount: -1}); - // Bit 2 is reserved, and set to 0: - test_dcs(0xEC, PDU_DCS_MSG_CODING_16BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], - {active: true, discard: false, msgCount: -1}); - - // Group 1111 - test_dcs(0xF0, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]); - test_dcs(0xF1, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_1]); - test_dcs(0xF2, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]); - test_dcs(0xF3, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_3]); - test_dcs(0xF4, PDU_DCS_MSG_CODING_8BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]); - test_dcs(0xF5, PDU_DCS_MSG_CODING_8BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_1]); - test_dcs(0xF6, PDU_DCS_MSG_CODING_8BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]); - test_dcs(0xF7, PDU_DCS_MSG_CODING_8BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_3]); - // Bit 3 is reserved and should be set to 0, but if it doesn't we should - // ignore it. - test_dcs(0xF8, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]); - - run_next_test(); -}); - -/** - * Verify GsmPDUHelper#writeStringAsSeptets() padding bits handling. - */ -add_test(function test_GsmPDUHelper_writeStringAsSeptets() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - helper.resetOctetWritten = function() { - helper.octetsWritten = 0; - }; - helper.writeHexOctet = function() { - helper.octetsWritten++; - }; - - let base = "AAAAAAAA"; // Base string of 8 characters long - for (let len = 0; len < 8; len++) { - let str = base.substring(0, len); - - for (let paddingBits = 0; paddingBits < 8; paddingBits++) { - do_print("Verifying GsmPDUHelper.writeStringAsSeptets(" - + str + ", " + paddingBits + ", <default>, <default>)"); - helper.resetOctetWritten(); - helper.writeStringAsSeptets(str, paddingBits, PDU_NL_IDENTIFIER_DEFAULT, - PDU_NL_IDENTIFIER_DEFAULT); - equal(Math.ceil(((len * 7) + paddingBits) / 8), - helper.octetsWritten); - } - } - - run_next_test(); -}); - -/** - * Verify that encoding with Spanish locking shift table generates the same - * septets as with GSM default alphabet table. - * - * Bug 1138841 - Incorrect Spanish national language locking shift table - * definition. - */ -add_test(function test_GsmPDUHelper_writeStringAsSeptets_spanish_fallback() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let buf = []; - helper.writeHexOctet = function(octet) { - buf.push(octet); - } - - // Simple message string which is covered by GSM default alphabet. - let msg = "The quick brown fox jumps over the lazy dog"; - - // Encoded with GSM default alphabet. - helper.writeStringAsSeptets(msg, 0 /* paddingBits */, - PDU_NL_IDENTIFIER_DEFAULT, PDU_NL_IDENTIFIER_DEFAULT); - let octetsWithDefaultTable = buf; - buf = []; - - // Encoded with Spanish locking shift table. - helper.writeStringAsSeptets(msg, 0 /* paddingBits */, - PDU_NL_IDENTIFIER_SPANISH, PDU_NL_IDENTIFIER_SPANISH); - - // The length and content should be equal to what encoded with GSM default - // alphabet. - equal(octetsWithDefaultTable.length, buf.length); - for (let i = 0; i < buf.length; i++) { - equal(octetsWithDefaultTable[i], buf[i]); - } - - run_next_test(); -}); - -/** - * Verify GsmPDUHelper#readAddress - */ -add_test(function test_GsmPDUHelper_readAddress() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - function test_address(addrHex, addrString) { - let uint16Array = []; - let ix = 0; - for (let i = 0; i < addrHex.length; ++i) { - uint16Array[i] = addrHex[i].charCodeAt(); - } - - context.Buf.readUint16 = function(){ - if(ix >= uint16Array.length) { - do_throw("out of range in uint16Array"); - } - return uint16Array[ix++]; - } - let length = helper.readHexOctet(); - let parsedAddr = helper.readAddress(length); - equal(parsedAddr, addrString); - } - - // For AlphaNumeric - test_address("04D01100", "_@"); - test_address("04D01000", "\u0394@"); - - // Direct prepand - test_address("0B914151245584F6", "+14154255486"); - test_address("0E914151245584B633", "+14154255486#33"); - - // PDU_TOA_NATIONAL - test_address("0BA14151245584F6", "14154255486"); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_sms_nl_tables.js b/dom/system/gonk/tests/test_ril_worker_sms_nl_tables.js deleted file mode 100644 index 32bc5dc2a..000000000 --- a/dom/system/gonk/tests/test_ril_worker_sms_nl_tables.js +++ /dev/null @@ -1,77 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -const ESCAPE = "\uffff"; -const RESCTL = "\ufffe"; -const LF = "\n"; -const CR = "\r"; -const SP = " "; -const FF = "\u000c"; - -function run_test() { - run_next_test(); -} - -/** - * Verify validity of the national language tables - */ -add_test(function test_nl_locking_shift_tables_validity() { - for (let lst = 0; lst < PDU_NL_LOCKING_SHIFT_TABLES.length; lst++) { - do_print("Verifying PDU_NL_LOCKING_SHIFT_TABLES[" + lst + "]"); - - let table = PDU_NL_LOCKING_SHIFT_TABLES[lst]; - - // Make sure table length is 128, or it will break table lookup algorithm. - equal(table.length, 128); - - // Make sure special values are preserved. - equal(table[PDU_NL_EXTENDED_ESCAPE], ESCAPE); - equal(table[PDU_NL_LINE_FEED], LF); - equal(table[PDU_NL_CARRIAGE_RETURN], CR); - equal(table[PDU_NL_SPACE], SP); - } - - run_next_test(); -}); - -add_test(function test_nl_single_shift_tables_validity() { - for (let sst = 0; sst < PDU_NL_SINGLE_SHIFT_TABLES.length; sst++) { - do_print("Verifying PDU_NL_SINGLE_SHIFT_TABLES[" + sst + "]"); - - let table = PDU_NL_SINGLE_SHIFT_TABLES[sst]; - - // Make sure table length is 128, or it will break table lookup algorithm. - equal(table.length, 128); - - // Make sure special values are preserved. - equal(table[PDU_NL_EXTENDED_ESCAPE], ESCAPE); - equal(table[PDU_NL_PAGE_BREAK], FF); - equal(table[PDU_NL_RESERVED_CONTROL], RESCTL); - } - - run_next_test(); -}); - -add_test(function test_gsm_sms_strict_7bit_charmap_validity() { - let defaultTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - let defaultShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - for (let from in GSM_SMS_STRICT_7BIT_CHARMAP) { - let to = GSM_SMS_STRICT_7BIT_CHARMAP[from]; - do_print("Verifying GSM_SMS_STRICT_7BIT_CHARMAP[\"\\u0x" - + from.charCodeAt(0).toString(16) + "\"] => \"\\u" - + to.charCodeAt(0).toString(16) + "\""); - - // Make sure "from" is not in default table - equal(defaultTable.indexOf(from), -1); - equal(defaultShiftTable.indexOf(from), -1); - // Make sure "to" is in default table - if ((defaultTable.indexOf(to) < 0) - && (defaultShiftTable.indexOf(to) < 0)) { - equal(false, true); - } - } - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_sms_segment_info.js b/dom/system/gonk/tests/test_ril_worker_sms_segment_info.js deleted file mode 100644 index 2b29ac60e..000000000 --- a/dom/system/gonk/tests/test_ril_worker_sms_segment_info.js +++ /dev/null @@ -1,115 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -XPCOMUtils.defineLazyGetter(this, "gSmsSegmentHelper", function() { - let ns = {}; - Cu.import("resource://gre/modules/SmsSegmentHelper.jsm", ns); - return ns.SmsSegmentHelper; -}); - -const ESCAPE = "\uffff"; -const RESCTL = "\ufffe"; - -function run_test() { - run_next_test(); -} - -/** - * Verify SmsSegmentHelper#countGsm7BitSeptets() and - * GsmPDUHelper#writeStringAsSeptets() algorithm match each other. - */ -add_test(function test_SmsSegmentHelper__countGsm7BitSeptets() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - helper.resetOctetWritten = function() { - helper.octetsWritten = 0; - }; - helper.writeHexOctet = function() { - helper.octetsWritten++; - }; - - function do_check_calc(str, expectedCalcLen, lst, sst, strict7BitEncoding, strToWrite) { - equal(expectedCalcLen, - gSmsSegmentHelper - .countGsm7BitSeptets(str, - PDU_NL_LOCKING_SHIFT_TABLES[lst], - PDU_NL_SINGLE_SHIFT_TABLES[sst], - strict7BitEncoding)); - - helper.resetOctetWritten(); - strToWrite = strToWrite || str; - helper.writeStringAsSeptets(strToWrite, 0, lst, sst); - equal(Math.ceil(expectedCalcLen * 7 / 8), helper.octetsWritten); - } - - // Test calculation encoded message length using both locking/single shift tables. - for (let lst = 0; lst < PDU_NL_LOCKING_SHIFT_TABLES.length; lst++) { - let langTable = PDU_NL_LOCKING_SHIFT_TABLES[lst]; - - let str = langTable.substring(0, PDU_NL_EXTENDED_ESCAPE) - + langTable.substring(PDU_NL_EXTENDED_ESCAPE + 1); - - for (let sst = 0; sst < PDU_NL_SINGLE_SHIFT_TABLES.length; sst++) { - let langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[sst]; - - // <escape>, <resctrl> should be ignored. - do_check_calc(ESCAPE + RESCTL, 0, lst, sst); - - // Characters defined in locking shift table should be encoded directly. - do_check_calc(str, str.length, lst, sst); - - let [str1, str2] = ["", ""]; - for (let i = 0; i < langShiftTable.length; i++) { - if ((i == PDU_NL_EXTENDED_ESCAPE) || (i == PDU_NL_RESERVED_CONTROL)) { - continue; - } - - let c = langShiftTable[i]; - if (langTable.indexOf(c) >= 0) { - str1 += c; - } else { - str2 += c; - } - } - - // Characters found in both locking/single shift tables should be - // directly encoded. - do_check_calc(str1, str1.length, lst, sst); - - // Characters found only in single shift tables should be encoded as - // <escape><code>, therefore doubles its original length. - do_check_calc(str2, str2.length * 2, lst, sst); - } - } - - // Bug 790192: support strict GSM SMS 7-Bit encoding - let str = "", strToWrite = "", gsmLen = 0; - for (let c in GSM_SMS_STRICT_7BIT_CHARMAP) { - str += c; - strToWrite += GSM_SMS_STRICT_7BIT_CHARMAP[c]; - if (PDU_NL_LOCKING_SHIFT_TABLES.indexOf(GSM_SMS_STRICT_7BIT_CHARMAP[c])) { - gsmLen += 1; - } else { - gsmLen += 2; - } - } - do_check_calc(str, gsmLen, - PDU_NL_IDENTIFIER_DEFAULT, PDU_NL_IDENTIFIER_DEFAULT, - true, strToWrite); - - run_next_test(); -}); - diff --git a/dom/system/gonk/tests/test_ril_worker_smsc_address.js b/dom/system/gonk/tests/test_ril_worker_smsc_address.js deleted file mode 100644 index c8c283b7c..000000000 --- a/dom/system/gonk/tests/test_ril_worker_smsc_address.js +++ /dev/null @@ -1,112 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -const SMSC_ATT = '+13123149810'; -const SMSC_ATT_TYPO = '+++1312@@@314$$$9,8,1,0'; -const SMSC_ATT_TEXT = '"+13123149810",145'; -const SMSC_ATT_TEXT_INCORRECT_TOA = '"+13123149810",129'; -const SMSC_ATT_PDU = '07913121139418F0'; -const SMSC_O2 = '+447802000332'; -const SMSC_O2_TEXT = '"+447802000332",145'; -const SMSC_O2_PDU = '0791448720003023'; -const SMSC_EMPTY = ''; -const SMSC_TON_UNKNOWN = '0407485455' -const SMSC_TON_UNKNOWN_TEXT = '"0407485455",129'; -const SMSC_TON_UNKNOWN_TEXT_NO_TOA = '"0407485455"'; -const SMSC_TON_UNKNOWN_TEXT_INVALID_TOA = '"0407485455",abc'; -const SMSC_TON_UNKNOWN_PDU = '06814070844555'; -const SMSC_EMPTY_PDU = 'FFFFFFFFFFFFFFFFFFFFFFFF'; -const SMSC_EMPTY_TEXT = ''; - -function run_test() { - run_next_test(); -} - -function setSmsc(context, smsc, ton, npi, expected) { - context.Buf.postRILMessage = function() { - equal(this.readString(), expected); - }; - - context.RIL.setSmscAddress({ - smscAddress: smsc, - typeOfNumber: ton, - numberPlanIdentification: npi - }); -} - -function getSmsc(worker, context, raw, smsc, ton, npi) { - worker.postMessage = function(message) { - equal(message.smscAddress, smsc); - equal(message.typeOfNumber, ton); - equal(message.numberPlanIdentification, npi); - } - - context.Buf.writeString(raw); - context.RIL[REQUEST_GET_SMSC_ADDRESS](0, { rilMessageType: "getSmscAddress"}); -} - -add_test(function test_setSmscAddress() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let parcelTypes = []; - context.Buf.newParcel = (type, options) => parcelTypes.push(type); - - // Test text mode. - worker.RILQUIRKS_SMSC_ADDRESS_FORMAT = "text"; - - setSmsc(context, SMSC_ATT, 1, 1, SMSC_ATT_TEXT); - equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS); - - setSmsc(context, SMSC_O2, 1, 1, SMSC_O2_TEXT); - equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS); - - setSmsc(context, SMSC_ATT_TYPO, 1, 1, SMSC_ATT_TEXT); - equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS); - - setSmsc(context, SMSC_TON_UNKNOWN, 0, 1, SMSC_TON_UNKNOWN_TEXT); - equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS); - - // Test pdu mode. - worker.RILQUIRKS_SMSC_ADDRESS_FORMAT = "pdu"; - - setSmsc(context, SMSC_ATT, 1, 1, SMSC_ATT_PDU); - equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS); - - setSmsc(context, SMSC_O2, 1, 1, SMSC_O2_PDU); - equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS); - - setSmsc(context, SMSC_ATT_TYPO, 1, 1, SMSC_ATT_PDU); - equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS); - - setSmsc(context, SMSC_TON_UNKNOWN, 0, 1, SMSC_TON_UNKNOWN_PDU); - equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS); - - run_next_test(); -}); - -add_test(function test_getSmscAddress() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - - // Test text mode. - worker.RILQUIRKS_SMSC_ADDRESS_FORMAT = "text"; - getSmsc(worker, context, SMSC_ATT_TEXT, SMSC_ATT, 1, 1); - getSmsc(worker, context, SMSC_ATT_TEXT_INCORRECT_TOA, SMSC_ATT, 1, 1); - getSmsc(worker, context, SMSC_O2_TEXT, SMSC_O2, 1, 1); - getSmsc(worker, context, SMSC_TON_UNKNOWN_TEXT, SMSC_TON_UNKNOWN, 0, 1); - getSmsc(worker, context, SMSC_TON_UNKNOWN_TEXT_NO_TOA, SMSC_TON_UNKNOWN, 0, 1); - getSmsc(worker, context, SMSC_TON_UNKNOWN_TEXT_INVALID_TOA, SMSC_TON_UNKNOWN, - 0, 1); - getSmsc(worker, context, SMSC_EMPTY_TEXT, SMSC_EMPTY, 0, 1); - - // Test pdu mode. - worker.RILQUIRKS_SMSC_ADDRESS_FORMAT = "pdu"; - getSmsc(worker, context, SMSC_ATT_PDU, SMSC_ATT, 1, 1); - getSmsc(worker, context, SMSC_O2_PDU, SMSC_O2, 1, 1); - getSmsc(worker, context, SMSC_TON_UNKNOWN_PDU, SMSC_TON_UNKNOWN, 0, 1); - getSmsc(worker, context, SMSC_EMPTY_PDU, SMSC_EMPTY, 0, 1); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_ssn.js b/dom/system/gonk/tests/test_ril_worker_ssn.js deleted file mode 100644 index ea0a2a599..000000000 --- a/dom/system/gonk/tests/test_ril_worker_ssn.js +++ /dev/null @@ -1,104 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -add_test(function test_notification() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - function Call(callIndex, number) { - this.callIndex = callIndex; - this.number = number; - } - - Call.prototype = { - // Should use CALL_STATE_ACTIVE. - // Any new outgoing call (state = dialing or alerting) will be drop if there - // is no pending outgoing call created before. - state: CALL_STATE_ACTIVE, - //callIndex: 0, - toa: 0, - isMpty: false, - isMT: false, - als: 0, - isVoice: true, - isVoicePrivacy: false, - //number: null, - numberPresentation: 0, - name: null, - namePresentation: 0, - uusInfo: null - }; - - let oneCall = { - 0: new Call(0, '00000') - }; - - let twoCalls = { - 0: new Call(0, '00000'), - 1: new Call(1, '11111') - }; - - function testNotification(calls, code, number, resultNotification) { - - let testInfo = {calls: calls, code: code, number: number, - resultNotification: resultNotification}; - do_print('Test case info: ' + JSON.stringify(testInfo)); - - // Set current calls. - context.RIL.sendChromeMessage({ - rilMessageType: "currentCalls", - calls: calls - }); - - let notificationInfo = { - notificationType: 1, // MT - code: code, - index: 0, - type: 0, - number: number - }; - - context.RIL._processSuppSvcNotification(notificationInfo); - - let postedMessage = workerHelper.postedMessage; - equal(postedMessage.rilMessageType, 'suppSvcNotification'); - equal(postedMessage.number, number); - equal(postedMessage.notification, resultNotification); - - // Clear all existed calls. - context.RIL.sendChromeMessage({ - rilMessageType: "currentCalls", - calls: {} - }); - } - - testNotification(oneCall, SUPP_SVC_NOTIFICATION_CODE2_PUT_ON_HOLD, null, - GECKO_SUPP_SVC_NOTIFICATION_REMOTE_HELD); - - testNotification(oneCall, SUPP_SVC_NOTIFICATION_CODE2_RETRIEVED, null, - GECKO_SUPP_SVC_NOTIFICATION_REMOTE_RESUMED); - - testNotification(twoCalls, SUPP_SVC_NOTIFICATION_CODE2_PUT_ON_HOLD, null, - GECKO_SUPP_SVC_NOTIFICATION_REMOTE_HELD); - - testNotification(twoCalls, SUPP_SVC_NOTIFICATION_CODE2_RETRIEVED, null, - GECKO_SUPP_SVC_NOTIFICATION_REMOTE_RESUMED); - - testNotification(twoCalls, SUPP_SVC_NOTIFICATION_CODE2_PUT_ON_HOLD, '00000', - GECKO_SUPP_SVC_NOTIFICATION_REMOTE_HELD); - - testNotification(twoCalls, SUPP_SVC_NOTIFICATION_CODE2_PUT_ON_HOLD, '11111', - GECKO_SUPP_SVC_NOTIFICATION_REMOTE_HELD); - - testNotification(twoCalls, SUPP_SVC_NOTIFICATION_CODE2_PUT_ON_HOLD, '22222', - GECKO_SUPP_SVC_NOTIFICATION_REMOTE_HELD); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_stk.js b/dom/system/gonk/tests/test_ril_worker_stk.js deleted file mode 100644 index 49b914e89..000000000 --- a/dom/system/gonk/tests/test_ril_worker_stk.js +++ /dev/null @@ -1,1698 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Helper function. - */ -function newUint8SupportOutgoingIndexWorker() { - let worker = newWorker(); - let index = 4; // index for read - let buf = [0, 0, 0, 0]; // Preserved parcel size - let context = worker.ContextPool._contexts[0]; - - context.Buf.writeUint8 = function(value) { - if (context.Buf.outgoingIndex >= buf.length) { - buf.push(value); - } else { - buf[context.Buf.outgoingIndex] = value; - } - - context.Buf.outgoingIndex++; - }; - - context.Buf.readUint8 = function() { - return buf[index++]; - }; - - context.Buf.seekIncoming = function(offset) { - index += offset; - }; - - worker.debug = do_print; - - return worker; -} - -// Test RIL requests related to STK. -/** - * Verify if RIL.sendStkTerminalProfile be called. - */ -add_test(function test_if_send_stk_terminal_profile() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let profileSend = false; - context.RIL.sendStkTerminalProfile = function(data) { - profileSend = true; - }; - - let iccStatus = { - gsmUmtsSubscriptionAppIndex: 0, - apps: [{ - app_state: CARD_APPSTATE_READY, - app_type: CARD_APPTYPE_USIM - }], - }; - worker.RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD = false; - - context.RIL._processICCStatus(iccStatus); - - equal(profileSend, false); - - run_next_test(); -}); - -/** - * Verify RIL.sendStkTerminalProfile - */ -add_test(function test_send_stk_terminal_profile() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - let buf = context.Buf; - - ril.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE); - - buf.seekIncoming(8); - let profile = buf.readString(); - for (let i = 0; i < STK_SUPPORTED_TERMINAL_PROFILE.length; i++) { - equal(parseInt(profile.substring(2 * i, 2 * i + 2), 16), - STK_SUPPORTED_TERMINAL_PROFILE[i]); - } - - run_next_test(); -}); - -/** - * Verify STK terminal response - */ -add_test(function test_stk_terminal_response() { - let worker = newUint8SupportOutgoingIndexWorker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let pduHelper = context.GsmPDUHelper; - - buf.sendParcel = function() { - // Type - equal(this.readInt32(), REQUEST_STK_SEND_TERMINAL_RESPONSE); - - // Token : we don't care - this.readInt32(); - - // Data Size, 44 = 2 * (TLV_COMMAND_DETAILS_SIZE(5) + - // TLV_DEVICE_ID_SIZE(4) + - // TLV_RESULT_SIZE(3) + - // TEXT LENGTH(10)) - equal(this.readInt32(), 44); - - // Command Details, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_COMMAND_DETAILS | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 3); - equal(pduHelper.readHexOctet(), 0x01); - equal(pduHelper.readHexOctet(), STK_CMD_PROVIDE_LOCAL_INFO); - equal(pduHelper.readHexOctet(), STK_LOCAL_INFO_NNA); - - // Device Identifies, Type-Length-Value(Source ID-Destination ID) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DEVICE_ID); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_ME); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_SIM); - - // Result - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_RESULT | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_RESULT_OK); - - // Text - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_TEXT_STRING | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 8); - equal(pduHelper.readHexOctet(), STK_TEXT_CODING_GSM_7BIT_PACKED); - equal(pduHelper.readSeptetsToString(7, 0, PDU_NL_IDENTIFIER_DEFAULT, - PDU_NL_IDENTIFIER_DEFAULT), "Mozilla"); - - run_next_test(); - }; - - let response = { - command: { - commandNumber: 0x01, - typeOfCommand: STK_CMD_PROVIDE_LOCAL_INFO, - commandQualifier: STK_LOCAL_INFO_NNA, - options: { - isPacked: true - } - }, - input: "Mozilla", - resultCode: STK_RESULT_OK - }; - context.RIL.sendStkTerminalResponse(response); -}); - -/** - * Verify STK terminal response : GET INPUT with empty string. - * - * @See |TERMINAL RESPONSE: GET INPUT 1.9.1A| of 27.22.4.3.1 GET INPUT (normal) - * in TS 102 384. - */ -add_test(function test_stk_terminal_response_get_input_empty_string() { - let worker = newUint8SupportOutgoingIndexWorker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let pduHelper = context.GsmPDUHelper; - - buf.sendParcel = function() { - // Type - equal(this.readInt32(), REQUEST_STK_SEND_TERMINAL_RESPONSE); - - // Token : we don't care - this.readInt32(); - - // Data Size, 30 = 2 * (TLV_COMMAND_DETAILS_SIZE(5) + - // TLV_DEVICE_ID_SIZE(4) + - // TLV_RESULT_SIZE(3) + - // TEXT LENGTH(3)) - equal(this.readInt32(), 30); - - // Command Details, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_COMMAND_DETAILS | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 3); - equal(pduHelper.readHexOctet(), 0x01); - equal(pduHelper.readHexOctet(), STK_CMD_GET_INPUT); - equal(pduHelper.readHexOctet(), 0x00); - - // Device Identifies, Type-Length-Value(Source ID-Destination ID) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DEVICE_ID); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_ME); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_SIM); - - // Result - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_RESULT | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_RESULT_OK); - - // Text - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_TEXT_STRING | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_TEXT_CODING_GSM_8BIT); - - run_next_test(); - }; - - let response = { - command: { - commandNumber: 0x01, - typeOfCommand: STK_CMD_GET_INPUT, - commandQualifier: 0x00, - options: { - minLength: 0, - maxLength: 1, - defaultText: "<SEND>" - } - }, - input: "", - resultCode: STK_RESULT_OK - }; - context.RIL.sendStkTerminalResponse(response); -}); - -/** - * Verify STK terminal response : GET INPUT with 160 unpacked characters. - * - * @See |TERMINAL RESPONSE: GET INPUT 1.8.1| of 27.22.4.3.1 GET INPUT (normal) - * in TS 102 384. - */ -add_test(function test_stk_terminal_response_get_input_160_unpacked_characters() { - let worker = newUint8SupportOutgoingIndexWorker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let pduHelper = context.GsmPDUHelper; - let iccPduHelper = context.ICCPDUHelper; - let TEST_TEXT_STRING = "***1111111111###" + - "***2222222222###" + - "***3333333333###" + - "***4444444444###" + - "***5555555555###" + - "***6666666666###" + - "***7777777777###" + - "***8888888888###" + - "***9999999999###" + - "***0000000000###"; - - buf.sendParcel = function() { - // Type - equal(this.readInt32(), REQUEST_STK_SEND_TERMINAL_RESPONSE); - - // Token : we don't care - this.readInt32(); - - // Data Size, 352 = 2 * (TLV_COMMAND_DETAILS_SIZE(5) + - // TLV_DEVICE_ID_SIZE(4) + - // TLV_RESULT_SIZE(3) + - // TEXT LENGTH(164)) - equal(this.readInt32(), 352); - - // Command Details, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_COMMAND_DETAILS | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 3); - equal(pduHelper.readHexOctet(), 0x01); - equal(pduHelper.readHexOctet(), STK_CMD_GET_INPUT); - equal(pduHelper.readHexOctet(), 0x00); - - // Device Identifies, Type-Length-Value(Source ID-Destination ID) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DEVICE_ID); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_ME); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_SIM); - - // Result - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_RESULT | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_RESULT_OK); - - // Text - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_TEXT_STRING | - COMPREHENSIONTLV_FLAG_CR); - // C-TLV Length Encoding: 161 = 0x81 0xA1 - equal(pduHelper.readHexOctet(), 0x81); - equal(pduHelper.readHexOctet(), 0xA1); - equal(pduHelper.readHexOctet(), STK_TEXT_CODING_GSM_8BIT); - equal(iccPduHelper.read8BitUnpackedToString(160), TEST_TEXT_STRING); - - run_next_test(); - }; - - let response = { - command: { - commandNumber: 0x01, - typeOfCommand: STK_CMD_GET_INPUT, - commandQualifier: 0x00, - options: { - minLength: 160, - maxLength: 160, - text: TEST_TEXT_STRING - } - }, - input: TEST_TEXT_STRING, - resultCode: STK_RESULT_OK - }; - context.RIL.sendStkTerminalResponse(response); -}); - -/** - * Verify STK terminal response : GET_INKEY - NO_RESPONSE_FROM_USER with - * duration provided. - * - * @See |27.22.4.2.8 GET INKEY (Variable Time out)| in TS 102 384. - */ -add_test(function test_stk_terminal_response_get_inkey_no_response_from_user() { - let worker = newUint8SupportOutgoingIndexWorker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let pduHelper = context.GsmPDUHelper; - - buf.sendParcel = function() { - // Type - equal(this.readInt32(), REQUEST_STK_SEND_TERMINAL_RESPONSE); - - // Token : we don't care - this.readInt32(); - - // Data Size, 32 = 2 * (TLV_COMMAND_DETAILS_SIZE(5) + - // TLV_DEVICE_ID_SIZE(4) + - // TLV_RESULT_SIZE(3) + - // DURATION(4)) - equal(this.readInt32(), 32); - - // Command Details, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_COMMAND_DETAILS | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 3); - equal(pduHelper.readHexOctet(), 0x01); - equal(pduHelper.readHexOctet(), STK_CMD_GET_INKEY); - equal(pduHelper.readHexOctet(), 0x00); - - // Device Identifies, Type-Length-Value(Source ID-Destination ID) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DEVICE_ID); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_ME); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_SIM); - - // Result - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_RESULT | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_RESULT_NO_RESPONSE_FROM_USER); - - // Duration, Type-Length-Value(Time unit, Time interval) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DURATION); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_TIME_UNIT_SECOND); - equal(pduHelper.readHexOctet(), 10); - - run_next_test(); - }; - - let response = { - command: { - commandNumber: 0x01, - typeOfCommand: STK_CMD_GET_INKEY, - commandQualifier: 0x00, - options: { - duration: { - timeUnit: STK_TIME_UNIT_SECOND, - timeInterval: 10 - }, - text: 'Enter "+"' - } - }, - resultCode: STK_RESULT_NO_RESPONSE_FROM_USER - }; - context.RIL.sendStkTerminalResponse(response); -}); - -/** - * Verify STK terminal response : GET_INKEY - YES/NO request - */ -add_test(function test_stk_terminal_response_get_inkey() { - function do_test(isYesNo) { - let worker = newUint8SupportOutgoingIndexWorker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let pduHelper = context.GsmPDUHelper; - - buf.sendParcel = function() { - // Type - equal(this.readInt32(), REQUEST_STK_SEND_TERMINAL_RESPONSE); - - // Token : we don't care - this.readInt32(); - - // Data Size, 32 = 2 * (TLV_COMMAND_DETAILS_SIZE(5) + - // TLV_DEVICE_ID_SIZE(4) + - // TLV_RESULT_SIZE(3) + - // TEXT LENGTH(4)) - equal(this.readInt32(), 32); - - // Command Details, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_COMMAND_DETAILS | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 3); - equal(pduHelper.readHexOctet(), 0x01); - equal(pduHelper.readHexOctet(), STK_CMD_GET_INKEY); - equal(pduHelper.readHexOctet(), 0x04); - - // Device Identifies, Type-Length-Value(Source ID-Destination ID) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DEVICE_ID); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_ME); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_SIM); - - // Result - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_RESULT | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_RESULT_OK); - - // Yes/No response - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_TEXT_STRING | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_TEXT_CODING_GSM_8BIT); - equal(pduHelper.readHexOctet(), isYesNo ? 0x01 : 0x00); - }; - - let response = { - command: { - commandNumber: 0x01, - typeOfCommand: STK_CMD_GET_INKEY, - commandQualifier: 0x04, - options: { - isYesNoRequested: true - } - }, - isYesNo: isYesNo, - resultCode: STK_RESULT_OK - }; - - context.RIL.sendStkTerminalResponse(response); - }; - - // Test "Yes" response - do_test(true); - // Test "No" response - do_test(false); - - run_next_test(); -}); - -/** - * Verify STK terminal response with additional information. - */ -add_test(function test_stk_terminal_response_with_additional_info() { - function do_test(aInfo) { - let worker = newUint8SupportOutgoingIndexWorker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let pduHelper = context.GsmPDUHelper; - - buf.sendParcel = function() { - // Type - equal(this.readInt32(), REQUEST_STK_SEND_TERMINAL_RESPONSE); - - // Token : we don't care - this.readInt32(); - - // Data Length 26 = 2 * (TLV_COMMAND_DETAILS_SIZE(5) + - // TLV_DEVICE_ID_SIZE(4) + - // TLV_RESULT_SIZE(4)) - equal(this.readInt32(), 26); - - // Command Details, Type-Length-Value(commandNumber, typeOfCommand, commandQualifier) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_COMMAND_DETAILS | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 3); - equal(pduHelper.readHexOctet(), 0x01); - equal(pduHelper.readHexOctet(), STK_CMD_DISPLAY_TEXT); - equal(pduHelper.readHexOctet(), 0x01); - - // Device Identifies, Type-Length-Value(Source ID-Destination ID) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DEVICE_ID); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_ME); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_SIM); - - // Result, Type-Length-Value(General result, Additional information on result) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_RESULT | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_RESULT_TERMINAL_CRNTLY_UNABLE_TO_PROCESS); - equal(pduHelper.readHexOctet(), aInfo); - }; - - let response = { - command: { - commandNumber: 0x01, - typeOfCommand: STK_CMD_DISPLAY_TEXT, - commandQualifier: 0x01, - options: { - isHighPriority: true - } - }, - resultCode: STK_RESULT_TERMINAL_CRNTLY_UNABLE_TO_PROCESS, - additionalInformation: aInfo - }; - - context.RIL.sendStkTerminalResponse(response); - }; - - do_test(0x01); // 'Screen is busy' - - run_next_test(); -}); - -// Test ComprehensionTlvHelper - -/** - * Verify ComprehensionTlvHelper.writeLocationInfoTlv - */ -add_test(function test_write_location_info_tlv() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let tlvHelper = context.ComprehensionTlvHelper; - - // Test with 2-digit mnc, and gsmCellId obtained from UMTS network. - let loc = { - mcc: "466", - mnc: "92", - gsmLocationAreaCode : 10291, - gsmCellId: 19072823 - }; - tlvHelper.writeLocationInfoTlv(loc); - - let tag = pduHelper.readHexOctet(); - equal(tag, COMPREHENSIONTLV_TAG_LOCATION_INFO | - COMPREHENSIONTLV_FLAG_CR); - - let length = pduHelper.readHexOctet(); - equal(length, 9); - - let mcc_mnc = pduHelper.readSwappedNibbleBcdString(3); - equal(mcc_mnc, "46692"); - - let lac = (pduHelper.readHexOctet() << 8) | pduHelper.readHexOctet(); - equal(lac, 10291); - - let cellId = (pduHelper.readHexOctet() << 24) | - (pduHelper.readHexOctet() << 16) | - (pduHelper.readHexOctet() << 8) | - (pduHelper.readHexOctet()); - equal(cellId, 19072823); - - // Test with 1-digit mnc, and gsmCellId obtained from GSM network. - loc = { - mcc: "466", - mnc: "02", - gsmLocationAreaCode : 10291, - gsmCellId: 65534 - }; - tlvHelper.writeLocationInfoTlv(loc); - - tag = pduHelper.readHexOctet(); - equal(tag, COMPREHENSIONTLV_TAG_LOCATION_INFO | - COMPREHENSIONTLV_FLAG_CR); - - length = pduHelper.readHexOctet(); - equal(length, 7); - - mcc_mnc = pduHelper.readSwappedNibbleBcdString(3); - equal(mcc_mnc, "46602"); - - lac = (pduHelper.readHexOctet() << 8) | pduHelper.readHexOctet(); - equal(lac, 10291); - - cellId = (pduHelper.readHexOctet() << 8) | (pduHelper.readHexOctet()); - equal(cellId, 65534); - - // Test with 3-digit mnc, and gsmCellId obtained from GSM network. - loc = { - mcc: "466", - mnc: "222", - gsmLocationAreaCode : 10291, - gsmCellId: 65534 - }; - tlvHelper.writeLocationInfoTlv(loc); - - tag = pduHelper.readHexOctet(); - equal(tag, COMPREHENSIONTLV_TAG_LOCATION_INFO | - COMPREHENSIONTLV_FLAG_CR); - - length = pduHelper.readHexOctet(); - equal(length, 7); - - mcc_mnc = pduHelper.readSwappedNibbleBcdString(3); - equal(mcc_mnc, "466222"); - - lac = (pduHelper.readHexOctet() << 8) | pduHelper.readHexOctet(); - equal(lac, 10291); - - cellId = (pduHelper.readHexOctet() << 8) | (pduHelper.readHexOctet()); - equal(cellId, 65534); - - run_next_test(); -}); - -/** - * Verify ComprehensionTlvHelper.writeErrorNumber - */ -add_test(function test_write_disconnecting_cause() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let tlvHelper = context.ComprehensionTlvHelper; - - tlvHelper.writeCauseTlv(RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_BUSY]); - let tag = pduHelper.readHexOctet(); - equal(tag, COMPREHENSIONTLV_TAG_CAUSE | COMPREHENSIONTLV_FLAG_CR); - let len = pduHelper.readHexOctet(); - equal(len, 2); // We have one cause. - let standard = pduHelper.readHexOctet(); - equal(standard, 0x60); - let cause = pduHelper.readHexOctet(); - equal(cause, 0x80 | CALL_FAIL_BUSY); - - run_next_test(); -}); - -/** - * Verify ComprehensionTlvHelper.getSizeOfLengthOctets - */ -add_test(function test_get_size_of_length_octets() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let tlvHelper = context.ComprehensionTlvHelper; - - let length = 0x70; - equal(tlvHelper.getSizeOfLengthOctets(length), 1); - - length = 0x80; - equal(tlvHelper.getSizeOfLengthOctets(length), 2); - - length = 0x180; - equal(tlvHelper.getSizeOfLengthOctets(length), 3); - - length = 0x18000; - equal(tlvHelper.getSizeOfLengthOctets(length), 4); - - run_next_test(); -}); - -/** - * Verify ComprehensionTlvHelper.writeLength - */ -add_test(function test_write_length() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let tlvHelper = context.ComprehensionTlvHelper; - - let length = 0x70; - tlvHelper.writeLength(length); - equal(pduHelper.readHexOctet(), length); - - length = 0x80; - tlvHelper.writeLength(length); - equal(pduHelper.readHexOctet(), 0x81); - equal(pduHelper.readHexOctet(), length); - - length = 0x180; - tlvHelper.writeLength(length); - equal(pduHelper.readHexOctet(), 0x82); - equal(pduHelper.readHexOctet(), (length >> 8) & 0xff); - equal(pduHelper.readHexOctet(), length & 0xff); - - length = 0x18000; - tlvHelper.writeLength(length); - equal(pduHelper.readHexOctet(), 0x83); - equal(pduHelper.readHexOctet(), (length >> 16) & 0xff); - equal(pduHelper.readHexOctet(), (length >> 8) & 0xff); - equal(pduHelper.readHexOctet(), length & 0xff); - - run_next_test(); -}); - -// Test Proactive commands. - -function test_stk_proactive_command(aOptions) { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let berHelper = context.BerTlvHelper; - let stkHelper = context.StkProactiveCmdHelper; - let stkFactory = context.StkCommandParamsFactory; - - let testPdu = aOptions.pdu; - let testTypeOfCommand = aOptions.typeOfCommand; - let testIcons = aOptions.icons; - let testFunc = aOptions.testFunc; - - if (testIcons) { - let ril = context.RIL; - ril.iccInfoPrivate.sst = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x30]; //IMG: 39 - ril.appType = CARD_APPTYPE_SIM; - - // skip asynchornous process in IconLoader.loadIcons(). - let iconLoader = context.IconLoader; - iconLoader.loadIcons = (recordNumbers, onsuccess, onerror) => { - onsuccess(testIcons); - }; - } - - for(let i = 0 ; i < testPdu.length; i++) { - pduHelper.writeHexOctet(testPdu[i]); - } - - let berTlv = berHelper.decode(testPdu.length); - let ctlvs = berTlv.value; - let ctlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_COMMAND_DETAILS, ctlvs); - let cmdDetails = ctlv.value; - equal(cmdDetails.typeOfCommand, testTypeOfCommand); - - stkFactory.createParam(cmdDetails, ctlvs, (aResult) => { - cmdDetails.options = aResult; - testFunc(context, cmdDetails, ctlvs); - }); -} - -/** - * Verify Proactive command helper : searchForSelectedTags - */ -add_test(function test_stk_proactive_command_search_for_selected_tags() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let berHelper = context.BerTlvHelper; - let stkHelper = context.StkProactiveCmdHelper; - - let tag_test = [ - 0xD0, - 0x3E, - 0x85, 0x0A, 0x61, 0x6C, 0x70, 0x68, 0x61, 0x20, 0x69, 0x64, 0x20, 0x31, - 0x85, 0x0A, 0x61, 0x6C, 0x70, 0x68, 0x61, 0x20, 0x69, 0x64, 0x20, 0x32, - 0x85, 0x0A, 0x61, 0x6C, 0x70, 0x68, 0x61, 0x20, 0x69, 0x64, 0x20, 0x33, - 0x85, 0x0A, 0x61, 0x6C, 0x70, 0x68, 0x61, 0x20, 0x69, 0x64, 0x20, 0x34, - 0x85, 0x0A, 0x61, 0x6C, 0x70, 0x68, 0x61, 0x20, 0x69, 0x64, 0x20, 0x35, - 0x85, 0x00]; - - for (let i = 0; i < tag_test.length; i++) { - pduHelper.writeHexOctet(tag_test[i]); - } - - let berTlv = berHelper.decode(tag_test.length); - let selectedCtlvs = - stkHelper.searchForSelectedTags(berTlv.value, [COMPREHENSIONTLV_TAG_ALPHA_ID]); - let tlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - equal(tlv.value.identifier, "alpha id 1"); - - tlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - equal(tlv.value.identifier, "alpha id 2"); - - tlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - equal(tlv.value.identifier, "alpha id 3"); - - tlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - equal(tlv.value.identifier, "alpha id 4"); - - tlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - equal(tlv.value.identifier, "alpha id 5"); - - // emulate that the alpha identifier is provided and is a null data object, - // which is converted to an empty string in ICCPDUHelper. - tlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - strictEqual(tlv.value.identifier, ""); - - // emulate that the alpha identifier is not provided - tlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - strictEqual(tlv, undefined); - - run_next_test(); -}); - -/** - * Verify Proactive Command : Refresh - */ -add_test(function test_stk_proactive_command_refresh() { - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x10, - 0x81, 0x03, 0x01, 0x01, 0x01, - 0x82, 0x02, 0x81, 0x82, - 0x92, 0x05, 0x01, 0x3F, 0x00, 0x2F, 0xE2 - ], - typeOfCommand: STK_CMD_REFRESH, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - let stkHelper = context.StkProactiveCmdHelper; - let ctlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_FILE_LIST, ctlvs); - equal(ctlv.value.fileList, "3F002FE2"); - } - }); - - run_next_test(); -}); - -/** - * Verify Proactive Command : Play Tone - */ -add_test(function test_stk_proactive_command_play_tone() { - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x1F, - 0x81, 0x03, 0x01, 0x20, 0x00, - 0x82, 0x02, 0x81, 0x03, - 0x85, 0x09, 0x44, 0x69, 0x61, 0x6C, 0x20, 0x54, 0x6F, 0x6E, 0x65, - 0x8E, 0x01, 0x01, - 0x84, 0x02, 0x01, 0x05, - 0x9E, 0x02, 0x00, 0x01 - ], - typeOfCommand: STK_CMD_PLAY_TONE, - icons: [1], - testFunc: (context, cmdDetails, ctlvs) => { - let playTone = cmdDetails.options; - - equal(playTone.text, "Dial Tone"); - equal(playTone.tone, STK_TONE_TYPE_DIAL_TONE); - equal(playTone.duration.timeUnit, STK_TIME_UNIT_SECOND); - equal(playTone.duration.timeInterval, 5); - equal(playTone.iconSelfExplanatory, true); - equal(playTone.icons, 1); - } - }); - - run_next_test(); -}); - -/** - * Verify Proactive Command : Poll Interval - */ -add_test(function test_stk_proactive_command_poll_interval() { - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x0D, - 0x81, 0x03, 0x01, 0x03, 0x00, - 0x82, 0x02, 0x81, 0x82, - 0x84, 0x02, 0x01, 0x14 - ], - typeOfCommand: STK_CMD_POLL_INTERVAL, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - let interval = cmdDetails.options; - - equal(interval.timeUnit, STK_TIME_UNIT_SECOND); - equal(interval.timeInterval, 0x14); - } - }); - - run_next_test(); -}); - -/** - * Verify Proactive Command: Display Text - */ -add_test(function test_stk_proactive_command_display_text() { - test_stk_proactive_command({ - pdu: [ - 0xd0, - 0x2c, - 0x81, 0x03, 0x01, 0x21, 0x80, - 0x82, 0x02, 0x81, 0x02, - 0x0d, 0x1d, 0x00, 0xd3, 0x30, 0x9b, 0xfc, 0x06, 0xc9, 0x5c, 0x30, 0x1a, - 0xa8, 0xe8, 0x02, 0x59, 0xc3, 0xec, 0x34, 0xb9, 0xac, 0x07, 0xc9, 0x60, - 0x2f, 0x58, 0xed, 0x15, 0x9b, 0xb9, 0x40, - 0x9e, 0x02, 0x00, 0x01 - ], - typeOfCommand: STK_CMD_DISPLAY_TEXT, - icons: [1], - testFunc: (context, cmdDetails, ctlvs) => { - let textMsg = cmdDetails.options; - - equal(textMsg.text, "Saldo 2.04 E. Validez 20/05/13. "); - equal(textMsg.iconSelfExplanatory, true); - equal(textMsg.icons, 1); - } - }); - - run_next_test(); -}); - -/** - * Verify Proactive Command: Set Up Event List. - */ -add_test(function test_stk_proactive_command_event_list() { - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x0F, - 0x81, 0x03, 0x01, 0x05, 0x00, - 0x82, 0x02, 0x81, 0x82, - 0x99, 0x04, 0x00, 0x01, 0x02, 0x03 - ], - typeOfCommand: STK_CMD_SET_UP_EVENT_LIST, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - let event = cmdDetails.options; - - equal(Array.isArray(event.eventList), true); - - for (let i = 0; i < event.eventList.length; i++) { - equal(event.eventList[i], i); - } - } - }); - - run_next_test(); -}); - -/** - * Verify Proactive Command : Get Input - */ -add_test(function test_stk_proactive_command_get_input() { - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x22, - 0x81, 0x03, 0x01, 0x23, 0x8F, - 0x82, 0x02, 0x81, 0x82, - 0x8D, 0x05, 0x04, 0x54, 0x65, 0x78, 0x74, - 0x91, 0x02, 0x01, 0x10, - 0x17, 0x08, 0x04, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6C, 0x74, - 0x9E, 0x02, 0x00, 0x01 - ], - typeOfCommand: STK_CMD_GET_INPUT, - icons: [1], - testFunc: (context, cmdDetails, ctlvs) => { - let input = cmdDetails.options; - - equal(input.text, "Text"); - equal(input.isAlphabet, true); - equal(input.isUCS2, true); - equal(input.hideInput, true); - equal(input.isPacked, true); - equal(input.isHelpAvailable, true); - equal(input.minLength, 0x01); - equal(input.maxLength, 0x10); - equal(input.defaultText, "Default"); - equal(input.iconSelfExplanatory, true); - equal(input.icons, 1); - } - }); - - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x11, - 0x81, 0x03, 0x01, 0x23, 0x00, - 0x82, 0x02, 0x81, 0x82, - 0x8D, 0x00, - 0x91, 0x02, 0x01, 0x10, - 0x17, 0x00 - ], - typeOfCommand: STK_CMD_GET_INPUT, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - let input = cmdDetails.options; - - equal(input.text, null); - equal(input.minLength, 0x01); - equal(input.maxLength, 0x10); - equal(input.defaultText, null); - } - }); - - run_next_test(); -}); - -/** - * Verify Proactive Command : More Time - */ -add_test(function test_stk_proactive_command_more_time() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let berHelper = context.BerTlvHelper; - let stkHelper = context.StkProactiveCmdHelper; - - let more_time_1 = [ - 0xD0, - 0x09, - 0x81, 0x03, 0x01, 0x02, 0x00, - 0x82, 0x02, 0x81, 0x82]; - - for(let i = 0 ; i < more_time_1.length; i++) { - pduHelper.writeHexOctet(more_time_1[i]); - } - - let berTlv = berHelper.decode(more_time_1.length); - let ctlvs = berTlv.value; - let tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_COMMAND_DETAILS, ctlvs); - equal(tlv.value.commandNumber, 0x01); - equal(tlv.value.typeOfCommand, STK_CMD_MORE_TIME); - equal(tlv.value.commandQualifier, 0x00); - - run_next_test(); -}); - -/** - * Verify Proactive Command : Select Item - */ -add_test(function test_stk_proactive_command_select_item() { - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x3D, - 0x81, 0x03, 0x01, 0x24, 0x00, - 0x82, 0x02, 0x81, 0x82, - 0x85, 0x05, 0x54, 0x69, 0x74, 0x6C, 0x65, - 0x8F, 0x07, 0x01, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x31, - 0x8F, 0x07, 0x02, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x32, - 0x8F, 0x07, 0x03, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x33, - 0x18, 0x03, 0x10, 0x15, 0x20, - 0x90, 0x01, 0x01, - 0x9E, 0x02, 0x00, 0x01, - 0x9F, 0x04, 0x00, 0x01, 0x02, 0x03 - ], - typeOfCommand: STK_CMD_SELECT_ITEM, - icons: [1, 1, 2, 3], - testFunc: (context, cmdDetails, ctlvs) => { - let menu = cmdDetails.options; - - equal(menu.title, "Title"); - equal(menu.iconSelfExplanatory, true); - equal(menu.icons, 1); - equal(menu.items[0].identifier, 1); - equal(menu.items[0].text, "item 1"); - equal(menu.items[0].iconSelfExplanatory, true); - equal(menu.items[0].icons, 1); - equal(menu.items[1].identifier, 2); - equal(menu.items[1].text, "item 2"); - equal(menu.items[1].iconSelfExplanatory, true); - equal(menu.items[1].icons, 2); - equal(menu.items[2].identifier, 3); - equal(menu.items[2].text, "item 3"); - equal(menu.items[2].iconSelfExplanatory, true); - equal(menu.items[2].icons, 3); - equal(menu.nextActionList[0], STK_CMD_SET_UP_CALL); - equal(menu.nextActionList[1], STK_CMD_LAUNCH_BROWSER); - equal(menu.nextActionList[2], STK_CMD_PLAY_TONE); - equal(menu.defaultItem, 0x00); - } - }); - - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x33, - 0x81, 0x03, 0x01, 0x24, 0x00, - 0x82, 0x02, 0x81, 0x82, - 0x85, 0x05, 0x54, 0x69, 0x74, 0x6C, 0x65, - 0x8F, 0x07, 0x01, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x31, - 0x8F, 0x07, 0x02, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x32, - 0x8F, 0x07, 0x03, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x33, - 0x18, 0x03, 0x00, 0x15, 0x81, - 0x90, 0x01, 0x03 - ], - typeOfCommand: STK_CMD_SELECT_ITEM, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - let menu = cmdDetails.options; - - equal(menu.title, "Title"); - equal(menu.items[0].identifier, 1); - equal(menu.items[0].text, "item 1"); - equal(menu.items[1].identifier, 2); - equal(menu.items[1].text, "item 2"); - equal(menu.items[2].identifier, 3); - equal(menu.items[2].text, "item 3"); - equal(menu.nextActionList[0], STK_NEXT_ACTION_NULL); - equal(menu.nextActionList[1], STK_CMD_LAUNCH_BROWSER); - equal(menu.nextActionList[2], STK_NEXT_ACTION_END_PROACTIVE_SESSION); - equal(menu.defaultItem, 0x02); - } - }); - - run_next_test(); -}); - -/** - * Verify Proactive Command : Set Up Menu - */ -add_test(function test_stk_proactive_command_set_up_menu() { - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x3A, - 0x81, 0x03, 0x01, 0x25, 0x00, - 0x82, 0x02, 0x81, 0x82, - 0x85, 0x05, 0x54, 0x69, 0x74, 0x6C, 0x65, - 0x8F, 0x07, 0x01, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x31, - 0x8F, 0x07, 0x02, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x32, - 0x8F, 0x07, 0x03, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x33, - 0x18, 0x03, 0x10, 0x15, 0x20, - 0x9E, 0x02, 0x00, 0x01, - 0x9F, 0x04, 0x00, 0x01, 0x02, 0x03 - ], - typeOfCommand: STK_CMD_SET_UP_MENU, - icons: [1, 1, 2, 3], - testFunc: (context, cmdDetails, ctlvs) => { - let menu = cmdDetails.options; - - equal(menu.title, "Title"); - equal(menu.iconSelfExplanatory, true); - equal(menu.icons, 1); - equal(menu.items[0].identifier, 1); - equal(menu.items[0].text, "item 1"); - equal(menu.items[0].iconSelfExplanatory, true); - equal(menu.items[0].icons, 1); - equal(menu.items[1].identifier, 2); - equal(menu.items[1].text, "item 2"); - equal(menu.items[1].iconSelfExplanatory, true); - equal(menu.items[1].icons, 2); - equal(menu.items[2].identifier, 3); - equal(menu.items[2].text, "item 3"); - equal(menu.items[2].iconSelfExplanatory, true); - equal(menu.items[2].icons, 3); - equal(menu.nextActionList[0], STK_CMD_SET_UP_CALL); - equal(menu.nextActionList[1], STK_CMD_LAUNCH_BROWSER); - equal(menu.nextActionList[2], STK_CMD_PLAY_TONE); - } - }); - - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x30, - 0x81, 0x03, 0x01, 0x25, 0x00, - 0x82, 0x02, 0x81, 0x82, - 0x85, 0x05, 0x54, 0x69, 0x74, 0x6C, 0x65, - 0x8F, 0x07, 0x01, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x31, - 0x8F, 0x07, 0x02, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x32, - 0x8F, 0x07, 0x03, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x33, - 0x18, 0x03, 0x81, 0x00, 0x00 - ], - typeOfCommand: STK_CMD_SET_UP_MENU, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - let menu = cmdDetails.options; - - equal(menu.title, "Title"); - equal(menu.items[0].identifier, 1); - equal(menu.items[0].text, "item 1"); - equal(menu.items[1].identifier, 2); - equal(menu.items[1].text, "item 2"); - equal(menu.items[2].identifier, 3); - equal(menu.items[2].text, "item 3"); - equal(menu.nextActionList[0], STK_NEXT_ACTION_END_PROACTIVE_SESSION); - equal(menu.nextActionList[1], STK_NEXT_ACTION_NULL); - equal(menu.nextActionList[2], STK_NEXT_ACTION_NULL); - } - }); - - run_next_test(); -}); - -/** - * Verify Proactive Command : Set Up Call - */ -add_test(function test_stk_proactive_command_set_up_call() { - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x31, - 0x81, 0x03, 0x01, 0x10, 0x04, - 0x82, 0x02, 0x81, 0x82, - 0x05, 0x0A, 0x44, 0x69, 0x73, 0x63, 0x6F, 0x6E, 0x6E, 0x65, 0x63, 0x74, - 0x86, 0x09, 0x81, 0x10, 0x32, 0x04, 0x21, 0x43, 0x65, 0x1C, 0x2C, - 0x05, 0x07, 0x4D, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x9E, 0x02, 0x00, 0x01, - 0x9E, 0x02, 0x01, 0x02 - ], - typeOfCommand: STK_CMD_SET_UP_CALL, - icons: [1, 2], - testFunc: (context, cmdDetails, ctlvs) => { - let setupCall = cmdDetails.options; - - equal(setupCall.address, "012340123456,1,2"); - equal(setupCall.confirmMessage.text, "Disconnect"); - equal(setupCall.confirmMessage.iconSelfExplanatory, true); - equal(setupCall.confirmMessage.icons, 1); - equal(setupCall.callMessage.text, "Message"); - equal(setupCall.callMessage.iconSelfExplanatory, false); - equal(setupCall.callMessage.icons, 2); - } - }); - - run_next_test(); -}); - -/** - * Verify Proactive Command : Timer Management - */ -add_test(function test_stk_proactive_command_timer_management() { - // Timer Management - Start - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x11, - 0x81, 0x03, 0x01, 0x27, 0x00, - 0x82, 0x02, 0x81, 0x82, - 0xA4, 0x01, 0x01, - 0xA5, 0x03, 0x10, 0x20, 0x30 - ], - typeOfCommand: STK_CMD_TIMER_MANAGEMENT, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - equal(cmdDetails.commandQualifier, STK_TIMER_START); - - let timer = cmdDetails.options; - - equal(timer.timerId, 0x01); - equal(timer.timerValue, (0x01 * 60 * 60) + (0x02 * 60) + 0x03); - } - }); - - // Timer Management - Deactivate - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x0C, - 0x81, 0x03, 0x01, 0x27, 0x01, - 0x82, 0x02, 0x81, 0x82, - 0xA4, 0x01, 0x01 - ], - typeOfCommand: STK_CMD_TIMER_MANAGEMENT, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - equal(cmdDetails.commandQualifier, STK_TIMER_DEACTIVATE); - - let timer = cmdDetails.options; - - equal(timer.timerId, 0x01); - ok(timer.timerValue === undefined); - } - }); - - run_next_test(); -}); - -/** - * Verify Proactive Command : Provide Local Information - */ -add_test(function test_stk_proactive_command_provide_local_information() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let berHelper = context.BerTlvHelper; - let stkHelper = context.StkProactiveCmdHelper; - let stkCmdHelper = context.StkCommandParamsFactory; - - // Verify IMEI - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x09, - 0x81, 0x03, 0x01, 0x26, 0x01, - 0x82, 0x02, 0x81, 0x82 - ], - typeOfCommand: STK_CMD_PROVIDE_LOCAL_INFO, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - equal(cmdDetails.commandQualifier, STK_LOCAL_INFO_IMEI); - - let provideLocalInfo = cmdDetails.options; - equal(provideLocalInfo.localInfoType, STK_LOCAL_INFO_IMEI); - } - }); - - // Verify Date and Time Zone - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x09, - 0x81, 0x03, 0x01, 0x26, 0x03, - 0x82, 0x02, 0x81, 0x82 - ], - typeOfCommand: STK_CMD_PROVIDE_LOCAL_INFO, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - equal(cmdDetails.commandQualifier, STK_LOCAL_INFO_DATE_TIME_ZONE); - - let provideLocalInfo = cmdDetails.options; - equal(provideLocalInfo.localInfoType, STK_LOCAL_INFO_DATE_TIME_ZONE); - } - }); - - run_next_test(); -}); - -/** - * Verify Proactive command : BIP Messages - */ -add_test(function test_stk_proactive_command_open_channel() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let berHelper = context.BerTlvHelper; - let stkHelper = context.StkProactiveCmdHelper; - let stkCmdHelper = context.StkCommandParamsFactory; - - // Open Channel - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x0F, - 0x81, 0x03, 0x01, 0x40, 0x00, - 0x82, 0x02, 0x81, 0x82, - 0x85, 0x04, 0x4F, 0x70, 0x65, 0x6E //alpha id: "Open" - ], - typeOfCommand: STK_CMD_OPEN_CHANNEL, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - let bipMsg = cmdDetails.options; - - equal(bipMsg.text, "Open"); - } - }); - - // Close Channel - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x10, - 0x81, 0x03, 0x01, 0x41, 0x00, - 0x82, 0x02, 0x81, 0x82, - 0x85, 0x05, 0x43, 0x6C, 0x6F, 0x73, 0x65 //alpha id: "Close" - ], - typeOfCommand: STK_CMD_CLOSE_CHANNEL, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - let bipMsg = cmdDetails.options; - - equal(bipMsg.text, "Close"); - } - }); - - // Receive Data - test_stk_proactive_command({ - pdu: [ - 0XD0, - 0X12, - 0x81, 0x03, 0x01, 0x42, 0x00, - 0x82, 0x02, 0x81, 0x82, - 0x85, 0x07, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65 //alpha id: "Receive" - ], - typeOfCommand: STK_CMD_RECEIVE_DATA, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - let bipMsg = cmdDetails.options; - - equal(bipMsg.text, "Receive"); - } - }); - - // Send Data - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x0F, - 0x81, 0x03, 0x01, 0x43, 0x00, - 0x82, 0x02, 0x81, 0x82, - 0x85, 0x04, 0x53, 0x65, 0x6E, 0x64 //alpha id: "Send" - ], - typeOfCommand: STK_CMD_SEND_DATA, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - let bipMsg = cmdDetails.options; - - equal(bipMsg.text, "Send"); - } - }); - - run_next_test(); -}); - -/** - * Verify Event Download Command : Location Status - */ -add_test(function test_stk_event_download_location_status() { - let worker = newUint8SupportOutgoingIndexWorker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let pduHelper = context.GsmPDUHelper; - - buf.sendParcel = function() { - // Type - equal(this.readInt32(), REQUEST_STK_SEND_ENVELOPE_COMMAND); - - // Token : we don't care - this.readInt32(); - - // Data Size, 42 = 2 * (2 + TLV_DEVICE_ID_SIZE(4) + - // TLV_EVENT_LIST_SIZE(3) + - // TLV_LOCATION_STATUS_SIZE(3) + - // TLV_LOCATION_INFO_GSM_SIZE(9)) - equal(this.readInt32(), 42); - - // BER tag - equal(pduHelper.readHexOctet(), BER_EVENT_DOWNLOAD_TAG); - - // BER length, 19 = TLV_DEVICE_ID_SIZE(4) + - // TLV_EVENT_LIST_SIZE(3) + - // TLV_LOCATION_STATUS_SIZE(3) + - // TLV_LOCATION_INFO_GSM_SIZE(9) - equal(pduHelper.readHexOctet(), 19); - - // Event List, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_EVENT_LIST | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_EVENT_TYPE_LOCATION_STATUS); - - // Device Identifies, Type-Length-Value(Source ID-Destination ID) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DEVICE_ID | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_ME); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_SIM); - - // Location Status, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_LOCATION_STATUS | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_SERVICE_STATE_NORMAL); - - // Location Info, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_LOCATION_INFO | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 7); - - equal(pduHelper.readHexOctet(), 0x21); // MCC + MNC - equal(pduHelper.readHexOctet(), 0x63); - equal(pduHelper.readHexOctet(), 0x54); - equal(pduHelper.readHexOctet(), 0); // LAC - equal(pduHelper.readHexOctet(), 0); - equal(pduHelper.readHexOctet(), 0); // Cell ID - equal(pduHelper.readHexOctet(), 0); - - run_next_test(); - }; - - let event = { - eventType: STK_EVENT_TYPE_LOCATION_STATUS, - locationStatus: STK_SERVICE_STATE_NORMAL, - locationInfo: { - mcc: "123", - mnc: "456", - gsmLocationAreaCode: 0, - gsmCellId: 0 - } - }; - context.RIL.sendStkEventDownload({ - event: event - }); -}); - -// Test Event Download commands. - -/** - * Verify Event Download Command : Language Selection - */ -add_test(function test_stk_event_download_language_selection() { - let worker = newUint8SupportOutgoingIndexWorker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let pduHelper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - - buf.sendParcel = function() { - // Type - equal(this.readInt32(), REQUEST_STK_SEND_ENVELOPE_COMMAND); - - // Token : we don't care - this.readInt32(); - - // Data Size, 26 = 2 * (2 + TLV_DEVICE_ID_SIZE(4) + - // TLV_EVENT_LIST_SIZE(3) + - // TLV_LANGUAGE(4)) - equal(this.readInt32(), 26); - - // BER tag - equal(pduHelper.readHexOctet(), BER_EVENT_DOWNLOAD_TAG); - - // BER length, 19 = TLV_DEVICE_ID_SIZE(4) + - // TLV_EVENT_LIST_SIZE(3) + - // TLV_LANGUAGE(4) - equal(pduHelper.readHexOctet(), 11); - - // Event List, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_EVENT_LIST | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_EVENT_TYPE_LANGUAGE_SELECTION); - - // Device Identifies, Type-Length-Value(Source ID-Destination ID) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DEVICE_ID | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_ME); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_SIM); - - // Language, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_LANGUAGE); - equal(pduHelper.readHexOctet(), 2); - equal(iccHelper.read8BitUnpackedToString(2), "zh"); - - run_next_test(); - }; - - let event = { - eventType: STK_EVENT_TYPE_LANGUAGE_SELECTION, - language: "zh" - }; - context.RIL.sendStkEventDownload({ - event: event - }); -}); - -/** - * Verify Event Download Command : User Activity - */ -add_test(function test_stk_event_download_user_activity() { - let worker = newUint8SupportOutgoingIndexWorker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let pduHelper = context.GsmPDUHelper; - - buf.sendParcel = function() { - // Type - equal(this.readInt32(), REQUEST_STK_SEND_ENVELOPE_COMMAND); - - // Token : we don't care - this.readInt32(); - - // Data Size, 18 = 2 * (2 + TLV_DEVICE_ID_SIZE(4) + TLV_EVENT_LIST_SIZE(3)) - equal(this.readInt32(), 18); - - // BER tag - equal(pduHelper.readHexOctet(), BER_EVENT_DOWNLOAD_TAG); - - // BER length, 7 = TLV_DEVICE_ID_SIZE(4) + TLV_EVENT_LIST_SIZE(3) - equal(pduHelper.readHexOctet(), 7); - - // Event List, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_EVENT_LIST | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_EVENT_TYPE_USER_ACTIVITY); - - // Device Identities, Type-Length-Value(Source ID-Destination ID) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DEVICE_ID | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_ME); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_SIM); - - run_next_test(); - }; - - let event = { - eventType: STK_EVENT_TYPE_USER_ACTIVITY - }; - context.RIL.sendStkEventDownload({ - event: event - }); -}); - -/** - * Verify Event Download Command : Idle Screen Available - */ -add_test(function test_stk_event_download_idle_screen_available() { - let worker = newUint8SupportOutgoingIndexWorker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let pduHelper = context.GsmPDUHelper; - - buf.sendParcel = function() { - // Type - equal(this.readInt32(), REQUEST_STK_SEND_ENVELOPE_COMMAND); - - // Token : we don't care - this.readInt32(); - - // Data Size, 18 = 2 * (2 + TLV_DEVICE_ID_SIZE(4) + TLV_EVENT_LIST_SIZE(3)) - equal(this.readInt32(), 18); - - // BER tag - equal(pduHelper.readHexOctet(), BER_EVENT_DOWNLOAD_TAG); - - // BER length, 7 = TLV_DEVICE_ID_SIZE(4) + TLV_EVENT_LIST_SIZE(3) - equal(pduHelper.readHexOctet(), 7); - - // Event List, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_EVENT_LIST | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_EVENT_TYPE_IDLE_SCREEN_AVAILABLE); - - // Device Identities, Type-Length-Value(Source ID-Destination ID) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DEVICE_ID | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_DISPLAY); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_SIM); - - run_next_test(); - }; - - let event = { - eventType: STK_EVENT_TYPE_IDLE_SCREEN_AVAILABLE - }; - context.RIL.sendStkEventDownload({ - event: event - }); -}); - -/** - * Verify Event Downloaded Command :Browser Termination - */ -add_test(function test_stk_event_download_browser_termination() { - let worker = newUint8SupportOutgoingIndexWorker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let pduHelper = context.GsmPDUHelper; - - buf.sendParcel = function() { - // Type - equal(this.readInt32(), REQUEST_STK_SEND_ENVELOPE_COMMAND); - - // Token : we don't care - this.readInt32(); - - // Data Size, 24 = 2 * ( 2+TLV_DEVICE_ID(4)+TLV_EVENT_LIST_SIZE(3) - // +TLV_BROWSER_TERMINATION_CAUSE(3) ) - equal(this.readInt32(), 24); - - // BER tag - equal(pduHelper.readHexOctet(), BER_EVENT_DOWNLOAD_TAG); - - // BER length, 10 = TLV_DEVICE_ID(4)+TLV_EVENT_LIST_SIZE(3) - // ++TLV_BROWSER_TERMINATION_CAUSE(3) - equal(pduHelper.readHexOctet(), 10); - - // Event List, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_EVENT_LIST | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_EVENT_TYPE_BROWSER_TERMINATION); - - // Device Identities, Type-Length-Value(Source ID-Destination ID) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DEVICE_ID | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_ME); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_SIM); - - // Browser Termination Case, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_BROWSER_TERMINATION_CAUSE | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_BROWSER_TERMINATION_CAUSE_USER); - - run_next_test(); - }; - - let event = { - eventType: STK_EVENT_TYPE_BROWSER_TERMINATION, - terminationCause: STK_BROWSER_TERMINATION_CAUSE_USER - }; - context.RIL.sendStkEventDownload({ - event: event - }); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_voiceprivacy.js b/dom/system/gonk/tests/test_ril_worker_voiceprivacy.js deleted file mode 100644 index 21829da22..000000000 --- a/dom/system/gonk/tests/test_ril_worker_voiceprivacy.js +++ /dev/null @@ -1,94 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -add_test(function test_setVoicePrivacyMode_success() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.RIL.setVoicePrivacyMode = function fakeSetVoicePrivacyMode(options) { - context.RIL[REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE](0, {}); - }; - - context.RIL.setVoicePrivacyMode({ - enabled: true - }); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, undefined); - - run_next_test(); -}); - -add_test(function test_setVoicePrivacyMode_generic_failure() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.RIL.setVoicePrivacyMode = function fakeSetVoicePrivacyMode(options) { - context.RIL[REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE](0, { - errorMsg: GECKO_ERROR_GENERIC_FAILURE - }); - }; - - context.RIL.setVoicePrivacyMode({ - enabled: true - }); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, GECKO_ERROR_GENERIC_FAILURE); - - run_next_test(); -}); - -add_test(function test_queryVoicePrivacyMode_success_enabled_true() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.Buf.readInt32List = function fakeReadUint32List() { - return [1]; - }; - - context.RIL.queryVoicePrivacyMode = function fakeQueryVoicePrivacyMode(options) { - context.RIL[REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE](1, {}); - }; - - context.RIL.queryVoicePrivacyMode(); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, undefined); - ok(postedMessage.enabled); - run_next_test(); -}); - -add_test(function test_queryVoicePrivacyMode_success_enabled_false() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.Buf.readInt32List = function fakeReadUint32List() { - return [0]; - }; - - context.RIL.queryVoicePrivacyMode = function fakeQueryVoicePrivacyMode(options) { - context.RIL[REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE](1, {}); - }; - - context.RIL.queryVoicePrivacyMode(); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, undefined); - ok(!postedMessage.enabled); - run_next_test(); -}); diff --git a/dom/system/gonk/tests/xpcshell.ini b/dom/system/gonk/tests/xpcshell.ini deleted file mode 100644 index 1e8b798a3..000000000 --- a/dom/system/gonk/tests/xpcshell.ini +++ /dev/null @@ -1,43 +0,0 @@ -[DEFAULT] -head = header_helpers.js -tail = - -[test_ril_worker_buf.js] -[test_ril_worker_icc_CardLock.js] -[test_ril_worker_icc_CardState.js] -[test_ril_worker_icc_BerTlvHelper.js] -[test_ril_worker_icc_GsmPDUHelper.js] -[test_ril_worker_icc_ICCContactHelper.js] -[test_ril_worker_icc_ICCIOHelper.js] -[test_ril_worker_icc_ICCPDUHelper.js] -[test_ril_worker_icc_ICCRecordHelper.js] -[test_ril_worker_icc_IconLoader.js] -[test_ril_worker_icc_ICCUtilsHelper.js] -[test_ril_worker_icc_SimRecordHelper.js] -[test_ril_worker_sms.js] -# Bug 916067 - B2G RIL: test_ril_worker_sms.js takes too long to finish -skip-if = true -[test_ril_worker_sms_cdma.js] -[test_ril_worker_sms_cdmapduhelper.js] -[test_ril_worker_sms_nl_tables.js] -[test_ril_worker_sms_gsmpduhelper.js] -[test_ril_worker_sms_segment_info.js] -[test_ril_worker_smsc_address.js] -[test_ril_worker_cf.js] -[test_ril_worker_cellbroadcast_config.js] -[test_ril_worker_cellbroadcast_gsm.js] -[test_ril_worker_cellbroadcast_umts.js] -[test_ril_worker_ruim.js] -[test_ril_worker_cw.js] -[test_ril_worker_clir.js] -[test_ril_worker_clip.js] -[test_ril_worker_ssn.js] -[test_ril_worker_voiceprivacy.js] -[test_ril_worker_ecm.js] -[test_ril_worker_stk.js] -requesttimeoutfactor = 4 -[test_ril_worker_barring_password.js] -[test_ril_worker_cdma_info_rec.js] -[test_ril_system_messenger.js] -# header_helpers.js is not needed for test_ril_system_messenger.js -head = diff --git a/dom/system/gonk/worker_buf.js b/dom/system/gonk/worker_buf.js deleted file mode 100644 index 7064eeac5..000000000 --- a/dom/system/gonk/worker_buf.js +++ /dev/null @@ -1,623 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - - -/** - * This object contains helpers buffering incoming data & deconstructing it - * into parcels as well as buffering outgoing data & constructing parcels. - * For that it maintains two buffers and corresponding uint8 views, indexes. - * - * The incoming buffer is a circular buffer where we store incoming data. - * As soon as a complete parcel is received, it is processed right away, so - * the buffer only needs to be large enough to hold one parcel. - * - * The outgoing buffer is to prepare outgoing parcels. The index is reset - * every time a parcel is sent. - */ - -var Buf = { - INT32_MAX: 2147483647, - UINT8_SIZE: 1, - UINT16_SIZE: 2, - UINT32_SIZE: 4, - PARCEL_SIZE_SIZE: 4, - PDU_HEX_OCTET_SIZE: 4, - - incomingBufferLength: 1024, - incomingBuffer: null, - incomingBytes: null, - incomingWriteIndex: 0, - incomingReadIndex: 0, - readIncoming: 0, - readAvailable: 0, - currentParcelSize: 0, - - outgoingBufferLength: 1024, - outgoingBuffer: null, - outgoingBytes: null, - outgoingIndex: 0, - outgoingBufferCalSizeQueue: null, - - _init: function() { - this.incomingBuffer = new ArrayBuffer(this.incomingBufferLength); - this.outgoingBuffer = new ArrayBuffer(this.outgoingBufferLength); - - this.incomingBytes = new Uint8Array(this.incomingBuffer); - this.outgoingBytes = new Uint8Array(this.outgoingBuffer); - - // Track where incoming data is read from and written to. - this.incomingWriteIndex = 0; - this.incomingReadIndex = 0; - - // Leave room for the parcel size for outgoing parcels. - this.outgoingIndex = this.PARCEL_SIZE_SIZE; - - // How many bytes we've read for this parcel so far. - this.readIncoming = 0; - - // How many bytes available as parcel data. - this.readAvailable = 0; - - // Size of the incoming parcel. If this is zero, we're expecting a new - // parcel. - this.currentParcelSize = 0; - - // Queue for storing outgoing override points - this.outgoingBufferCalSizeQueue = []; - }, - - /** - * Mark current outgoingIndex as start point for calculation length of data - * written to outgoingBuffer. - * Mark can be nested for here uses queue to remember marks. - * - * @param writeFunction - * Function to write data length into outgoingBuffer, this function is - * also used to allocate buffer for data length. - * Raw data size(in Uint8) is provided as parameter calling writeFunction. - * If raw data size is not in proper unit for writing, user can adjust - * the length value in writeFunction before writing. - **/ - startCalOutgoingSize: function(writeFunction) { - let sizeInfo = {index: this.outgoingIndex, - write: writeFunction}; - - // Allocate buffer for data lemgtj. - writeFunction.call(0); - - // Get size of data length buffer for it is not counted into data size. - sizeInfo.size = this.outgoingIndex - sizeInfo.index; - - // Enqueue size calculation information. - this.outgoingBufferCalSizeQueue.push(sizeInfo); - }, - - /** - * Calculate data length since last mark, and write it into mark position. - **/ - stopCalOutgoingSize: function() { - let sizeInfo = this.outgoingBufferCalSizeQueue.pop(); - - // Remember current outgoingIndex. - let currentOutgoingIndex = this.outgoingIndex; - // Calculate data length, in uint8. - let writeSize = this.outgoingIndex - sizeInfo.index - sizeInfo.size; - - // Write data length to mark, use same function for allocating buffer to make - // sure there is no buffer overloading. - this.outgoingIndex = sizeInfo.index; - sizeInfo.write(writeSize); - - // Restore outgoingIndex. - this.outgoingIndex = currentOutgoingIndex; - }, - - /** - * Grow the incoming buffer. - * - * @param min_size - * Minimum new size. The actual new size will be the the smallest - * power of 2 that's larger than this number. - */ - growIncomingBuffer: function(min_size) { - if (DEBUG) { - debug("Current buffer of " + this.incomingBufferLength + - " can't handle incoming " + min_size + " bytes."); - } - let oldBytes = this.incomingBytes; - this.incomingBufferLength = - 2 << Math.floor(Math.log(min_size)/Math.log(2)); - if (DEBUG) debug("New incoming buffer size: " + this.incomingBufferLength); - this.incomingBuffer = new ArrayBuffer(this.incomingBufferLength); - this.incomingBytes = new Uint8Array(this.incomingBuffer); - if (this.incomingReadIndex <= this.incomingWriteIndex) { - // Read and write index are in natural order, so we can just copy - // the old buffer over to the bigger one without having to worry - // about the indexes. - this.incomingBytes.set(oldBytes, 0); - } else { - // The write index has wrapped around but the read index hasn't yet. - // Write whatever the read index has left to read until it would - // circle around to the beginning of the new buffer, and the rest - // behind that. - let head = oldBytes.subarray(this.incomingReadIndex); - let tail = oldBytes.subarray(0, this.incomingReadIndex); - this.incomingBytes.set(head, 0); - this.incomingBytes.set(tail, head.length); - this.incomingReadIndex = 0; - this.incomingWriteIndex += head.length; - } - if (DEBUG) { - debug("New incoming buffer size is " + this.incomingBufferLength); - } - }, - - /** - * Grow the outgoing buffer. - * - * @param min_size - * Minimum new size. The actual new size will be the the smallest - * power of 2 that's larger than this number. - */ - growOutgoingBuffer: function(min_size) { - if (DEBUG) { - debug("Current buffer of " + this.outgoingBufferLength + - " is too small."); - } - let oldBytes = this.outgoingBytes; - this.outgoingBufferLength = - 2 << Math.floor(Math.log(min_size)/Math.log(2)); - this.outgoingBuffer = new ArrayBuffer(this.outgoingBufferLength); - this.outgoingBytes = new Uint8Array(this.outgoingBuffer); - this.outgoingBytes.set(oldBytes, 0); - if (DEBUG) { - debug("New outgoing buffer size is " + this.outgoingBufferLength); - } - }, - - /** - * Functions for reading data from the incoming buffer. - * - * These are all little endian, apart from readParcelSize(); - */ - - /** - * Ensure position specified is readable. - * - * @param index - * Data position in incoming parcel, valid from 0 to - * currentParcelSize. - */ - ensureIncomingAvailable: function(index) { - if (index >= this.currentParcelSize) { - throw new Error("Trying to read data beyond the parcel end!"); - } else if (index < 0) { - throw new Error("Trying to read data before the parcel begin!"); - } - }, - - /** - * Seek in current incoming parcel. - * - * @param offset - * Seek offset in relative to current position. - */ - seekIncoming: function(offset) { - // Translate to 0..currentParcelSize - let cur = this.currentParcelSize - this.readAvailable; - - let newIndex = cur + offset; - this.ensureIncomingAvailable(newIndex); - - // ... incomingReadIndex -->| - // 0 new cur currentParcelSize - // |================|=======|====================| - // |<-- cur -->|<- readAvailable ->| - // |<-- newIndex -->|<-- new readAvailable -->| - this.readAvailable = this.currentParcelSize - newIndex; - - // Translate back: - if (this.incomingReadIndex < cur) { - // The incomingReadIndex is wrapped. - newIndex += this.incomingBufferLength; - } - newIndex += (this.incomingReadIndex - cur); - newIndex %= this.incomingBufferLength; - this.incomingReadIndex = newIndex; - }, - - readUint8Unchecked: function() { - let value = this.incomingBytes[this.incomingReadIndex]; - this.incomingReadIndex = (this.incomingReadIndex + 1) % - this.incomingBufferLength; - return value; - }, - - readUint8: function() { - // Translate to 0..currentParcelSize - let cur = this.currentParcelSize - this.readAvailable; - this.ensureIncomingAvailable(cur); - - this.readAvailable--; - return this.readUint8Unchecked(); - }, - - readUint8Array: function(length) { - // Translate to 0..currentParcelSize - let last = this.currentParcelSize - this.readAvailable; - last += (length - 1); - this.ensureIncomingAvailable(last); - - let array = new Uint8Array(length); - for (let i = 0; i < length; i++) { - array[i] = this.readUint8Unchecked(); - } - - this.readAvailable -= length; - return array; - }, - - readUint16: function() { - return this.readUint8() | this.readUint8() << 8; - }, - - readInt32: function() { - return this.readUint8() | this.readUint8() << 8 | - this.readUint8() << 16 | this.readUint8() << 24; - }, - - readInt64: function() { - // Avoid using bitwise operators as the operands of all bitwise operators - // are converted to signed 32-bit integers. - return this.readUint8() + - this.readUint8() * Math.pow(2, 8) + - this.readUint8() * Math.pow(2, 16) + - this.readUint8() * Math.pow(2, 24) + - this.readUint8() * Math.pow(2, 32) + - this.readUint8() * Math.pow(2, 40) + - this.readUint8() * Math.pow(2, 48) + - this.readUint8() * Math.pow(2, 56); - }, - - readInt32List: function() { - let length = this.readInt32(); - let ints = []; - for (let i = 0; i < length; i++) { - ints.push(this.readInt32()); - } - return ints; - }, - - readString: function() { - let string_len = this.readInt32(); - if (string_len < 0 || string_len >= this.INT32_MAX) { - return null; - } - let s = ""; - for (let i = 0; i < string_len; i++) { - s += String.fromCharCode(this.readUint16()); - } - // Strings are \0\0 delimited, but that isn't part of the length. And - // if the string length is even, the delimiter is two characters wide. - // It's insane, I know. - this.readStringDelimiter(string_len); - return s; - }, - - readStringList: function() { - let num_strings = this.readInt32(); - let strings = []; - for (let i = 0; i < num_strings; i++) { - strings.push(this.readString()); - } - return strings; - }, - - readStringDelimiter: function(length) { - let delimiter = this.readUint16(); - if (!(length & 1)) { - delimiter |= this.readUint16(); - } - if (DEBUG) { - if (delimiter !== 0) { - debug("Something's wrong, found string delimiter: " + delimiter); - } - } - }, - - readParcelSize: function() { - return this.readUint8Unchecked() << 24 | - this.readUint8Unchecked() << 16 | - this.readUint8Unchecked() << 8 | - this.readUint8Unchecked(); - }, - - /** - * Functions for writing data to the outgoing buffer. - */ - - /** - * Ensure position specified is writable. - * - * @param index - * Data position in outgoing parcel, valid from 0 to - * outgoingBufferLength. - */ - ensureOutgoingAvailable: function(index) { - if (index >= this.outgoingBufferLength) { - this.growOutgoingBuffer(index + 1); - } - }, - - writeUint8: function(value) { - this.ensureOutgoingAvailable(this.outgoingIndex); - - this.outgoingBytes[this.outgoingIndex] = value; - this.outgoingIndex++; - }, - - writeUint16: function(value) { - this.writeUint8(value & 0xff); - this.writeUint8((value >> 8) & 0xff); - }, - - writeInt32: function(value) { - this.writeUint8(value & 0xff); - this.writeUint8((value >> 8) & 0xff); - this.writeUint8((value >> 16) & 0xff); - this.writeUint8((value >> 24) & 0xff); - }, - - writeString: function(value) { - if (value == null) { - this.writeInt32(-1); - return; - } - this.writeInt32(value.length); - for (let i = 0; i < value.length; i++) { - this.writeUint16(value.charCodeAt(i)); - } - // Strings are \0\0 delimited, but that isn't part of the length. And - // if the string length is even, the delimiter is two characters wide. - // It's insane, I know. - this.writeStringDelimiter(value.length); - }, - - writeStringList: function(strings) { - this.writeInt32(strings.length); - for (let i = 0; i < strings.length; i++) { - this.writeString(strings[i]); - } - }, - - writeStringDelimiter: function(length) { - this.writeUint16(0); - if (!(length & 1)) { - this.writeUint16(0); - } - }, - - writeParcelSize: function(value) { - /** - * Parcel size will always be the first thing in the parcel byte - * array, but the last thing written. Store the current index off - * to a temporary to be reset after we write the size. - */ - let currentIndex = this.outgoingIndex; - this.outgoingIndex = 0; - this.writeUint8((value >> 24) & 0xff); - this.writeUint8((value >> 16) & 0xff); - this.writeUint8((value >> 8) & 0xff); - this.writeUint8(value & 0xff); - this.outgoingIndex = currentIndex; - }, - - copyIncomingToOutgoing: function(length) { - if (!length || (length < 0)) { - return; - } - - let translatedReadIndexEnd = - this.currentParcelSize - this.readAvailable + length - 1; - this.ensureIncomingAvailable(translatedReadIndexEnd); - - let translatedWriteIndexEnd = this.outgoingIndex + length - 1; - this.ensureOutgoingAvailable(translatedWriteIndexEnd); - - let newIncomingReadIndex = this.incomingReadIndex + length; - if (newIncomingReadIndex < this.incomingBufferLength) { - // Reading won't cause wrapping, go ahead with builtin copy. - this.outgoingBytes - .set(this.incomingBytes.subarray(this.incomingReadIndex, - newIncomingReadIndex), - this.outgoingIndex); - } else { - // Not so lucky. - newIncomingReadIndex %= this.incomingBufferLength; - this.outgoingBytes - .set(this.incomingBytes.subarray(this.incomingReadIndex, - this.incomingBufferLength), - this.outgoingIndex); - if (newIncomingReadIndex) { - let firstPartLength = this.incomingBufferLength - this.incomingReadIndex; - this.outgoingBytes.set(this.incomingBytes.subarray(0, newIncomingReadIndex), - this.outgoingIndex + firstPartLength); - } - } - - this.incomingReadIndex = newIncomingReadIndex; - this.readAvailable -= length; - this.outgoingIndex += length; - }, - - /** - * Parcel management - */ - - /** - * Write incoming data to the circular buffer. - * - * @param incoming - * Uint8Array containing the incoming data. - */ - writeToIncoming: function(incoming) { - // We don't have to worry about the head catching the tail since - // we process any backlog in parcels immediately, before writing - // new data to the buffer. So the only edge case we need to handle - // is when the incoming data is larger than the buffer size. - let minMustAvailableSize = incoming.length + this.readIncoming; - if (minMustAvailableSize > this.incomingBufferLength) { - this.growIncomingBuffer(minMustAvailableSize); - } - - // We can let the typed arrays do the copying if the incoming data won't - // wrap around the edges of the circular buffer. - let remaining = this.incomingBufferLength - this.incomingWriteIndex; - if (remaining >= incoming.length) { - this.incomingBytes.set(incoming, this.incomingWriteIndex); - } else { - // The incoming data would wrap around it. - let head = incoming.subarray(0, remaining); - let tail = incoming.subarray(remaining); - this.incomingBytes.set(head, this.incomingWriteIndex); - this.incomingBytes.set(tail, 0); - } - this.incomingWriteIndex = (this.incomingWriteIndex + incoming.length) % - this.incomingBufferLength; - }, - - /** - * Process incoming data. - * - * @param incoming - * Uint8Array containing the incoming data. - */ - processIncoming: function(incoming) { - if (DEBUG) { - debug("Received " + incoming.length + " bytes."); - debug("Already read " + this.readIncoming); - } - - this.writeToIncoming(incoming); - this.readIncoming += incoming.length; - while (true) { - if (!this.currentParcelSize) { - // We're expecting a new parcel. - if (this.readIncoming < this.PARCEL_SIZE_SIZE) { - // We don't know how big the next parcel is going to be, need more - // data. - if (DEBUG) debug("Next parcel size unknown, going to sleep."); - return; - } - this.currentParcelSize = this.readParcelSize(); - if (DEBUG) { - debug("New incoming parcel of size " + this.currentParcelSize); - } - // The size itself is not included in the size. - this.readIncoming -= this.PARCEL_SIZE_SIZE; - } - - if (this.readIncoming < this.currentParcelSize) { - // We haven't read enough yet in order to be able to process a parcel. - if (DEBUG) debug("Read " + this.readIncoming + ", but parcel size is " - + this.currentParcelSize + ". Going to sleep."); - return; - } - - // Alright, we have enough data to process at least one whole parcel. - // Let's do that. - let expectedAfterIndex = (this.incomingReadIndex + this.currentParcelSize) - % this.incomingBufferLength; - - if (DEBUG) { - let parcel; - if (expectedAfterIndex < this.incomingReadIndex) { - let head = this.incomingBytes.subarray(this.incomingReadIndex); - let tail = this.incomingBytes.subarray(0, expectedAfterIndex); - parcel = Array.slice(head).concat(Array.slice(tail)); - } else { - parcel = Array.slice(this.incomingBytes.subarray( - this.incomingReadIndex, expectedAfterIndex)); - } - debug("Parcel (size " + this.currentParcelSize + "): " + parcel); - } - - if (DEBUG) debug("We have at least one complete parcel."); - try { - this.readAvailable = this.currentParcelSize; - this.processParcel(); - } catch (ex) { - if (DEBUG) debug("Parcel handling threw " + ex + "\n" + ex.stack); - } - - // Ensure that the whole parcel was consumed. - if (this.incomingReadIndex != expectedAfterIndex) { - if (DEBUG) { - debug("Parcel handler didn't consume whole parcel, " + - Math.abs(expectedAfterIndex - this.incomingReadIndex) + - " bytes left over"); - } - this.incomingReadIndex = expectedAfterIndex; - } - this.readIncoming -= this.currentParcelSize; - this.readAvailable = 0; - this.currentParcelSize = 0; - } - }, - - /** - * Communicate with the IPC thread. - */ - sendParcel: function() { - // Compute the size of the parcel and write it to the front of the parcel - // where we left room for it. Note that he parcel size does not include - // the size itself. - let parcelSize = this.outgoingIndex - this.PARCEL_SIZE_SIZE; - this.writeParcelSize(parcelSize); - - // This assumes that postRILMessage will make a copy of the ArrayBufferView - // right away! - let parcel = this.outgoingBytes.subarray(0, this.outgoingIndex); - if (DEBUG) debug("Outgoing parcel: " + Array.slice(parcel)); - this.onSendParcel(parcel); - this.outgoingIndex = this.PARCEL_SIZE_SIZE; - }, - - getCurrentParcelSize: function() { - return this.currentParcelSize; - }, - - getReadAvailable: function() { - return this.readAvailable; - } - - /** - * Process one parcel. - * - * |processParcel| is an implementation provided incoming parcel processing - * function invoked when we have received a complete parcel. Implementation - * may call multiple read functions to extract data from the incoming buffer. - */ - //processParcel: function() { - // let something = this.readInt32(); - // ... - //}, - - /** - * Write raw data out to underlying channel. - * - * |onSendParcel| is an implementation provided stream output function - * invoked when we're really going to write something out. We assume the - * data are completely copied to some output buffer in this call and may - * be destroyed when it's done. - * - * @param parcel - * An array of numeric octet data. - */ - //onSendParcel: function(parcel) { - // ... - //} -}; - -module.exports = { Buf: Buf }; |