Messaging: Remove GServices

We don't have an actual implementation returning anything but the
defaults, so apply the defaults directly anywhere we need them

Change-Id: Ic651b4b13977799f2f4d2c702c430798fbff77f8
This commit is contained in:
Michael W
2024-12-15 15:50:57 +01:00
parent 7f22a3eea7
commit a2f67b4f7b
64 changed files with 91 additions and 3763 deletions

View File

@@ -264,14 +264,6 @@
android:theme="@style/BugleTheme"
android:parentActivityName="com.android.messaging.ui.conversation.ConversationActivity" />
<activity
android:name=".ui.debug.DebugMmsConfigActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:screenOrientation="user"
android:theme="@style/BugleTheme.DialogActivity"
android:exported="false">
</activity>
<provider android:name=".datamodel.MessagingContentProvider" android:label="@string/app_name"
android:authorities="com.android.messaging.datamodel.MessagingContentProvider"
android:exported="false" >
@@ -371,18 +363,6 @@
android:excludeFromRecents="true">
</activity>
<activity android:name=".ui.appsettings.ApnSettingsActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:screenOrientation="user"
android:theme="@style/BugleTheme"
android:parentActivityName="com.android.messaging.ui.appsettings.SettingsActivity" />
<activity android:name=".ui.appsettings.ApnEditorActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:screenOrientation="user"
android:theme="@style/BugleTheme"
android:parentActivityName="com.android.messaging.ui.appsettings.ApnSettingsActivity"/>
<receiver android:name=".receiver.BootAndPackageReplacedReceiver"
android:exported="true">
<intent-filter>

View File

@@ -1,69 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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.
-->
<!--
This is the layout file for an ApnPreference in the ApnSettingsActivity. The preference
is a list item.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
style="@style/ApnPreferenceLayoutStyle">
<RelativeLayout
android:id="@+id/text_layout"
android:layout_width="0dip"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:layout_weight="1"
android:focusable="true"
android:background="?android:attr/selectableItemBackground">
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="true"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceListItem" />
<TextView
android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@android:id/title"
android:layout_alignStart="@android:id/title"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary"
android:maxLines="2" />
</RelativeLayout>
<RadioButton
android:id="@+id/apn_radiobutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dip"
android:layout_marginEnd="8dip"
android:layout_gravity="center_vertical"
android:clickable="true" />
</LinearLayout>

View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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.
-->
<fragment
xmlns:android="http://schemas.android.com/apk/res/android"
class="com.android.messaging.ui.debug.DebugMmsConfigFragment"
android:id="@+id/debug_mmsconfig_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />

View File

@@ -1,46 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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.
-->
<com.android.messaging.ui.debug.DebugMmsConfigItemView
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="@android:color/background_light"
android:gravity="center_vertical"
android:clickable="true"
style="@style/DebugMmsConfigItemStyle" >
<TextView
android:id="@+id/title"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:singleLine="true"
android:maxLines="1"
android:gravity="center_vertical"/>
<Switch
android:id="@+id/switch_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:visibility="gone" />
<TextView
android:id="@+id/text_value"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:singleLine="true"
android:gravity="center_vertical"
android:visibility="gone"/>
</com.android.messaging.ui.debug.DebugMmsConfigItemView>

View File

@@ -1,32 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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.
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="6dp"
android:background="@color/conversation_background"
>
<ListView android:id="@+id/dump_file_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawSelectorOnTop="false"
android:longClickable="false"/>
</FrameLayout>

View File

@@ -1,53 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_margin="16dp">
<TextView
android:id="@+id/sim_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/debug_sub_id_spinner_text" />
<Spinner
android:id="@+id/sim_selector"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#555555" />
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:divider="@null"
android:dividerHeight="0px" />
</LinearLayout>

View File

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" >
<item
android:id="@+id/action_debug_options"
android:orderInCategory="9900"
android:title="@string/action_debug_options"
android:showAsAction="never"/>
</menu>

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 The Android Open Source Project
Copyright (C) 2024 The LineageOS Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -42,10 +43,4 @@
android:title="@string/action_settings"
appcompat:showAsAction="never"/>
<item
android:id="@+id/action_debug_options"
android:orderInCategory="9900"
android:title="@string/action_debug_options"
appcompat:showAsAction="never"/>
</menu>

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 The Android Open Source Project
Copyright (C) 2024 The LineageOS Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -57,5 +58,4 @@
<enum name="subcompact" value="2" />
</attr>
</declare-styleable>
<attr name="apnPreferenceStyle" format="reference" />
</resources>

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 The Android Open Source Project
Copyright (C) 2024 The LineageOS Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -45,21 +46,12 @@
<string name="wireless_alerts_key" translatable="false">buglesub_wireless_alerts_key</string>
<string name="apn_list_pref_key" translatable="false">buglesub_apn_list</string>
<!-- Debug preferences -->
<string name="debug_pref_key" translatable="false">debug_category</string>
<string name="dump_sms_pref_key" translatable="false">dump_sms</string>
<bool name="dump_sms_pref_default" translatable="false">false</bool>
<string name="dump_mms_pref_key" translatable="false">dump_mms</string>
<bool name="dump_mms_pref_default" translatable="false">false</bool>
<!-- SMS/MMS settings keys -->
<!--
TODO: Several of these are currently unused but are expected to be needed to
implement SMS/MMS delivery and basic settings. Once we have the core functionality in place
we should do a pass to remove any unused values here.
-->
<string name="sms_apns_key" translatable="false">sms_apns_key</string>
<string name="use_local_apn_pref_key" translatable="false">use_local_apn_pref_key</string>
<bool name="use_local_apn_pref_default" translatable="false">false</bool>

View File

@@ -688,50 +688,6 @@
<!-- Label for new message button in share intent dialog -->
<string name="share_cancel">Cancel</string>
<!-- Screen title after user selects APNs setting option -->
<string name="apn_edit">Edit access point</string>
<!-- Edit access point label summary text when no value has been set -->
<string name="apn_not_set">Not set</string>
<!-- Edit access point labels: A label the user can give to the APN to allow him to differentiate it from the others -->
<string name="apn_name">Name</string>
<!-- Edit access point labels: -->
<string name="apn_mmsc">MMSC</string>
<!-- Edit access point labels: The proxy to use for MMS (multimedia messages)-->
<string name="apn_mms_proxy">MMS proxy</string>
<!-- Edit access point labels: The port on the proxy used for MMS-->
<string name="apn_mms_port">MMS port</string>
<!-- Edit access point labels: -->
<string name="apn_mcc">MCC</string>
<!-- Edit access point labels: -->
<string name="apn_mnc">MNC</string>
<!-- Edit access point screen menu option to delete this APN -->
<string name="menu_delete_apn">Delete APN</string>
<!-- APNs screen menu option to create a brand spanking new APN -->
<string name="menu_new_apn">New APN</string>
<!-- Edit access point screen menu option to save the user's changes for this APN to the persistent storage -->
<string name="menu_save_apn">Save</string>
<!-- Edit access point screen menu option to discard the user's changes for this APN -->
<string name="menu_discard_apn_change">Discard</string>
<!-- APN error dialog messages: -->
<string name="error_apn_name_empty">The Name field can\'t be empty.</string>
<!-- APN error dialog messages: -->
<string name="error_mcc_not3">MCC field must be 3 digits.</string>
<!-- APN error dialog messages: -->
<string name="error_mnc_not23">MNC field must be 2 or 3 digits.</string>
<!-- The message of dialog indicated restoring default APN settings in progress -->
<string name="restore_default_apn">Restoring default APN settings.</string>
<!-- APNs screen menu option to reset default APN settings -->
<string name="menu_restore_default_apn">Reset to default</string>
<!-- APNs screen toast message to inform reset default APN settings is completed -->
<string name="restore_default_apn_completed">Reset default APN settings completed.</string>
<!-- Name to assign to a Network Access Point that was saved without a name -->
<string name="untitled_apn">Untitled</string>
<!-- Title for Access Point Names settings -->
<string name="sms_apns_title">Access Point Names</string>
<!-- Title for Access Point Names settings activity -->
<string name="apn_settings">APNs</string>
<!-- Error message for users that aren't allowed to modify Access Point Names settings [CHAR LIMIT=none] -->
<string name="apn_settings_not_available">Access Point Name settings are not available for this user</string>
<!-- Alert dialog title to copy information displayed in dialog to system clipboard. -->
<string name="copy_to_clipboard_dialog_title">Copy to clipboard?</string>
<!-- Alert dialog accept to copy information displayed in dialog to system clipboard. -->

View File

@@ -34,7 +34,6 @@
<item name="colorAccent">@color/lineage_accent</item>
<item name="android:textColorHighlight">@color/text_highlight_color</item>
<item name="actionBarStyle">@style/BugleActionBar</item>
<item name="apnPreferenceStyle">@style/ApnPreference</item>
<item name="alertDialogTheme">@style/AlertDialogTheme</item>
</style>
@@ -466,15 +465,6 @@
<item name="colorAccent">@color/search_view_text_cursor</item>
</style>
<style name="ApnPreference">
<item name="android:layout">@layout/apn_preference_layout</item>
</style>
<style name="ApnPreferenceLayoutStyle">
<item name="android:paddingStart">?android:attr/listPreferredItemPaddingStart</item>
<item name="android:paddingEnd">?android:attr/listPreferredItemPaddingEnd</item>
</style>
<style name="SettingsListItem">
<item name="android:textSize">@dimen/settings_list_text_size</item>
<item name="android:textColor">@color/settings_list_text_primary</item>

View File

@@ -1,63 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
android:title="@string/apn_edit">
<EditTextPreference
android:title="@string/apn_name"
android:dialogTitle="@string/apn_name"
android:key="apn_name"
android:singleLine="true"
android:inputType="text"
/>
<EditTextPreference
android:title="@string/apn_mmsc"
android:dialogTitle="@string/apn_mmsc"
android:key="apn_mmsc"
android:singleLine="true"
android:inputType="textUri"
/>
<EditTextPreference
android:title="@string/apn_mms_proxy"
android:dialogTitle="@string/apn_mms_proxy"
android:key="apn_mms_proxy"
android:singleLine="true"
android:inputType="textUri"
/>
<EditTextPreference
android:title="@string/apn_mms_port"
android:dialogTitle="@string/apn_mms_port"
android:key="apn_mms_port"
android:singleLine="true"
android:inputType="number"
/>
<EditTextPreference
android:title="@string/apn_mcc"
android:dialogTitle="@string/apn_mcc"
android:key="apn_mcc"
android:singleLine="true"
android:inputType="number"
/>
<EditTextPreference
android:title="@string/apn_mnc"
android:dialogTitle="@string/apn_mnc"
android:key="apn_mnc"
android:singleLine="true"
android:inputType="number"
/>
</PreferenceScreen>

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 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.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
android:title="@string/apn_settings" android:key="@string/apn_list_pref_key">
</PreferenceScreen>

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 The Android Open Source Project
Copyright (C) 2024 The LineageOS Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -57,23 +58,4 @@
<PreferenceScreen
android:key="@string/advanced_pref_key"
android:title="@string/advanced_settings" />
<PreferenceCategory
android:key="@string/debug_pref_key"
android:title="@string/debug_category_pref_title">
<CheckBoxPreference
android:key="@string/dump_sms_pref_key"
android:title="@string/dump_sms_pref_title"
android:summary="@string/dump_sms_pref_summary"
android:defaultValue="@bool/dump_sms_pref_default" />
<CheckBoxPreference
android:key="@string/dump_mms_pref_key"
android:title="@string/dump_mms_pref_title"
android:summary="@string/dump_mms_pref_summary"
android:defaultValue="@bool/dump_mms_pref_default" />
</PreferenceCategory>
</PreferenceScreen>

View File

@@ -55,9 +55,5 @@
android:summary="@string/delivery_reports_pref_summary"
android:defaultValue="@bool/delivery_reports_pref_default" />
<PreferenceScreen
android:key="@string/sms_apns_key"
android:title="@string/sms_apns_title" />
</PreferenceCategory>
</PreferenceScreen>

View File

