Merge remote-tracking branch 'upstream/main'

This commit is contained in:
adbenitez
2024-12-07 17:10:18 +01:00
12 changed files with 267 additions and 93 deletions
+5
View File
@@ -389,6 +389,11 @@
android:exported="true">
</activity>
<activity android:name=".WebxdcStoreActivity"
android:theme="@style/TextSecure.LightTheme"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize|uiMode">
</activity>
<activity android:name=".FullMsgActivity"
android:theme="@style/TextSecure.LightTheme"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
@@ -160,8 +160,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
private static final int GROUP_EDIT = 6;
private static final int TAKE_PHOTO = 7;
private static final int RECORD_VIDEO = 8;
private static final int PICK_LOCATION = 9; // TODO: i think, this can be deleted
private static final int SMS_DEFAULT = 11; // TODO: i think, this can be deleted
private static final int PICK_WEBXDC = 9;
private GlideRequests glideRequests;
protected ComposeText composeText;
@@ -335,8 +334,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
public void onActivityResult(final int reqCode, int resultCode, Intent data) {
super.onActivityResult(reqCode, resultCode, data);
if ((data == null && reqCode != TAKE_PHOTO && reqCode != RECORD_VIDEO && reqCode != SMS_DEFAULT) ||
(resultCode != RESULT_OK && reqCode != SMS_DEFAULT))
if (resultCode != RESULT_OK || (data == null && reqCode != TAKE_PHOTO && reqCode != RECORD_VIDEO))
{
return;
}
@@ -372,6 +370,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
setMedia(data.getData(), docMediaType);
break;
case PICK_WEBXDC:
setMedia(data.getData(), MediaType.DOCUMENT);
break;
case PICK_CONTACT:
addAttachmentContactInfo(data.getIntExtra(AttachContactActivity.CONTACT_ID_EXTRA, 0));
break;
@@ -399,16 +401,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
break;
case PICK_LOCATION:
break;
case ScribbleActivity.SCRIBBLE_REQUEST_CODE:
setMedia(data.getData(), MediaType.IMAGE);
break;
case SMS_DEFAULT:
initializeSecurity(isSecureText, isDefaultSms);
break;
}
}
@@ -931,6 +926,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
case AttachmentTypeSelector.RECORD_VIDEO:
attachmentManager.captureVideo(this, RECORD_VIDEO);
break;
case AttachmentTypeSelector.ADD_WEBXDC:
AttachmentManager.selectWebxdc(this, PICK_WEBXDC); break;
}
}
@@ -0,0 +1,136 @@
package org.thoughtcrime.securesms;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.view.MenuItem;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
import androidx.appcompat.app.ActionBar;
import com.b44t.messenger.DcContext;
import com.b44t.messenger.rpc.HttpResponse;
import com.b44t.messenger.rpc.Rpc;
import com.b44t.messenger.rpc.RpcException;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.providers.PersistentBlobProvider;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.Prefs;
import java.io.ByteArrayInputStream;
import java.util.HashMap;
public class WebxdcStoreActivity extends PassphraseRequiredActionBarActivity {
private static final String TAG = WebxdcStoreActivity.class.getSimpleName();
private DcContext dcContext;
private Rpc rpc;
@Override
protected void onCreate(Bundle state, boolean ready) {
setContentView(R.layout.web_view_activity);
rpc = DcHelper.getRpc(this);
dcContext = DcHelper.getContext(this);
WebView webView = findViewById(R.id.webview);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setTitle(R.string.webxdc_apps);
}
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
String ext = MediaUtil.getFileExtensionFromUrl(Uri.parse(url).getPath());
if ("xdc".equals(ext)) {
try {
HttpResponse httpResponse = rpc.getHttpResponse(dcContext.getAccountId(), url);
Uri uri = PersistentBlobProvider.getInstance().create(WebxdcStoreActivity.this, httpResponse.getBlob(), "application/octet-stream", "app.xdc");
Intent intent = new Intent();
intent.setData(uri);
setResult(Activity.RESULT_OK, intent);
finish();
} catch (RpcException e) {
e.printStackTrace();
Toast.makeText(WebxdcStoreActivity.this, "Error: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
} else {
WebViewActivity.openUrlInBrowser(WebxdcStoreActivity.this, url);
}
return true;
}
@TargetApi(Build.VERSION_CODES.N)
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
return shouldOverrideUrlLoading(view, request.getUrl().toString());
}
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
return interceptRequest(request.getUrl().toString());
}
});
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setAllowFileAccess(false);
webSettings.setAllowContentAccess(false);
webSettings.setGeolocationEnabled(false);
webSettings.setAllowFileAccessFromFileURLs(false);
webSettings.setAllowUniversalAccessFromFileURLs(false);
webSettings.setDatabaseEnabled(true);
webSettings.setDomStorageEnabled(true);
webView.setNetworkAvailable(true); // this does not block network but sets `window.navigator.isOnline` in js land
webView.loadUrl(Prefs.getWebxdcStoreUrl(this));
}
private WebResourceResponse interceptRequest(String url) {
WebResourceResponse res = null;
try {
if (url == null) {
throw new Exception("no url specified");
}
HttpResponse httpResponse = rpc.getHttpResponse(dcContext.getAccountId(), url);
String mimeType = httpResponse.getMimetype();
if (mimeType == null) {
mimeType = "application/octet-stream";
}
ByteArrayInputStream data = new ByteArrayInputStream(httpResponse.getBlob());
res = new WebResourceResponse(mimeType, httpResponse.getEncoding(), data);
} catch (Exception e) {
e.printStackTrace();
ByteArrayInputStream data = new ByteArrayInputStream(("Could not load apps. Are you online?\n\n" + e.getMessage()).getBytes());
res = new WebResourceResponse("text/plain", "UTF-8", data);
}
HashMap<String, String> headers = new HashMap<>();
headers.put("access-control-allow-origin", "*");
res.setResponseHeaders(headers);
return res;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
}
return false;
}
}
@@ -41,6 +41,7 @@ public class AttachmentTypeSelector extends PopupWindow {
public static final int TAKE_PHOTO = 5;
public static final int ADD_LOCATION = 6;
public static final int RECORD_VIDEO = 7;
public static final int ADD_WEBXDC = 8;
private static final int ANIMATION_DURATION = 300;
@@ -53,7 +54,7 @@ public class AttachmentTypeSelector extends PopupWindow {
//private final @NonNull ImageView cameraButton;
private final @NonNull ImageView videoButton;
private final @NonNull ImageView locationButton;
private final @NonNull ImageView closeButton;
private final @NonNull ImageView webxdcButton;
private @Nullable View currentAnchor;
private @Nullable AttachmentClickedListener listener;
@@ -76,7 +77,7 @@ public class AttachmentTypeSelector extends PopupWindow {
//this.cameraButton = ViewUtil.findById(layout, R.id.camera_button);
this.videoButton = ViewUtil.findById(layout, R.id.record_video_button);
this.locationButton = ViewUtil.findById(layout, R.id.location_button);
this.closeButton = ViewUtil.findById(layout, R.id.close_button);
this.webxdcButton = ViewUtil.findById(layout, R.id.webxdc_button);
this.imageButton.setOnClickListener(new PropagatingClickListener(ADD_GALLERY));
this.videoChatButton.setOnClickListener(new PropagatingClickListener(INVITE_VIDEO_CHAT));
@@ -85,7 +86,7 @@ public class AttachmentTypeSelector extends PopupWindow {
//this.cameraButton.setOnClickListener(new PropagatingClickListener(TAKE_PHOTO));
this.videoButton.setOnClickListener(new PropagatingClickListener(RECORD_VIDEO));
this.locationButton.setOnClickListener(new PropagatingClickListener(ADD_LOCATION));
this.closeButton.setOnClickListener(new CloseClickListener());
this.webxdcButton.setOnClickListener(new PropagatingClickListener(ADD_WEBXDC));
this.recentRail.setListener(new RecentPhotoSelectedListener());
if (!Prefs.isLocationStreamingEnabled(context)) {
@@ -140,8 +141,8 @@ public class AttachmentTypeSelector extends PopupWindow {
animateButtonIn(contactButton, ANIMATION_DURATION / 3);
animateButtonIn(locationButton, ANIMATION_DURATION / 4);
animateButtonIn(documentButton, ANIMATION_DURATION / 4);
animateButtonIn(webxdcButton, 0);
animateButtonIn(videoChatButton, 0);
animateButtonIn(closeButton, 0);
}
@Override
@@ -289,13 +290,6 @@ public class AttachmentTypeSelector extends PopupWindow {
}
private class CloseClickListener implements View.OnClickListener {
@Override
public void onClick(View v) {
dismiss();
}
}
public interface AttachmentClickedListener {
public void onClick(int type);
public void onQuickAttachment(Uri uri);
@@ -50,6 +50,7 @@ import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.MediaPreviewActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.ShareLocationDialog;
import org.thoughtcrime.securesms.WebxdcStoreActivity;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.attachments.UriAttachment;
import org.thoughtcrime.securesms.audio.AudioSlidePlayer;
@@ -451,6 +452,11 @@ public class AttachmentManager {
selectMediaType(activity, "*/*", null, requestCode);
}
public static void selectWebxdc(Activity activity, int requestCode) {
Intent intent = new Intent(activity, WebxdcStoreActivity.class);
activity.startActivityForResult(intent, requestCode);
}
public static void selectGallery(Activity activity, int requestCode) {
// to enable camera roll,
// we're asking for "gallery permissions" also on newer systems that do not strictly require that.
@@ -42,6 +42,7 @@ import org.thoughtcrime.securesms.connect.DcEventCenter;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.mms.AttachmentManager;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.util.Prefs;
import org.thoughtcrime.securesms.util.ScreenLockUtil;
import org.thoughtcrime.securesms.util.StorageUtil;
import org.thoughtcrime.securesms.util.StreamUtil;
@@ -134,6 +135,10 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
webrtcInstance.setOnPreferenceClickListener(new WebrtcInstanceListener());
updateWebrtcSummary();
Preference webxdcStore = this.findPreference(Prefs.WEBXDC_STORE_URL_PREF);
webxdcStore.setOnPreferenceClickListener(new WebxdcStoreUrlListener());
updateWebxdcStoreSummary();
Preference developerModeEnabled = this.findPreference("pref_developer_mode_enabled");
developerModeEnabled.setOnPreferenceChangeListener((preference, newValue) -> {
WebView.setWebContentsDebuggingEnabled((Boolean) newValue);
@@ -280,6 +285,29 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
}
}
private class WebxdcStoreUrlListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
View gl = View.inflate(getActivity(), R.layout.single_line_input, null);
EditText inputField = gl.findViewById(R.id.input_field);
inputField.setHint(Prefs.DEFAULT_WEBXDC_STORE_URL);
inputField.setText(Prefs.getWebxdcStoreUrl(getActivity()));
inputField.setSelection(inputField.getText().length());
inputField.setInputType(TYPE_TEXT_VARIATION_URI);
new AlertDialog.Builder(getActivity())
.setTitle(R.string.webxdc_store_url)
.setMessage(R.string.webxdc_store_url_explain)
.setView(gl)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok, (dlg, btn) -> {
Prefs.setWebxdcStoreUrl(getActivity(), inputField.getText().toString());
updateWebxdcStoreSummary();
})
.show();
return true;
}
}
private void updateWebrtcSummary() {
Preference webrtcInstance = this.findPreference("pref_webrtc_instance");
if (webrtcInstance != null) {
@@ -288,6 +316,13 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
}
}
private void updateWebxdcStoreSummary() {
Preference preference = this.findPreference(Prefs.WEBXDC_STORE_URL_PREF);
if (preference != null) {
preference.setSummary(Prefs.getWebxdcStoreUrl(getActivity()));
}
}
private void openRegistrationActivity() {
Intent intent = new Intent(getActivity(), RegistrationActivity.class);
startActivity(intent);
@@ -62,6 +62,8 @@ public class Prefs {
public static final boolean ALWAYS_LOAD_REMOTE_CONTENT_DEFAULT = false;
public static final String LAST_DEVICE_MSG_LABEL = "pref_last_device_msg_id";
public static final String WEBXDC_STORE_URL_PREF = "pref_webxdc_store_url";
public static final String DEFAULT_WEBXDC_STORE_URL = "https://webxdc.org/apps/";
public enum VibrateState {
DEFAULT(0), ENABLED(1), DISABLED(2);
@@ -144,6 +146,15 @@ public class Prefs {
return getStringPreference(context, THEME_PREF, DynamicTheme.systemThemeAvailable() ? DynamicTheme.SYSTEM : DynamicTheme.LIGHT);
}
public static String getWebxdcStoreUrl(Context context) {
return getStringPreference(context, WEBXDC_STORE_URL_PREF, DEFAULT_WEBXDC_STORE_URL);
}
public static void setWebxdcStoreUrl(Context context, String url) {
if (url == null || url.trim().isEmpty() || DEFAULT_WEBXDC_STORE_URL.equals(url)) url = null;
setStringPreference(context, WEBXDC_STORE_URL_PREF, url);
}
public static void setPromptedDozeMsgId(Context context, int msg_id) {
setIntegerPreference(context, PROMPTED_DOZE_MSG_ID_PREF, msg_id);
}
@@ -0,0 +1,3 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#FFFFFF" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M4,8h4L8,4L4,4v4zM10,20h4v-4h-4v4zM4,20h4v-4L4,16v4zM4,14h4v-4L4,10v4zM10,14h4v-4h-4v4zM16,4v4h4L20,4h-4zM10,8h4L14,4h-4v4zM16,14h4v-4h-4v4zM16,20h4v-4h-4v4z"/>
</vector>
@@ -78,58 +78,50 @@
</LinearLayout>
<LinearLayout android:id="@+id/location_linear_layout"
android:layout_width="match_parent"
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_weight="1"
android:orientation="vertical">
<org.thoughtcrime.securesms.components.CircleColorImageView
android:id="@+id/document_button"
android:layout_width="53dp"
android:layout_height="53dp"
android:src="@drawable/ic_insert_drive_file_white_24dp"
android:scaleType="center"
android:contentDescription="@string/file"
app:circleColor="@color/document_icon"/>
<TextView android:layout_marginTop="10dp"
style="@style/AttachmentTypeLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/file"/>
</LinearLayout>
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<org.thoughtcrime.securesms.components.CircleColorImageView
android:id="@+id/location_button"
android:layout_width="53dp"
android:layout_height="53dp"
android:src="@drawable/ic_location_on_white_24dp"
android:scaleType="center"
android:visibility="visible"
android:contentDescription="@string/location"
app:circleColor="@color/location_icon"/>
android:id="@+id/webxdc_button"
android:layout_width="53dp"
android:layout_height="53dp"
android:src="@drawable/baseline_apps_24"
android:scaleType="center"
android:contentDescription="@string/webxdc_apps"
app:circleColor="@color/apps_icon"
/>
<TextView android:layout_marginTop="10dp"
android:id="@+id/location_button_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="visible"
style="@style/AttachmentTypeLabel"
android:text="@string/location"/>
</LinearLayout>
<LinearLayout android:id="@+id/apps_linear_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical"
android:visibility="invisible">
<org.thoughtcrime.securesms.components.CircleColorImageView
android:id="@+id/apps_button"
android:layout_width="53dp"
android:layout_height="53dp"
android:src="@drawable/ic_location_on_white_24dp"
android:scaleType="center"
android:visibility="visible"
android:contentDescription="@string/location"
app:circleColor="@color/location_icon"/>
<TextView android:layout_marginTop="10dp"
android:id="@+id/apps_button_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="visible"
style="@style/AttachmentTypeLabel"
android:text="@string/location"/>
android:text="@string/webxdc_apps"/>
</LinearLayout>
@@ -169,26 +161,30 @@
</LinearLayout>
<LinearLayout android:layout_width="match_parent"
<LinearLayout android:id="@+id/location_linear_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<org.thoughtcrime.securesms.components.CircleColorImageView
android:id="@+id/document_button"
android:id="@+id/location_button"
android:layout_width="53dp"
android:layout_height="53dp"
android:src="@drawable/ic_insert_drive_file_white_24dp"
android:src="@drawable/ic_location_on_white_24dp"
android:scaleType="center"
android:contentDescription="@string/file"
app:circleColor="@color/document_icon"/>
android:visibility="visible"
android:contentDescription="@string/location"
app:circleColor="@color/location_icon"/>
<TextView android:layout_marginTop="10dp"
style="@style/AttachmentTypeLabel"
android:id="@+id/location_button_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/file"/>
android:visibility="visible"
style="@style/AttachmentTypeLabel"
android:text="@string/location"/>
</LinearLayout>
@@ -216,30 +212,14 @@
</LinearLayout>
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<org.thoughtcrime.securesms.components.CircleColorImageView
android:id="@+id/close_button"
android:layout_width="53dp"
android:layout_height="53dp"
android:src="@drawable/ic_keyboard_arrow_down_white_24dp"
android:scaleType="center"
android:contentDescription="@string/cancel"
app:circleColor="?attr/close_icon_color"/>
<TextView android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AttachmentTypeLabel"
android:text=" "/>
<!-- fill the gap -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:visibility="invisible">
</LinearLayout>
</LinearLayout>
</LinearLayout>
+1
View File
@@ -13,6 +13,7 @@
<color name="contact_icon">#608496</color>
<color name="gallery_icon">#a47ad9</color>
<color name="location_icon">#66BB6A</color>
<color name="apps_icon">#77bdc4</color>
<color name="core_white">#ffffff</color>
<color name="core_light_02">#F9FAFA</color>
+2
View File
@@ -190,6 +190,8 @@
<string name="webxdc_app">App</string>
<!-- plural of "App"; used to present "Webxdc App" (https://webxdc.org) in a user friendly way. Please stay close to the original term and keep it short (it is used in menus with few screen space). -->
<string name="webxdc_apps">Apps</string>
<string name="webxdc_store_url">App Picker URL</string>
<string name="webxdc_store_url_explain">If set, the URL will be used as the App Picker instead of the default one</string>
<string name="unknown">Unknown</string>
<string name="green">Green</string>
@@ -26,6 +26,10 @@
android:title="@string/videochat_instance"
android:summary="@string/none"/>
<Preference android:key="pref_webxdc_store_url"
android:title="@string/webxdc_store_url"
android:summary="@string/none"/>
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:defaultValue="true"
android:key="pref_webxdc_realtime_enabled"