remove android 4 compatibility code
|
@ -28,11 +28,6 @@ public class FcmReceiveService extends FirebaseMessagingService {
|
|||
private static volatile String prefixedToken;
|
||||
|
||||
public static void register(Context context) {
|
||||
if (Build.VERSION.SDK_INT < 19) {
|
||||
Log.w(TAG, "FCM not available on SDK < 19");
|
||||
triedRegistering = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (FcmReceiveService.prefixedToken != null) {
|
||||
Log.i(TAG, "FCM already registered");
|
||||
|
|
|
@ -36,7 +36,6 @@ import org.thoughtcrime.securesms.connect.KeepAliveService;
|
|||
import org.thoughtcrime.securesms.connect.NetworkStateReceiver;
|
||||
import org.thoughtcrime.securesms.crypto.DatabaseSecret;
|
||||
import org.thoughtcrime.securesms.crypto.DatabaseSecretProvider;
|
||||
import org.thoughtcrime.securesms.crypto.PRNGFixes;
|
||||
import org.thoughtcrime.securesms.geolocation.DcLocationManager;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||
import org.thoughtcrime.securesms.notifications.FcmReceiveService;
|
||||
|
@ -178,7 +177,6 @@ public class ApplicationContext extends MultiDexApplication {
|
|||
|
||||
KeepAliveService.maybeStartSelf(this);
|
||||
|
||||
initializeRandomNumberFix();
|
||||
initializeLogging();
|
||||
initializeJobManager();
|
||||
InChatSounds.getInstance(this);
|
||||
|
@ -226,10 +224,6 @@ public class ApplicationContext extends MultiDexApplication {
|
|||
return jobManager;
|
||||
}
|
||||
|
||||
private void initializeRandomNumberFix() {
|
||||
PRNGFixes.apply();
|
||||
}
|
||||
|
||||
private void initializeLogging() {
|
||||
SignalProtocolLoggerProvider.setProvider(new AndroidSignalProtocolLogger());
|
||||
}
|
||||
|
|
|
@ -152,10 +152,6 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
|
|||
this.findPreference(PREFERENCE_CATEGORY_HELP)
|
||||
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_HELP));
|
||||
|
||||
if (VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
tintIcons(getActivity());
|
||||
}
|
||||
|
||||
DcHelper.getEventCenter(getActivity()).addObserver(DcContext.DC_EVENT_CONNECTIVITY_CHANGED, this);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,9 +33,6 @@ public abstract class BaseActionBarActivity extends AppCompatActivity {
|
|||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
onPreCreate();
|
||||
if (BaseActivity.isMenuWorkaroundRequired()) {
|
||||
forceOverflowMenu();
|
||||
}
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
|
@ -46,20 +43,6 @@ public abstract class BaseActionBarActivity extends AppCompatActivity {
|
|||
dynamicTheme.onResume(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
return (keyCode == KeyEvent.KEYCODE_MENU && BaseActivity.isMenuWorkaroundRequired()) || super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_MENU && BaseActivity.isMenuWorkaroundRequired()) {
|
||||
openOptionsMenu();
|
||||
return true;
|
||||
}
|
||||
return super.onKeyUp(keyCode, event);
|
||||
}
|
||||
|
||||
private void initializeScreenshotSecurity() {
|
||||
if (Prefs.isScreenSecurityEnabled(this)) {
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
public abstract class BaseActivity extends FragmentActivity {
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
return (keyCode == KeyEvent.KEYCODE_MENU && isMenuWorkaroundRequired()) || super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_MENU && isMenuWorkaroundRequired()) {
|
||||
openOptionsMenu();
|
||||
return true;
|
||||
}
|
||||
return super.onKeyUp(keyCode, event);
|
||||
}
|
||||
|
||||
public static boolean isMenuWorkaroundRequired() {
|
||||
return VERSION.SDK_INT < VERSION_CODES.KITKAT && ("LGE".equalsIgnoreCase(Build.MANUFACTURER) || "E6710".equalsIgnoreCase(Build.DEVICE));
|
||||
}
|
||||
}
|
|
@ -364,9 +364,7 @@ public abstract class BaseConversationListFragment extends Fragment implements A
|
|||
|
||||
mode.setTitle("1");
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
requireActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -395,11 +393,9 @@ public abstract class BaseConversationListFragment extends Fragment implements A
|
|||
actionMode = null;
|
||||
getListAdapter().initializeBatchMode(false);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
TypedArray color = requireActivity().getTheme().obtainStyledAttributes(new int[]{android.R.attr.statusBarColor});
|
||||
requireActivity().getWindow().setStatusBarColor(color.getColor(0, Color.BLACK));
|
||||
color.recycle();
|
||||
}
|
||||
|
||||
Context context = getContext();
|
||||
if (context != null) {
|
||||
|
|
|
@ -136,9 +136,7 @@ public class ContactSelectionListFragment extends Fragment
|
|||
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
|
||||
MenuInflater inflater = getActivity().getMenuInflater();
|
||||
inflater.inflate(R.menu.contact_list, menu);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
getActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
}
|
||||
setCorrectMenuVisibility(menu);
|
||||
actionMode.setTitle("1");
|
||||
return true;
|
||||
|
@ -170,12 +168,10 @@ public class ContactSelectionListFragment extends Fragment
|
|||
ContactSelectionListFragment.this.actionMode = null;
|
||||
getContactSelectionListAdapter().resetActionModeSelection();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
TypedArray color = getActivity().getTheme().obtainStyledAttributes(new int[]{android.R.attr.statusBarColor});
|
||||
getActivity().getWindow().setStatusBarColor(color.getColor(0, Color.BLACK));
|
||||
color.recycle();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return view;
|
||||
|
|
|
@ -940,12 +940,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||
case AttachmentTypeSelector.TAKE_PHOTO:
|
||||
attachmentManager.capturePhoto(this, TAKE_PHOTO); break;
|
||||
case AttachmentTypeSelector.RECORD_VIDEO:
|
||||
if(VideoRecoder.canRecode()) {
|
||||
attachmentManager.captureVideo(this, RECORD_VIDEO);
|
||||
}
|
||||
else {
|
||||
Toast.makeText(this, "This device does not support video-compression (requires Android 4.4 KitKat)", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -893,11 +893,9 @@ public class ConversationFragment extends MessageSelectorFragment
|
|||
|
||||
mode.setTitle("1");
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
Window window = getActivity().getWindow();
|
||||
statusBarColor = window.getStatusBarColor();
|
||||
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
}
|
||||
|
||||
setCorrectMenuVisibility(menu);
|
||||
ConversationAdaptiveActionsToolbar.adjustMenuActions(menu, 10, requireActivity().getWindow().getDecorView().getMeasuredWidth());
|
||||
|
@ -914,9 +912,7 @@ public class ConversationFragment extends MessageSelectorFragment
|
|||
((ConversationAdapter)list.getAdapter()).clearSelection();
|
||||
list.getAdapter().notifyDataSetChanged();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
getActivity().getWindow().setStatusBarColor(statusBarColor);
|
||||
}
|
||||
|
||||
actionMode = null;
|
||||
hideAddReactionView();
|
||||
|
|
|
@ -495,9 +495,7 @@ public class ConversationItem extends BaseConversationItem
|
|||
audioViewStub.get().setAudio(new AudioSlide(context, messageRecord), duration);
|
||||
audioViewStub.get().setOnClickListener(passthroughClickListener);
|
||||
audioViewStub.get().setOnLongClickListener(passthroughClickListener);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
audioViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
}
|
||||
|
||||
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
|
@ -515,9 +513,7 @@ public class ConversationItem extends BaseConversationItem
|
|||
documentViewStub.get().setDocument(new DocumentSlide(context, messageRecord));
|
||||
documentViewStub.get().setDocumentClickListener(new ThumbnailClickListener());
|
||||
documentViewStub.get().setOnLongClickListener(passthroughClickListener);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
documentViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
}
|
||||
|
||||
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
|
@ -534,9 +530,7 @@ public class ConversationItem extends BaseConversationItem
|
|||
webxdcViewStub.get().setWebxdc(messageRecord, context.getString(R.string.webxdc_app));
|
||||
webxdcViewStub.get().setWebxdcClickListener(new ThumbnailClickListener());
|
||||
webxdcViewStub.get().setOnLongClickListener(passthroughClickListener);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
webxdcViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
}
|
||||
|
||||
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
|
@ -554,9 +548,7 @@ public class ConversationItem extends BaseConversationItem
|
|||
vcardViewStub.get().setVcardClickListener(new ThumbnailClickListener());
|
||||
vcardViewStub.get().setOnLongClickListener(passthroughClickListener);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
vcardViewStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
}
|
||||
|
||||
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
|
@ -592,9 +584,7 @@ public class ConversationItem extends BaseConversationItem
|
|||
mediaThumbnailStub.get().setOnLongClickListener(passthroughClickListener);
|
||||
mediaThumbnailStub.get().setOnClickListener(passthroughClickListener);
|
||||
mediaThumbnailStub.get().showShade(TextUtils.isEmpty(messageRecord.getText()));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
mediaThumbnailStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
}
|
||||
|
||||
setThumbnailOutlineCorners(messageRecord, showSender);
|
||||
|
||||
|
@ -617,9 +607,7 @@ public class ConversationItem extends BaseConversationItem
|
|||
stickerStub.get().setThumbnailClickListener(new StickerClickListener());
|
||||
stickerStub.get().setOnLongClickListener(passthroughClickListener);
|
||||
stickerStub.get().setOnClickListener(passthroughClickListener);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
stickerStub.get().setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
|
||||
}
|
||||
|
||||
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
|
|
|
@ -174,10 +174,8 @@ class ConversationItemSwipeCallback extends ItemTouchHelper.SimpleCallback {
|
|||
vibrate(viewHolder.itemView.getContext());
|
||||
}
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
recyclerView.cancelPendingInputEvents();
|
||||
}
|
||||
}
|
||||
|
||||
private static void resetProgress(RecyclerView.ViewHolder viewHolder) {
|
||||
ConversationSwipeAnimationHelper.update((ConversationItem) viewHolder.itemView,
|
||||
|
@ -199,11 +197,7 @@ class ConversationItemSwipeCallback extends ItemTouchHelper.SimpleCallback {
|
|||
}
|
||||
|
||||
private static float getSignFromDirection(@NonNull View view) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
return view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? -1f : 1f;
|
||||
} else {
|
||||
return 1f;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean sameSign(float dX, float sign) {
|
||||
|
|
|
@ -29,7 +29,6 @@ public class ConversationListItemInboxZero extends LinearLayout implements Binda
|
|||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public ConversationListItemInboxZero(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
|
|
|
@ -197,12 +197,11 @@ public class LogViewFragment extends Fragment {
|
|||
asMegs(info.maxMemory()));
|
||||
}
|
||||
|
||||
@TargetApi(VERSION_CODES.KITKAT)
|
||||
public static String getMemoryClass(Context context) {
|
||||
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
String lowMem = "";
|
||||
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT && activityManager.isLowRamDevice()) {
|
||||
if (activityManager.isLowRamDevice()) {
|
||||
lowMem = ", low-mem device";
|
||||
}
|
||||
return activityManager.getMemoryClass() + lowMem;
|
||||
|
@ -252,10 +251,8 @@ public class LogViewFragment extends Fragment {
|
|||
|
||||
Locale locale = Util.getLocale();
|
||||
builder.append("lang=").append(locale.toString()).append("\n");
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
boolean isRtl = Util.getLayoutDirection(context) == View.LAYOUT_DIRECTION_RTL;
|
||||
builder.append("rtl=").append(isRtl).append("\n");
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
boolean notifPermGranted = PermissionChecker.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) == PermissionChecker.PERMISSION_GRANTED;
|
||||
|
|
|
@ -228,11 +228,9 @@ public class ProfileDocumentsFragment
|
|||
mode.getMenuInflater().inflate(R.menu.profile_context, menu);
|
||||
mode.setTitle("1");
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
Window window = getActivity().getWindow();
|
||||
originalStatusBarColor = window.getStatusBarColor();
|
||||
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
}
|
||||
setCorrectMenuVisibility(menu);
|
||||
return true;
|
||||
}
|
||||
|
@ -282,9 +280,7 @@ public class ProfileDocumentsFragment
|
|||
actionMode = null;
|
||||
getListAdapter().clearSelection();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
getActivity().getWindow().setStatusBarColor(originalStatusBarColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -219,11 +219,9 @@ public class ProfileGalleryFragment
|
|||
mode.getMenuInflater().inflate(R.menu.profile_context, menu);
|
||||
mode.setTitle("1");
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
Window window = getActivity().getWindow();
|
||||
originalStatusBarColor = window.getStatusBarColor();
|
||||
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
}
|
||||
setCorrectMenuVisibility(menu);
|
||||
return true;
|
||||
}
|
||||
|
@ -269,9 +267,7 @@ public class ProfileGalleryFragment
|
|||
actionMode = null;
|
||||
getListAdapter().clearSelection();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
getActivity().getWindow().setStatusBarColor(originalStatusBarColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -268,11 +268,9 @@ public class ProfileSettingsFragment extends Fragment
|
|||
menu.findItem(R.id.menu_select_all).setVisible(false);
|
||||
mode.setTitle("1");
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
Window window = getActivity().getWindow();
|
||||
originalStatusBarColor = window.getStatusBarColor();
|
||||
window.setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -314,11 +312,9 @@ public class ProfileSettingsFragment extends Fragment
|
|||
public void onDestroyActionMode(ActionMode mode) {
|
||||
actionMode = null;
|
||||
adapter.clearSelection();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
getActivity().getWindow().setStatusBarColor(originalStatusBarColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
|
|
|
@ -100,14 +100,10 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
|
|||
|
||||
public static void openWebxdcActivity(Context context, int msgId, boolean hideActionBar) {
|
||||
if (!Util.isClickedRecently()) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
if (Prefs.isDeveloperModeEnabled(context)) {
|
||||
WebView.setWebContentsDebuggingEnabled(true);
|
||||
}
|
||||
context.startActivity(getWebxdcIntent(context, msgId, hideActionBar));
|
||||
} else {
|
||||
Toast.makeText(context, "At least Android 5.0 (Lollipop) required for Webxdc.", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -329,7 +325,7 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
|
|||
res = new WebResourceResponse("text/plain", "UTF-8", targetStream);
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !internetAccess) {
|
||||
if (!internetAccess) {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("Content-Security-Policy",
|
||||
"default-src 'self'; "
|
||||
|
@ -348,14 +344,12 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE
|
|||
}
|
||||
|
||||
private void callJavaScriptFunction(String func) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
if (internetAccess) {
|
||||
webView.evaluateJavascript("window." + func + ";", null);
|
||||
} else {
|
||||
webView.evaluateJavascript("document.getElementById('frame').contentWindow." + func + ";", null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEvent(@NonNull DcEvent event) {
|
||||
|
|
|
@ -176,7 +176,7 @@ public class WelcomeActivity extends BaseActionBarActivity implements DcEventCen
|
|||
.withPermanentDenialDialog(getString(R.string.perm_explain_access_to_storage_denied))
|
||||
.onAllGranted(() -> {
|
||||
File imexDir = DcHelper.getImexDir();
|
||||
if (Build.VERSION.SDK_INT >= 30) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
AttachmentManager.selectMediaType(this, "application/x-tar", null, PICK_BACKUP, StorageUtil.getDownloadUri());
|
||||
} else {
|
||||
final String backupFile = dcContext.imexHasBackup(imexDir.getAbsolutePath());
|
||||
|
|
|
@ -130,15 +130,10 @@ public class AttachmentTypeSelector extends PopupWindow {
|
|||
public void onGlobalLayout() {
|
||||
getContentView().getViewTreeObserver().removeGlobalOnLayoutListener(this);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
animateWindowInCircular(anchor, getContentView());
|
||||
} else {
|
||||
animateWindowInTranslate(getContentView());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
animateButtonIn(cameraButton, ANIMATION_DURATION / 2);
|
||||
animateButtonIn(videoButton, ANIMATION_DURATION / 2);
|
||||
animateButtonIn(imageButton, ANIMATION_DURATION / 3);
|
||||
|
@ -148,15 +143,10 @@ public class AttachmentTypeSelector extends PopupWindow {
|
|||
animateButtonIn(videoChatButton, 0);
|
||||
animateButtonIn(closeButton, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismiss() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
animateWindowOutCircular(currentAnchor, getContentView());
|
||||
} else {
|
||||
animateWindowOutTranslate(getContentView());
|
||||
}
|
||||
}
|
||||
|
||||
public void setListener(@Nullable AttachmentClickedListener listener) {
|
||||
|
@ -186,7 +176,6 @@ public class AttachmentTypeSelector extends PopupWindow {
|
|||
button.startAnimation(animation);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
private void animateWindowInCircular(@Nullable View anchor, @NonNull View contentView) {
|
||||
Pair<Integer, Integer> coordinates = getClickOrigin(anchor, contentView);
|
||||
Animator animator = ViewAnimationUtils.createCircularReveal(contentView,
|
||||
|
@ -205,7 +194,6 @@ public class AttachmentTypeSelector extends PopupWindow {
|
|||
getContentView().startAnimation(animation);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
private void animateWindowOutCircular(@Nullable View anchor, @NonNull View contentView) {
|
||||
Pair<Integer, Integer> coordinates = getClickOrigin(anchor, contentView);
|
||||
Animator animator = ViewAnimationUtils.createCircularReveal(getContentView(),
|
||||
|
|
|
@ -71,12 +71,10 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
|
|||
this.pauseButton.setOnClickListener(new PauseClickedListener());
|
||||
this.seekBar.setOnSeekBarChangeListener(new SeekBarModifiedListener());
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
this.playButton.setImageDrawable(context.getDrawable(R.drawable.play_icon));
|
||||
this.pauseButton.setImageDrawable(context.getDrawable(R.drawable.pause_icon));
|
||||
this.playButton.setBackground(context.getDrawable(R.drawable.ic_circle_fill_white_48dp));
|
||||
this.pauseButton.setBackground(context.getDrawable(R.drawable.ic_circle_fill_white_48dp));
|
||||
}
|
||||
|
||||
setTint(getContext().getResources().getColor(R.color.audio_icon));
|
||||
}
|
||||
|
@ -192,13 +190,8 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
|
|||
}
|
||||
|
||||
public void setTint(int foregroundTint) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
this.playButton.setBackgroundTintList(ColorStateList.valueOf(foregroundTint));
|
||||
this.pauseButton.setBackgroundTintList(ColorStateList.valueOf(foregroundTint));
|
||||
} else {
|
||||
this.playButton.setColorFilter(foregroundTint, PorterDuff.Mode.SRC_IN);
|
||||
this.pauseButton.setColorFilter(foregroundTint, PorterDuff.Mode.SRC_IN);
|
||||
}
|
||||
|
||||
this.seekBar.getProgressDrawable().setColorFilter(foregroundTint, PorterDuff.Mode.SRC_IN);
|
||||
|
||||
|
@ -220,25 +213,20 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
|
|||
private void togglePlayToPause() {
|
||||
controlToggle.displayQuick(pauseButton);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
AnimatedVectorDrawable playToPauseDrawable = (AnimatedVectorDrawable) getContext().getDrawable(R.drawable.play_to_pause_animation);
|
||||
pauseButton.setImageDrawable(playToPauseDrawable);
|
||||
playToPauseDrawable.start();
|
||||
}
|
||||
}
|
||||
|
||||
private void togglePauseToPlay() {
|
||||
controlToggle.displayQuick(playButton);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
AnimatedVectorDrawable pauseToPlayDrawable = (AnimatedVectorDrawable) getContext().getDrawable(R.drawable.pause_to_play_animation);
|
||||
playButton.setImageDrawable(pauseToPlayDrawable);
|
||||
pauseToPlayDrawable.start();
|
||||
}
|
||||
}
|
||||
|
||||
private class PlayClickedListener implements View.OnClickListener {
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
try {
|
||||
|
@ -279,7 +267,6 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
|
|||
}
|
||||
|
||||
private class PauseClickedListener implements View.OnClickListener {
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Log.w(TAG, "pausebutton onClick");
|
||||
|
|
|
@ -122,7 +122,6 @@ public class ComposeText extends AppCompatEditText {
|
|||
editorInfo.imeOptions &= ~EditorInfo.IME_FLAG_NO_ENTER_ACTION;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT < 21) return inputConnection;
|
||||
if (mediaListener == null) return inputConnection;
|
||||
if (inputConnection == null) return null;
|
||||
|
||||
|
|
|
@ -120,15 +120,10 @@ public class ConversationItemThumbnail extends FrameLayout {
|
|||
@SuppressWarnings("SuspiciousNameCombination")
|
||||
@Override
|
||||
protected void dispatchDraw(Canvas canvas) {
|
||||
if (cornerMask.isLegacy()) {
|
||||
cornerMask.mask(canvas);
|
||||
}
|
||||
|
||||
super.dispatchDraw(canvas);
|
||||
|
||||
if (!cornerMask.isLegacy()) {
|
||||
cornerMask.mask(canvas);
|
||||
}
|
||||
|
||||
final float halfStrokeWidth = outlinePaint.getStrokeWidth() / 2;
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import android.graphics.Path;
|
|||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import android.view.View;
|
||||
|
||||
|
@ -20,11 +20,7 @@ public class CornerMask {
|
|||
private final RectF bounds = new RectF();
|
||||
|
||||
public CornerMask(@NonNull View view) {
|
||||
if (isLegacy()) {
|
||||
view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
|
||||
} else {
|
||||
view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||
}
|
||||
|
||||
clearPaint.setColor(Color.BLACK);
|
||||
clearPaint.setStyle(Paint.Style.FILL);
|
||||
|
@ -44,19 +40,10 @@ public class CornerMask {
|
|||
// Note: There's a bug in the P beta where most PorterDuff modes aren't working. But CLEAR does.
|
||||
// So we find and inverse path and use Mode.CLEAR for versions that support Path.op().
|
||||
// See issue https://issuetracker.google.com/issues/111394085.
|
||||
if (!isLegacy()) {
|
||||
outline.reset();
|
||||
outline.addRect(bounds, Path.Direction.CW);
|
||||
outline.op(corners, Path.Op.DIFFERENCE);
|
||||
canvas.drawPath(outline, clearPaint);
|
||||
} else {
|
||||
corners.addRoundRect(bounds, radii, Path.Direction.CW);
|
||||
canvas.clipPath(corners);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isLegacy() {
|
||||
return Build.VERSION.SDK_INT < 19;
|
||||
}
|
||||
|
||||
public void setRadius(int radius) {
|
||||
|
|
|
@ -104,7 +104,7 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
|
|||
}
|
||||
|
||||
private void updateKeyboardState() {
|
||||
if (viewInset == 0 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) viewInset = getViewInset();
|
||||
if (viewInset == 0) viewInset = getViewInset();
|
||||
|
||||
getWindowVisibleDisplayFrame(rect);
|
||||
|
||||
|
@ -148,7 +148,6 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
|
|||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
private int getViewInset() {
|
||||
try {
|
||||
Field attachInfoField = View.class.getDeclaredField("mAttachInfo");
|
||||
|
@ -219,11 +218,7 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
|
|||
return Surface.ROTATION_0;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
return ServiceUtil.getWindowManager(getContext()).getDefaultDisplay().getRotation();
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 30) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
getContext().getDisplay().getRealMetrics(displayMetrics);
|
||||
} else {
|
||||
ServiceUtil.getWindowManager(getContext()).getDefaultDisplay().getRealMetrics(displayMetrics);
|
||||
|
|
|
@ -40,7 +40,6 @@ public class MediaView extends FrameLayout {
|
|||
initialize();
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public MediaView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
initialize();
|
||||
|
|
|
@ -78,7 +78,6 @@ public class QuoteView extends FrameLayout implements RecipientForeverObserver {
|
|||
initialize(attrs);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public QuoteView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
initialize(attrs);
|
||||
|
|
|
@ -29,7 +29,6 @@ public class RepeatableImageKey extends ImageButton {
|
|||
init();
|
||||
}
|
||||
|
||||
@TargetApi(VERSION_CODES.LOLLIPOP)
|
||||
public RepeatableImageKey(Context context, AttributeSet attrs, int defStyleAttr,
|
||||
int defStyleRes)
|
||||
{
|
||||
|
|
|
@ -130,15 +130,11 @@ public class SearchToolbar extends LinearLayout {
|
|||
|
||||
searchItem.expandActionView();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
Animator animator = ViewAnimationUtils.createCircularReveal(this, (int) x, (int) y, 0, getWidth());
|
||||
animator.setDuration(400);
|
||||
|
||||
setVisibility(View.VISIBLE);
|
||||
animator.start();
|
||||
} else {
|
||||
setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,7 +149,6 @@ public class SearchToolbar extends LinearLayout {
|
|||
|
||||
if (listener != null) listener.onSearchClosed();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
Animator animator = ViewAnimationUtils.createCircularReveal(this, (int) x, (int) y, getWidth(), 0);
|
||||
animator.setDuration(400);
|
||||
animator.addListener(new AnimationCompleteListener() {
|
||||
|
@ -163,9 +158,6 @@ public class SearchToolbar extends LinearLayout {
|
|||
}
|
||||
});
|
||||
animator.start();
|
||||
} else {
|
||||
setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@ public class SwitchPreferenceCompat extends CheckBoxPreference {
|
|||
setLayoutRes();
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public SwitchPreferenceCompat(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
setLayoutRes();
|
||||
|
|
|
@ -463,7 +463,7 @@ public class CameraView extends ViewGroup {
|
|||
}
|
||||
final float newWidth = visibleRect.width() * scale;
|
||||
final float newHeight = visibleRect.height() * scale;
|
||||
final float centerX = (VERSION.SDK_INT < 14 || isTroublemaker()) ? previewWidth - newWidth / 2 : previewWidth / 2;
|
||||
final float centerX = isTroublemaker() ? previewWidth - newWidth / 2 : previewWidth / 2;
|
||||
final float centerY = previewHeight / 2;
|
||||
|
||||
visibleRect.set((int) (centerX - newWidth / 2),
|
||||
|
|
|
@ -260,9 +260,7 @@ public class DcHelper {
|
|||
}
|
||||
|
||||
public static File getImexDir() {
|
||||
// DIRECTORY_DOCUMENTS is only available since KitKat;
|
||||
// as we also support Ice Cream Sandwich and Jellybean (2017: 11% in total), this is no option.
|
||||
// Moreover, DIRECTORY_DOWNLOADS seems to be easier accessible by the user,
|
||||
// DIRECTORY_DOCUMENTS could be used but DIRECTORY_DOWNLOADS seems to be easier accessible by the user,
|
||||
// eg. "Download Managers" are nearly always installed.
|
||||
// CAVE: do not use DownloadManager to add the file as it is deleted on uninstall then ...
|
||||
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
|
||||
|
|
|
@ -1,345 +0,0 @@
|
|||
/*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will Google be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, as long as the origin is not misrepresented.
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.crypto;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Process;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.Provider;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.SecureRandomSpi;
|
||||
import java.security.Security;
|
||||
|
||||
/**
|
||||
* This class is taken directly from the Android blog post announcing this bug:
|
||||
* http://android-developers.blogspot.com/2013/08/some-securerandom-thoughts.html
|
||||
*
|
||||
* Since I still don't know exactly what the source of this bug was, I'm using
|
||||
* this class verbatim under the assumption that the Android team knows what
|
||||
* they're doing. Although, at this point, that is perhaps a foolish assumption.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fixes for the output of the default PRNG having low entropy.
|
||||
*
|
||||
* The fixes need to be applied via {@link #apply()} before any use of Java
|
||||
* Cryptography Architecture primitives. A good place to invoke them is in the
|
||||
* application's {@code onCreate}.
|
||||
*/
|
||||
public final class PRNGFixes {
|
||||
|
||||
private static final int VERSION_CODE_JELLY_BEAN = 16;
|
||||
private static final int VERSION_CODE_JELLY_BEAN_MR2 = 18;
|
||||
private static final byte[] BUILD_FINGERPRINT_AND_DEVICE_SERIAL =
|
||||
getBuildFingerprintAndDeviceSerial();
|
||||
|
||||
/** Hidden constructor to prevent instantiation. */
|
||||
private PRNGFixes() {}
|
||||
|
||||
/**
|
||||
* Applies all fixes.
|
||||
*
|
||||
* @throws SecurityException if a fix is needed but could not be applied.
|
||||
*/
|
||||
public static void apply() {
|
||||
applyOpenSSLFix();
|
||||
installLinuxPRNGSecureRandom();
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the fix for OpenSSL PRNG having low entropy. Does nothing if the
|
||||
* fix is not needed.
|
||||
*
|
||||
* @throws SecurityException if the fix is needed but could not be applied.
|
||||
*/
|
||||
private static void applyOpenSSLFix() throws SecurityException {
|
||||
if ((Build.VERSION.SDK_INT < VERSION_CODE_JELLY_BEAN)
|
||||
|| (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2)) {
|
||||
// No need to apply the fix
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Mix in the device- and invocation-specific seed.
|
||||
Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto")
|
||||
.getMethod("RAND_seed", byte[].class)
|
||||
.invoke(null, generateSeed());
|
||||
|
||||
// Mix output of Linux PRNG into OpenSSL's PRNG
|
||||
int bytesRead = (Integer) Class.forName(
|
||||
"org.apache.harmony.xnet.provider.jsse.NativeCrypto")
|
||||
.getMethod("RAND_load_file", String.class, long.class)
|
||||
.invoke(null, "/dev/urandom", 1024);
|
||||
if (bytesRead != 1024) {
|
||||
throw new IOException(
|
||||
"Unexpected number of bytes read from Linux PRNG: "
|
||||
+ bytesRead);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new SecurityException("Failed to seed OpenSSL PRNG", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs a Linux PRNG-backed {@code SecureRandom} implementation as the
|
||||
* default. Does nothing if the implementation is already the default or if
|
||||
* there is not need to install the implementation.
|
||||
*
|
||||
* @throws SecurityException if the fix is needed but could not be applied.
|
||||
*/
|
||||
private static void installLinuxPRNGSecureRandom()
|
||||
throws SecurityException {
|
||||
if (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2) {
|
||||
// No need to apply the fix
|
||||
return;
|
||||
}
|
||||
|
||||
// Install a Linux PRNG-based SecureRandom implementation as the
|
||||
// default, if not yet installed.
|
||||
Provider[] secureRandomProviders =
|
||||
Security.getProviders("SecureRandom.SHA1PRNG");
|
||||
if ((secureRandomProviders == null)
|
||||
|| (secureRandomProviders.length < 1)
|
||||
|| (!LinuxPRNGSecureRandomProvider.class.equals(
|
||||
secureRandomProviders[0].getClass()))) {
|
||||
Security.insertProviderAt(new LinuxPRNGSecureRandomProvider(), 1);
|
||||
}
|
||||
|
||||
// Assert that new SecureRandom() and
|
||||
// SecureRandom.getInstance("SHA1PRNG") return a SecureRandom backed
|
||||
// by the Linux PRNG-based SecureRandom implementation.
|
||||
SecureRandom rng1 = new SecureRandom();
|
||||
if (!LinuxPRNGSecureRandomProvider.class.equals(
|
||||
rng1.getProvider().getClass())) {
|
||||
throw new SecurityException(
|
||||
"new SecureRandom() backed by wrong Provider: "
|
||||
+ rng1.getProvider().getClass());
|
||||
}
|
||||
|
||||
SecureRandom rng2;
|
||||
try {
|
||||
rng2 = SecureRandom.getInstance("SHA1PRNG");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new SecurityException("SHA1PRNG not available", e);
|
||||
}
|
||||
if (!LinuxPRNGSecureRandomProvider.class.equals(
|
||||
rng2.getProvider().getClass())) {
|
||||
throw new SecurityException(
|
||||
"SecureRandom.getInstance(\"SHA1PRNG\") backed by wrong"
|
||||
+ " Provider: " + rng2.getProvider().getClass());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code Provider} of {@code SecureRandom} engines which pass through
|
||||
* all requests to the Linux PRNG.
|
||||
*/
|
||||
private static class LinuxPRNGSecureRandomProvider extends Provider {
|
||||
|
||||
public LinuxPRNGSecureRandomProvider() {
|
||||
super("LinuxPRNG",
|
||||
1.0,
|
||||
"A Linux-specific random number provider that uses"
|
||||
+ " /dev/urandom");
|
||||
// Although /dev/urandom is not a SHA-1 PRNG, some apps
|
||||
// explicitly request a SHA1PRNG SecureRandom and we thus need to
|
||||
// prevent them from getting the default implementation whose output
|
||||
// may have low entropy.
|
||||
put("SecureRandom.SHA1PRNG", LinuxPRNGSecureRandom.class.getName());
|
||||
put("SecureRandom.SHA1PRNG ImplementedIn", "Software");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link SecureRandomSpi} which passes all requests to the Linux PRNG
|
||||
* ({@code /dev/urandom}).
|
||||
*/
|
||||
public static class LinuxPRNGSecureRandom extends SecureRandomSpi {
|
||||
|
||||
/*
|
||||
* IMPLEMENTATION NOTE: Requests to generate bytes and to mix in a seed
|
||||
* are passed through to the Linux PRNG (/dev/urandom). Instances of
|
||||
* this class seed themselves by mixing in the current time, PID, UID,
|
||||
* build fingerprint, and hardware serial number (where available) into
|
||||
* Linux PRNG.
|
||||
*
|
||||
* Concurrency: Read requests to the underlying Linux PRNG are
|
||||
* serialized (on sLock) to ensure that multiple threads do not get
|
||||
* duplicated PRNG output.
|
||||
*/
|
||||
|
||||
private static final File URANDOM_FILE = new File("/dev/urandom");
|
||||
|
||||
private static final Object sLock = new Object();
|
||||
|
||||
/**
|
||||
* Input stream for reading from Linux PRNG or {@code null} if not yet
|
||||
* opened.
|
||||
*
|
||||
* @GuardedBy("sLock")
|
||||
*/
|
||||
private static DataInputStream sUrandomIn;
|
||||
|
||||
/**
|
||||
* Output stream for writing to Linux PRNG or {@code null} if not yet
|
||||
* opened.
|
||||
*
|
||||
* @GuardedBy("sLock")
|
||||
*/
|
||||
private static OutputStream sUrandomOut;
|
||||
|
||||
/**
|
||||
* Whether this engine instance has been seeded. This is needed because
|
||||
* each instance needs to seed itself if the client does not explicitly
|
||||
* seed it.
|
||||
*/
|
||||
private boolean mSeeded;
|
||||
|
||||
@Override
|
||||
protected void engineSetSeed(byte[] bytes) {
|
||||
try {
|
||||
OutputStream out;
|
||||
synchronized (sLock) {
|
||||
out = getUrandomOutputStream();
|
||||
}
|
||||
out.write(bytes);
|
||||
out.flush();
|
||||
} catch (IOException e) {
|
||||
// On a small fraction of devices /dev/urandom is not writable.
|
||||
// Log and ignore.
|
||||
Log.w(PRNGFixes.class.getSimpleName(),
|
||||
"Failed to mix seed into " + URANDOM_FILE);
|
||||
} finally {
|
||||
mSeeded = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineNextBytes(byte[] bytes) {
|
||||
if (!mSeeded) {
|
||||
// Mix in the device- and invocation-specific seed.
|
||||
engineSetSeed(generateSeed());
|
||||
}
|
||||
|
||||
try {
|
||||
DataInputStream in;
|
||||
synchronized (sLock) {
|
||||
in = getUrandomInputStream();
|
||||
}
|
||||
synchronized (in) {
|
||||
in.readFully(bytes);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException(
|
||||
"Failed to read from " + URANDOM_FILE, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] engineGenerateSeed(int size) {
|
||||
byte[] seed = new byte[size];
|
||||
engineNextBytes(seed);
|
||||
return seed;
|
||||
}
|
||||
|
||||
private DataInputStream getUrandomInputStream() {
|
||||
synchronized (sLock) {
|
||||
if (sUrandomIn == null) {
|
||||
// NOTE: Consider inserting a BufferedInputStream between
|
||||
// DataInputStream and FileInputStream if you need higher
|
||||
// PRNG output performance and can live with future PRNG
|
||||
// output being pulled into this process prematurely.
|
||||
try {
|
||||
sUrandomIn = new DataInputStream(
|
||||
new FileInputStream(URANDOM_FILE));
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Failed to open "
|
||||
+ URANDOM_FILE + " for reading", e);
|
||||
}
|
||||
}
|
||||
return sUrandomIn;
|
||||
}
|
||||
}
|
||||
|
||||
private OutputStream getUrandomOutputStream() throws IOException {
|
||||
synchronized (sLock) {
|
||||
if (sUrandomOut == null) {
|
||||
sUrandomOut = new FileOutputStream(URANDOM_FILE);
|
||||
}
|
||||
return sUrandomOut;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a device- and invocation-specific seed to be mixed into the
|
||||
* Linux PRNG.
|
||||
*/
|
||||
private static byte[] generateSeed() {
|
||||
try {
|
||||
ByteArrayOutputStream seedBuffer = new ByteArrayOutputStream();
|
||||
DataOutputStream seedBufferOut =
|
||||
new DataOutputStream(seedBuffer);
|
||||
seedBufferOut.writeLong(System.currentTimeMillis());
|
||||
seedBufferOut.writeLong(System.nanoTime());
|
||||
seedBufferOut.writeInt(Process.myPid());
|
||||
seedBufferOut.writeInt(Process.myUid());
|
||||
seedBufferOut.write(BUILD_FINGERPRINT_AND_DEVICE_SERIAL);
|
||||
seedBufferOut.close();
|
||||
return seedBuffer.toByteArray();
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Failed to generate seed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hardware serial number of this device.
|
||||
*
|
||||
* @return serial number or {@code null} if not available.
|
||||
*/
|
||||
private static String getDeviceSerialNumber() {
|
||||
// We're using the Reflection API because Build.SERIAL is only available
|
||||
// since API Level 9 (Gingerbread, Android 2.3).
|
||||
try {
|
||||
return (String) Build.class.getField("SERIAL").get(null);
|
||||
} catch (Exception ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] getBuildFingerprintAndDeviceSerial() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
String fingerprint = Build.FINGERPRINT;
|
||||
if (fingerprint != null) {
|
||||
result.append(fingerprint);
|
||||
}
|
||||
String serial = getDeviceSerialNumber();
|
||||
if (serial != null) {
|
||||
result.append(serial);
|
||||
}
|
||||
try {
|
||||
return result.toString().getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException("UTF-8 encoding not supported");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -585,7 +585,7 @@ public class AttachmentManager {
|
|||
final Intent intent = new Intent();
|
||||
intent.setType(type);
|
||||
|
||||
if (extraMimeType != null && Build.VERSION.SDK_INT >= 19) {
|
||||
if (extraMimeType != null) {
|
||||
intent.putExtra(Intent.EXTRA_MIME_TYPES, extraMimeType);
|
||||
}
|
||||
|
||||
|
@ -597,7 +597,6 @@ public class AttachmentManager {
|
|||
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
|
||||
try {
|
||||
activity.startActivityForResult(intent, requestCode);
|
||||
|
@ -605,7 +604,6 @@ public class AttachmentManager {
|
|||
} catch (ActivityNotFoundException anfe) {
|
||||
Log.w(TAG, "couldn't complete ACTION_OPEN_DOCUMENT, no activity found. falling back.");
|
||||
}
|
||||
}
|
||||
|
||||
intent.setAction(Intent.ACTION_GET_CONTENT);
|
||||
|
||||
|
|
|
@ -187,9 +187,7 @@ public class AdvancedPreferenceFragment extends ListSummaryPreferenceFragment
|
|||
|
||||
Preference developerModeEnabled = this.findPreference("pref_developer_mode_enabled");
|
||||
developerModeEnabled.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
WebView.setWebContentsDebuggingEnabled((Boolean) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ public class ProfilePreference extends Preference {
|
|||
private TextView profileNameView;
|
||||
private TextView profileAddressView;
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public ProfilePreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
initialize();
|
||||
|
|
|
@ -63,15 +63,10 @@ public class AvatarHelper {
|
|||
}
|
||||
|
||||
public static void cropAvatar(Activity context, Uri imageUri) {
|
||||
if (Build.VERSION.SDK_INT >= 19) { // Image editor requires Android 4.4 KitKat or newer.
|
||||
Intent intent = new Intent(context, ScribbleActivity.class);
|
||||
intent.setData(imageUri);
|
||||
intent.putExtra(ScribbleActivity.CROP_AVATAR, true);
|
||||
context.startActivityForResult(intent, ScribbleActivity.SCRIBBLE_REQUEST_CODE);
|
||||
} else {
|
||||
Uri outputFile = Uri.fromFile(new File(context.getCacheDir(), "cropped"));
|
||||
Crop.of(imageUri, outputFile).asSquare().start(context);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -59,9 +59,6 @@ public class AddReactionView extends LinearLayout {
|
|||
}
|
||||
anyReactionView = findViewById(R.id.reaction_any);
|
||||
anyReactionView.setOnClickListener(v -> anyReactionClicked());
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
anyReactionView.setVisibility(View.GONE); // EmojiPickerView requires SDK 21 or newer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -96,11 +96,7 @@ public final class ImageEditorHud extends LinearLayout {
|
|||
}
|
||||
|
||||
private void initializeVisibilityMap() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
setVisibleViewsWhenInMode(Mode.NONE, drawButton, highlightButton, blurButton, textButton, stickerButton, cropButton, undoButton, saveButton);
|
||||
} else {
|
||||
setVisibleViewsWhenInMode(Mode.NONE, drawButton, highlightButton, textButton, stickerButton, cropButton, undoButton, saveButton);
|
||||
}
|
||||
|
||||
setVisibleViewsWhenInMode(Mode.DRAW, confirmButton, undoButton, colorPicker, colorPalette);
|
||||
|
||||
|
|
|
@ -117,16 +117,13 @@ final class UriGlideRenderer implements Renderer {
|
|||
|
||||
rendererContext.restore();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
renderBlurOverlay(rendererContext);
|
||||
}
|
||||
} else if (rendererContext.isBlockingLoad()) {
|
||||
// If failed to load, we draw a black out, in case image was sticker positioned to cover private info.
|
||||
rendererContext.canvas.drawRect(Bounds.FULL_BOUNDS, paint);
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(17)
|
||||
private void renderBlurOverlay(RendererContext rendererContext) {
|
||||
boolean renderMask = false;
|
||||
|
||||
|
|
|
@ -98,7 +98,6 @@ public class VerticalSlideColorPicker extends View {
|
|||
init();
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public VerticalSlideColorPicker(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
init();
|
||||
|
|
|
@ -15,10 +15,6 @@ public final class AccessibilityUtil {
|
|||
Log.e("AccessibilityUtil", "animationsDisabled: context was null");
|
||||
return false;
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
return Settings.Global.getFloat(context.getContentResolver(), Settings.Global.ANIMATOR_DURATION_SCALE, 1) == 0f;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,11 +110,7 @@ public class DateUtils extends android.text.format.DateUtils {
|
|||
}
|
||||
|
||||
private static String getLocalizedPattern(String template) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
return DateFormat.getBestDateTimePattern(Util.getLocale(), template);
|
||||
} else {
|
||||
return new SimpleDateFormat(template, Util.getLocale()).toLocalizedPattern();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getFormatedDuration(long millis) {
|
||||
|
|
|
@ -16,8 +16,7 @@ public class FileProviderUtil {
|
|||
private static final String AUTHORITY = BuildConfig.APPLICATION_ID+".fileprovider";
|
||||
|
||||
public static Uri getUriFor(@NonNull Context context, @NonNull File file) throws IllegalStateException, NullPointerException {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) return FileProvider.getUriForFile(context, AUTHORITY, file);
|
||||
else return Uri.fromFile(file);
|
||||
return FileProvider.getUriForFile(context, AUTHORITY, file);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ public class ScreenLockUtil {
|
|||
public static boolean applyScreenLock(Activity activity, String title, String descr, int requestCode) {
|
||||
KeyguardManager keyguardManager = (KeyguardManager) activity.getSystemService(Context.KEYGUARD_SERVICE);
|
||||
Intent intent;
|
||||
if (keyguardManager != null && isScreenLockAvailable()) {
|
||||
if (keyguardManager != null) {
|
||||
intent = keyguardManager.createConfirmDeviceCredentialIntent(title, descr);
|
||||
if (intent != null) {
|
||||
activity.startActivityForResult(intent, requestCode);
|
||||
|
@ -22,7 +22,4 @@ public class ScreenLockUtil {
|
|||
return false;
|
||||
}
|
||||
|
||||
private static boolean isScreenLockAvailable() {
|
||||
return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,29 +20,17 @@ public class StorageUtil {
|
|||
}
|
||||
|
||||
public static @NonNull Uri getVideoUri() {
|
||||
if (Build.VERSION.SDK_INT < 21) {
|
||||
return getLegacyUri(Environment.DIRECTORY_MOVIES);
|
||||
} else {
|
||||
return MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
|
||||
}
|
||||
}
|
||||
|
||||
public static @NonNull
|
||||
Uri getAudioUri() {
|
||||
if (Build.VERSION.SDK_INT < 21) {
|
||||
return getLegacyUri(Environment.DIRECTORY_MUSIC);
|
||||
} else {
|
||||
return MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
|
||||
}
|
||||
}
|
||||
|
||||
public static @NonNull Uri getImageUri() {
|
||||
if (Build.VERSION.SDK_INT < 21) {
|
||||
return getLegacyUri(Environment.DIRECTORY_PICTURES);
|
||||
} else {
|
||||
return MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
|
||||
}
|
||||
}
|
||||
|
||||
public static @NonNull Uri getDownloadUri() {
|
||||
if (Build.VERSION.SDK_INT < 29) {
|
||||
|
|
|
@ -257,12 +257,10 @@ public class Util {
|
|||
return Arrays.hashCode(objects);
|
||||
}
|
||||
|
||||
@TargetApi(VERSION_CODES.KITKAT)
|
||||
public static boolean isLowMemory(Context context) {
|
||||
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
|
||||
return (VERSION.SDK_INT >= VERSION_CODES.KITKAT && activityManager.isLowRamDevice()) ||
|
||||
activityManager.getLargeMemoryClass() <= 64;
|
||||
return activityManager.isLowRamDevice() || activityManager.getLargeMemoryClass() <= 64;
|
||||
}
|
||||
|
||||
public static int clamp(int value, int min, int max) {
|
||||
|
@ -386,10 +384,7 @@ public class Util {
|
|||
}
|
||||
|
||||
public static int getLayoutDirection(Context context) {
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
Configuration configuration = context.getResources().getConfiguration();
|
||||
return configuration.getLayoutDirection();
|
||||
}
|
||||
return ViewCompat.LAYOUT_DIRECTION_LTR;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -168,18 +168,15 @@ public class ViewUtil {
|
|||
|
||||
@SuppressLint("RtlHardcoded")
|
||||
public static void setTextViewGravityStart(final @NonNull TextView textView, @NonNull Context context) {
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
if (Util.getLayoutDirection(context) == View.LAYOUT_DIRECTION_RTL) {
|
||||
textView.setGravity(Gravity.RIGHT);
|
||||
} else {
|
||||
textView.setGravity(Gravity.LEFT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void mirrorIfRtl(View view, Context context) {
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1 &&
|
||||
Util.getLayoutDirection(context) == View.LAYOUT_DIRECTION_RTL) {
|
||||
if (Util.getLayoutDirection(context) == View.LAYOUT_DIRECTION_RTL) {
|
||||
view.setScaleX(-1.0f);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
package org.thoughtcrime.securesms.video.recode;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaCodecInfo;
|
||||
import android.media.MediaCodecList;
|
||||
import android.media.MediaExtractor;
|
||||
import android.media.MediaFormat;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
@ -36,14 +32,7 @@ public class VideoRecoder {
|
|||
|
||||
private static final String TAG = VideoRecoder.class.getSimpleName();
|
||||
|
||||
private boolean videoConvertFirstWrite = true;
|
||||
private final static String MIME_TYPE = "video/avc";
|
||||
private final static int PROCESSOR_TYPE_OTHER = 0;
|
||||
private final static int PROCESSOR_TYPE_QCOM = 1;
|
||||
private final static int PROCESSOR_TYPE_INTEL = 2;
|
||||
private final static int PROCESSOR_TYPE_MTK = 3;
|
||||
private final static int PROCESSOR_TYPE_SEC = 4;
|
||||
private final static int PROCESSOR_TYPE_TI = 5;
|
||||
private final boolean cancelCurrentVideoConversion = false;
|
||||
private final Object videoConvertSync = new Object();
|
||||
|
||||
|
@ -57,7 +46,6 @@ public class VideoRecoder {
|
|||
}
|
||||
}
|
||||
|
||||
@TargetApi(16)
|
||||
private int selectTrack(MediaExtractor extractor, boolean audio) {
|
||||
int numTracks = extractor.getTrackCount();
|
||||
for (int i = 0; i < numTracks; i++) {
|
||||
|
@ -76,60 +64,6 @@ public class VideoRecoder {
|
|||
return -5;
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
private static MediaCodecInfo selectCodec(String mimeType) {
|
||||
int numCodecs = MediaCodecList.getCodecCount();
|
||||
MediaCodecInfo lastCodecInfo = null;
|
||||
for (int i = 0; i < numCodecs; i++) {
|
||||
MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
|
||||
if (!codecInfo.isEncoder()) {
|
||||
continue;
|
||||
}
|
||||
String[] types = codecInfo.getSupportedTypes();
|
||||
for (String type : types) {
|
||||
if (type.equalsIgnoreCase(mimeType)) {
|
||||
lastCodecInfo = codecInfo;
|
||||
if (!lastCodecInfo.getName().equals("OMX.SEC.avc.enc")) {
|
||||
return lastCodecInfo;
|
||||
} else if (lastCodecInfo.getName().equals("OMX.SEC.AVC.Encoder")) {
|
||||
return lastCodecInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return lastCodecInfo;
|
||||
}
|
||||
|
||||
private static boolean isRecognizedFormat(int colorFormat) {
|
||||
switch (colorFormat) {
|
||||
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar:
|
||||
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar:
|
||||
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar:
|
||||
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar:
|
||||
case MediaCodecInfo.CodecCapabilities.COLOR_TI_FormatYUV420PackedSemiPlanar:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
private static int selectColorFormat(MediaCodecInfo codecInfo, String mimeType) {
|
||||
MediaCodecInfo.CodecCapabilities capabilities = codecInfo.getCapabilitiesForType(mimeType);
|
||||
int lastColorFormat = 0;
|
||||
for (int i = 0; i < capabilities.colorFormats.length; i++) {
|
||||
int colorFormat = capabilities.colorFormats[i];
|
||||
if (isRecognizedFormat(colorFormat)) {
|
||||
lastColorFormat = colorFormat;
|
||||
if (!(codecInfo.getName().equals("OMX.SEC.AVC.Encoder") && colorFormat == 19)) {
|
||||
return colorFormat;
|
||||
}
|
||||
}
|
||||
}
|
||||
return lastColorFormat;
|
||||
}
|
||||
|
||||
@TargetApi(16)
|
||||
private long readAndWriteTrack(MediaExtractor extractor, MP4Builder mediaMuxer, MediaCodec.BufferInfo info, long start, long end, File file, boolean isAudio) throws Exception {
|
||||
int trackIndex = selectTrack(extractor, isAudio);
|
||||
if (trackIndex >= 0) {
|
||||
|
@ -199,7 +133,6 @@ public class VideoRecoder {
|
|||
return -1;
|
||||
}
|
||||
|
||||
@TargetApi(16)
|
||||
private boolean convertVideo(final VideoEditedInfo videoEditedInfo, String destPath) {
|
||||
|
||||
long startTime = videoEditedInfo.startTime;
|
||||
|
@ -214,13 +147,6 @@ public class VideoRecoder {
|
|||
int rotateRender = 0;
|
||||
File cacheFile = new File(destPath);
|
||||
|
||||
if (Build.VERSION.SDK_INT < 18 && resultHeight > resultWidth && resultWidth != originalWidth && resultHeight != originalHeight) {
|
||||
int temp = resultHeight;
|
||||
resultHeight = resultWidth;
|
||||
resultWidth = temp;
|
||||
rotationValue = 90;
|
||||
rotateRender = 270;
|
||||
} else if (Build.VERSION.SDK_INT > 20) {
|
||||
if (rotationValue == 90) {
|
||||
int temp = resultHeight;
|
||||
resultHeight = resultWidth;
|
||||
|
@ -237,7 +163,6 @@ public class VideoRecoder {
|
|||
rotationValue = 0;
|
||||
rotateRender = 90;
|
||||
}
|
||||
}
|
||||
|
||||
File inputFile = new File(videoEditedInfo.originalPath);
|
||||
if (!inputFile.canRead()) {
|
||||
|
@ -246,7 +171,6 @@ public class VideoRecoder {
|
|||
return false;
|
||||
}
|
||||
|
||||
videoConvertFirstWrite = true;
|
||||
boolean error = false;
|
||||
long videoStartTime = startTime;
|
||||
|
||||
|
@ -282,71 +206,12 @@ public class VideoRecoder {
|
|||
boolean outputDone = false;
|
||||
boolean inputDone = false;
|
||||
boolean decoderDone = false;
|
||||
int swapUV = 0;
|
||||
int videoTrackIndex = -5;
|
||||
|
||||
int colorFormat;
|
||||
int processorType = PROCESSOR_TYPE_OTHER;
|
||||
String manufacturer = Build.MANUFACTURER.toLowerCase();
|
||||
if (Build.VERSION.SDK_INT < 18) {
|
||||
MediaCodecInfo codecInfo = selectCodec(MIME_TYPE);
|
||||
colorFormat = selectColorFormat(codecInfo, MIME_TYPE);
|
||||
if (colorFormat == 0) {
|
||||
throw new RuntimeException("no supported color format");
|
||||
}
|
||||
String codecName = codecInfo.getName();
|
||||
if (codecName.contains("OMX.qcom.")) {
|
||||
processorType = PROCESSOR_TYPE_QCOM;
|
||||
if (Build.VERSION.SDK_INT == 16) {
|
||||
if (manufacturer.equals("lge") || manufacturer.equals("nokia")) {
|
||||
swapUV = 1;
|
||||
}
|
||||
}
|
||||
} else if (codecName.contains("OMX.Intel.")) {
|
||||
processorType = PROCESSOR_TYPE_INTEL;
|
||||
} else if (codecName.equals("OMX.MTK.VIDEO.ENCODER.AVC")) {
|
||||
processorType = PROCESSOR_TYPE_MTK;
|
||||
} else if (codecName.equals("OMX.SEC.AVC.Encoder")) {
|
||||
processorType = PROCESSOR_TYPE_SEC;
|
||||
swapUV = 1;
|
||||
} else if (codecName.equals("OMX.TI.DUCATI1.VIDEO.H264E")) {
|
||||
processorType = PROCESSOR_TYPE_TI;
|
||||
}
|
||||
//Log.i("DeltaChat", "codec = " + codecInfo.getName() + " manufacturer = " + manufacturer + "device = " + Build.MODEL);
|
||||
} else {
|
||||
colorFormat = MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
|
||||
}
|
||||
//Log.i("DeltaChat", "colorFormat = " + colorFormat);
|
||||
|
||||
int resultHeightAligned = resultHeight;
|
||||
int padding = 0;
|
||||
int bufferSize = resultWidth * resultHeight * 3 / 2;
|
||||
if (processorType == PROCESSOR_TYPE_OTHER) {
|
||||
if (resultHeight % 16 != 0) {
|
||||
resultHeightAligned += (16 - (resultHeight % 16));
|
||||
padding = resultWidth * (resultHeightAligned - resultHeight);
|
||||
bufferSize += padding * 5 / 4;
|
||||
}
|
||||
} else if (processorType == PROCESSOR_TYPE_QCOM) {
|
||||
if (!manufacturer.toLowerCase().equals("lge")) {
|
||||
int uvoffset = (resultWidth * resultHeight + 2047) & ~2047;
|
||||
padding = uvoffset - (resultWidth * resultHeight);
|
||||
bufferSize += padding;
|
||||
}
|
||||
} else if (processorType == PROCESSOR_TYPE_TI) {
|
||||
//resultHeightAligned = 368;
|
||||
//bufferSize = resultWidth * resultHeightAligned * 3 / 2;
|
||||
//resultHeightAligned += (16 - (resultHeight % 16));
|
||||
//padding = resultWidth * (resultHeightAligned - resultHeight);
|
||||
//bufferSize += padding * 5 / 4;
|
||||
} else if (processorType == PROCESSOR_TYPE_MTK) {
|
||||
if (manufacturer.equals("baidu")) {
|
||||
resultHeightAligned += (16 - (resultHeight % 16));
|
||||
padding = resultWidth * (resultHeightAligned - resultHeight);
|
||||
bufferSize += padding * 5 / 4;
|
||||
}
|
||||
}
|
||||
|
||||
extractor.selectTrack(videoIndex);
|
||||
if (startTime > 0) {
|
||||
extractor.seekTo(startTime, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
|
||||
|
@ -360,39 +225,21 @@ public class VideoRecoder {
|
|||
outputFormat.setInteger(MediaFormat.KEY_BIT_RATE, resultVideoBitrate != 0 ? resultVideoBitrate : 921600);
|
||||
outputFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 25);
|
||||
outputFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10);
|
||||
if (Build.VERSION.SDK_INT < 18) {
|
||||
outputFormat.setInteger("stride", resultWidth + 32);
|
||||
outputFormat.setInteger("slice-height", resultHeight);
|
||||
}
|
||||
|
||||
encoder = MediaCodec.createEncoderByType(MIME_TYPE);
|
||||
encoder.configure(outputFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
|
||||
if (Build.VERSION.SDK_INT >= 18) {
|
||||
inputSurface = new InputSurface(encoder.createInputSurface());
|
||||
inputSurface.makeCurrent();
|
||||
}
|
||||
encoder.start();
|
||||
|
||||
decoder = MediaCodec.createDecoderByType(inputFormat.getString(MediaFormat.KEY_MIME));
|
||||
if (Build.VERSION.SDK_INT >= 18) {
|
||||
outputSurface = new OutputSurface();
|
||||
} else {
|
||||
outputSurface = new OutputSurface(resultWidth, resultHeight, rotateRender);
|
||||
}
|
||||
decoder.configure(inputFormat, outputSurface.getSurface(), null, 0);
|
||||
decoder.start();
|
||||
|
||||
final int TIMEOUT_USEC = 2500;
|
||||
ByteBuffer[] decoderInputBuffers = null;
|
||||
ByteBuffer[] encoderOutputBuffers = null;
|
||||
ByteBuffer[] encoderInputBuffers = null;
|
||||
if (Build.VERSION.SDK_INT < 21) {
|
||||
decoderInputBuffers = decoder.getInputBuffers();
|
||||
encoderOutputBuffers = encoder.getOutputBuffers();
|
||||
if (Build.VERSION.SDK_INT < 18) {
|
||||
encoderInputBuffers = encoder.getInputBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
checkConversionCanceled();
|
||||
|
||||
|
@ -405,11 +252,7 @@ public class VideoRecoder {
|
|||
int inputBufIndex = decoder.dequeueInputBuffer(TIMEOUT_USEC);
|
||||
if (inputBufIndex >= 0) {
|
||||
ByteBuffer inputBuf;
|
||||
if (Build.VERSION.SDK_INT < 21) {
|
||||
inputBuf = decoderInputBuffers[inputBufIndex];
|
||||
} else {
|
||||
inputBuf = decoder.getInputBuffer(inputBufIndex);
|
||||
}
|
||||
int chunkSize = extractor.readSampleData(inputBuf, 0);
|
||||
if (chunkSize < 0) {
|
||||
decoder.queueInputBuffer(inputBufIndex, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
|
||||
|
@ -439,9 +282,6 @@ public class VideoRecoder {
|
|||
if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
|
||||
encoderOutputAvailable = false;
|
||||
} else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
|
||||
if (Build.VERSION.SDK_INT < 21) {
|
||||
encoderOutputBuffers = encoder.getOutputBuffers();
|
||||
}
|
||||
} else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
|
||||
MediaFormat newFormat = encoder.getOutputFormat();
|
||||
if (videoTrackIndex == -5) {
|
||||
|
@ -451,11 +291,7 @@ public class VideoRecoder {
|
|||
throw new RuntimeException("unexpected result from encoder.dequeueOutputBuffer: " + encoderStatus);
|
||||
} else {
|
||||
ByteBuffer encodedData;
|
||||
if (Build.VERSION.SDK_INT < 21) {
|
||||
encodedData = encoderOutputBuffers[encoderStatus];
|
||||
} else {
|
||||
encodedData = encoder.getOutputBuffer(encoderStatus);
|
||||
}
|
||||
if (encodedData == null) {
|
||||
throw new RuntimeException("encoderOutputBuffer " + encoderStatus + " was null");
|
||||
}
|
||||
|
@ -513,11 +349,7 @@ public class VideoRecoder {
|
|||
throw new RuntimeException("unexpected result from decoder.dequeueOutputBuffer: " + decoderStatus);
|
||||
} else {
|
||||
boolean doRender;
|
||||
if (Build.VERSION.SDK_INT >= 18) {
|
||||
doRender = info.size != 0;
|
||||
} else {
|
||||
doRender = info.size != 0 || info.presentationTimeUs != 0;
|
||||
}
|
||||
if (endTime > 0 && info.presentationTimeUs >= endTime) {
|
||||
inputDone = true;
|
||||
decoderDone = true;
|
||||
|
@ -542,40 +374,15 @@ public class VideoRecoder {
|
|||
Log.w(TAG, "error while waiting for recording output surface", e);
|
||||
}
|
||||
if (!errorWait) {
|
||||
if (Build.VERSION.SDK_INT >= 18) {
|
||||
outputSurface.drawImage(false);
|
||||
inputSurface.setPresentationTime(info.presentationTimeUs * 1000);
|
||||
inputSurface.swapBuffers();
|
||||
} else {
|
||||
Log.w(TAG, "Cannot proceed with the current SDK version");
|
||||
return false; // TODO: this should be caught much earlier
|
||||
/*
|
||||
int inputBufIndex = encoder.dequeueInputBuffer(TIMEOUT_USEC);
|
||||
if (inputBufIndex >= 0) {
|
||||
outputSurface.drawImage(true);
|
||||
ByteBuffer rgbBuf = outputSurface.getFrame();
|
||||
ByteBuffer yuvBuf = encoderInputBuffers[inputBufIndex];
|
||||
yuvBuf.clear();
|
||||
Utilities.convertVideoFrame(rgbBuf, yuvBuf, colorFormat, resultWidth, resultHeight, padding, swapUV);
|
||||
encoder.queueInputBuffer(inputBufIndex, 0, bufferSize, info.presentationTimeUs, 0);
|
||||
} else {
|
||||
//Log.i("DeltaChat", "input buffer not available");
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
|
||||
decoderOutputAvailable = false;
|
||||
//Log.i("DeltaChat", "decoder stream end");
|
||||
if (Build.VERSION.SDK_INT >= 18) {
|
||||
encoder.signalEndOfInputStream();
|
||||
} else {
|
||||
int inputBufIndex = encoder.dequeueInputBuffer(TIMEOUT_USEC);
|
||||
if (inputBufIndex >= 0) {
|
||||
encoder.queueInputBuffer(inputBufIndex, 0, 1, info.presentationTimeUs, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -662,45 +469,6 @@ public class VideoRecoder {
|
|||
int estimatedBytes;
|
||||
}
|
||||
|
||||
public static boolean canRecode()
|
||||
{
|
||||
boolean canRecode = true;
|
||||
if (Build.VERSION.SDK_INT < 16 /*= Jelly Bean 4.1 (before that codecInfo.getName() was not there) */) {
|
||||
Log.w(TAG, "Cannot recode: API < 16");
|
||||
canRecode = false;
|
||||
}
|
||||
else if (Build.VERSION.SDK_INT < 18 /*= Jelly Bean 4.3*/) {
|
||||
try {
|
||||
MediaCodecInfo codecInfo = VideoRecoder.selectCodec(VideoRecoder.MIME_TYPE);
|
||||
if (codecInfo == null) {
|
||||
Log.w(TAG, "Cannot recode: cannot select codec");
|
||||
canRecode = false;
|
||||
} else {
|
||||
String name = codecInfo.getName();
|
||||
if (name.equals("OMX.google.h264.encoder") ||
|
||||
name.equals("OMX.ST.VFM.H264Enc") ||
|
||||
name.equals("OMX.Exynos.avc.enc") ||
|
||||
name.equals("OMX.MARVELL.VIDEO.HW.CODA7542ENCODER") ||
|
||||
name.equals("OMX.MARVELL.VIDEO.H264ENCODER") ||
|
||||
name.equals("OMX.k3.video.encoder.avc") ||
|
||||
name.equals("OMX.TI.DUCATI1.VIDEO.H264E")) {
|
||||
Log.w(TAG, "Cannot recode: no supported codec found");
|
||||
canRecode = false;
|
||||
} else {
|
||||
if (VideoRecoder.selectColorFormat(codecInfo, VideoRecoder.MIME_TYPE) == 0) {
|
||||
Log.w(TAG, "Cannot recode: cannot select color format");
|
||||
canRecode = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "Cannot recode: Determinating recoding capabilities failed unexpectedly", e);
|
||||
canRecode = false;
|
||||
}
|
||||
}
|
||||
return canRecode;
|
||||
}
|
||||
|
||||
private static VideoEditedInfo getVideoEditInfoFromFile(String videoPath) {
|
||||
// load information for the given video
|
||||
VideoEditedInfo vei = new VideoEditedInfo();
|
||||
|
@ -811,11 +579,6 @@ public class VideoRecoder {
|
|||
}
|
||||
msg.setDuration((int)vei.originalDurationMs);
|
||||
|
||||
if (!canRecode()) {
|
||||
alert(context, String.format("Recoding failed for %s: this system cannot recode videos", inPath));
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if video bitrate is already reasonable
|
||||
final int MAX_KBPS = 1500000;
|
||||
final long MAX_BYTES = DcHelper.getInt(context, "sys.msgsize_max_recommended");
|
||||
|
|
Before Width: | Height: | Size: 1,002 B After Width: | Height: | Size: 1,002 B |
Before Width: | Height: | Size: 750 B |
Before Width: | Height: | Size: 532 B After Width: | Height: | Size: 532 B |
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/touch_highlight">
|
||||
<item android:id="@android:id/mask">
|
||||
<shape android:shape="oval">
|
||||
<solid android:color="@color/black" />
|
||||
</shape>
|
||||
</item>
|
||||
</ripple>
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/delta_primary">
|
||||
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
|
||||
<item>
|
||||
<selector>
|
||||
<item android:drawable="@color/primary_alpha33" android:state_selected="true" />
|
||||
</selector>
|
||||
</item>
|
||||
</ripple>
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/delta_primary">
|
||||
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
|
||||
<item>
|
||||
<selector>
|
||||
<item android:drawable="@color/primary_alpha33" android:state_selected="true" />
|
||||
</selector>
|
||||
</item>
|
||||
</ripple>
|
|
@ -1,11 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/delta_primary">
|
||||
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
|
||||
<item>
|
||||
<selector>
|
||||
<item android:drawable="@color/primary_alpha33" android:state_selected="true" />
|
||||
<item android:drawable="@color/pinned_bg" />
|
||||
</selector>
|
||||
</item>
|
||||
</ripple>
|
|
@ -1,11 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/delta_primary">
|
||||
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
|
||||
<item>
|
||||
<selector>
|
||||
<item android:drawable="@color/primary_alpha33" android:state_selected="true" />
|
||||
<item android:drawable="@color/pinned_bg_dark" />
|
||||
</selector>
|
||||
</item>
|
||||
</ripple>
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/touch_highlight">
|
||||
<item
|
||||
android:id="@android:id/mask"
|
||||
android:drawable="@android:color/white" />
|
||||
</ripple>
|
|
@ -1,12 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Like touch_highlight_background, but creates a stronger (i.e. better visible)
|
||||
visual feedback when the button is pressed. -->
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/delta_primary">
|
||||
<item android:id="@android:id/mask" android:drawable="@android:color/white" />
|
||||
<item>
|
||||
<selector>
|
||||
<item android:drawable="@color/touch_highlight_strong" android:state_pressed="true" />
|
||||
</selector>
|
||||
</item>
|
||||
</ripple>
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
@ -1,8 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true">
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/touch_highlight">
|
||||
<item android:id="@android:id/mask">
|
||||
<shape android:shape="oval">
|
||||
<solid android:color="@color/touch_highlight" />
|
||||
<solid android:color="@color/black" />
|
||||
</shape>
|
||||
</item>
|
||||
</selector>
|
||||
</ripple>
|
|
@ -1,6 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/delta_primary">
|
||||
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
|
||||
<item>
|
||||
<selector>
|
||||
<item android:drawable="@color/primary_alpha33" android:state_selected="true" />
|
||||
<item android:drawable="@color/primary_alpha33" android:state_pressed="true" />
|
||||
<item android:drawable="@color/primary_alpha_focus" android:state_focused="true" />
|
||||
</selector>
|
||||
</item>
|
||||
</ripple>
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/delta_primary">
|
||||
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
|
||||
<item>
|
||||
<selector>
|
||||
<item android:drawable="@color/primary_alpha33" android:state_selected="true" />
|
||||
<item android:drawable="@color/primary_alpha33" android:state_pressed="true" />
|
||||
<item android:drawable="@color/primary_alpha_focus" android:state_focused="true" />
|
||||
</selector>
|
||||
</item>
|
||||
</ripple>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:drawable="@drawable/pause_icon"
|
||||
tools:targetApi="lollipop">
|
||||
>
|
||||
|
||||
<target
|
||||
android:name="@string/play_icon_group_parts"
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/delta_primary">
|
||||
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
|
||||
<item>
|
||||
<selector>
|
||||
<item android:drawable="@color/primary_alpha33" android:state_selected="true" />
|
||||
<item android:drawable="@color/primary_alpha33" android:state_pressed="true" />
|
||||
<item android:drawable="@color/primary_alpha_focus" android:state_focused="true" />
|
||||
<item android:drawable="@color/pinned_bg" />
|
||||
</selector>
|
||||
</item>
|
||||
</ripple>
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/delta_primary">
|
||||
<item android:id="@android:id/mask" android:drawable="@android:color/black" />
|
||||
<item>
|
||||
<selector>
|
||||
<item android:drawable="@color/primary_alpha33" android:state_selected="true" />
|
||||
<item android:drawable="@color/primary_alpha33" android:state_pressed="true" />
|
||||
<item android:drawable="@color/primary_alpha_focus" android:state_focused="true" />
|
||||
<item android:drawable="@color/pinned_bg_dark" />
|
||||
</selector>
|
||||
</item>
|
||||
</ripple>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:drawable="@drawable/play_icon"
|
||||
tools:targetApi="lollipop">
|
||||
>
|
||||
|
||||
<target
|
||||
android:name="@string/play_icon_group_parts"
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true" android:drawable="@color/touch_highlight" />
|
||||
<item android:state_focused="true" android:drawable="@color/delta_primary" />
|
||||
<item android:drawable="@android:color/transparent" />
|
||||
</selector>
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/touch_highlight">
|
||||
<item
|
||||
android:id="@android:id/mask"
|
||||
android:drawable="@android:color/white" />
|
||||
</ripple>
|
|
@ -1,6 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true" android:drawable="@color/touch_highlight_strong" />
|
||||
<item android:state_focused="true" android:drawable="@color/delta_primary" />
|
||||
<item android:drawable="@android:color/transparent" />
|
||||
<!-- Like touch_highlight_background, but creates a stronger (i.e. better visible)
|
||||
visual feedback when the button is pressed. -->
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/delta_primary">
|
||||
<item android:id="@android:id/mask" android:drawable="@android:color/white" />
|
||||
<item>
|
||||
<selector>
|
||||
<item android:drawable="@color/touch_highlight_strong" android:state_pressed="true" />
|
||||
</selector>
|
||||
</item>
|
||||
</ripple>
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="touch_highlight">#22000000</color>
|
||||
</resources>
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="TextSecure.ScribbleTheme" parent="TextSecure.DarkNoActionBar">
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowFullscreen">true</item>
|
||||
</style>
|
||||
</resources>
|
|
@ -36,7 +36,7 @@
|
|||
<color name="conversation_compose_divider">#32000000</color>
|
||||
|
||||
<color name="action_mode_status_bar">@color/gray50</color>
|
||||
<color name="touch_highlight">#400099cc</color>
|
||||
<color name="touch_highlight">#22000000</color>
|
||||
<color name="touch_highlight_strong">#5C4CB8DB</color>
|
||||
|
||||
<color name="sticker_selected_color">#99ffffff</color>
|
||||
|
|
|
@ -256,6 +256,8 @@
|
|||
</style>
|
||||
|
||||
<style name="TextSecure.ScribbleTheme" parent="TextSecure.DarkNoActionBar">
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowFullscreen">true</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
|