@@ -33,21 +33,9 @@ public class MmsManager {
*/
public static final int DEFAULT_SUB_ID = -1;
// Whether to force legacy MMS sending
private static volatile boolean sForceLegacyMms = false;
// Cached computed overrides for carrier configuration values
private static final SparseArray<Bundle> sConfigOverridesMap = new SparseArray<>();
/**
* Set the flag about whether to force to use legacy system APIs instead of system MMS API
*
* @param forceLegacyMms value to set
*/
public static void setForceLegacyMms(boolean forceLegacyMms) {
sForceLegacyMms = forceLegacyMms;
}
/**
* Set the size of thread pool for request execution.
*
@@ -136,14 +124,10 @@ public class MmsManager {
*/
public static void sendMultimediaMessage(int subId, Context context, Uri contentUri,
String locationUrl, PendingIntent sentIntent) {
if (shouldUseLegacyMms()) {
MmsService.startRequest(context, new SendRequest(locationUrl, contentUri, sentIntent));
} else {
subId = Utils.getEffectiveSubscriptionId(subId);
final SmsManager smsManager = Utils.getSmsManager(subId);
smsManager.sendMultimediaMessage(context, contentUri, locationUrl,
getConfigOverrides(subId), sentIntent);
}
subId = Utils.getEffectiveSubscriptionId(subId);
final SmsManager smsManager = Utils.getSmsManager(subId);
smsManager.sendMultimediaMessage(context, contentUri, locationUrl,
getConfigOverrides(subId), sentIntent);
}
/**
@@ -158,24 +142,10 @@ public class MmsManager {
*/
public static void downloadMultimediaMessage(int subId, Context context, String locationUrl,
Uri contentUri, PendingIntent downloadedIntent) {
if (shouldUseLegacyMms()) {
MmsService.startRequest(context,
new DownloadRequest(locationUrl, contentUri, downloadedIntent));
} else {
subId = Utils.getEffectiveSubscriptionId(subId);
final SmsManager smsManager = Utils.getSmsManager(subId);
smsManager.downloadMultimediaMessage(context, locationUrl, contentUri,
getConfigOverrides(subId), downloadedIntent);
}
}
/**
* Checks if we should use legacy APIs for MMS.
*
* @return true if forced to use legacy APIs or platform doesn't supports MMS APIs.
*/
public static boolean shouldUseLegacyMms() {
return sForceLegacyMms;
subId = Utils.getEffectiveSubscriptionId(subId);
final SmsManager smsManager = Utils.getSmsManager(subId);
smsManager.downloadMultimediaMessage(context, locationUrl, contentUri,
getConfigOverrides(subId), downloadedIntent);
}
/**

View File

@@ -38,9 +38,6 @@ import com.android.messaging.sms.BugleApnSettingsLoader;
import com.android.messaging.sms.BugleUserAgentInfoLoader;
import com.android.messaging.sms.MmsConfig;
import com.android.messaging.ui.ConversationDrawables;
import com.android.messaging.util.BugleGservices;
import com.android.messaging.util.BugleGservicesKeys;
import com.android.messaging.util.BuglePrefs;
import com.android.messaging.util.BuglePrefsKeys;
import com.android.messaging.util.DebugUtils;
import com.android.messaging.util.LogUtil;
@@ -83,8 +80,6 @@ public class BugleApplication extends Application implements UncaughtExceptionHa
public void initializeSync(final Factory factory) {
Trace.beginSection("app.initializeSync");
final Context context = factory.getApplicationContext();
final BugleGservices bugleGservices = factory.getBugleGservices();
final BuglePrefs buglePrefs = factory.getApplicationPrefs();
final DataModel dataModel = factory.getDataModel();
final CarrierConfigValuesLoader carrierConfigValuesLoader =
factory.getCarrierConfigValuesLoader();
@@ -94,7 +89,7 @@ public class BugleApplication extends Application implements UncaughtExceptionHa
BugleApplication.updateAppConfig(context);
// Initialize MMS lib
initMmsLib(context, bugleGservices, carrierConfigValuesLoader);
initMmsLib(context, carrierConfigValuesLoader);
// Initialize APN database
ApnDatabase.initializeAppContext(context);
// Fixup messages in flight if we crashed and send any pending
@@ -116,21 +111,12 @@ public class BugleApplication extends Application implements UncaughtExceptionHa
Context.RECEIVER_EXPORTED/*UNAUDITED*/);
}
private static void initMmsLib(final Context context, final BugleGservices bugleGservices,
private static void initMmsLib(final Context context,
final CarrierConfigValuesLoader carrierConfigValuesLoader) {
MmsManager.setApnSettingsLoader(new BugleApnSettingsLoader(context));
MmsManager.setCarrierConfigValuesLoader(carrierConfigValuesLoader);
MmsManager.setUserAgentInfoLoader(new BugleUserAgentInfoLoader(context));
MmsManager.setUseWakeLock(true);
// If Gservices is configured not to use mms api, force MmsManager to always use
// legacy mms sending logic
MmsManager.setForceLegacyMms(!bugleGservices.getBoolean(
BugleGservicesKeys.USE_MMS_API_IF_PRESENT,
BugleGservicesKeys.USE_MMS_API_IF_PRESENT_DEFAULT));
bugleGservices.registerForChanges(() -> MmsManager.setForceLegacyMms(
!bugleGservices.getBoolean(
BugleGservicesKeys.USE_MMS_API_IF_PRESENT,
BugleGservicesKeys.USE_MMS_API_IF_PRESENT_DEFAULT)));
}
public static void updateAppConfig(final Context context) {

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 The Android Open Source Project
* Copyright (C) 2024 The LineageOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,7 +27,6 @@ import com.android.messaging.datamodel.media.MediaResourceManager;
import com.android.messaging.sms.BugleCarrierConfigValuesLoader;
import com.android.messaging.ui.UIIntents;
import com.android.messaging.util.Assert;
import com.android.messaging.util.BugleGservices;
import com.android.messaging.util.BuglePrefs;
import com.android.messaging.util.MediaUtil;
import com.android.messaging.util.PhoneUtils;
@@ -56,7 +56,6 @@ public abstract class Factory {
public abstract Context getApplicationContext();
public abstract DataModel getDataModel();
public abstract BugleGservices getBugleGservices();
public abstract BuglePrefs getApplicationPrefs();
public abstract BuglePrefs getSubscriptionPrefs(int subId);
public abstract BuglePrefs getWidgetPrefs();

View File

@@ -35,8 +35,6 @@ import com.android.messaging.ui.UIIntents;
import com.android.messaging.ui.UIIntentsImpl;
import com.android.messaging.util.Assert;
import com.android.messaging.util.BugleApplicationPrefs;
import com.android.messaging.util.BugleGservices;
import com.android.messaging.util.BugleGservicesImpl;
import com.android.messaging.util.BuglePrefs;
import com.android.messaging.util.BugleSubscriptionPrefs;
import com.android.messaging.util.BugleWidgetPrefs;
@@ -51,7 +49,6 @@ import java.util.concurrent.ConcurrentHashMap;
class FactoryImpl extends Factory {
private BugleApplication mApplication;
private DataModel mDataModel;
private BugleGservices mBugleGservices;
private BugleApplicationPrefs mBugleApplicationPrefs;
private BugleWidgetPrefs mBugleWidgetPrefs;
private Context mApplicationContext;
@@ -89,7 +86,6 @@ class FactoryImpl extends Factory {
factory.mMemoryCacheManager = new MemoryCacheManager();
factory.mMediaCacheManager = new BugleMediaCacheManager();
factory.mMediaResourceManager = new MediaResourceManager();
factory.mBugleGservices = new BugleGservicesImpl(applicationContext);
factory.mBugleApplicationPrefs = new BugleApplicationPrefs(applicationContext);
factory.mDataModel = new DataModelImpl(applicationContext);
factory.mBugleWidgetPrefs = new BugleWidgetPrefs(applicationContext);
@@ -99,9 +95,6 @@ class FactoryImpl extends Factory {
factory.mSubscriptionPrefs = new SparseArray<BugleSubscriptionPrefs>();
factory.mCarrierConfigValuesLoader = new BugleCarrierConfigValuesLoader(applicationContext);
Assert.initializeGservices(factory.mBugleGservices);
LogUtil.initializeGservices(factory.mBugleGservices);
if (OsUtil.hasRequiredPermissions()) {
factory.onRequiredPermissionsAcquired();
}
@@ -135,11 +128,6 @@ class FactoryImpl extends Factory {
return mDataModel;
}
@Override
public BugleGservices getBugleGservices() {
return mBugleGservices;
}
@Override
public BuglePrefs getApplicationPrefs() {
return mBugleApplicationPrefs;

View File

@@ -68,7 +68,6 @@ import com.android.messaging.sms.MmsUtils;
import com.android.messaging.ui.UIIntents;
import com.android.messaging.util.Assert;
import com.android.messaging.util.AvatarUriUtil;
import com.android.messaging.util.BugleGservices;
import com.android.messaging.util.BugleGservicesKeys;
import com.android.messaging.util.BuglePrefs;
import com.android.messaging.util.BuglePrefsKeys;
@@ -605,10 +604,9 @@ public class BugleNotifications {
// Find out the last time we dinged for this conversation
Long lastTime = sLastMessageDingTime.get(conversationId);
if (sTimeBetweenDingsMs == 0) {
sTimeBetweenDingsMs = BugleGservices.get().getInt(
BugleGservicesKeys.NOTIFICATION_TIME_BETWEEN_RINGS_SECONDS,
BugleGservicesKeys.NOTIFICATION_TIME_BETWEEN_RINGS_SECONDS_DEFAULT) *
1000;
sTimeBetweenDingsMs =
BugleGservicesKeys.NOTIFICATION_TIME_BETWEEN_RINGS_SECONDS_DEFAULT *
1000;
}
if (lastTime == null
|| SystemClock.elapsedRealtime() - lastTime > sTimeBetweenDingsMs) {

View File

@@ -27,17 +27,13 @@ import android.database.sqlite.SQLiteQueryBuilder;
import android.database.sqlite.SQLiteStatement;
import android.util.SparseArray;
import com.android.messaging.Factory;
import com.android.messaging.R;
import com.android.messaging.util.Assert;
import com.android.messaging.util.BugleGservicesKeys;
import com.android.messaging.util.DebugUtils;
import com.android.messaging.util.LogUtil;
import com.android.messaging.util.UiUtils;
import java.util.Locale;
import java.util.Stack;
import java.util.regex.Pattern;
public class DatabaseWrapper {
private static final String TAG = LogUtil.BUGLE_DATABASE_TAG;
@@ -45,12 +41,6 @@ public class DatabaseWrapper {
private final SQLiteDatabase mDatabase;
private final Context mContext;
private final boolean mLog;
/**
* Set mExplainQueryPlanRegexp (via {@link BugleGservicesKeys#EXPLAIN_QUERY_PLAN_REGEXP}
* to regex matching queries to see query plans. For example, ".*" to show all query plans.
*/
// See
private final String mExplainQueryPlanRegexp;
private static final int sTimingThreshold = 50; // in milliseconds
public static final int INDEX_INSERT_MESSAGE_PART = 0;
@@ -77,8 +67,6 @@ public class DatabaseWrapper {
DatabaseWrapper(final Context context, final SQLiteDatabase db) {
mLog = LogUtil.isLoggable(LogUtil.BUGLE_DATABASE_PERF_TAG, LogUtil.VERBOSE);
mExplainQueryPlanRegexp = Factory.get().getBugleGservices().getString(
BugleGservicesKeys.EXPLAIN_QUERY_PLAN_REGEXP, null);
mDatabase = db;
mContext = context;
mCompiledStatements = new SparseArray<SQLiteStatement>();
@@ -96,10 +84,6 @@ public class DatabaseWrapper {
return compiled;
}
private void maybePlayDebugNoise() {
DebugUtils.maybePlayDebugNoise(mContext, DebugUtils.DEBUG_SOUND_DB_OP);
}
private static void printTiming(final long t1, final String msg) {
final int transactionDepth = sTransactionDepth.get().size();
final long t2 = System.currentTimeMillis();
@@ -190,64 +174,10 @@ public class DatabaseWrapper {
}
}
private void explainQueryPlan(final SQLiteQueryBuilder qb, final SQLiteDatabase db,
final String[] projection, final String selection,
@SuppressWarnings("unused")
final String[] queryArgs,
final String groupBy,
@SuppressWarnings("unused")
final String having,
final String sortOrder, final String limit) {
final String queryString = qb.buildQuery(
projection,
selection,
groupBy,
null/*having*/,
sortOrder,
limit);
explainQueryPlan(db, queryString, queryArgs);
}
private void explainQueryPlan(final SQLiteDatabase db, final String sql,
final String[] queryArgs) {
if (!Pattern.matches(mExplainQueryPlanRegexp, sql)) {
return;
}
final Cursor planCursor = db.rawQuery("explain query plan " + sql, queryArgs);
try {
if (planCursor != null && planCursor.moveToFirst()) {
final int detailColumn = planCursor.getColumnIndex("detail");
final StringBuilder sb = new StringBuilder();
do {
sb.append(planCursor.getString(detailColumn));
sb.append("\n");
} while (planCursor.moveToNext());
if (sb.length() > 0) {
sb.setLength(sb.length() - 1);
}
LogUtil.v(TAG, "for query " + sql + "\nplan is: "
+ sb);
}
} catch (final Exception e) {
LogUtil.w(TAG, "Query plan failed ", e);
} finally {
if (planCursor != null) {
planCursor.close();
}
}
}
public Cursor query(final String searchTable, final String[] projection,
final String selection, final String[] selectionArgs, final String groupBy,
final String having, final String orderBy, final String limit) {
if (mExplainQueryPlanRegexp != null) {
final SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables(searchTable);
explainQueryPlan(qb, mDatabase, projection, selection, selectionArgs,
groupBy, having, orderBy, limit);
}
maybePlayDebugNoise();
long t1 = 0;
if (mLog) {
t1 = System.currentTimeMillis();
@@ -274,11 +204,6 @@ public class DatabaseWrapper {
public Cursor query(final SQLiteQueryBuilder qb,
final String[] projection, final String selection, final String[] queryArgs,
final String groupBy, final String having, final String sortOrder, final String limit) {
if (mExplainQueryPlanRegexp != null) {
explainQueryPlan(qb, mDatabase, projection, selection, queryArgs,
groupBy, having, sortOrder, limit);
}
maybePlayDebugNoise();
long t1 = 0;
if (mLog) {
t1 = System.currentTimeMillis();
@@ -300,7 +225,6 @@ public class DatabaseWrapper {
if (mLog) {
t1 = System.currentTimeMillis();
}
maybePlayDebugNoise();
final long retval =
DatabaseUtils.queryNumEntries(mDatabase, table, selection, selectionArgs);
if (mLog){
@@ -313,14 +237,10 @@ public class DatabaseWrapper {
}
public Cursor rawQuery(final String sql, final String[] args) {
if (mExplainQueryPlanRegexp != null) {
explainQueryPlan(mDatabase, sql, args);
}
long t1 = 0;
if (mLog) {
t1 = System.currentTimeMillis();
}
maybePlayDebugNoise();
final Cursor cursor = mDatabase.rawQuery(sql, args);
if (mLog) {
printTiming(
@@ -336,7 +256,6 @@ public class DatabaseWrapper {
if (mLog) {
t1 = System.currentTimeMillis();
}
maybePlayDebugNoise();
int count = 0;
try {
count = mDatabase.update(table, values, selection, selectionArgs);
@@ -356,7 +275,6 @@ public class DatabaseWrapper {
if (mLog) {
t1 = System.currentTimeMillis();
}
maybePlayDebugNoise();
int count = 0;
try {
count = mDatabase.delete(table, whereClause, whereArgs);
@@ -378,7 +296,6 @@ public class DatabaseWrapper {
if (mLog) {
t1 = System.currentTimeMillis();
}
maybePlayDebugNoise();
long rowId = -1;
try {
rowId = mDatabase.insert(table, nullColumnHack, values);
@@ -398,7 +315,6 @@ public class DatabaseWrapper {
if (mLog) {
t1 = System.currentTimeMillis();
}
maybePlayDebugNoise();
long rowId = -1;
try {
rowId = mDatabase.replace(table, nullColumnHack, values);
@@ -421,7 +337,6 @@ public class DatabaseWrapper {
if (mLog) {
t1 = System.currentTimeMillis();
}
maybePlayDebugNoise();
try {
mDatabase.execSQL(sql, bindArgs);
} catch (SQLiteFullException ex) {
@@ -439,7 +354,6 @@ public class DatabaseWrapper {
if (mLog) {
t1 = System.currentTimeMillis();
}
maybePlayDebugNoise();
try {
mDatabase.execSQL(sql);
} catch (SQLiteFullException ex) {
@@ -457,7 +371,6 @@ public class DatabaseWrapper {
if (mLog) {
t1 = System.currentTimeMillis();
}
maybePlayDebugNoise();
final SQLiteStatement statement = mDatabase.compileStatement(sql);
int rowsUpdated = 0;
try {

View File

@@ -51,7 +51,6 @@ import com.android.messaging.sms.MmsUtils;
import com.android.messaging.ui.UIIntents;
import com.android.messaging.util.Assert;
import com.android.messaging.util.AvatarUriUtil;
import com.android.messaging.util.BugleGservices;
import com.android.messaging.util.BugleGservicesKeys;
import com.android.messaging.util.ContentType;
import com.android.messaging.util.ConversationIdSet;
@@ -1009,13 +1008,9 @@ public abstract class MessageNotificationState extends NotificationState {
private static int getMaxMessagesInConversationNotification() {
if (!BugleNotifications.isWearCompanionAppInstalled()) {
return BugleGservices.get().getInt(
BugleGservicesKeys.MAX_MESSAGES_IN_CONVERSATION_NOTIFICATION,
BugleGservicesKeys.MAX_MESSAGES_IN_CONVERSATION_NOTIFICATION_DEFAULT);
return BugleGservicesKeys.MAX_MESSAGES_IN_CONVERSATION_NOTIFICATION_DEFAULT;
}
return BugleGservices.get().getInt(
BugleGservicesKeys.MAX_MESSAGES_IN_CONVERSATION_NOTIFICATION_WITH_WEARABLE,
BugleGservicesKeys.MAX_MESSAGES_IN_CONVERSATION_NOTIFICATION_WITH_WEARABLE_DEFAULT);
return BugleGservicesKeys.MAX_MESSAGES_IN_CONVERSATION_NOTIFICATION_WITH_WEARABLE_DEFAULT;
}
/**

View File

@@ -452,8 +452,6 @@ public class MessagingContentProvider extends ContentProvider {
defaultSmsApp = "None";
}
writer.println("Default SMS app: " + defaultSmsApp);
// Now dump logs
LogUtil.dump(writer);
}
@Override

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 The Android Open Source Project
* Copyright (C) 2024 The LineageOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,7 +28,6 @@ import com.android.messaging.datamodel.action.SyncMessagesAction;
import com.android.messaging.datamodel.data.ParticipantData;
import com.android.messaging.sms.MmsUtils;
import com.android.messaging.util.Assert;
import com.android.messaging.util.BugleGservices;
import com.android.messaging.util.BugleGservicesKeys;
import com.android.messaging.util.BuglePrefs;
import com.android.messaging.util.BuglePrefsKeys;
@@ -206,13 +206,11 @@ public class SyncManager {
* @return 0 if allowed to run now, else delay in ms
*/
public long delayUntilFullSync(final long startTimestamp) {
final BugleGservices bugleGservices = BugleGservices.get();
final BuglePrefs prefs = BuglePrefs.getApplicationPrefs();
final long lastFullSyncTime = prefs.getLong(BuglePrefsKeys.LAST_FULL_SYNC_TIME, -1L);
final long smsFullSyncBackoffTimeMillis = bugleGservices.getLong(
BugleGservicesKeys.SMS_FULL_SYNC_BACKOFF_TIME_MILLIS,
BugleGservicesKeys.SMS_FULL_SYNC_BACKOFF_TIME_MILLIS_DEFAULT);
final long smsFullSyncBackoffTimeMillis =
BugleGservicesKeys.SMS_FULL_SYNC_BACKOFF_TIME_MILLIS_DEFAULT;
final long noFullSyncBefore = (lastFullSyncTime < 0 ? startTimestamp :
lastFullSyncTime + smsFullSyncBackoffTimeMillis);

View File

@@ -1,127 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
* Copyright (C) 2024 The LineageOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.messaging.datamodel.action;
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.NonNull;
import com.android.messaging.Factory;
import com.android.messaging.datamodel.DatabaseHelper;
import com.android.messaging.util.DebugUtils;
import com.android.messaging.util.LogUtil;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class DumpDatabaseAction extends Action implements Parcelable {
private static final String TAG = LogUtil.BUGLE_DATAMODEL_TAG;
public static final String DUMP_NAME = "db_copy.db";
private static final int BUFFER_SIZE = 16384;
/**
* Copy the database to external storage
*/
public static void dumpDatabase() {
final DumpDatabaseAction action = new DumpDatabaseAction();
action.start();
}
private DumpDatabaseAction() {
}
@Override
protected Object executeAction() {
final Context context = Factory.get().getApplicationContext();
final String dbName = DatabaseHelper.DATABASE_NAME;
BufferedOutputStream bos = null;
BufferedInputStream bis = null;
long originalSize = 0;
final File inFile = context.getDatabasePath(dbName);
if (inFile.exists() && inFile.isFile()) {
originalSize = inFile.length();
}
final File outFile = DebugUtils.getDebugFile(DUMP_NAME, true);
if (outFile != null) {
int totalBytes = 0;
try {
bos = new BufferedOutputStream(new FileOutputStream(outFile));
bis = new BufferedInputStream(new FileInputStream(inFile));
final byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = bis.read(buffer)) > 0) {
bos.write(buffer, 0, bytesRead);
totalBytes += bytesRead;
}
} catch (final IOException e) {
LogUtil.w(TAG, "Exception copying the database;"
+ " destination may not be complete.", e);
} finally {
if (bos != null) {
try {
bos.close();
} catch (final IOException e) {
// Nothing to do
}
}
if (bis != null) {
try {
bis.close();
} catch (final IOException e) {
// Nothing to do
}
}
DebugUtils.ensureReadable(outFile);
LogUtil.i(TAG, "Dump complete; orig size: " + originalSize +
", copy size: " + totalBytes);
}
}
return null;
}
private DumpDatabaseAction(final Parcel in) {
super(in);
}
public static final Parcelable.Creator<DumpDatabaseAction> CREATOR
= new Parcelable.Creator<DumpDatabaseAction>() {
@Override
public DumpDatabaseAction createFromParcel(final Parcel in) {
return new DumpDatabaseAction(in);
}
@Override
public DumpDatabaseAction[] newArray(final int size) {
return new DumpDatabaseAction[size];
}
};
@Override
public void writeToParcel(@NonNull final Parcel parcel, final int flags) {
writeActionToParcel(parcel, flags);
}
}

View File

@@ -1,156 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
* Copyright (C) 2024 The LineageOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.messaging.datamodel.action;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.provider.Telephony.Threads;
import android.provider.Telephony.ThreadsColumns;
import androidx.annotation.NonNull;
import com.android.messaging.Factory;
import com.android.messaging.mmslib.SqliteWrapper;
import com.android.messaging.util.DebugUtils;
import com.android.messaging.util.LogUtil;
public class LogTelephonyDatabaseAction extends Action implements Parcelable {
// Because we use sanitizePII, we should also use BUGLE_TAG
private static final String TAG = LogUtil.BUGLE_TAG;
private static final String[] ALL_THREADS_PROJECTION = {
Threads._ID,
Threads.DATE,
Threads.MESSAGE_COUNT,
Threads.RECIPIENT_IDS,
Threads.SNIPPET,
Threads.SNIPPET_CHARSET,
Threads.READ,
Threads.ERROR,
Threads.HAS_ATTACHMENT };
// Constants from the Telephony Database
private static final int ID = 0;
private static final int DATE = 1;
private static final int MESSAGE_COUNT = 2;
private static final int RECIPIENT_IDS = 3;
private static final int SNIPPET = 4;
private static final int SNIPPET_CHAR_SET = 5;
private static final int READ = 6;
private static final int ERROR = 7;
private static final int HAS_ATTACHMENT = 8;
/**
* Log telephony data to logcat
*/
public static void dumpDatabase() {
final LogTelephonyDatabaseAction action = new LogTelephonyDatabaseAction();
action.start();
}
private LogTelephonyDatabaseAction() {
}
@Override
protected Object executeAction() {
final Context context = Factory.get().getApplicationContext();
if (!DebugUtils.isDebugEnabled()) {
LogUtil.e(TAG, "Can't log telephony database unless debugging is enabled");
return null;
}
if (!LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
LogUtil.w(TAG, "Can't log telephony database unless DEBUG is turned on for TAG: " +
TAG);
return null;
}
LogUtil.d(TAG, "\n");
LogUtil.d(TAG, "Dump of canoncial_addresses table");
LogUtil.d(TAG, "*********************************");
Cursor cursor = SqliteWrapper.query(context, context.getContentResolver(),
Uri.parse("content://mms-sms/canonical-addresses"), null, null, null, null);
if (cursor == null) {
LogUtil.w(TAG, "null Cursor in content://mms-sms/canonical-addresses");
} else {
try {
while (cursor.moveToNext()) {
long id = cursor.getLong(0);
String number = cursor.getString(1);
LogUtil.d(TAG, LogUtil.sanitizePII("id: " + id + " number: " + number));
}
} finally {
cursor.close();
}
}
LogUtil.d(TAG, "\n");
LogUtil.d(TAG, "Dump of threads table");
LogUtil.d(TAG, "*********************");
cursor = SqliteWrapper.query(context, context.getContentResolver(),
Threads.CONTENT_URI.buildUpon().appendQueryParameter("simple", "true").build(),
ALL_THREADS_PROJECTION, null, null, "date ASC");
try {
while (cursor.moveToNext()) {
LogUtil.d(TAG, LogUtil.sanitizePII("threadId: " + cursor.getLong(ID) +
" " + ThreadsColumns.DATE + " : " + cursor.getLong(DATE) +
" " + ThreadsColumns.MESSAGE_COUNT + " : " + cursor.getInt(MESSAGE_COUNT) +
" " + ThreadsColumns.SNIPPET + " : " + cursor.getString(SNIPPET) +
" " + ThreadsColumns.READ + " : " + cursor.getInt(READ) +
" " + ThreadsColumns.ERROR + " : " + cursor.getInt(ERROR) +
" " + ThreadsColumns.HAS_ATTACHMENT + " : " +
cursor.getInt(HAS_ATTACHMENT) +
" " + ThreadsColumns.RECIPIENT_IDS + " : " +
cursor.getString(RECIPIENT_IDS)));
}
} finally {
cursor.close();
}
return null;
}
private LogTelephonyDatabaseAction(final Parcel in) {
super(in);
}
public static final Parcelable.Creator<LogTelephonyDatabaseAction> CREATOR
= new Parcelable.Creator<LogTelephonyDatabaseAction>() {
@Override
public LogTelephonyDatabaseAction createFromParcel(final Parcel in) {
return new LogTelephonyDatabaseAction(in);
}
@Override
public LogTelephonyDatabaseAction[] newArray(final int size) {
return new LogTelephonyDatabaseAction[size];
}
};
@Override
public void writeToParcel(@NonNull final Parcel parcel, final int flags) {
writeActionToParcel(parcel, flags);
}
}

View File

@@ -271,9 +271,6 @@ public class ProcessDownloadedMmsAction extends Action {
if (downloadedData != null) {
final RetrieveConf retrieveConf =
MmsSender.parseRetrieveConf(downloadedData, subId);
if (MmsUtils.isDumpMmsEnabled()) {
MmsUtils.dumpPdu(downloadedData, retrieveConf);
}
if (retrieveConf != null) {
// Insert the downloaded MMS into telephony
final Uri notificationUri = actionParameters.getParcelable(

View File

@@ -35,7 +35,6 @@ import com.android.messaging.datamodel.DatabaseWrapper;
import com.android.messaging.datamodel.MessagingContentProvider;
import com.android.messaging.datamodel.data.MessageData;
import com.android.messaging.datamodel.data.ParticipantData;
import com.android.messaging.util.BugleGservices;
import com.android.messaging.util.BugleGservicesKeys;
import com.android.messaging.util.BuglePrefs;
import com.android.messaging.util.BuglePrefsKeys;
@@ -153,12 +152,8 @@ public class ProcessPendingMessagesAction extends Action implements Parcelable {
final ProcessPendingMessagesAction action = new ProcessPendingMessagesAction();
action.actionParameters.putInt(KEY_SUB_ID, subId);
final long initialBackoffMs = BugleGservices.get().getLong(
BugleGservicesKeys.INITIAL_MESSAGE_RESEND_DELAY_MS,
BugleGservicesKeys.INITIAL_MESSAGE_RESEND_DELAY_MS_DEFAULT);
final long maxDelayMs = BugleGservices.get().getLong(
BugleGservicesKeys.MAX_MESSAGE_RESEND_DELAY_MS,
BugleGservicesKeys.MAX_MESSAGE_RESEND_DELAY_MS_DEFAULT);
final long initialBackoffMs = BugleGservicesKeys.INITIAL_MESSAGE_RESEND_DELAY_MS_DEFAULT;
final long maxDelayMs = BugleGservicesKeys.MAX_MESSAGE_RESEND_DELAY_MS_DEFAULT;
long delayMs;
long nextDelayMs = initialBackoffMs;
do {

View File

@@ -43,7 +43,6 @@ import com.android.messaging.sms.DatabaseMessages.MmsMessage;
import com.android.messaging.sms.DatabaseMessages.SmsMessage;
import com.android.messaging.sms.MmsUtils;
import com.android.messaging.util.Assert;
import com.android.messaging.util.BugleGservices;
import com.android.messaging.util.BugleGservicesKeys;
import com.android.messaging.util.BuglePrefs;
import com.android.messaging.util.BuglePrefsKeys;
@@ -76,10 +75,8 @@ public class SyncMessagesAction extends Action implements Parcelable {
* Start a full sync (backed off a few seconds to avoid pulling sending/receiving messages).
*/
public static void fullSync() {
final BugleGservices bugleGservices = BugleGservices.get();
final long smsSyncBackoffTimeMillis = bugleGservices.getLong(
BugleGservicesKeys.SMS_SYNC_BACKOFF_TIME_MILLIS,
BugleGservicesKeys.SMS_SYNC_BACKOFF_TIME_MILLIS_DEFAULT);
final long smsSyncBackoffTimeMillis =
BugleGservicesKeys.SMS_SYNC_BACKOFF_TIME_MILLIS_DEFAULT;
final long now = System.currentTimeMillis();
// TODO: Could base this off most recent message in db but now should be okay...
@@ -94,10 +91,8 @@ public class SyncMessagesAction extends Action implements Parcelable {
* Start an incremental sync to pull messages since last sync (backed off a few seconds)..
*/
public static void sync() {
final BugleGservices bugleGservices = BugleGservices.get();
final long smsSyncBackoffTimeMillis = bugleGservices.getLong(
BugleGservicesKeys.SMS_SYNC_BACKOFF_TIME_MILLIS,
BugleGservicesKeys.SMS_SYNC_BACKOFF_TIME_MILLIS_DEFAULT);
final long smsSyncBackoffTimeMillis =
BugleGservicesKeys.SMS_SYNC_BACKOFF_TIME_MILLIS_DEFAULT;
final long now = System.currentTimeMillis();
// TODO: Could base this off most recent message in db but now should be okay...
@@ -195,20 +190,16 @@ public class SyncMessagesAction extends Action implements Parcelable {
@Override
protected Bundle doBackgroundWork() {
final BugleGservices bugleGservices = BugleGservices.get();
final DatabaseWrapper db = DataModel.get().getDatabase();
final int maxMessagesToScan = bugleGservices.getInt(
BugleGservicesKeys.SMS_SYNC_BATCH_MAX_MESSAGES_TO_SCAN,
BugleGservicesKeys.SMS_SYNC_BATCH_MAX_MESSAGES_TO_SCAN_DEFAULT);
final int maxMessagesToScan =
BugleGservicesKeys.SMS_SYNC_BATCH_MAX_MESSAGES_TO_SCAN_DEFAULT;
final int initialMaxMessagesToUpdate = actionParameters.getInt(KEY_MAX_UPDATE);
final int smsSyncSubsequentBatchSizeMin = bugleGservices.getInt(
BugleGservicesKeys.SMS_SYNC_BATCH_SIZE_MIN,
BugleGservicesKeys.SMS_SYNC_BATCH_SIZE_MIN_DEFAULT);
final int smsSyncSubsequentBatchSizeMax = bugleGservices.getInt(
BugleGservicesKeys.SMS_SYNC_BATCH_SIZE_MAX,
BugleGservicesKeys.SMS_SYNC_BATCH_SIZE_MAX_DEFAULT);
final int smsSyncSubsequentBatchSizeMin =
BugleGservicesKeys.SMS_SYNC_BATCH_SIZE_MIN_DEFAULT;
final int smsSyncSubsequentBatchSizeMax =
BugleGservicesKeys.SMS_SYNC_BATCH_SIZE_MAX_DEFAULT;
// Cap sync size to GServices limits
final int maxMessagesToUpdate = Math.max(smsSyncSubsequentBatchSizeMin,
@@ -512,10 +503,8 @@ public class SyncMessagesAction extends Action implements Parcelable {
* @return Target number of messages to sync for next batch
*/
private static int nextBatchSize(final int messagesUpdated, final long txnTimeMillis) {
final BugleGservices bugleGservices = BugleGservices.get();
final long smsSyncSubsequentBatchTimeLimitMillis = bugleGservices.getLong(
BugleGservicesKeys.SMS_SYNC_BATCH_TIME_LIMIT_MILLIS,
BugleGservicesKeys.SMS_SYNC_BATCH_TIME_LIMIT_MILLIS_DEFAULT);
final long smsSyncSubsequentBatchTimeLimitMillis =
BugleGservicesKeys.SMS_SYNC_BATCH_TIME_LIMIT_MILLIS_DEFAULT;
if (txnTimeMillis <= 0) {
return 0;

View File

@@ -30,7 +30,6 @@ import com.android.messaging.datamodel.DatabaseHelper.MessageColumns;
import com.android.messaging.datamodel.DatabaseHelper.PartColumns;
import com.android.messaging.datamodel.DatabaseHelper.ParticipantColumns;
import com.android.messaging.util.Assert;
import com.android.messaging.util.BugleGservices;
import com.android.messaging.util.BugleGservicesKeys;
import com.android.messaging.util.ContentType;
import com.android.messaging.util.Dates;
@@ -396,9 +395,7 @@ public class ConversationMessageData {
if (!TextUtils.isEmpty(firstTextPart)) {
sb.append(firstTextPart);
}
separator = BugleGservices.get().getString(
BugleGservicesKeys.MMS_TEXT_CONCAT_SEPARATOR,
BugleGservicesKeys.MMS_TEXT_CONCAT_SEPARATOR_DEFAULT);
separator = BugleGservicesKeys.MMS_TEXT_CONCAT_SEPARATOR_DEFAULT;
}
final String partText = part.getText();
if (!TextUtils.isEmpty(partText)) {

View File

@@ -34,7 +34,6 @@ import com.android.messaging.sms.MmsUtils;
import com.android.messaging.util.Assert;
import com.android.messaging.util.Assert.DoesNotRunOnMainThread;
import com.android.messaging.util.Assert.RunsOnMainThread;
import com.android.messaging.util.BugleGservices;
import com.android.messaging.util.BugleGservicesKeys;
import com.android.messaging.util.LogUtil;
import com.android.messaging.util.PhoneUtils;
@@ -471,9 +470,7 @@ public class DraftMessageData extends BindableData implements ReadDraftDataActio
}
private int getAttachmentLimit() {
return BugleGservices.get().getInt(
BugleGservicesKeys.MMS_ATTACHMENT_LIMIT,
BugleGservicesKeys.MMS_ATTACHMENT_LIMIT_DEFAULT);
return BugleGservicesKeys.MMS_ATTACHMENT_LIMIT_DEFAULT;
}
public void removeAttachment(final MessagePartData attachment) {

View File

@@ -32,10 +32,8 @@ import com.android.messaging.datamodel.DatabaseHelper.MessageColumns;
import com.android.messaging.datamodel.DatabaseWrapper;
import com.android.messaging.sms.MmsUtils;
import com.android.messaging.util.Assert;
import com.android.messaging.util.BugleGservices;
import com.android.messaging.util.BugleGservicesKeys;
import com.android.messaging.util.Dates;
import com.android.messaging.util.DebugUtils;
import com.android.messaging.util.OsUtil;
import java.util.ArrayList;
@@ -564,17 +562,13 @@ public class MessageData implements Parcelable {
}
public final boolean getInResendWindow(final long now) {
final long maxAgeToResend = BugleGservices.get().getLong(
BugleGservicesKeys.MESSAGE_RESEND_TIMEOUT_MS,
BugleGservicesKeys.MESSAGE_RESEND_TIMEOUT_MS_DEFAULT);
final long maxAgeToResend = BugleGservicesKeys.MESSAGE_RESEND_TIMEOUT_MS_DEFAULT;
final long age = now - mRetryStartTimestamp;
return age < maxAgeToResend;
}
public final boolean getInDownloadWindow(final long now) {
final long maxAgeToRedownload = BugleGservices.get().getLong(
BugleGservicesKeys.MESSAGE_DOWNLOAD_TIMEOUT_MS,
BugleGservicesKeys.MESSAGE_DOWNLOAD_TIMEOUT_MS_DEFAULT);
final long maxAgeToRedownload = BugleGservicesKeys.MESSAGE_DOWNLOAD_TIMEOUT_MS_DEFAULT;
final long age = now - mRetryStartTimestamp;
return age < maxAgeToRedownload;
}
@@ -586,11 +580,9 @@ public class MessageData implements Parcelable {
return false;
}
// Should show option for manual download if status is manual download or failed
// If debug is enabled, allow to download an expired or unavailable message.
return (status == BUGLE_STATUS_INCOMING_DOWNLOAD_FAILED ||
status == BUGLE_STATUS_INCOMING_YET_TO_MANUAL_DOWNLOAD ||
// If debug is enabled, allow to download an expired or unavailable message.
(DebugUtils.isDebugEnabled()
&& status == BUGLE_STATUS_INCOMING_EXPIRED_OR_NOT_AVAILABLE));
status == BUGLE_STATUS_INCOMING_YET_TO_MANUAL_DOWNLOAD);
}
public boolean canDownloadMessage() {
@@ -611,11 +603,9 @@ public class MessageData implements Parcelable {
return false;
}
// Can redownload if status is manual download not started or download failed
// If debug is enabled, allow to download an expired or unavailable message.
return (mStatus == BUGLE_STATUS_INCOMING_DOWNLOAD_FAILED ||
mStatus == BUGLE_STATUS_INCOMING_YET_TO_MANUAL_DOWNLOAD ||
// If debug is enabled, allow to download an expired or unavailable message.
(DebugUtils.isDebugEnabled()
&& mStatus == BUGLE_STATUS_INCOMING_EXPIRED_OR_NOT_AVAILABLE));
mStatus == BUGLE_STATUS_INCOMING_YET_TO_MANUAL_DOWNLOAD);
}
static boolean getShowResendMessage(final int status) {

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 The Android Open Source Project
* Copyright (C) 2024 The LineageOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,7 +35,6 @@ import androidx.core.app.NotificationManagerCompat;
import java.util.ArrayList;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import com.android.messaging.Factory;
import com.android.messaging.R;
@@ -44,9 +44,6 @@ import com.android.messaging.datamodel.NoConfirmationSmsSendService;
import com.android.messaging.datamodel.action.ReceiveSmsMessageAction;
import com.android.messaging.sms.MmsUtils;
import com.android.messaging.ui.UIIntents;
import com.android.messaging.util.BugleGservices;
import com.android.messaging.util.BugleGservicesKeys;
import com.android.messaging.util.DebugUtils;
import com.android.messaging.util.LogUtil;
import com.android.messaging.util.NotificationsUtil;
import com.android.messaging.util.OsUtil;
@@ -125,10 +122,6 @@ public final class SmsReceiver extends BroadcastReceiver {
int subId = PhoneUtils.getDefault().getEffectiveIncomingSubIdFromSystem(
intent, EXTRA_SUB_ID);
deliverSmsMessages(context, subId, errorCode, messages);
if (MmsUtils.isDumpSmsEnabled()) {
final String format = intent.getStringExtra("format");
DebugUtils.dumpSms(messages[0].getTimestampMillis(), messages, format);
}
}
public static void deliverSmsMessages(final Context context, final int subId,
@@ -148,8 +141,7 @@ public final class SmsReceiver extends BroadcastReceiver {
messageValues.put(Sms.Inbox.SEEN, 0);
messageValues.put(Sms.SUBSCRIPTION_ID, subId);
if (messages[0].getMessageClass() == android.telephony.SmsMessage.MessageClass.CLASS_0 ||
DebugUtils.debugClassZeroSmsEnabled()) {
if (messages[0].getMessageClass() == android.telephony.SmsMessage.MessageClass.CLASS_0) {
Factory.get().getUIIntents().launchClassZeroActivity(context, messageValues);
} else {
final ReceiveSmsMessageAction action = new ReceiveSmsMessageAction(messageValues);
@@ -228,30 +220,6 @@ public final class SmsReceiver extends BroadcastReceiver {
return Factory.get().getApplicationContext().getPackageName() + ":secondaryuser";
}
/**
* Compile all of the patterns we check for to ignore system SMS messages.
*/
private static void compileIgnoreSmsPatterns() {
// Get the pattern set from GServices
final String smsIgnoreRegex = BugleGservices.get().getString(
BugleGservicesKeys.SMS_IGNORE_MESSAGE_REGEX,
BugleGservicesKeys.SMS_IGNORE_MESSAGE_REGEX_DEFAULT);
if (smsIgnoreRegex != null) {
final String[] ignoreSmsExpressions = smsIgnoreRegex.split("\n");
if (ignoreSmsExpressions.length != 0) {
sIgnoreSmsPatterns = new ArrayList<Pattern>();
for (int i = 0; i < ignoreSmsExpressions.length; i++) {
try {
sIgnoreSmsPatterns.add(Pattern.compile(ignoreSmsExpressions[i]));
} catch (PatternSyntaxException e) {
LogUtil.e(TAG, "compileIgnoreSmsPatterns: Skipping bad expression: " +
ignoreSmsExpressions[i]);
}
}
}
}
}
/**
* Get the SMS messages from the specified SMS intent.
* @return the messages. If there is an error or the message should be ignored, return null.
@@ -263,27 +231,6 @@ public final class SmsReceiver extends BroadcastReceiver {
if (messages == null || messages.length < 1) {
return null;
}
// Sometimes, SmsMessage.mWrappedSmsMessage is null causing NPE when we access
// the methods on it although the SmsMessage itself is not null. So do this check
// before we do anything on the parsed SmsMessages.
try {
final String messageBody = messages[0].getDisplayMessageBody();
if (messageBody != null) {
// Compile patterns if necessary
if (sIgnoreSmsPatterns == null) {
compileIgnoreSmsPatterns();
}
// Check against filters
for (final Pattern pattern : sIgnoreSmsPatterns) {
if (pattern.matcher(messageBody).matches()) {
return null;
}
}
}
} catch (final NullPointerException e) {
LogUtil.e(TAG, "shouldIgnoreMessage: NPE inside SmsMessage");
return null;
}
return messages;
}

View File

@@ -31,8 +31,6 @@ import android.util.SparseArray;
import com.android.messaging.datamodel.data.ParticipantData;
import com.android.messaging.mmslib.SqliteWrapper;
import com.android.messaging.util.BugleGservices;
import com.android.messaging.util.BugleGservicesKeys;
import com.android.messaging.util.LogUtil;
import com.android.messaging.util.PhoneUtils;
@@ -336,11 +334,6 @@ public class BugleApnSettingsLoader implements ApnSettingsLoader {
}
private void loadLocked(final int subId, final String apnName, final List<Apn> apns) {
// Try Gservices first
loadFromGservices(apns);
if (apns.size() > 0) {
return;
}
// Try system APN table
loadFromSystem(subId, apnName, apns);
if (apns.size() > 0) {
@@ -353,26 +346,6 @@ public class BugleApnSettingsLoader implements ApnSettingsLoader {
}
}
/**
* Load from Gservices if APN setting is set in Gservices
*
* @param apns the list used to return results
*/
private void loadFromGservices(final List<Apn> apns) {
final BugleGservices gservices = BugleGservices.get();
final String mmsc = gservices.getString(BugleGservicesKeys.MMS_MMSC, null);
if (TextUtils.isEmpty(mmsc)) {
return;
}
LogUtil.i(LogUtil.BUGLE_TAG, "Loading APNs from gservices");
final String proxy = gservices.getString(BugleGservicesKeys.MMS_PROXY_ADDRESS, null);
final int port = gservices.getInt(BugleGservicesKeys.MMS_PROXY_PORT, -1);
final Apn apn = BaseApn.from("mms", mmsc, proxy, Integer.toString(port));
if (apn != null) {
apns.add(apn);
}
}
/**
* Load matching APNs from telephony provider.
* We try different combinations of the query to work around some platform quirks.

View File

@@ -22,7 +22,6 @@ import android.support.v7.mms.UserAgentInfoLoader;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import com.android.messaging.util.BugleGservices;
import com.android.messaging.util.BugleGservicesKeys;
import com.android.messaging.util.LogUtil;
import com.android.messaging.util.VersionUtil;
@@ -86,9 +85,7 @@ public class BugleUserAgentInfoLoader implements UserAgentInfoLoader {
}
// if the UAProfUrl isn't set, get it from Gservices
if (TextUtils.isEmpty(mUAProfUrl)) {
mUAProfUrl = BugleGservices.get().getString(
BugleGservicesKeys.MMS_UA_PROFILE_URL,
BugleGservicesKeys.MMS_UA_PROFILE_URL_DEFAULT);
mUAProfUrl = BugleGservicesKeys.MMS_UA_PROFILE_URL_DEFAULT;
}
}
}

View File

@@ -67,7 +67,6 @@ import com.android.messaging.mmslib.pdu.SendConf;
import com.android.messaging.mmslib.pdu.SendReq;
import com.android.messaging.sms.SmsSender.SendResult;
import com.android.messaging.util.Assert;
import com.android.messaging.util.BugleGservices;
import com.android.messaging.util.BugleGservicesKeys;
import com.android.messaging.util.BuglePrefs;
import com.android.messaging.util.ContentType;
@@ -1538,44 +1537,6 @@ public class MmsUtils {
sUseSystemApn = turnOn;
}
/**
* Checks if we should dump sms, based on both the setting and the global debug
* flag
*
* @return if dump sms is enabled
*/
public static boolean isDumpSmsEnabled() {
if (!DebugUtils.isDebugEnabled()) {
return false;
}
return getDumpSmsOrMmsPref(R.string.dump_sms_pref_key, R.bool.dump_sms_pref_default);
}
/**
* Checks if we should dump mms, based on both the setting and the global debug
* flag
*
* @return if dump mms is enabled
*/
public static boolean isDumpMmsEnabled() {
if (!DebugUtils.isDebugEnabled()) {
return false;
}
return getDumpSmsOrMmsPref(R.string.dump_mms_pref_key, R.bool.dump_mms_pref_default);
}
/**
* Load the value of dump sms or mms setting preference
*/
private static boolean getDumpSmsOrMmsPref(final int prefKeyRes, final int defaultKeyRes) {
final Context context = Factory.get().getApplicationContext();
final Resources resources = context.getResources();
final BuglePrefs prefs = BuglePrefs.getApplicationPrefs();
final String key = resources.getString(prefKeyRes);
final boolean defaultValue = resources.getBoolean(defaultKeyRes);
return prefs.getBoolean(key, defaultValue);
}
public static final Uri MMS_PART_CONTENT_URI = Uri.parse("content://mms/part");
/**
@@ -1731,9 +1692,7 @@ public class MmsUtils {
public static MessagePartData createMmsMessagePart(final DatabaseMessages.MmsPart part) {
MessagePartData messagePart = null;
if (part.isText()) {
final int mmsTextLengthLimit =
BugleGservices.get().getInt(BugleGservicesKeys.MMS_TEXT_LIMIT,
BugleGservicesKeys.MMS_TEXT_LIMIT_DEFAULT);
final int mmsTextLengthLimit = BugleGservicesKeys.MMS_TEXT_LIMIT_DEFAULT;
String text = part.mText;
if (text != null && text.length() > mmsTextLengthLimit) {
// Limit the text to a reasonable value. We ran into a situation where a vcard
@@ -1806,44 +1765,30 @@ public class MmsUtils {
int status = MMS_REQUEST_MANUAL_RETRY;
try {
RetrieveConf retrieveConf = null;
if (DebugUtils.isDebugEnabled() &&
MediaScratchFileProvider
.isMediaScratchSpaceUri(Uri.parse(contentLocation))) {
if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
LogUtil.d(TAG, "MmsUtils: Reading MMS from dump file: " + contentLocation);
}
final String fileName = Uri.parse(contentLocation).getPathSegments().get(1);
final byte[] data = DebugUtils.receiveFromDumpFile(fileName);
retrieveConf = receiveFromDumpFile(data);
} else {
if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
LogUtil.d(TAG, "MmsUtils: Downloading MMS via MMS lib API; notification "
+ "message: " + notificationUri);
}
if (subId < 0) {
LogUtil.e(TAG, "MmsUtils: Incoming MMS came from unknown SIM");
throw new MmsFailureException(MMS_REQUEST_NO_RETRY,
"Message from unknown SIM");
}
if (extras == null) {
extras = new Bundle();
}
extras.putParcelable(DownloadMmsAction.EXTRA_NOTIFICATION_URI, notificationUri);
extras.putInt(DownloadMmsAction.EXTRA_SUB_ID, subId);
extras.putString(DownloadMmsAction.EXTRA_SUB_PHONE_NUMBER, subPhoneNumber);
extras.putString(DownloadMmsAction.EXTRA_TRANSACTION_ID, transactionId);
extras.putString(DownloadMmsAction.EXTRA_CONTENT_LOCATION, contentLocation);
extras.putBoolean(DownloadMmsAction.EXTRA_AUTO_DOWNLOAD, autoDownload);
extras.putLong(DownloadMmsAction.EXTRA_RECEIVED_TIMESTAMP,
receivedTimestampInSeconds);
extras.putLong(DownloadMmsAction.EXTRA_EXPIRY, expiry);
MmsSender.downloadMms(context, subId, contentLocation, extras);
return STATUS_PENDING; // Download happens asynchronously; no status to return
if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
LogUtil.d(TAG, "MmsUtils: Downloading MMS via MMS lib API; notification "
+ "message: " + notificationUri);
}
return insertDownloadedMessageAndSendResponse(context, notificationUri, subId,
subPhoneNumber, transactionId, contentLocation, autoDownload,
receivedTimestampInSeconds, expiry, retrieveConf);
if (subId < 0) {
LogUtil.e(TAG, "MmsUtils: Incoming MMS came from unknown SIM");
throw new MmsFailureException(MMS_REQUEST_NO_RETRY,
"Message from unknown SIM");
}
if (extras == null) {
extras = new Bundle();
}
extras.putParcelable(DownloadMmsAction.EXTRA_NOTIFICATION_URI, notificationUri);
extras.putInt(DownloadMmsAction.EXTRA_SUB_ID, subId);
extras.putString(DownloadMmsAction.EXTRA_SUB_PHONE_NUMBER, subPhoneNumber);
extras.putString(DownloadMmsAction.EXTRA_TRANSACTION_ID, transactionId);
extras.putString(DownloadMmsAction.EXTRA_CONTENT_LOCATION, contentLocation);
extras.putBoolean(DownloadMmsAction.EXTRA_AUTO_DOWNLOAD, autoDownload);
extras.putLong(DownloadMmsAction.EXTRA_RECEIVED_TIMESTAMP,
receivedTimestampInSeconds);
extras.putLong(DownloadMmsAction.EXTRA_EXPIRY, expiry);
MmsSender.downloadMms(context, subId, contentLocation, extras);
return STATUS_PENDING; // Download happens asynchronously; no status to return
} catch (final MmsFailureException e) {
LogUtil.e(TAG, "MmsUtils: failed to download message " + notificationUri, e);

View File

@@ -33,7 +33,6 @@ import com.android.messaging.Factory;
import com.android.messaging.R;
import com.android.messaging.receiver.SendStatusReceiver;
import com.android.messaging.util.Assert;
import com.android.messaging.util.BugleGservices;
import com.android.messaging.util.BugleGservicesKeys;
import com.android.messaging.util.LogUtil;
import com.android.messaging.util.PhoneUtils;
@@ -225,9 +224,8 @@ public class SmsSender {
context, subId, dest, messages, serviceCenter, requireDeliveryReport, messageUri);
// Wait for pending intent to come back
synchronized (pendingResult) {
final long smsSendTimeoutInMillis = BugleGservices.get().getLong(
BugleGservicesKeys.SMS_SEND_TIMEOUT_IN_MILLIS,
BugleGservicesKeys.SMS_SEND_TIMEOUT_IN_MILLIS_DEFAULT);
final long smsSendTimeoutInMillis =
BugleGservicesKeys.SMS_SEND_TIMEOUT_IN_MILLIS_DEFAULT;
final long beginTime = SystemClock.elapsedRealtime();
long waitTime = smsSendTimeoutInMillis;
// We could possibly be woken up while still pending

View File

@@ -154,11 +154,6 @@ public abstract class UIIntents {
public abstract void launchCreateNewConversationActivity(final Context context,
final MessageData draft);
/**
* Launch debug activity to set MMS config options.
*/
public abstract void launchDebugMmsConfigActivity(final Context context);
/**
* Launch an activity to change settings.
*/
@@ -325,16 +320,6 @@ public abstract class UIIntents {
public abstract PendingIntent getPendingIntentForSecondaryUserNewMessageNotification(
final Context context);
/**
* Get an intent for showing the APN editor.
*/
public abstract Intent getApnEditorIntent(final Context context, final String rowId, int subId);
/**
* Get an intent for showing the APN settings.
*/
public abstract Intent getApnSettingsIntent(final Context context, final int subId);
/**
* Get an intent for showing advanced settings.
*/

View File

@@ -23,7 +23,6 @@ import android.app.role.RoleManager;
import android.appwidget.AppWidgetManager;
import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
@@ -34,7 +33,7 @@ import android.os.Bundle;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Intents;
import android.provider.MediaStore;
import android.provider.Telephony;
import androidx.annotation.Nullable;
import androidx.core.app.TaskStackBuilder;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
@@ -50,8 +49,6 @@ import com.android.messaging.datamodel.data.MessagePartData;
import com.android.messaging.datamodel.data.ParticipantData;
import com.android.messaging.receiver.NotificationReceiver;
import com.android.messaging.sms.MmsSmsUtils;
import com.android.messaging.ui.appsettings.ApnEditorActivity;
import com.android.messaging.ui.appsettings.ApnSettingsActivity;
import com.android.messaging.ui.appsettings.ApplicationSettingsActivity;
import com.android.messaging.ui.appsettings.PerSubscriptionSettingsActivity;
import com.android.messaging.ui.appsettings.SettingsActivity;
@@ -62,7 +59,6 @@ import com.android.messaging.ui.conversationlist.ArchivedConversationListActivit
import com.android.messaging.ui.conversationlist.ConversationListActivity;
import com.android.messaging.ui.conversationlist.ForwardMessageActivity;
import com.android.messaging.ui.conversationsettings.PeopleAndOptionsActivity;
import com.android.messaging.ui.debug.DebugMmsConfigActivity;
import com.android.messaging.ui.photoviewer.BuglePhotoViewActivity;
import com.android.messaging.util.Assert;
import com.android.messaging.util.ContentType;
@@ -192,11 +188,6 @@ public class UIIntentsImpl extends UIIntents {
context.startActivity(intent);
}
@Override
public void launchDebugMmsConfigActivity(final Context context) {
context.startActivity(new Intent(context, DebugMmsConfigActivity.class));
}
@Override
public void launchAddContactActivity(final Context context, final String destination) {
final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
@@ -449,21 +440,6 @@ public class UIIntentsImpl extends UIIntents {
return getPendingIntentForConversationListActivity(context);
}
@Override
public Intent getApnEditorIntent(final Context context, final String rowId, final int subId) {
final Intent intent = new Intent(context, ApnEditorActivity.class);
intent.putExtra(UI_INTENT_EXTRA_APN_ROW_ID, rowId);
intent.putExtra(UI_INTENT_EXTRA_SUB_ID, subId);
return intent;
}
@Override
public Intent getApnSettingsIntent(final Context context, final int subId) {
final Intent intent = new Intent(context, ApnSettingsActivity.class)
.putExtra(UI_INTENT_EXTRA_SUB_ID, subId);
return intent;
}
@Override
public Intent getAdvancedSettingsIntent(final Context context) {
return getPerSubscriptionSettingsIntent(context, ParticipantData.DEFAULT_SELF_SUB_ID, null);

View File

@@ -1,466 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
* Copyright (C) 2024 The LineageOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.messaging.ui.appsettings;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.ContentValues;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.provider.Telephony;
import androidx.annotation.NonNull;
import androidx.core.app.NavUtils;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import com.android.messaging.R;
import com.android.messaging.datamodel.data.ParticipantData;
import com.android.messaging.sms.ApnDatabase;
import com.android.messaging.sms.BugleApnSettingsLoader;
import com.android.messaging.ui.BugleActionBarActivity;
import com.android.messaging.ui.UIIntents;
import com.android.messaging.util.PhoneUtils;
public class ApnEditorActivity extends BugleActionBarActivity {
private static final int ERROR_DIALOG_ID = 0;
private static final String ERROR_MESSAGE_KEY = "error_msg";
private ApnEditorFragment mApnEditorFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// Display the fragment as the main content.
mApnEditorFragment = new ApnEditorFragment();
mApnEditorFragment.setSubId(getIntent().getIntExtra(UIIntents.UI_INTENT_EXTRA_SUB_ID,
ParticipantData.DEFAULT_SELF_SUB_ID));
getFragmentManager().beginTransaction()
.replace(android.R.id.content, mApnEditorFragment)
.commit();
}
@Override
public boolean onOptionsItemSelected(@NonNull final MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected Dialog onCreateDialog(int id, Bundle args) {
if (id == ERROR_DIALOG_ID) {
String msg = args.getString(ERROR_MESSAGE_KEY);
return new AlertDialog.Builder(this)
.setPositiveButton(android.R.string.ok, null)
.setMessage(msg)
.create();
}
return super.onCreateDialog(id);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK: {
if (mApnEditorFragment.validateAndSave(false)) {
finish();
}
return true;
}
}
return super.onKeyDown(keyCode, event);
}
@Override
protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {
super.onPrepareDialog(id, dialog);
if (id == ERROR_DIALOG_ID) {
final String msg = args.getString(ERROR_MESSAGE_KEY);
if (msg != null) {
((AlertDialog) dialog).setMessage(msg);
}
}
}
public static class ApnEditorFragment extends PreferenceFragment implements
SharedPreferences.OnSharedPreferenceChangeListener {
private static final String SAVED_POS = "pos";
private static final int MENU_DELETE = Menu.FIRST;
private static final int MENU_SAVE = Menu.FIRST + 1;
private static final int MENU_CANCEL = Menu.FIRST + 2;
private EditTextPreference mMmsProxy;
private EditTextPreference mMmsPort;
private EditTextPreference mName;
private EditTextPreference mMmsc;
private EditTextPreference mMcc;
private EditTextPreference mMnc;
private static String sNotSet;
private String mCurMnc;
private String mCurMcc;
private Cursor mCursor;
private boolean mNewApn;
private boolean mFirstTime;
private String mCurrentId;
private int mSubId;
/**
* Standard projection for the interesting columns of a normal note.
*/
private static final String[] sProjection = new String[] {
Telephony.Carriers._ID, // 0
Telephony.Carriers.NAME, // 1
Telephony.Carriers.MMSC, // 2
Telephony.Carriers.MCC, // 3
Telephony.Carriers.MNC, // 4
Telephony.Carriers.NUMERIC, // 5
Telephony.Carriers.MMSPROXY, // 6
Telephony.Carriers.MMSPORT, // 7
Telephony.Carriers.TYPE, // 8
};
private static final int ID_INDEX = 0;
private static final int NAME_INDEX = 1;
private static final int MMSC_INDEX = 2;
private static final int MCC_INDEX = 3;
private static final int MNC_INDEX = 4;
private static final int NUMERIC_INDEX = 5;
private static final int MMSPROXY_INDEX = 6;
private static final int MMSPORT_INDEX = 7;
private static final int TYPE_INDEX = 8;
private SQLiteDatabase mDatabase;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
addPreferencesFromResource(R.xml.apn_editor);
setHasOptionsMenu(true);
sNotSet = getResources().getString(R.string.apn_not_set);
mName = (EditTextPreference) findPreference("apn_name");
mMmsProxy = (EditTextPreference) findPreference("apn_mms_proxy");
mMmsPort = (EditTextPreference) findPreference("apn_mms_port");
mMmsc = (EditTextPreference) findPreference("apn_mmsc");
mMcc = (EditTextPreference) findPreference("apn_mcc");
mMnc = (EditTextPreference) findPreference("apn_mnc");
final Intent intent = getActivity().getIntent();
mFirstTime = savedInstanceState == null;
mCurrentId = intent.getStringExtra(UIIntents.UI_INTENT_EXTRA_APN_ROW_ID);
mNewApn = mCurrentId == null;
mDatabase = ApnDatabase.getApnDatabase().getWritableDatabase();
if (mNewApn) {
fillUi();
} else {
// Do initial query not on the UI thread
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
if (mCurrentId != null) {
String selection = Telephony.Carriers._ID + " =?";
String[] selectionArgs = new String[]{ mCurrentId };
mCursor = mDatabase.query(ApnDatabase.APN_TABLE, sProjection, selection,
selectionArgs, null, null, null, null);
}
return null;
}
@Override
protected void onPostExecute(Void result) {
if (mCursor == null) {
getActivity().finish();
return;
}
mCursor.moveToFirst();
fillUi();
}
}.execute((Void) null);
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (mCursor != null) {
mCursor.close();
mCursor = null;
}
}
@Override
public void onResume() {
super.onResume();
getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onPause() {
getPreferenceScreen().getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(this);
super.onPause();
}
public void setSubId(final int subId) {
mSubId = subId;
}
private void fillUi() {
if (mNewApn) {
mMcc.setText(null);
mMnc.setText(null);
String numeric = PhoneUtils.get(mSubId).getSimOperatorNumeric();
// MCC is first 3 chars and then in 2 - 3 chars of MNC
if (numeric != null && numeric.length() > 4) {
// Country code
String mcc = numeric.substring(0, 3);
// Network code
String mnc = numeric.substring(3);
// Auto populate MNC and MCC for new entries, based on what SIM reports
mMcc.setText(mcc);
mMnc.setText(mnc);
mCurMnc = mnc;
mCurMcc = mcc;
}
mName.setText(null);
mMmsProxy.setText(null);
mMmsPort.setText(null);
mMmsc.setText(null);
} else if (mFirstTime) {
mFirstTime = false;
// Fill in all the values from the db in both text editor and summary
mName.setText(mCursor.getString(NAME_INDEX));
mMmsProxy.setText(mCursor.getString(MMSPROXY_INDEX));
mMmsPort.setText(mCursor.getString(MMSPORT_INDEX));
mMmsc.setText(mCursor.getString(MMSC_INDEX));
mMcc.setText(mCursor.getString(MCC_INDEX));
mMnc.setText(mCursor.getString(MNC_INDEX));
}
mName.setSummary(checkNull(mName.getText()));
mMmsProxy.setSummary(checkNull(mMmsProxy.getText()));
mMmsPort.setSummary(checkNull(mMmsPort.getText()));
mMmsc.setSummary(checkNull(mMmsc.getText()));
mMcc.setSummary(checkNull(mMcc.getText()));
mMnc.setSummary(checkNull(mMnc.getText()));
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
// If it's a new APN, then cancel will delete the new entry in onPause
if (!mNewApn) {
menu.add(0, MENU_DELETE, 0, R.string.menu_delete_apn)
.setIcon(R.drawable.ic_delete_small_dark);
}
menu.add(0, MENU_SAVE, 0, R.string.menu_save_apn)
.setIcon(android.R.drawable.ic_menu_save);
menu.add(0, MENU_CANCEL, 0, R.string.menu_discard_apn_change)
.setIcon(android.R.drawable.ic_menu_close_clear_cancel);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_DELETE:
deleteApn();
return true;
case MENU_SAVE:
if (validateAndSave(false)) {
getActivity().finish();
}
return true;
case MENU_CANCEL:
getActivity().finish();
return true;
case android.R.id.home:
getActivity().onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onSaveInstanceState(Bundle icicle) {
super.onSaveInstanceState(icicle);
if (validateAndSave(true) && mCursor != null) {
icicle.putInt(SAVED_POS, mCursor.getInt(ID_INDEX));
}
}
/**
* Check the key fields' validity and save if valid.
* @param force save even if the fields are not valid, if the app is
* being suspended
* @return true if the data was saved
*/
private boolean validateAndSave(boolean force) {
final String name = checkNotSet(mName.getText());
final String mcc = checkNotSet(mMcc.getText());
final String mnc = checkNotSet(mMnc.getText());
if (getErrorMsg() != null && !force) {
final Bundle bundle = new Bundle();
bundle.putString(ERROR_MESSAGE_KEY, getErrorMsg());
getActivity().showDialog(ERROR_DIALOG_ID, bundle);
return false;
}
// Make database changes not on the UI thread
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
ContentValues values = new ContentValues();
// Add a placeholder name "Untitled", if the user exits the screen without
// adding a name but entered other information worth keeping.
values.put(Telephony.Carriers.NAME, name.length() < 1 ?
getResources().getString(R.string.untitled_apn) : name);
values.put(Telephony.Carriers.MMSPROXY, checkNotSet(mMmsProxy.getText()));
values.put(Telephony.Carriers.MMSPORT, checkNotSet(mMmsPort.getText()));
values.put(Telephony.Carriers.MMSC, checkNotSet(mMmsc.getText()));
values.put(Telephony.Carriers.TYPE, BugleApnSettingsLoader.APN_TYPE_MMS);
values.put(Telephony.Carriers.MCC, mcc);
values.put(Telephony.Carriers.MNC, mnc);
values.put(Telephony.Carriers.NUMERIC, mcc + mnc);
if (mCurMnc != null && mCurMcc != null) {
if (mCurMnc.equals(mnc) && mCurMcc.equals(mcc)) {
values.put(Telephony.Carriers.CURRENT, 1);
}
}
if (mNewApn) {
mDatabase.insert(ApnDatabase.APN_TABLE, null, values);
} else {
// update the APN
String selection = Telephony.Carriers._ID + " =?";
String[] selectionArgs = new String[]{ mCurrentId };
int updated = mDatabase.update(ApnDatabase.APN_TABLE, values,
selection, selectionArgs);
}
return null;
}
}.execute((Void) null);
return true;
}
private void deleteApn() {
// Make database changes not on the UI thread
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
// delete the APN
String where = Telephony.Carriers._ID + " =?";
String[] whereArgs = new String[]{ mCurrentId };
mDatabase.delete(ApnDatabase.APN_TABLE, where, whereArgs);
return null;
}
}.execute((Void) null);
getActivity().finish();
}
private String checkNull(String value) {
if (value == null || value.length() == 0) {
return sNotSet;
} else {
return value;
}
}
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Preference pref = findPreference(key);
if (pref != null) {
pref.setSummary(checkNull(sharedPreferences.getString(key, "")));
}
}
private String getErrorMsg() {
String errorMsg = null;
String name = checkNotSet(mName.getText());
String mcc = checkNotSet(mMcc.getText());
String mnc = checkNotSet(mMnc.getText());
if (name.length() < 1) {
errorMsg = getString(R.string.error_apn_name_empty);
} else if (mcc.length() != 3) {
errorMsg = getString(R.string.error_mcc_not3);
} else if ((mnc.length() & 0xFFFE) != 2) {
errorMsg = getString(R.string.error_mnc_not23);
}
return errorMsg;
}
private String checkNotSet(String value) {
if (value == null || value.equals(sNotSet)) {
return "";
} else {
return value;
}
}
}
}

View File

@@ -1,143 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.messaging.ui.appsettings;
import android.content.Context;
import android.preference.Preference;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.RadioButton;
import android.widget.RelativeLayout;
import com.android.messaging.R;
import com.android.messaging.datamodel.data.ParticipantData;
import com.android.messaging.ui.UIIntents;
/**
* ApnPreference implements a pref, typically used as a list item, that has a title/summary on
* the left and a radio button on the right.
*
*/
public class ApnPreference extends Preference implements
CompoundButton.OnCheckedChangeListener, OnClickListener {
static final String TAG = "ApnPreference";
public ApnPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public ApnPreference(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.apnPreferenceStyle);
}
public ApnPreference(Context context) {
this(context, null);
}
private static String mSelectedKey = null;
private static CompoundButton mCurrentChecked = null;
private boolean mProtectFromCheckedChange = false;
private boolean mSelectable = true;
private int mSubId = ParticipantData.DEFAULT_SELF_SUB_ID;
@Override
public View getView(View convertView, ViewGroup parent) {
View view = super.getView(convertView, parent);
View widget = view.findViewById(R.id.apn_radiobutton);
if ((widget != null) && widget instanceof RadioButton) {
RadioButton rb = (RadioButton) widget;
if (mSelectable) {
rb.setOnCheckedChangeListener(this);
boolean isChecked = getKey().equals(mSelectedKey);
if (isChecked) {
mCurrentChecked = rb;
mSelectedKey = getKey();
}
mProtectFromCheckedChange = true;
rb.setChecked(isChecked);
mProtectFromCheckedChange = false;
} else {
rb.setVisibility(View.GONE);
}
rb.setContentDescription(getTitle());
}
View textLayout = view.findViewById(R.id.text_layout);
if ((textLayout != null) && textLayout instanceof RelativeLayout) {
textLayout.setOnClickListener(this);
}
return view;
}
public boolean isChecked() {
return getKey().equals(mSelectedKey);
}
public void setChecked() {
mSelectedKey = getKey();
}
public void setSubId(final int subId) {
mSubId = subId;
}
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Log.i(TAG, "ID: " + getKey() + " :" + isChecked);
if (mProtectFromCheckedChange) {
return;
}
if (isChecked) {
if (mCurrentChecked != null) {
mCurrentChecked.setChecked(false);
}
mCurrentChecked = buttonView;
mSelectedKey = getKey();
callChangeListener(mSelectedKey);
} else {
mCurrentChecked = null;
mSelectedKey = null;
}
buttonView.setContentDescription(getTitle());
}
public void onClick(android.view.View v) {
if ((v != null) && (R.id.text_layout == v.getId())) {
Context context = getContext();
if (context != null) {
context.startActivity(
UIIntents.get().getApnEditorIntent(context, getKey(), mSubId));
}
}
}
public void setSelectable(boolean selectable) {
mSelectable = selectable;
}
public boolean getSelectable() {
return mSelectable;
}
}

View File

@@ -1,402 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
* Copyright (C) 2024 The LineageOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.messaging.ui.appsettings;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.UserManager;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
import android.provider.Telephony;
import androidx.annotation.NonNull;
import androidx.core.app.NavUtils;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.android.messaging.R;
import com.android.messaging.datamodel.data.ParticipantData;
import com.android.messaging.sms.ApnDatabase;
import com.android.messaging.sms.BugleApnSettingsLoader;
import com.android.messaging.ui.BugleActionBarActivity;
import com.android.messaging.ui.UIIntents;
import com.android.messaging.util.PhoneUtils;
public class ApnSettingsActivity extends BugleActionBarActivity {
private static final int DIALOG_RESTORE_DEFAULTAPN = 1001;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// Display the fragment as the main content.
final ApnSettingsFragment fragment = new ApnSettingsFragment();
fragment.setSubId(getIntent().getIntExtra(UIIntents.UI_INTENT_EXTRA_SUB_ID,
ParticipantData.DEFAULT_SELF_SUB_ID));
getFragmentManager().beginTransaction()
.replace(android.R.id.content, fragment)
.commit();
}
@Override
public boolean onOptionsItemSelected(@NonNull final MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected Dialog onCreateDialog(int id) {
if (id == DIALOG_RESTORE_DEFAULTAPN) {
ProgressDialog dialog = new ProgressDialog(this);
dialog.setMessage(getResources().getString(R.string.restore_default_apn));
dialog.setCancelable(false);
return dialog;
}
return null;
}
public static class ApnSettingsFragment extends PreferenceFragment implements
Preference.OnPreferenceChangeListener {
public static final String EXTRA_POSITION = "position";
public static final String APN_ID = "apn_id";
private static final String[] APN_PROJECTION = {
Telephony.Carriers._ID, // 0
Telephony.Carriers.NAME, // 1
Telephony.Carriers.APN, // 2
Telephony.Carriers.TYPE // 3
};
private static final int ID_INDEX = 0;
private static final int NAME_INDEX = 1;
private static final int APN_INDEX = 2;
private static final int TYPES_INDEX = 3;
private static final int MENU_NEW = Menu.FIRST;
private static final int MENU_RESTORE = Menu.FIRST + 1;
private static final int EVENT_RESTORE_DEFAULTAPN_START = 1;
private static final int EVENT_RESTORE_DEFAULTAPN_COMPLETE = 2;
private static boolean mRestoreDefaultApnMode;
private RestoreApnUiHandler mRestoreApnUiHandler;
private RestoreApnProcessHandler mRestoreApnProcessHandler;
private HandlerThread mRestoreDefaultApnThread;
private String mSelectedKey;
private static final ContentValues sCurrentNullMap;
private static final ContentValues sCurrentSetMap;
private UserManager mUm;
private boolean mUnavailable;
private int mSubId;
static {
sCurrentNullMap = new ContentValues(1);
sCurrentNullMap.putNull(Telephony.Carriers.CURRENT);
sCurrentSetMap = new ContentValues(1);
sCurrentSetMap.put(Telephony.Carriers.CURRENT, "2"); // 2 for user-selected APN,
// 1 for Bugle-selected APN
}
private SQLiteDatabase mDatabase;
public void setSubId(final int subId) {
mSubId = subId;
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mDatabase = ApnDatabase.getApnDatabase().getWritableDatabase();
mUm = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
if (!mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) {
setHasOptionsMenu(true);
}
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final ListView lv = (ListView) getView().findViewById(android.R.id.list);
TextView empty = (TextView) getView().findViewById(android.R.id.empty);
if (empty != null) {
empty.setText(R.string.apn_settings_not_available);
lv.setEmptyView(empty);
}
if (mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) {
mUnavailable = true;
setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getActivity()));
return;
}
addPreferencesFromResource(R.xml.apn_settings);
lv.setItemsCanFocus(true);
}
@Override
public void onResume() {
super.onResume();
if (mUnavailable) {
return;
}
if (!mRestoreDefaultApnMode) {
fillList();
}
}
@Override
public void onPause() {
super.onPause();
if (mUnavailable) {
return;
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (mRestoreDefaultApnThread != null) {
mRestoreDefaultApnThread.quit();
}
}
private void fillList() {
final String mccMnc = PhoneUtils.getMccMncString(PhoneUtils.get(mSubId).getMccMnc());
new AsyncTask<Void, Void, Cursor>() {
@Override
protected Cursor doInBackground(Void... params) {
String selection = Telephony.Carriers.NUMERIC + " =?";
String[] selectionArgs = new String[]{ mccMnc };
final Cursor cursor = mDatabase.query(ApnDatabase.APN_TABLE, APN_PROJECTION,
selection, selectionArgs, null, null, null, null);
return cursor;
}
@Override
protected void onPostExecute(Cursor cursor) {
if (cursor != null) {
try {
PreferenceGroup apnList = (PreferenceGroup)
findPreference(getString(R.string.apn_list_pref_key));
apnList.removeAll();
mSelectedKey = BugleApnSettingsLoader.getFirstTryApn(mDatabase, mccMnc);
while (cursor.moveToNext()) {
String name = cursor.getString(NAME_INDEX);
String apn = cursor.getString(APN_INDEX);
String key = cursor.getString(ID_INDEX);
String type = cursor.getString(TYPES_INDEX);
if (BugleApnSettingsLoader.isValidApnType(type,
BugleApnSettingsLoader.APN_TYPE_MMS)) {
ApnPreference pref = new ApnPreference(getActivity());
pref.setKey(key);
pref.setTitle(name);
pref.setSummary(apn);
pref.setPersistent(false);
pref.setOnPreferenceChangeListener(ApnSettingsFragment.this);
pref.setSelectable(true);
// Turn on the radio button for the currently selected APN. If
// there is no selected APN, don't select an APN.
if ((mSelectedKey != null && mSelectedKey.equals(key))) {
pref.setChecked();
}
apnList.addPreference(pref);
}
}
} finally {
cursor.close();
}
}
}
}.execute((Void) null);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (!mUnavailable) {
menu.add(0, MENU_NEW, 0,
getResources().getString(R.string.menu_new_apn))
.setIcon(R.drawable.ic_add_white)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
menu.add(0, MENU_RESTORE, 0,
getResources().getString(R.string.menu_restore_default_apn))
.setIcon(android.R.drawable.ic_menu_upload);
}
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_NEW:
addNewApn();
return true;
case MENU_RESTORE:
restoreDefaultApn();
return true;
}
return super.onOptionsItemSelected(item);
}
private void addNewApn() {
startActivity(UIIntents.get().getApnEditorIntent(getActivity(), null, mSubId));
}
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
Preference preference) {
startActivity(
UIIntents.get().getApnEditorIntent(getActivity(), preference.getKey(), mSubId));
return true;
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (newValue instanceof String) {
setSelectedApnKey((String) newValue);
}
return true;
}
// current=2 means user selected APN
private static final String UPDATE_SELECTION = Telephony.Carriers.CURRENT + " =?";
private static final String[] UPDATE_SELECTION_ARGS = new String[] { "2" };
private void setSelectedApnKey(final String key) {
mSelectedKey = key;
// Make database changes not on the UI thread
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
// null out the previous "current=2" APN
mDatabase.update(ApnDatabase.APN_TABLE, sCurrentNullMap,
UPDATE_SELECTION, UPDATE_SELECTION_ARGS);
// set the new "current" APN (2)
String selection = Telephony.Carriers._ID + " =?";
String[] selectionArgs = new String[]{ key };
mDatabase.update(ApnDatabase.APN_TABLE, sCurrentSetMap,
selection, selectionArgs);
return null;
}
}.execute((Void) null);
}
private boolean restoreDefaultApn() {
getActivity().showDialog(DIALOG_RESTORE_DEFAULTAPN);
mRestoreDefaultApnMode = true;
if (mRestoreApnUiHandler == null) {
mRestoreApnUiHandler = new RestoreApnUiHandler();
}
if (mRestoreApnProcessHandler == null ||
mRestoreDefaultApnThread == null) {
mRestoreDefaultApnThread = new HandlerThread(
"Restore default APN Handler: Process Thread");
mRestoreDefaultApnThread.start();
mRestoreApnProcessHandler = new RestoreApnProcessHandler(
mRestoreDefaultApnThread.getLooper(), mRestoreApnUiHandler);
}
mRestoreApnProcessHandler.sendEmptyMessage(EVENT_RESTORE_DEFAULTAPN_START);
return true;
}
private class RestoreApnUiHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_RESTORE_DEFAULTAPN_COMPLETE:
fillList();
getPreferenceScreen().setEnabled(true);
mRestoreDefaultApnMode = false;
final Activity activity = getActivity();
activity.dismissDialog(DIALOG_RESTORE_DEFAULTAPN);
Toast.makeText(activity, getResources().getString(
R.string.restore_default_apn_completed), Toast.LENGTH_LONG)
.show();
break;
}
}
}
private static class RestoreApnProcessHandler extends Handler {
private final Handler mCachedRestoreApnUiHandler;
public RestoreApnProcessHandler(Looper looper, Handler restoreApnUiHandler) {
super(looper);
this.mCachedRestoreApnUiHandler = restoreApnUiHandler;
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_RESTORE_DEFAULTAPN_START:
ApnDatabase.forceBuildAndLoadApnTables();
mCachedRestoreApnUiHandler.sendEmptyMessage(
EVENT_RESTORE_DEFAULTAPN_COMPLETE);
break;
}
}
}
}
}

View File

@@ -38,7 +38,6 @@ import com.android.messaging.ui.BugleActionBarActivity;
import com.android.messaging.ui.LicenseActivity;
import com.android.messaging.ui.UIIntents;
import com.android.messaging.util.BuglePrefs;
import com.android.messaging.util.DebugUtils;
import com.android.messaging.util.PhoneUtils;
public class ApplicationSettingsActivity extends BugleActionBarActivity {
@@ -117,12 +116,6 @@ public class ApplicationSettingsActivity extends BugleActionBarActivity {
(SwitchPreference) findPreference(mSwipeRightToDeleteConversationkey);
mIsSmsPreferenceClicked = false;
if (!DebugUtils.isDebugEnabled()) {
final Preference debugCategory = findPreference(getString(
R.string.debug_pref_key));
getPreferenceScreen().removePreference(debugCategory);
}
final PreferenceScreen advancedScreen = (PreferenceScreen) findPreference(
getString(R.string.advanced_pref_key));
final boolean topLevel = getActivity().getIntent().getBooleanExtra(

View File

@@ -138,23 +138,6 @@ public class PerSubscriptionSettingsActivity extends BugleActionBarActivity {
advancedCategory.removePreference(deliveryReportsPref);
}
// Access Point Names (APNs)
final PreferenceScreen apnsScreen =
(PreferenceScreen) findPreference(getString(R.string.sms_apns_key));
if (!MmsManager.shouldUseLegacyMms()
|| (MmsUtils.useSystemApnTable() && !ApnDatabase.doesDatabaseExist())) {
// 1) Remove the ability to edit the local APN prefs if it doesn't use legacy APIs.
// 2) Don't remove the ability to edit the local APN prefs if this device lets us
// access the system APN, but we can't find the MCC/MNC in the APN table and we
// created the local APN table in case the MCC/MNC was in there. In other words,
// if the local APN table exists, let the user edit it.
advancedCategory.removePreference((Preference) apnsScreen);
} else {
apnsScreen.setIntent(UIIntents.get()
.getApnSettingsIntent(getPreferenceScreen().getContext(), mSubId));
}
// We want to disable preferences if we are not the default app, but we do all of the
// above first so that the user sees the correct information on the screen
if (!PhoneUtils.getDefault().isDefaultSmsApp()) {

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 The Android Open Source Project
* Copyright (C) 2024 The LineageOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,7 +18,6 @@ package com.android.messaging.ui.contact;
import android.content.Context;
import android.database.Cursor;
import android.database.MergeCursor;
import androidx.core.util.Pair;
import android.text.TextUtils;
import android.text.util.Rfc822Token;
@@ -35,8 +35,6 @@ import com.android.ex.chips.RecipientEntry;
import com.android.messaging.R;
import com.android.messaging.util.Assert;
import com.android.messaging.util.Assert.DoesNotRunOnMainThread;
import com.android.messaging.util.BugleGservices;
import com.android.messaging.util.BugleGservicesKeys;
import com.android.messaging.util.ContactRecipientEntryUtils;
import com.android.messaging.util.ContactUtil;
import com.android.messaging.util.PhoneUtils;
@@ -116,40 +114,16 @@ public final class ContactRecipientAdapter extends BaseRecipientAdapter {
@DoesNotRunOnMainThread
private CursorResult getFilteredResultsCursor(final String searchText) {
Assert.isNotMainThread();
if (BugleGservices.get().getBoolean(
BugleGservicesKeys.ALWAYS_AUTOCOMPLETE_EMAIL_ADDRESS,
BugleGservicesKeys.ALWAYS_AUTOCOMPLETE_EMAIL_ADDRESS_DEFAULT)) {
final Cursor personalFilterPhonesCursor = ContactUtil
.filterPhones(getContext(), searchText).performSynchronousQuery();
final Cursor personalFilterEmailsCursor = ContactUtil
.filterEmails(getContext(), searchText).performSynchronousQuery();
final Cursor personalCursor = new MergeCursor(
new Cursor[]{personalFilterEmailsCursor, personalFilterPhonesCursor});
final CursorResult cursorResult =
new CursorResult(personalCursor, false /* sorted */);
// Including enterprise result starting from N.
final Cursor enterpriseFilterPhonesCursor = ContactUtil.filterPhonesEnterprise(
getContext(), searchText).performSynchronousQuery();
final Cursor enterpriseFilterEmailsCursor = ContactUtil.filterEmailsEnterprise(
getContext(), searchText).performSynchronousQuery();
final Cursor enterpriseCursor = new MergeCursor(
new Cursor[]{enterpriseFilterEmailsCursor,
enterpriseFilterPhonesCursor});
cursorResult.enterpriseCursor = enterpriseCursor;
return cursorResult;
} else {
final Cursor personalFilterDestinationCursor = ContactUtil
.filterDestination(getContext(), searchText).performSynchronousQuery();
final CursorResult cursorResult = new CursorResult(personalFilterDestinationCursor,
true);
// Including enterprise result starting from N.
final Cursor enterpriseFilterDestinationCursor = ContactUtil
.filterDestinationEnterprise(getContext(), searchText)
.performSynchronousQuery();
cursorResult.enterpriseCursor = enterpriseFilterDestinationCursor;
return cursorResult;
}
final Cursor personalFilterDestinationCursor = ContactUtil
.filterDestination(getContext(), searchText).performSynchronousQuery();
final CursorResult cursorResult = new CursorResult(personalFilterDestinationCursor,
true);
// Including enterprise result starting from N.
final Cursor enterpriseFilterDestinationCursor = ContactUtil
.filterDestinationEnterprise(getContext(), searchText)
.performSynchronousQuery();
cursorResult.enterpriseCursor = enterpriseFilterDestinationCursor;
return cursorResult;
}
@Override

View File

@@ -37,9 +37,7 @@ import com.android.messaging.sms.MmsUtils;
import com.android.messaging.util.Assert;
import com.android.messaging.util.Assert.DoesNotRunOnMainThread;
import com.android.messaging.util.Dates;
import com.android.messaging.util.DebugUtils;
import com.android.messaging.util.PhoneUtils;
import com.android.messaging.util.SafeAsyncTask;
import java.util.List;
@@ -52,22 +50,8 @@ public class MessageDetailsDialog {
public static void show(final Context context, final ConversationMessageData data,
final ConversationParticipantsData participants, final ParticipantData self) {
if (DebugUtils.isDebugEnabled()) {
new SafeAsyncTask<Void, Void, String>() {
@Override
protected String doInBackgroundTimed(Void... params) {
return getMessageDetails(context, data, participants, self);
}
@Override
protected void onPostExecute(String messageDetails) {
showDialog(context, messageDetails);
}
}.executeOnThreadPool(null, null, null);
} else {
String messageDetails = getMessageDetails(context, data, participants, self);
showDialog(context, messageDetails);
}
String messageDetails = getMessageDetails(context, data, participants, self);
showDialog(context, messageDetails);
}
private static String getMessageDetails(final Context context,
@@ -140,10 +124,6 @@ public class MessageDetailsDialog {
appendSimInfo(res, self, details);
if (DebugUtils.isDebugEnabled()) {
appendDebugInfo(details, data);
}
return details.toString();
}
@@ -206,10 +186,6 @@ public class MessageDetailsDialog {
appendSimInfo(res, self, details);
if (DebugUtils.isDebugEnabled()) {
appendDebugInfo(details, data);
}
return details.toString();
}

View File

@@ -40,9 +40,6 @@ import com.android.messaging.ui.UIIntents;
import com.android.messaging.ui.contact.AddContactsConfirmationDialog;
import com.android.messaging.ui.conversationlist.ConversationListFragment.ConversationListFragmentHost;
import com.android.messaging.ui.conversationlist.MultiSelectActionModeCallback.SelectedConversation;
import com.android.messaging.util.BugleGservices;
import com.android.messaging.util.BugleGservicesKeys;
import com.android.messaging.util.DebugUtils;
import com.android.messaging.util.PhoneUtils;
import com.android.messaging.util.Trace;
import com.android.messaging.util.UiUtils;
@@ -268,10 +265,6 @@ public abstract class AbstractConversationListActivity extends BugleActionBarAc
conversationId);
}
public void onActionBarDebug() {
DebugUtils.showDebugOptions(this);
}
private static class UpdateDestinationBlockedActionSnackBar
implements UpdateDestinationBlockedAction.UpdateDestinationBlockedActionListener {
private final Context mContext;

View File

@@ -21,11 +21,9 @@ import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import android.view.Menu;
import android.view.MenuItem;
import com.android.messaging.R;
import com.android.messaging.util.DebugUtils;
public class ArchivedConversationListActivity extends AbstractConversationListActivity {
@@ -60,25 +58,8 @@ public class ArchivedConversationListActivity extends AbstractConversationListAc
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (super.onCreateOptionsMenu(menu)) {
return true;
}
getMenuInflater().inflate(R.menu.archived_conversation_list_menu, menu);
final MenuItem item = menu.findItem(R.id.action_debug_options);
if (item != null) {
final boolean enableDebugItems = DebugUtils.isDebugEnabled();
item.setVisible(enableDebugItems).setEnabled(enableDebugItems);
}
return true;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem menuItem) {
public boolean onOptionsItemSelected(MenuItem menuItem) {
switch(menuItem.getItemId()) {
case R.id.action_debug_options:
onActionBarDebug();
return true;
case android.R.id.home:
onActionBarHome();
return true;

View File

@@ -27,7 +27,6 @@ import android.view.MenuItem;
import com.android.messaging.R;
import com.android.messaging.ui.UIIntents;
import com.android.messaging.util.DebugUtils;
import com.android.messaging.util.Trace;
public class ConversationListActivity extends AbstractConversationListActivity {
@@ -77,11 +76,6 @@ public class ConversationListActivity extends AbstractConversationListActivity {
return true;
}
getMenuInflater().inflate(R.menu.conversation_list_fragment_menu, menu);
final MenuItem item = menu.findItem(R.id.action_debug_options);
if (item != null) {
final boolean enableDebugItems = DebugUtils.isDebugEnabled();
item.setVisible(enableDebugItems).setEnabled(enableDebugItems);
}
return true;
}
@@ -94,9 +88,6 @@ public class ConversationListActivity extends AbstractConversationListActivity {
case R.id.action_settings:
onActionBarSettings();
return true;
case R.id.action_debug_options:
onActionBarDebug();
return true;
case R.id.action_show_archived:
onActionBarArchived();
return true;

View File

@@ -1,34 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.messaging.ui.debug;
import android.os.Bundle;
import com.android.messaging.R;
import com.android.messaging.ui.BaseBugleActivity;
/**
* Show list of all MmsConfig key/value pairs and allow editing.
*/
public class DebugMmsConfigActivity extends BaseBugleActivity {
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.debug_mmsconfig_activity);
}
}

View File

@@ -1,150 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.messaging.ui.debug;
import android.app.Fragment;
import android.content.Context;
import android.os.Bundle;
import android.telephony.SubscriptionInfo;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;
import com.android.messaging.R;
import com.android.messaging.sms.MmsConfig;
import com.android.messaging.ui.debug.DebugMmsConfigItemView.MmsConfigItemListener;
import com.android.messaging.util.PhoneUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
* Show list of all MmsConfig key/value pairs and allow editing.
*/
public class DebugMmsConfigFragment extends Fragment {
@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
final Bundle savedInstanceState) {
final View fragmentView = inflater.inflate(R.layout.mms_config_debug_fragment, container,
false);
final ListView listView = (ListView) fragmentView.findViewById(android.R.id.list);
final Spinner spinner = (Spinner) fragmentView.findViewById(R.id.sim_selector);
final Integer[] subIdArray = getActiveSubIds();
ArrayAdapter<Integer> spinnerAdapter = new ArrayAdapter<Integer>(getActivity(),
android.R.layout.simple_spinner_item, subIdArray);
spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(spinnerAdapter);
spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
listView.setAdapter(new MmsConfigAdapter(getActivity(), subIdArray[position]));
final int[] mccmnc = PhoneUtils.get(subIdArray[position]).getMccMnc();
// Set the title with the mcc/mnc
final TextView title = (TextView) fragmentView.findViewById(R.id.sim_title);
title.setText("(" + mccmnc[0] + "/" + mccmnc[1] + ") " +
getActivity().getString(R.string.debug_sub_id_spinner_text));
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
return fragmentView;
}
public static Integer[] getActiveSubIds() {
final List<SubscriptionInfo> subRecords =
PhoneUtils.getDefault().getActiveSubscriptionInfoList();
if (subRecords == null) {
return new Integer[0];
}
final Integer[] retArray = new Integer[subRecords.size()];
for (int i = 0; i < subRecords.size(); i++) {
retArray[i] = subRecords.get(i).getSubscriptionId();
}
return retArray;
}
private class MmsConfigAdapter extends BaseAdapter implements
DebugMmsConfigItemView.MmsConfigItemListener {
private final LayoutInflater mInflater;
private final List<String> mKeys;
private final MmsConfig mMmsConfig;
public MmsConfigAdapter(Context context, int subId) {
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mMmsConfig = MmsConfig.get(subId);
mKeys = new ArrayList<>(mMmsConfig.keySet());
Iterator<String> it = mKeys.iterator();
while (it.hasNext()) {
// Remove a config if the MmsConfig.sKeyTypeMap doesn't have it.
if (MmsConfig.getKeyType(it.next()) == null) {
it.remove();
}
}
Collections.sort(mKeys);
}
@Override
public View getView(final int position, final View convertView, final ViewGroup parent) {
final DebugMmsConfigItemView view;
if (convertView != null && convertView instanceof DebugMmsConfigItemView) {
view = (DebugMmsConfigItemView) convertView;
} else {
view = (DebugMmsConfigItemView) mInflater.inflate(
R.layout.debug_mmsconfig_item_view, parent, false);
}
final String key = mKeys.get(position);
view.bind(key,
MmsConfig.getKeyType(key),
String.valueOf(mMmsConfig.getValue(key)),
this);
return view;
}
@Override
public void onValueChanged(String key, String keyType, String value) {
mMmsConfig.update(keyType, key, value);
notifyDataSetChanged();
}
@Override
public int getCount() {
return mKeys.size();
}
@Override
public Object getItem(int position) {
return mKeys.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
}
}

View File

@@ -1,131 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
* Copyright (C) 2024 The LineageOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.messaging.ui.debug;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.text.InputType;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Switch;
import android.widget.TextView;
import com.android.messaging.R;
import com.android.messaging.sms.MmsConfig;
import com.android.messaging.util.LogUtil;
public class DebugMmsConfigItemView extends LinearLayout implements OnClickListener,
OnCheckedChangeListener, DialogInterface.OnClickListener {
public interface MmsConfigItemListener {
void onValueChanged(String key, String keyType, String value);
}
private TextView mTitle;
private TextView mTextValue;
private Switch mSwitch;
private String mKey;
private String mKeyType;
private MmsConfigItemListener mListener;
private EditText mEditText;
public DebugMmsConfigItemView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
}
@Override
protected void onFinishInflate () {
mTitle = (TextView) findViewById(R.id.title);
mTextValue = (TextView) findViewById(R.id.text_value);
mSwitch = (Switch) findViewById(R.id.switch_button);
setOnClickListener(this);
mSwitch.setOnCheckedChangeListener(this);
}
public void bind(final String key, final String keyType, final String value,
final MmsConfigItemListener listener) {
mListener = listener;
mKey = key;
mKeyType = keyType;
mTitle.setText(key);
switch (keyType) {
case MmsConfig.KEY_TYPE_BOOL:
mSwitch.setVisibility(View.VISIBLE);
mTextValue.setVisibility(View.GONE);
mSwitch.setChecked(Boolean.valueOf(value));
break;
case MmsConfig.KEY_TYPE_STRING:
case MmsConfig.KEY_TYPE_INT:
mTextValue.setVisibility(View.VISIBLE);
mSwitch.setVisibility(View.GONE);
mTextValue.setText(value);
break;
default:
mTextValue.setVisibility(View.GONE);
mSwitch.setVisibility(View.GONE);
LogUtil.e(LogUtil.BUGLE_TAG, "Unexpected keytype: " + keyType);
break;
}
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
mListener.onValueChanged(mKey, mKeyType, String.valueOf(isChecked));
}
@Override
public void onClick(View v) {
if (MmsConfig.KEY_TYPE_BOOL.equals(mKeyType)) {
return;
}
final Context context = getContext();
mEditText = new EditText(context);
mEditText.setText(mTextValue.getText());
mEditText.setFocusable(true);
if (MmsConfig.KEY_TYPE_INT.equals(mKeyType)) {
mEditText.setInputType(InputType.TYPE_CLASS_PHONE);
} else {
mEditText.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
}
final AlertDialog dialog = new AlertDialog.Builder(context)
.setTitle(mKey)
.setView(mEditText)
.setPositiveButton(android.R.string.ok, this)
.setNegativeButton(android.R.string.cancel, null)
.create();
dialog.setOnShowListener(dialog1 -> {
mEditText.requestFocus();
mEditText.selectAll();
((InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE))
.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, 0);
});
dialog.show();
}
@Override
public void onClick(DialogInterface dialog, int which) {
mListener.onValueChanged(mKey, mKeyType, mEditText.getText().toString());
}
}

View File

@@ -1,171 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
* Copyright (C) 2024 The LineageOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.messaging.ui.debug;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.telephony.SmsMessage;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import com.android.messaging.R;
import com.android.messaging.datamodel.action.ReceiveMmsMessageAction;
import com.android.messaging.datamodel.data.ParticipantData;
import com.android.messaging.receiver.SmsReceiver;
import com.android.messaging.sms.MmsUtils;
import com.android.messaging.util.DebugUtils;
import com.android.messaging.util.LogUtil;
/**
* Class that displays UI for choosing SMS/MMS dump files for debugging
*/
public class DebugSmsMmsFromDumpFileDialogFragment extends DialogFragment {
public static final String APPLICATION_OCTET_STREAM = "application/octet-stream";
public static final String KEY_DUMP_FILES = "dump_files";
public static final String KEY_ACTION = "action";
public static final String ACTION_LOAD = "load";
public static final String ACTION_EMAIL = "email";
private String[] mDumpFiles;
private String mAction;
public static DebugSmsMmsFromDumpFileDialogFragment newInstance(final String[] dumpFiles,
final String action) {
final DebugSmsMmsFromDumpFileDialogFragment frag =
new DebugSmsMmsFromDumpFileDialogFragment();
final Bundle args = new Bundle();
args.putSerializable(KEY_DUMP_FILES, dumpFiles);
args.putString(KEY_ACTION, action);
frag.setArguments(args);
return frag;
}
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final Bundle args = getArguments();
mDumpFiles = (String[]) args.getSerializable(KEY_DUMP_FILES);
mAction = args.getString(KEY_ACTION);
final LayoutInflater inflater = getActivity().getLayoutInflater();
final View layout = inflater.inflate(
R.layout.debug_sms_mms_from_dump_file_dialog, null/*root*/);
final ListView list = (ListView) layout.findViewById(R.id.dump_file_list);
list.setAdapter(new DumpFileListAdapter(getActivity(), mDumpFiles));
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
final Resources resources = getResources();
if (ACTION_LOAD.equals(mAction)) {
builder.setTitle(resources.getString(
R.string.load_sms_mms_from_dump_file_dialog_title));
} else if (ACTION_EMAIL.equals(mAction)) {
builder.setTitle(resources.getString(
R.string.email_sms_mms_from_dump_file_dialog_title));
}
builder.setView(layout);
return builder.create();
}
private class DumpFileListAdapter extends ArrayAdapter<String> {
public DumpFileListAdapter(final Context context, final String[] dumpFiles) {
super(context, R.layout.sms_mms_dump_file_list_item, dumpFiles);
}
@NonNull
@Override
public View getView(final int position, final View view, @NonNull final ViewGroup parent) {
TextView actionItemView;
if (view == null || !(view instanceof TextView)) {
final LayoutInflater inflater = LayoutInflater.from(getContext());
actionItemView = (TextView) inflater.inflate(
R.layout.sms_mms_dump_file_list_item, parent, false);
} else {
actionItemView = (TextView) view;
}
final String file = getItem(position);
actionItemView.setText(file);
actionItemView.setOnClickListener(view1 -> {
dismiss();
if (ACTION_LOAD.equals(mAction)) {
receiveFromDumpFile(file);
} else if (ACTION_EMAIL.equals(mAction)) {
emailDumpFile(file);
}
});
return actionItemView;
}
}
/**
* Load MMS/SMS from the dump file
*/
private void receiveFromDumpFile(final String dumpFileName) {
if (dumpFileName.startsWith(MmsUtils.SMS_DUMP_PREFIX)) {
final SmsMessage[] messages = DebugUtils.retreiveSmsFromDumpFile(dumpFileName);
if (messages != null) {
SmsReceiver.deliverSmsMessages(getActivity(), ParticipantData.DEFAULT_SELF_SUB_ID,
0, messages);
} else {
LogUtil.e(LogUtil.BUGLE_TAG,
"receiveFromDumpFile: invalid sms dump file " + dumpFileName);
}
} else if (dumpFileName.startsWith(MmsUtils.MMS_DUMP_PREFIX)) {
final byte[] data = MmsUtils.createDebugNotificationInd(dumpFileName);
if (data != null) {
final ReceiveMmsMessageAction action = new ReceiveMmsMessageAction(
ParticipantData.DEFAULT_SELF_SUB_ID, data);
action.start();
} else {
LogUtil.e(LogUtil.BUGLE_TAG,
"receiveFromDumpFile: invalid mms dump file " + dumpFileName);
}
} else {
LogUtil.e(LogUtil.BUGLE_TAG,
"receiveFromDumpFile: invalid dump file name " + dumpFileName);
}
}
/**
* Launch email app to send the dump file
*/
private void emailDumpFile(final String file) {
final Resources resources = getResources();
final String fileLocation = "file://"
+ Environment.getExternalStorageDirectory() + "/" + file;
final Intent sharingIntent = new Intent(Intent.ACTION_SEND);
sharingIntent.setType(APPLICATION_OCTET_STREAM);
sharingIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(fileLocation));
sharingIntent.putExtra(Intent.EXTRA_SUBJECT,
resources.getString(R.string.email_sms_mms_dump_file_subject));
getActivity().startActivity(Intent.createChooser(sharingIntent,
resources.getString(R.string.email_sms_mms_dump_file_chooser_title)));
}
}

View File

@@ -45,8 +45,6 @@ import com.android.messaging.sms.MmsConfig;
import com.android.messaging.ui.mediapicker.camerafocus.FocusOverlayManager;
import com.android.messaging.ui.mediapicker.camerafocus.RenderOverlay;
import com.android.messaging.util.Assert;
import com.android.messaging.util.BugleGservices;
import com.android.messaging.util.BugleGservicesKeys;
import com.android.messaging.util.LogUtil;
import com.android.messaging.util.OsUtil;
import com.android.messaging.util.UiUtils;
@@ -975,9 +973,7 @@ class CameraManager implements FocusOverlayManager.Listener {
screenWidth *= scaleFactor;
screenHeight *= scaleFactor;
final float aspectRatio = BugleGservices.get().getFloat(
BugleGservicesKeys.CAMERA_ASPECT_RATIO,
screenWidth / (float) screenHeight);
final float aspectRatio = screenWidth / (float) screenHeight;
final List<Camera.Size> sizes = new ArrayList<Camera.Size>(
mCamera.getParameters().getSupportedPictureSizes());
final int maxPixels = maxWidth * maxHeight;

View File

@@ -40,27 +40,12 @@ public final class Assert {
sShouldCrash = sIsEngBuild = true;
}
private static void refreshGservices(final BugleGservices gservices) {
sShouldCrash = sIsEngBuild;
if (!sShouldCrash) {
sShouldCrash = gservices.getBoolean(
BugleGservicesKeys.ASSERTS_FATAL,
BugleGservicesKeys.ASSERTS_FATAL_DEFAULT);
}
}
// Static initializer block to find out if we're running an eng or
// release build.
static {
setIfEngBuild();
}
// This is called from FactoryImpl once the Gservices class is initialized.
public static void initializeGservices (final BugleGservices gservices) {
gservices.registerForChanges(() -> refreshGservices(gservices));
refreshGservices(gservices);
}
/**
* Halt execution if this is not an eng build.
* <p>Intended for use in code paths that should be run only for tests and never on

View File

@@ -1,72 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.messaging.util;
import com.android.messaging.Factory;
/**
* A thin wrapper for getting GServices value. During constructor time a one time background thread
* will cache all GServices key with the prefix of "bugle_". All get calls will wait for Gservices
* to finish caching the first time. In practice, the background thread will finish before any get
* request.
*/
public abstract class BugleGservices {
static final String BUGLE_GSERVICES_PREFIX = "bugle_";
public static BugleGservices get() {
return Factory.get().getBugleGservices();
}
public abstract void registerForChanges(final Runnable r);
/**
* @param key The key to look up in GServices
* @param defaultValue The default value if value in GServices is null or if
* NumberFormatException is caught.
* @return The corresponding value, or the default value.
*/
public abstract long getLong(final String key, final long defaultValue);
/**
* @param key The key to look up in GServices
* @param defaultValue The default value if value in GServices is null or if
* NumberFormatException is caught.
* @return The corresponding value, or the default value.
*/
public abstract int getInt(final String key, final int defaultValue);
/**
* @param key The key to look up in GServices
* @param defaultValue The default value if value in GServices is null.
* @return The corresponding value, or the default value.
*/
public abstract boolean getBoolean(final String key, final boolean defaultValue);
/**
* @param key The key to look up in GServices
* @param defaultValue The default value if value in GServices is null.
* @return The corresponding value, or the default value.
*/
public abstract String getString(final String key, final String defaultValue);
/**
* @param key The key to look up in GServices
* @param defaultValue The default value if value in GServices is null.
* @return The corresponding value, or the default value.
*/
public abstract float getFloat(final String key, final float defaultValue);
}

View File

@@ -1,68 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.messaging.util;
import android.content.Context;
/**
* A thin wrapper for getting GServices value.
*/
public class BugleGservicesImpl extends BugleGservices {
public BugleGservicesImpl(final Context context) {
}
@Override
public void registerForChanges(final Runnable r) {
}
/**
* Asserts that the key has the expected prefix.
*/
private void assertKeyAndWaitForGservices(final String key) {
Assert.isTrue(key.startsWith(BUGLE_GSERVICES_PREFIX));
}
@Override
public long getLong(final String key, final long defaultValue) {
assertKeyAndWaitForGservices(key);
return defaultValue;
}
@Override
public int getInt(final String key, final int defaultValue) {
assertKeyAndWaitForGservices(key);
return defaultValue;
}
@Override
public boolean getBoolean(final String key, final boolean defaultValue) {
assertKeyAndWaitForGservices(key);
return defaultValue;
}
@Override
public String getString(final String key, final String defaultValue) {
assertKeyAndWaitForGservices(key);
return defaultValue;
}
@Override
public float getFloat(final String key, final float defaultValue) {
assertKeyAndWaitForGservices(key);
return defaultValue;
}
}

View File

@@ -24,49 +24,29 @@ package com.android.messaging.util;
public final class BugleGservicesKeys {
private BugleGservicesKeys() {} // do not instantiate
/**
* Whether to enable extra debugging features on the client. Default is
* {@value #ENABLE_DEBUGGING_FEATURES_DEFAULT}.
*/
public static final String ENABLE_DEBUGGING_FEATURES
= "bugle_debugging";
public static final boolean ENABLE_DEBUGGING_FEATURES_DEFAULT
= false;
/**
* Whether to enable saving extra logs. Default is {@value #ENABLE_LOG_SAVER_DEFAULT}.
*/
public static final String ENABLE_LOG_SAVER = "bugle_logsaver";
public static final boolean ENABLE_LOG_SAVER_DEFAULT = false;
/**
* Time in milliseconds of initial (attempt 1) resend backoff for failing messages
*/
public static final String INITIAL_MESSAGE_RESEND_DELAY_MS = "bugle_resend_delay_in_millis";
public static final long INITIAL_MESSAGE_RESEND_DELAY_MS_DEFAULT = 5 * 1000L;
/**
* Time in milliseconds of max resend backoff for failing messages
*/
public static final String MAX_MESSAGE_RESEND_DELAY_MS = "bugle_max_resend_delay_in_millis";
public static final long MAX_MESSAGE_RESEND_DELAY_MS_DEFAULT = 2 * 60 * 60 * 1000L;
/**
* Time in milliseconds of resend window for unsent messages
*/
public static final String MESSAGE_RESEND_TIMEOUT_MS = "bugle_resend_timeout_in_millis";
public static final long MESSAGE_RESEND_TIMEOUT_MS_DEFAULT = 20 * 60 * 1000L;
/**
* Time in milliseconds of download window for new mms notifications
*/
public static final String MESSAGE_DOWNLOAD_TIMEOUT_MS = "bugle_download_timeout_in_millis";
public static final long MESSAGE_DOWNLOAD_TIMEOUT_MS_DEFAULT = 20 * 60 * 1000L;
/**
* Time in milliseconds for SMS send timeout
*/
public static final String SMS_SEND_TIMEOUT_IN_MILLIS = "bugle_sms_send_timeout";
public static final long SMS_SEND_TIMEOUT_IN_MILLIS_DEFAULT = 5 * 60 * 1000L;
/**
@@ -87,17 +67,9 @@ public final class BugleGservicesKeys {
* whatever reasons. Keeping this low ensures responsiveness of the application.
* 4. The limit on number of total messages to scan in one batch.
*/
public static final String SMS_SYNC_BATCH_SIZE_MIN =
"bugle_sms_sync_batch_size_min";
public static final int SMS_SYNC_BATCH_SIZE_MIN_DEFAULT = 80;
public static final String SMS_SYNC_BATCH_SIZE_MAX =
"bugle_sms_sync_batch_size_max";
public static final int SMS_SYNC_BATCH_SIZE_MAX_DEFAULT = 1000;
public static final String SMS_SYNC_BATCH_TIME_LIMIT_MILLIS =
"bugle_sms_sync_batch_time_limit";
public static final long SMS_SYNC_BATCH_TIME_LIMIT_MILLIS_DEFAULT = 400;
public static final String SMS_SYNC_BATCH_MAX_MESSAGES_TO_SCAN =
"bugle_sms_sync_batch_max_messages_to_scan";
public static final int SMS_SYNC_BATCH_MAX_MESSAGES_TO_SCAN_DEFAULT =
SMS_SYNC_BATCH_SIZE_MAX_DEFAULT * 4;
@@ -108,18 +80,13 @@ public final class BugleGservicesKeys {
* when bringing in changes made outside the application. It also represents a buffer
* to ensure that sync doesn't trigger based on changes made within the application.
*/
public static final String SMS_SYNC_BACKOFF_TIME_MILLIS =
"bugle_sms_sync_backoff_time";
public static final long SMS_SYNC_BACKOFF_TIME_MILLIS_DEFAULT = 5000L;
/**
* Just in case if we fall into a loop of full sync -> still not synchronized -> full sync ...
* This forces a backoff time so that we at most do full sync once a while (an hour by default)
*/
public static final String SMS_FULL_SYNC_BACKOFF_TIME_MILLIS =
"bugle_sms_full_sync_backoff_time";
public static final long SMS_FULL_SYNC_BACKOFF_TIME_MILLIS_DEFAULT = 60 * 60 * 1000;
/**
* MMS UA profile url.
*
@@ -127,66 +94,30 @@ public final class BugleGservicesKeys {
* latest and greatest phones. However, if we're on KitKat or below we can't get the phone's
* UA profile and thus we need to send them the default url.
*/
public static final String MMS_UA_PROFILE_URL =
"bugle_mms_uaprofurl";
public static final String MMS_UA_PROFILE_URL_DEFAULT =
"http://www.gstatic.com/android/sms/mms_ua_profile.xml";
/**
* MMS apn mmsc
*/
public static final String MMS_MMSC =
"bugle_mms_mmsc";
/**
* MMS apn proxy ip address
*/
public static final String MMS_PROXY_ADDRESS =
"bugle_mms_proxy_address";
/**
* MMS apn proxy port
*/
public static final String MMS_PROXY_PORT =
"bugle_mms_proxy_port";
/**
* List of known SMS system messages that we will ignore (no deliver, no abort) so that the
* user doesn't see them and the appropriate app is able to handle them. We are delivering
* these as a \n delimited list of patterns, however we should eventually move to storing
* them with the per-carrier mms config xml file.
*/
public static final String SMS_IGNORE_MESSAGE_REGEX =
"bugle_sms_ignore_message_regex";
public static final String SMS_IGNORE_MESSAGE_REGEX_DEFAULT = "";
/**
* When receiving or importing an mms, limit the length of text to this limit. Huge blocks
* of text can cause the app to hang/ANR/or crash in native text code..
*/
public static final String MMS_TEXT_LIMIT = "bugle_mms_text_limit";
public static final int MMS_TEXT_LIMIT_DEFAULT = 2000;
/**
* Max number of attachments the user may add to a single message.
*/
public static final String MMS_ATTACHMENT_LIMIT = "bugle_mms_attachment_limit";
public static final int MMS_ATTACHMENT_LIMIT_DEFAULT = 10;
/**
* The max number of messages to show in a single conversation notification. We always show
* the most recent message. If this value is >1, we may also include prior messages as well.
*/
public static final String MAX_MESSAGES_IN_CONVERSATION_NOTIFICATION =
"bugle_max_messages_in_conversation_notification";
public static final int MAX_MESSAGES_IN_CONVERSATION_NOTIFICATION_DEFAULT = 7;
/**
* Time (in seconds) between notification ringing for incoming messages of the same
* conversation. We won't ding more often than this value for messages coming in at a high rate.
*/
public static final String NOTIFICATION_TIME_BETWEEN_RINGS_SECONDS
= "bugle_notification_time_between_rings_seconds";
public static final int NOTIFICATION_TIME_BETWEEN_RINGS_SECONDS_DEFAULT = 10;
/**
@@ -195,91 +126,11 @@ public final class BugleGservicesKeys {
* less screen real estate, so we may want to optimize for that case. Note that if a wearable
* is paired, this value will apply to notifications as shown both on the watch and the phone.
*/
public static final String MAX_MESSAGES_IN_CONVERSATION_NOTIFICATION_WITH_WEARABLE =
"bugle_max_messages_in_conversation_notification_with_wearable";
public static final int MAX_MESSAGES_IN_CONVERSATION_NOTIFICATION_WITH_WEARABLE_DEFAULT = 1;
/**
* Regular expression to match against query. If it matches then display
* the query plan for this query.
*/
public static final String EXPLAIN_QUERY_PLAN_REGEXP = "bugle_query_plan_regexp";
/**
* Whether asserts are fatal on user/userdebug builds.
* Default is {@value #ASSERTS_FATAL_DEFAULT}.
*/
public static final String ASSERTS_FATAL = "bugle_asserts_fatal";
public static final boolean ASSERTS_FATAL_DEFAULT = false;
/**
* Whether to use API for sending/downloading MMS (if present, true for L).
* Default is {@value #USE_MMS_API_IF_PRESENT_DEFAULT}.
*/
public static final String USE_MMS_API_IF_PRESENT = "bugle_use_mms_api";
public static final boolean USE_MMS_API_IF_PRESENT_DEFAULT = true;
/**
* Whether to always auto-complete email addresses for sending MMS. By default, Bugle starts
* to auto-complete after the user has typed the "@" character.
* Default is (@value ALWAYS_AUTOCOMPLETE_EMAIL_ADDRESS_DEFAULT}.
*/
public static final String ALWAYS_AUTOCOMPLETE_EMAIL_ADDRESS =
"bugle_always_autocomplete_email_address";
public static final boolean ALWAYS_AUTOCOMPLETE_EMAIL_ADDRESS_DEFAULT = false;
// We typically request an aspect ratio close the the screen size, but some cameras can be
// flaky and not work well in certain aspect ratios. This allows us to guide the CameraManager
// to pick a more reliable aspect ratio. The value is a float like 1.333f or 1.777f. There is
// no hard coded default because the default is the screen aspect ratio.
public static final String CAMERA_ASPECT_RATIO = "bugle_camera_aspect_ratio";
/**
* The recent time range within which we should check MMS WAP Push duplication
* If the value is 0, it signals that we should use old dedup algorithm for wap push
*/
public static final String MMS_WAP_PUSH_DEDUP_TIME_LIMIT_SECS =
"bugle_mms_wap_push_dedup_time_limit_secs";
public static final long MMS_WAP_PUSH_DEDUP_TIME_LIMIT_SECS_DEFAULT = 7 * 24 * 3600; // 7 days
/**
* Whether to use persistent, on-disk LogSaver
*/
public static final String PERSISTENT_LOGSAVER = "bugle_persistent_logsaver";
public static final boolean PERSISTENT_LOGSAVER_DEFAULT = false;
/**
* For in-memory LogSaver, what's the size of memory buffer in number of records
*/
public static final String IN_MEMORY_LOGSAVER_RECORD_COUNT =
"bugle_in_memory_logsaver_record_count";
public static final int IN_MEMORY_LOGSAVER_RECORD_COUNT_DEFAULT = 500;
/**
* For on-disk LogSaver, what's the size of file rotation set
*/
public static final String PERSISTENT_LOGSAVER_ROTATION_SET_SIZE =
"bugle_persistent_logsaver_rotation_set_size";
public static final int PERSISTENT_LOGSAVER_ROTATION_SET_SIZE_DEFAULT = 8;
/**
* For on-disk LogSaver, what's the byte limit of a single log file
*/
public static final String PERSISTENT_LOGSAVER_FILE_LIMIT_BYTES =
"bugle_persistent_logsaver_file_limit";
public static final int PERSISTENT_LOGSAVER_FILE_LIMIT_BYTES_DEFAULT = 256 * 1024; // 256KB
/**
* We concatenate all text parts in an MMS to form the message text. This specifies
* the separator between the combinated text parts. Default is ' ' (space).
*/
public static final String MMS_TEXT_CONCAT_SEPARATOR = "bugle_mms_text_concat_separator";
public static final String MMS_TEXT_CONCAT_SEPARATOR_DEFAULT = " ";
/**
* Whether to enable transcoding GIFs. We sometimes need to compress GIFs to make them small
* enough to send via MMS (which often limits messages to 1 MB in size).
*/
public static final String ENABLE_GIF_TRANSCODING = "bugle_gif_transcoding";
public static final boolean ENABLE_GIF_TRANSCODING_DEFAULT = true;
}

View File

@@ -17,304 +17,22 @@
package com.android.messaging.util;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.Intent;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Environment;
import android.telephony.SmsMessage;
import android.text.TextUtils;
import android.widget.ArrayAdapter;
import androidx.annotation.NonNull;
import com.android.messaging.Factory;
import com.android.messaging.R;
import com.android.messaging.datamodel.SyncManager;
import com.android.messaging.datamodel.action.DumpDatabaseAction;
import com.android.messaging.datamodel.action.LogTelephonyDatabaseAction;
import com.android.messaging.sms.MmsUtils;
import com.android.messaging.ui.UIIntents;
import com.android.messaging.ui.debug.DebugSmsMmsFromDumpFileDialogFragment;
import com.google.common.io.ByteStreams;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StreamCorruptedException;
public class DebugUtils {
private static final String TAG = "bugle.util.DebugUtils";
private static boolean sDebugNoise;
private static boolean sDebugClassZeroSms;
private static MediaPlayer [] sMediaPlayer;
private static final Object sLock = new Object();
public static final int DEBUG_SOUND_SERVER_REQUEST = 0;
public static final int DEBUG_SOUND_DB_OP = 1;
public static void maybePlayDebugNoise(final Context context, final int sound) {
if (sDebugNoise) {
synchronized (sLock) {
try {
if (sMediaPlayer == null) {
sMediaPlayer = new MediaPlayer[2];
sMediaPlayer[DEBUG_SOUND_SERVER_REQUEST] =
MediaPlayer.create(context, R.raw.server_request_debug);
sMediaPlayer[DEBUG_SOUND_DB_OP] =
MediaPlayer.create(context, R.raw.db_op_debug);
sMediaPlayer[DEBUG_SOUND_DB_OP].setVolume(1.0F, 1.0F);
sMediaPlayer[DEBUG_SOUND_SERVER_REQUEST].setVolume(0.3F, 0.3F);
}
if (sMediaPlayer[sound] != null) {
sMediaPlayer[sound].start();
}
} catch (final IllegalArgumentException e) {
LogUtil.e(TAG, "MediaPlayer exception", e);
} catch (final SecurityException e) {
LogUtil.e(TAG, "MediaPlayer exception", e);
} catch (final IllegalStateException e) {
LogUtil.e(TAG, "MediaPlayer exception", e);
}
}
}
}
public static boolean isDebugEnabled() {
return BugleGservices.get().getBoolean(BugleGservicesKeys.ENABLE_DEBUGGING_FEATURES,
BugleGservicesKeys.ENABLE_DEBUGGING_FEATURES_DEFAULT);
}
public abstract static class DebugAction {
final String mTitle;
public DebugAction(final String title) {
mTitle = title;
}
@NonNull
@Override
public String toString() {
return mTitle;
}
public abstract void run();
}
public static void showDebugOptions(final Activity host) {
final AlertDialog.Builder builder = new AlertDialog.Builder(host);
final ArrayAdapter<DebugAction> arrayAdapter = new ArrayAdapter<DebugAction>(
host, android.R.layout.simple_list_item_1);
arrayAdapter.add(new DebugAction("Dump Database") {
@Override
public void run() {
DumpDatabaseAction.dumpDatabase();
}
});
arrayAdapter.add(new DebugAction("Log Telephony Data") {
@Override
public void run() {
LogTelephonyDatabaseAction.dumpDatabase();
}
});
arrayAdapter.add(new DebugAction("Toggle Noise") {
@Override
public void run() {
sDebugNoise = !sDebugNoise;
}
});
arrayAdapter.add(new DebugAction("Force sync SMS") {
@Override
public void run() {
final BuglePrefs prefs = BuglePrefs.getApplicationPrefs();
prefs.putLong(BuglePrefsKeys.LAST_FULL_SYNC_TIME, -1);
SyncManager.forceSync();
}
});
arrayAdapter.add(new DebugAction("Sync SMS") {
@Override
public void run() {
SyncManager.sync();
}
});
arrayAdapter.add(new DebugAction("Load SMS/MMS from dump file") {
@Override
public void run() {
new DebugSmsMmsDumpTask(host,
DebugSmsMmsFromDumpFileDialogFragment.ACTION_LOAD).executeOnThreadPool();
}
});
arrayAdapter.add(new DebugAction("Email SMS/MMS dump file") {
@Override
public void run() {
new DebugSmsMmsDumpTask(host,
DebugSmsMmsFromDumpFileDialogFragment.ACTION_EMAIL).executeOnThreadPool();
}
});
arrayAdapter.add(new DebugAction("MMS Config...") {
@Override
public void run() {
UIIntents.get().launchDebugMmsConfigActivity(host);
}
});
arrayAdapter.add(new DebugAction(sDebugClassZeroSms ? "Turn off Class 0 sms test" :
"Turn on Class Zero test") {
@Override
public void run() {
sDebugClassZeroSms = !sDebugClassZeroSms;
}
});
arrayAdapter.add(new DebugAction("Test sharing a file URI") {
@Override
public void run() {
shareFileUri();
}
});
builder.setAdapter(arrayAdapter, (arg0, pos) -> arrayAdapter.getItem(pos).run());
builder.create().show();
}
/**
* Task to list all the dump files and perform an action on it
*/
private static class DebugSmsMmsDumpTask extends SafeAsyncTask<Void, Void, String[]> {
private final String mAction;
private final Activity mHost;
public DebugSmsMmsDumpTask(final Activity host, final String action) {
mHost = host;
mAction = action;
}
@Override
protected void onPostExecute(final String[] result) {
if (result == null || result.length < 1) {
return;
}
final FragmentManager fragmentManager = mHost.getFragmentManager();
final FragmentTransaction ft = fragmentManager.beginTransaction();
final DebugSmsMmsFromDumpFileDialogFragment dialog =
DebugSmsMmsFromDumpFileDialogFragment.newInstance(result, mAction);
dialog.show(fragmentManager, ""/*tag*/);
}
@Override
protected String[] doInBackgroundTimed(final Void... params) {
final File dir = DebugUtils.getDebugFilesDir();
return dir.list((dir1, filename) -> filename != null
&& ((mAction == DebugSmsMmsFromDumpFileDialogFragment.ACTION_EMAIL
&& filename.equals(DumpDatabaseAction.DUMP_NAME))
|| filename.startsWith(MmsUtils.MMS_DUMP_PREFIX)
|| filename.startsWith(MmsUtils.SMS_DUMP_PREFIX)));
}
}
/**
* Dump the received raw SMS data into a file on external storage
*
* @param id The ID to use as part of the dump file name
* @param messages The raw SMS data
*/
public static void dumpSms(final long id, final android.telephony.SmsMessage[] messages,
final String format) {
try {
final String dumpFileName = MmsUtils.SMS_DUMP_PREFIX + id;
final File dumpFile = DebugUtils.getDebugFile(dumpFileName, true);
if (dumpFile != null) {
final FileOutputStream fos = new FileOutputStream(dumpFile);
final DataOutputStream dos = new DataOutputStream(fos);
try {
final int chars = (TextUtils.isEmpty(format) ? 0 : format.length());
dos.writeInt(chars);
if (chars > 0) {
dos.writeUTF(format);
}
dos.writeInt(messages.length);
for (final android.telephony.SmsMessage message : messages) {
final byte[] pdu = message.getPdu();
dos.writeInt(pdu.length);
dos.write(pdu, 0, pdu.length);
}
dos.flush();
} finally {
dos.close();
ensureReadable(dumpFile);
}
}
} catch (final IOException e) {
LogUtil.e(LogUtil.BUGLE_TAG, "dumpSms: " + e, e);
}
}
/**
* Load MMS/SMS from the dump file
*/
public static SmsMessage[] retreiveSmsFromDumpFile(final String dumpFileName) {
SmsMessage[] messages = null;
final File inputFile = DebugUtils.getDebugFile(dumpFileName, false);
if (inputFile != null) {
FileInputStream fis = null;
DataInputStream dis = null;
try {
fis = new FileInputStream(inputFile);
dis = new DataInputStream(fis);
// SMS dump
String format = null;
final int chars = dis.readInt();
if (chars > 0) {
format = dis.readUTF();
}
final int count = dis.readInt();
final SmsMessage[] messagesTemp = new SmsMessage[count];
for (int i = 0; i < count; i++) {
final int length = dis.readInt();
final byte[] pdu = new byte[length];
dis.read(pdu, 0, length);
messagesTemp[i] = SmsMessage.createFromPdu(pdu, format);
}
messages = messagesTemp;
} catch (final FileNotFoundException e) {
// Nothing to do
} catch (final StreamCorruptedException e) {
// Nothing to do
} catch (final IOException e) {
// Nothing to do
} finally {
if (dis != null) {
try {
dis.close();
} catch (final IOException e) {
// Nothing to do
}
}
}
}
return messages;
}
public static File getDebugFile(final String fileName, final boolean create) {
final File dir = getDebugFilesDir();
final File file = new File(dir, fileName);
@@ -416,24 +134,4 @@ public class DebugUtils {
// Never found ourself in the stack?!
return null;
}
/**
* Returns a boolean indicating whether ClassZero debugging is enabled. If enabled, any received
* sms is treated as if it were a class zero message and displayed by the ClassZeroActivity.
*/
public static boolean debugClassZeroSmsEnabled() {
return sDebugClassZeroSms;
}
/** Shares a ringtone file via file URI. */
private static void shareFileUri() {
final String packageName = "com.android.messaging";
final String fileName = "/system/media/audio/ringtones/Andromeda.ogg";
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setPackage(packageName);
intent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + fileName));
intent.setType("image/*");
Factory.get().getApplicationContext().startActivity(intent);
}
}

View File

@@ -42,9 +42,6 @@ public class GifTranscoder {
}
public static boolean transcode(Context context, String filePath, String outFilePath) {
if (!isEnabled()) {
return false;
}
final long inputSize = new File(filePath).length();
Stopwatch stopwatch = Stopwatch.createStarted();
final boolean success = transcodeInternal(filePath, outFilePath);
@@ -77,19 +74,6 @@ public class GifTranscoder {
}
public static boolean canBeTranscoded(int width, int height) {
if (!isEnabled()) {
return false;
}
return width >= MIN_WIDTH && height >= MIN_HEIGHT;
}
private static boolean isEnabled() {
final boolean enabled = BugleGservices.get().getBoolean(
BugleGservicesKeys.ENABLE_GIF_TRANSCODING,
BugleGservicesKeys.ENABLE_GIF_TRANSCODING_DEFAULT);
if (!enabled) {
LogUtil.w(TAG, "GIF transcoding is disabled");
}
return enabled;
}
}

View File

@@ -1,293 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.messaging.util;
import android.os.Process;
import android.util.Log;
import com.android.messaging.Factory;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Save the app's own log to dump along with adb bugreport
*/
public abstract class LogSaver {
/**
* Writes the accumulated log entries, from oldest to newest, to the specified PrintWriter.
* Log lines are emitted in much the same form as logcat -v threadtime -- specifically,
* lines will include a timestamp, pid, tid, level, and tag.
*
* @param writer The PrintWriter to output
*/
public abstract void dump(PrintWriter writer);
/**
* Log a line
*
* @param level The log level to use
* @param tag The log tag
* @param msg The message of the log line
*/
public abstract void log(int level, String tag, String msg);
/**
* Check if the LogSaver still matches the current Gservices settings
*
* @return true if matches, false otherwise
*/
public abstract boolean isCurrent();
private LogSaver() {
}
public static LogSaver newInstance() {
final boolean persistent = BugleGservices.get().getBoolean(
BugleGservicesKeys.PERSISTENT_LOGSAVER,
BugleGservicesKeys.PERSISTENT_LOGSAVER_DEFAULT);
if (persistent) {
final int setSize = BugleGservices.get().getInt(
BugleGservicesKeys.PERSISTENT_LOGSAVER_ROTATION_SET_SIZE,
BugleGservicesKeys.PERSISTENT_LOGSAVER_ROTATION_SET_SIZE_DEFAULT);
final int fileLimitBytes = BugleGservices.get().getInt(
BugleGservicesKeys.PERSISTENT_LOGSAVER_FILE_LIMIT_BYTES,
BugleGservicesKeys.PERSISTENT_LOGSAVER_FILE_LIMIT_BYTES_DEFAULT);
return new DiskLogSaver(setSize, fileLimitBytes);
} else {
final int size = BugleGservices.get().getInt(
BugleGservicesKeys.IN_MEMORY_LOGSAVER_RECORD_COUNT,
BugleGservicesKeys.IN_MEMORY_LOGSAVER_RECORD_COUNT_DEFAULT);
return new MemoryLogSaver(size);
}
}
/**
* A circular in-memory log to be used to log potentially verbose logs. The logs will be
* persisted in memory in the application and can be dumped by various dump() methods.
* For example, adb shell dumpsys activity provider com.android.messaging.
* The dump will also show up in bugreports.
*/
private static final class MemoryLogSaver extends LogSaver {
/**
* Record to store a single log entry. Stores timestamp, tid, level, tag, and message.
* It can be reused when the circular log rolls over. This avoids creating new objects.
*/
private static class LogRecord {
int mTid;
String mLevelString;
long mTimeMillis; // from System.currentTimeMillis
String mTag;
String mMessage;
LogRecord() {
}
void set(int tid, int level, long time, String tag, String message) {
this.mTid = tid;
this.mTimeMillis = time;
this.mTag = tag;
this.mMessage = message;
this.mLevelString = getLevelString(level);
}
}
private final int mSize;
private final CircularArray<LogRecord> mLogList;
private final Object mLock;
private final SimpleDateFormat mSdf = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
public MemoryLogSaver(final int size) {
mSize = size;
mLogList = new CircularArray<LogRecord>(size);
mLock = new Object();
}
@Override
public void dump(PrintWriter writer) {
int pid = Process.myPid();
synchronized (mLock) {
for (int i = 0; i < mLogList.count(); i++) {
LogRecord rec = mLogList.get(i);
writer.println(String.format("%s %5d %5d %s %s: %s",
mSdf.format(rec.mTimeMillis),
pid, rec.mTid, rec.mLevelString, rec.mTag, rec.mMessage));
}
}
}
@Override
public void log(int level, String tag, String msg) {
synchronized (mLock) {
LogRecord rec = mLogList.getFree();
if (rec == null) {
rec = new LogRecord();
}
rec.set(Process.myTid(), level, System.currentTimeMillis(), tag, msg);
mLogList.add(rec);
}
}
@Override
public boolean isCurrent() {
final boolean persistent = BugleGservices.get().getBoolean(
BugleGservicesKeys.PERSISTENT_LOGSAVER,
BugleGservicesKeys.PERSISTENT_LOGSAVER_DEFAULT);
if (persistent) {
return false;
}
final int size = BugleGservices.get().getInt(
BugleGservicesKeys.IN_MEMORY_LOGSAVER_RECORD_COUNT,
BugleGservicesKeys.IN_MEMORY_LOGSAVER_RECORD_COUNT_DEFAULT);
return size == mSize;
}
}
/**
* A persistent, on-disk log saver. It uses the standard Java util logger along with
* a rotation log file set to store the logs in app's local file directory "app_logs".
*/
private static final class DiskLogSaver extends LogSaver {
private static final String DISK_LOG_DIR_NAME = "logs";
private final int mSetSize;
private final int mFileLimitBytes;
private Logger mDiskLogger;
public DiskLogSaver(final int setSize, final int fileLimitBytes) {
Assert.isTrue(setSize > 0);
Assert.isTrue(fileLimitBytes > 0);
mSetSize = setSize;
mFileLimitBytes = fileLimitBytes;
initDiskLog();
}
private static void clearDefaultHandlers(Logger logger) {
Assert.notNull(logger);
for (Handler handler : logger.getHandlers()) {
logger.removeHandler(handler);
}
}
private void initDiskLog() {
mDiskLogger = Logger.getLogger(LogUtil.BUGLE_TAG);
// We don't want the default console handler
clearDefaultHandlers(mDiskLogger);
// Don't want duplicate print in system log
mDiskLogger.setUseParentHandlers(false);
// FileHandler manages the log files in a fixed rotation set
final File logDir = Factory.get().getApplicationContext().getDir(
DISK_LOG_DIR_NAME, 0/*mode*/);
FileHandler handler = null;
try {
handler = new FileHandler(
logDir + "/%g.log", mFileLimitBytes, mSetSize, true/*append*/);
} catch (Exception e) {
Log.e(LogUtil.BUGLE_TAG, "LogSaver: fail to init disk logger", e);
return;
}
final Formatter formatter = new Formatter() {
@Override
public String format(java.util.logging.LogRecord r) {
return r.getMessage();
}
};
handler.setFormatter(formatter);
handler.setLevel(Level.ALL);
mDiskLogger.addHandler(handler);
}
@Override
public void dump(PrintWriter writer) {
for (int i = mSetSize - 1; i >= 0; i--) {
final File logDir = Factory.get().getApplicationContext().getDir(
DISK_LOG_DIR_NAME, 0/*mode*/);
final String logFilePath = logDir + "/" + i + ".log";
try {
final File logFile = new File(logFilePath);
if (!logFile.exists()) {
continue;
}
final BufferedReader reader = new BufferedReader(new FileReader(logFile));
for (String line; (line = reader.readLine()) != null;) {
line = line.trim();
writer.println(line);
}
} catch (FileNotFoundException e) {
Log.w(LogUtil.BUGLE_TAG, "LogSaver: can not find log file " + logFilePath);
} catch (IOException e) {
Log.w(LogUtil.BUGLE_TAG, "LogSaver: can not read log file", e);
}
}
}
@Override
public void log(int level, String tag, String msg) {
final SimpleDateFormat sdf = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
mDiskLogger.info(String.format("%s %5d %5d %s %s: %s\n",
sdf.format(System.currentTimeMillis()),
Process.myPid(), Process.myTid(), getLevelString(level), tag, msg));
}
@Override
public boolean isCurrent() {
final boolean persistent = BugleGservices.get().getBoolean(
BugleGservicesKeys.PERSISTENT_LOGSAVER,
BugleGservicesKeys.PERSISTENT_LOGSAVER_DEFAULT);
if (!persistent) {
return false;
}
final int setSize = BugleGservices.get().getInt(
BugleGservicesKeys.PERSISTENT_LOGSAVER_ROTATION_SET_SIZE,
BugleGservicesKeys.PERSISTENT_LOGSAVER_ROTATION_SET_SIZE_DEFAULT);
final int fileLimitBytes = BugleGservices.get().getInt(
BugleGservicesKeys.PERSISTENT_LOGSAVER_FILE_LIMIT_BYTES,
BugleGservicesKeys.PERSISTENT_LOGSAVER_FILE_LIMIT_BYTES_DEFAULT);
return setSize == mSetSize && fileLimitBytes == mFileLimitBytes;
}
}
private static String getLevelString(final int level) {
switch (level) {
case android.util.Log.DEBUG:
return "D";
case android.util.Log.WARN:
return "W";
case android.util.Log.INFO:
return "I";
case android.util.Log.VERBOSE:
return "V";
case android.util.Log.ERROR:
return "E";
case android.util.Log.ASSERT:
return "A";
default:
return "?";
}
}
}

View File

@@ -36,33 +36,6 @@ public class LogUtil {
public static final int INFO = android.util.Log.INFO;
public static final int ERROR = android.util.Log.ERROR;
// If this is non-null, DEBUG and higher logs will be tracked in-memory. It will not include
// VERBOSE logs.
private static LogSaver sDebugLogSaver;
private static volatile boolean sCaptureDebugLogs;
/**
* Read Gservices to see if logging should be enabled.
*/
public static void refreshGservices(final BugleGservices gservices) {
sCaptureDebugLogs = gservices.getBoolean(
BugleGservicesKeys.ENABLE_LOG_SAVER,
BugleGservicesKeys.ENABLE_LOG_SAVER_DEFAULT);
if (sCaptureDebugLogs && (sDebugLogSaver == null || !sDebugLogSaver.isCurrent())) {
// We were not capturing logs before. We are now.
sDebugLogSaver = LogSaver.newInstance();
} else if (!sCaptureDebugLogs && sDebugLogSaver != null) {
// We were capturing logs. We aren't anymore.
sDebugLogSaver = null;
}
}
// This is called from FactoryImpl once the Gservices class is initialized.
public static void initializeGservices (final BugleGservices gservices) {
gservices.registerForChanges(() -> refreshGservices(gservices));
refreshGservices(gservices);
}
/**
* Send a {@link #VERBOSE} log message.
* @param tag Used to identify the source of a log message. It usually identifies
@@ -214,26 +187,6 @@ public class LogUtil {
*/
private static void println(final int level, final String tag, final String msg) {
android.util.Log.println(level, tag, msg);
LogSaver serviceLog = sDebugLogSaver;
if (serviceLog != null && level >= android.util.Log.DEBUG) {
serviceLog.log(level, tag, msg);
}
}
/**
* Save logging into LogSaver only, for dumping to bug report
*
* @param level The priority/type of this log message
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
*/
public static void save(final int level, final String tag, final String msg) {
LogSaver serviceLog = sDebugLogSaver;
if (serviceLog != null) {
serviceLog.log(level, tag, msg);
}
}
/**
@@ -260,11 +213,4 @@ public class LogUtil {
return "Redacted-" + text.length();
}
}
public static void dump(java.io.PrintWriter out) {
final LogSaver logsaver = sDebugLogSaver;
if (logsaver != null) {
logsaver.dump(out);
}
}
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 The Android Open Source Project
* Copyright (C) 2024 The LineageOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -59,8 +60,6 @@ public class LoggingTimer {
final String logMessage = String.format("Used %dms for %s", elapsedMs, mName);
LogUtil.save(LogUtil.DEBUG, mTag, logMessage);
if (mWarnLimitMillis != NO_WARN_LIMIT && elapsedMs > mWarnLimitMillis) {
LogUtil.w(mTag, logMessage);
} else if (LogUtil.isLoggable(mTag, LogUtil.VERBOSE)) {