diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index c49d61bb..601e9ba4 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -83,7 +83,7 @@ android { defaultConfig { minSdkVersion 8 targetSdkVersion 19 - versionCode 281 - versionName "1.6.0" + versionCode 286 + versionName "1.6.1" } } diff --git a/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java index 298e2ad3..65752a19 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java @@ -174,15 +174,23 @@ public class AndroidUtilities { public static File getCacheDir() { if (externalCacheNotAvailableState == 1 || externalCacheNotAvailableState == 0 && Environment.getExternalStorageState().startsWith(Environment.MEDIA_MOUNTED)) { externalCacheNotAvailableState = 1; - File file = ApplicationLoader.applicationContext.getExternalCacheDir(); - if (file != null) { - return file; + try { + File file = ApplicationLoader.applicationContext.getExternalCacheDir(); + if (file != null) { + return file; + } + } catch (Exception e) { + FileLog.e("tmessages", e); } } externalCacheNotAvailableState = 2; - File file = ApplicationLoader.applicationContext.getCacheDir(); - if (file != null) { - return file; + try { + File file = ApplicationLoader.applicationContext.getCacheDir(); + if (file != null) { + return file; + } + } catch (Exception e) { + FileLog.e("tmessages", e); } return new File(""); } diff --git a/TMessagesProj/src/main/java/org/telegram/android/NotificationsController.java b/TMessagesProj/src/main/java/org/telegram/android/NotificationsController.java index e03e61c2..419d82f9 100644 --- a/TMessagesProj/src/main/java/org/telegram/android/NotificationsController.java +++ b/TMessagesProj/src/main/java/org/telegram/android/NotificationsController.java @@ -354,30 +354,45 @@ public class NotificationsController { .setContentIntent(contentIntent); String lastMessage = null; - NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle(); - inboxStyle.setBigContentTitle(name); - int count = Math.min(10, pushMessages.size()); - for (int i = 0; i < count; i++) { - String message = getStringForMessage(pushMessages.get(i)); + if (pushMessages.size() == 1) { + String message = lastMessage = getStringForMessage(pushMessages.get(0)); if (message == null) { - continue; + return; } - if (i == 0) { - lastMessage = message; - } - if (pushDialogs.size() == 1) { - if (replace) { - if (chat != null) { - message = message.replace(" @ " + name, ""); - } else { - message = message.replace(name + ": ", "").replace(name + " ", ""); - } + if (replace) { + if (chat != null) { + message = message.replace(" @ " + name, ""); + } else { + message = message.replace(name + ": ", "").replace(name + " ", ""); } } - inboxStyle.addLine(message); + mBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(message)); + } else { + NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle(); + inboxStyle.setBigContentTitle(name); + int count = Math.min(10, pushMessages.size()); + for (int i = 0; i < count; i++) { + String message = getStringForMessage(pushMessages.get(i)); + if (message == null) { + continue; + } + if (i == 0) { + lastMessage = message; + } + if (pushDialogs.size() == 1) { + if (replace) { + if (chat != null) { + message = message.replace(" @ " + name, ""); + } else { + message = message.replace(name + ": ", "").replace(name + " ", ""); + } + } + } + inboxStyle.addLine(message); + } + inboxStyle.setSummaryText(detailText); + mBuilder.setStyle(inboxStyle); } - inboxStyle.setSummaryText(detailText); - mBuilder.setStyle(inboxStyle); if (photoPath != null) { Bitmap img = FileLoader.getInstance().getImageFromMemory(photoPath, null, null, "50_50", false); @@ -547,38 +562,47 @@ public class NotificationsController { public void processDialogsUpdateRead(final HashMap dialogsToUpdate, boolean replace) { int old_unread_count = total_unread_count; + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE); for (HashMap.Entry entry : dialogsToUpdate.entrySet()) { - Long dialog_id = entry.getKey(); + long dialog_id = entry.getKey(); + + int notify_override = preferences.getInt("notify2_" + dialog_id, 0); + boolean isChat = (int)dialog_id < 0; Integer currentCount = pushDialogs.get(dialog_id); - Integer newCount = entry.getValue(); - if (replace) { - if (currentCount != null) { - total_unread_count -= currentCount; - } - if (newCount == 0) { - pushDialogs.remove(dialog_id); + if (!(notify_override == 2 || (!preferences.getBoolean("EnableAll", true) || isChat && !preferences.getBoolean("EnableGroup", true)) && notify_override == 0)) { + Integer newCount = entry.getValue(); + if (replace) { + if (currentCount != null) { + total_unread_count -= currentCount; + } + if (newCount == 0) { + pushDialogs.remove(dialog_id); + } else { + total_unread_count += newCount; + pushDialogs.put(dialog_id, newCount); + } } else { + if (currentCount == null) { + currentCount = 0; + } + currentCount += newCount; total_unread_count += newCount; - pushDialogs.put(dialog_id, newCount); + pushDialogs.put(dialog_id, currentCount); } - } else { - if (currentCount == null) { - currentCount = 0; - } - currentCount += newCount; - total_unread_count += newCount; - pushDialogs.put(dialog_id, currentCount); } } if (old_unread_count != total_unread_count) { showOrUpdateNotification(notifyCheck); notifyCheck = false; } - setBadge(ApplicationLoader.applicationContext, total_unread_count); + if (preferences.getBoolean("badgeNumber", true)) { + setBadge(ApplicationLoader.applicationContext, total_unread_count); + } } public void processLoadedUnreadMessages(HashMap dialogs) { pushDialogs.clear(); + total_unread_count = 0; SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE); String dialogsToLoad = ""; for (HashMap.Entry entry : dialogs.entrySet()) { @@ -594,7 +618,20 @@ public class NotificationsController { dialogsToLoad += "" + dialog_id; } } - setBadge(ApplicationLoader.applicationContext, total_unread_count); + if (total_unread_count == 0) { + pushMessages.clear(); + pushMessagesDict.clear(); + popupMessages.clear(); + showOrUpdateNotification(false); + NotificationCenter.getInstance().postNotificationName(pushMessagesUpdated); + } + if (preferences.getBoolean("badgeNumber", true)) { + setBadge(ApplicationLoader.applicationContext, total_unread_count); + } + } + + public void setBadgeEnabled(boolean enabled) { + setBadge(ApplicationLoader.applicationContext, enabled ? total_unread_count : 0); } private void setBadge(Context context, int count) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager.java b/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager.java index ce85bd5a..ca032f9e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager.java @@ -101,15 +101,18 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. public void run() { Utilities.stageQueue.handler.removeCallbacks(stageRunnable); if (datacenters != null) { + Datacenter datacenter = datacenterWithId(currentDatacenterId); if (sendingPushPing && lastPushPingTime < System.currentTimeMillis() - 30000 || Math.abs(lastPushPingTime - System.currentTimeMillis()) > 60000 * 3 + 10000) { lastPushPingTime = 0; sendingPushPing = false; + if (datacenter != null && datacenter.pushConnection != null) { + datacenter.pushConnection.suspendConnection(true); + } FileLog.e("tmessages", "push ping timeout"); } if (lastPushPingTime < System.currentTimeMillis() - 60000 * 3) { FileLog.e("tmessages", "time for push ping"); lastPushPingTime = System.currentTimeMillis(); - Datacenter datacenter = datacenterWithId(currentDatacenterId); if (datacenter != null) { generatePing(datacenter, true); } @@ -448,7 +451,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. datacenter = new Datacenter(); datacenter.datacenterId = 4; - datacenter.addAddressAndPort("31.210.235.12", 443); + datacenter.addAddressAndPort("149.154.167.90", 443); datacenters.put(datacenter.datacenterId, datacenter); datacenter = new Datacenter(); @@ -2374,7 +2377,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. FileLog.e("tmessages", "no network available"); } } catch (Exception e) { - FileLog.e("tmessages", "NETWORK STATE GET ERROR"); + FileLog.e("tmessages", "NETWORK STATE GET ERROR", e); } } final int stateCopy = connectionState; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java index aaac83a3..cf54747f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java @@ -674,7 +674,7 @@ public class FileLoadOperation { } } - if (downloadedBytes % downloadChunkSize == 0 || totalBytesCount > 0 && totalBytesCount > downloadedBytes) { + if (totalBytesCount != downloadedBytes && downloadedBytes % downloadChunkSize == 0 || totalBytesCount > 0 && totalBytesCount > downloadedBytes) { startDownloadRequest(); } else { onFinishLoadingFile(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/HandshakeAction.java b/TMessagesProj/src/main/java/org/telegram/messenger/HandshakeAction.java index d2632e96..49f6ceda 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/HandshakeAction.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/HandshakeAction.java @@ -174,17 +174,13 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti } ByteBufferDesc sendMessageData(TLObject message, long messageId) { - ByteBufferDesc innerOs = BuffersStorage.getInstance().getFreeBuffer(message.getObjectSize()); - message.serializeToStream(innerOs); - message.freeResources(); - - ByteBufferDesc messageOs = BuffersStorage.getInstance().getFreeBuffer(8 + 8 + 4 + innerOs.length()); + int messageLength = message.getObjectSize(); + ByteBufferDesc messageOs = BuffersStorage.getInstance().getFreeBuffer(8 + 8 + 4 + messageLength); messageOs.writeInt64(0); messageOs.writeInt64(messageId); - messageOs.writeInt32(innerOs.length()); - innerOs.position(0); - messageOs.writeRaw(innerOs); - BuffersStorage.getInstance().reuseFreeBuffer(innerOs); + messageOs.writeInt32(messageLength); + message.serializeToStream(messageOs); + message.freeResources(); datacenter.connection.sendData(messageOs, false, false); return messageOs; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ApplicationLoader.java b/TMessagesProj/src/main/java/org/telegram/ui/ApplicationLoader.java index f93145ef..949dced5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ApplicationLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ApplicationLoader.java @@ -30,6 +30,7 @@ import com.google.android.gms.common.GooglePlayServicesUtil; import com.google.android.gms.gcm.GoogleCloudMessaging; import org.telegram.android.AndroidUtilities; +import org.telegram.android.ContactsController; import org.telegram.android.NotificationsService; import org.telegram.messenger.BuildVars; import org.telegram.messenger.ConnectionsManager; @@ -128,6 +129,8 @@ public class ApplicationLoader extends Application { ApplicationLoader app = (ApplicationLoader)ApplicationLoader.applicationContext; app.initPlayServices(); FileLog.e("tmessages", "app initied"); + + ContactsController.getInstance().checkAppAccount(); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatOrUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatOrUserCell.java index 1bf92a35..8aa33a10 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatOrUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatOrUserCell.java @@ -307,7 +307,7 @@ public class ChatOrUserCell extends BaseCell { nameString = nameString2.replace("\n", " "); } if (nameString.length() == 0) { - if (user.phone != null && user.phone.length() != 0) { + if (user != null && user.phone != null && user.phone.length() != 0) { nameString = PhoneFormat.getInstance().format("+" + user.phone); } else { nameString = LocaleController.getString("HiddenName", R.string.HiddenName); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 6c47363c..07d4546d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -89,7 +89,8 @@ import java.util.HashMap; import java.util.concurrent.Semaphore; public class ChatActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, MessagesActivity.MessagesActivityDelegate, - DocumentSelectActivity.DocumentSelectActivityDelegate, PhotoViewer.PhotoViewerProvider, PhotoPickerActivity.PhotoPickerActivityDelegate { + DocumentSelectActivity.DocumentSelectActivityDelegate, PhotoViewer.PhotoViewerProvider, PhotoPickerActivity.PhotoPickerActivityDelegate, + VideoEditorActivity.VideoEditorActivityDelegate { private ChatActivityEnterView chatActivityEnterView; private View timeItem; @@ -1318,7 +1319,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } currentPicturePath = null; } - processSendingVideo(videoPath); + /*if(android.os.Build.VERSION.SDK_INT >= 10) { + Bundle args = new Bundle(); + args.putString("videoPath", videoPath); + VideoEditorActivity fragment = new VideoEditorActivity(args); + fragment.setDelegate(this); + presentFragment(fragment); + } else {*/ + processSendingVideo(videoPath); + //} } else if (requestCode == 21) { if (data == null || data.getData() == null) { showAttachmentError(); @@ -1339,6 +1348,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + @Override + public void didFinishedVideoConverting(String videoPath) { + processSendingVideo(videoPath); + } + private void showAttachmentError() { if (getParentActivity() == null) { return; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java index c0485467..a31d9eff 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java @@ -133,6 +133,9 @@ public class LocationActivity extends BaseFragment implements NotificationCenter } avatarImageView = (BackupImageView)fragmentView.findViewById(R.id.location_avatar_view); + if (avatarImageView != null) { + avatarImageView.processDetach = false; + } nameTextView = (TextView)fragmentView.findViewById(R.id.location_name_label); distanceTextView = (TextView)fragmentView.findViewById(R.id.location_distance_label); View bottomView = fragmentView.findViewById(R.id.location_bottom_view); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/MessagesActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/MessagesActivity.java index 6a98eca3..ecdbd2c3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/MessagesActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/MessagesActivity.java @@ -506,12 +506,12 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter builder.setMessage(LocaleController.formatStringSimple(selectAlertString, Utilities.formatName(user.first_name, user.last_name))); } CheckBox checkBox = null; - if (delegate instanceof ChatActivity) { + /*if (delegate instanceof ChatActivity) { checkBox = new CheckBox(getParentActivity()); checkBox.setText(LocaleController.getString("ForwardFromMyName", R.string.ForwardFromMyName)); checkBox.setChecked(false); builder.setView(checkBox); - } + }*/ final CheckBox checkBoxFinal = checkBox; builder.setPositiveButton(R.string.OK, new DialogInterface.OnClickListener() { @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java index c6f1b7dc..c2f86eaf 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java @@ -150,6 +150,7 @@ public class PopupNotificationActivity extends Activity implements NotificationC NotificationCenter.getInstance().addObserver(this, MessagesController.updateInterfaces); NotificationCenter.getInstance().addObserver(this, MediaController.audioProgressDidChanged); NotificationCenter.getInstance().addObserver(this, MediaController.audioDidReset); + NotificationCenter.getInstance().addObserver(this, MessagesController.contactsDidLoaded); NotificationCenter.getInstance().addObserver(this, 999); chatActivityEnterView = new ChatActivityEnterView(); @@ -940,6 +941,8 @@ public class PopupNotificationActivity extends Activity implements NotificationC view.invalidate(); } } + } else if (id == MessagesController.contactsDidLoaded) { + updateSubtitle(); } } @@ -962,6 +965,7 @@ public class PopupNotificationActivity extends Activity implements NotificationC NotificationCenter.getInstance().removeObserver(this, MessagesController.updateInterfaces); NotificationCenter.getInstance().removeObserver(this, MediaController.audioProgressDidChanged); NotificationCenter.getInstance().removeObserver(this, MediaController.audioDidReset); + NotificationCenter.getInstance().removeObserver(this, MessagesController.contactsDidLoaded); NotificationCenter.getInstance().removeObserver(this, 999); if (chatActivityEnterView != null) { chatActivityEnterView.onDestroy(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java index 3ac4d235..1c4d1697 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java @@ -293,7 +293,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter } else if (i == notificationRow) { presentFragment(new SettingsNotificationsActivity()); } else if (i == blockedRow) { - presentFragment(new SettingsBlockedUsers()); + presentFragment(new SettingsBlockedUsersActivity()); } else if (i == backgroundRow) { presentFragment(new SettingsWallpapersActivity()); } else if (i == askQuestionRow) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsBlockedUsers.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsBlockedUsersActivity.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/ui/SettingsBlockedUsers.java rename to TMessagesProj/src/main/java/org/telegram/ui/SettingsBlockedUsersActivity.java index 54345daf..29afea2a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsBlockedUsers.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsBlockedUsersActivity.java @@ -38,7 +38,7 @@ import org.telegram.ui.Views.ActionBar.BaseFragment; import java.util.ArrayList; import java.util.HashMap; -public class SettingsBlockedUsers extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, ContactsActivity.ContactsActivityDelegate { +public class SettingsBlockedUsersActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, ContactsActivity.ContactsActivityDelegate { private ListView listView; private ListAdapter listViewAdapter; private boolean loading; @@ -82,7 +82,7 @@ public class SettingsBlockedUsers extends BaseFragment implements NotificationCe args.putBoolean("usersAsSections", true); args.putBoolean("returnAsResult", true); ContactsActivity fragment = new ContactsActivity(args); - fragment.setDelegate(SettingsBlockedUsers.this); + fragment.setDelegate(SettingsBlockedUsersActivity.this); presentFragment(fragment); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsNotificationsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsNotificationsActivity.java index 4e504247..9b7298bb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsNotificationsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsNotificationsActivity.java @@ -28,6 +28,7 @@ import android.widget.TextView; import android.widget.Toast; import org.telegram.android.LocaleController; +import org.telegram.android.NotificationsController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.TLObject; import org.telegram.messenger.TLRPC; @@ -67,7 +68,8 @@ public class SettingsNotificationsActivity extends BaseFragment implements Notif private int inappPreviewRow; private int eventsSectionRow; private int contactJoinedRow; - private int pebbleSectionRow; + private int otherSectionRow; + private int badgeNumberRow; private int pebbleAlertRow; private int resetSectionRow; private int resetNotificationsRow; @@ -96,7 +98,8 @@ public class SettingsNotificationsActivity extends BaseFragment implements Notif inappPreviewRow = rowCount++; eventsSectionRow = rowCount++; contactJoinedRow = rowCount++; - pebbleSectionRow = rowCount++; + otherSectionRow = rowCount++; + badgeNumberRow = rowCount++; pebbleAlertRow = rowCount++; resetSectionRow = rowCount++; resetNotificationsRow = rowCount++; @@ -279,6 +282,14 @@ public class SettingsNotificationsActivity extends BaseFragment implements Notif editor.putBoolean("EnablePebbleNotifications", !enabled); editor.commit(); listView.invalidateViews(); + } else if (i == badgeNumberRow) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + boolean enabled = preferences.getBoolean("badgeNumber", true); + editor.putBoolean("badgeNumber", !enabled); + editor.commit(); + listView.invalidateViews(); + NotificationsController.getInstance().setBadgeEnabled(!enabled); } else if (i == notificationsServiceRow) { final SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); boolean enabled = preferences.getBoolean("pushService", true); @@ -480,7 +491,7 @@ public class SettingsNotificationsActivity extends BaseFragment implements Notif @Override public boolean isEnabled(int i) { - return !(i == messageSectionRow || i == groupSectionRow || i == inappSectionRow || i == eventsSectionRow || i == pebbleSectionRow || i == resetSectionRow); + return !(i == messageSectionRow || i == groupSectionRow || i == inappSectionRow || i == eventsSectionRow || i == otherSectionRow || i == resetSectionRow); } @Override @@ -520,8 +531,8 @@ public class SettingsNotificationsActivity extends BaseFragment implements Notif textView.setText(LocaleController.getString("InAppNotifications", R.string.InAppNotifications)); } else if (i == eventsSectionRow) { textView.setText(LocaleController.getString("Events", R.string.Events)); - } else if (i == pebbleSectionRow) { - textView.setText(LocaleController.getString("Pebble", R.string.Pebble)); + } else if (i == otherSectionRow) { + textView.setText(LocaleController.getString("PhoneOther", R.string.PhoneOther)); } else if (i == resetSectionRow) { textView.setText(LocaleController.getString("Reset", R.string.Reset)); } @@ -581,12 +592,16 @@ public class SettingsNotificationsActivity extends BaseFragment implements Notif divider.setVisibility(View.INVISIBLE); } else if (i == pebbleAlertRow) { enabled = preferences.getBoolean("EnablePebbleNotifications", false); - textView.setText(LocaleController.getString("Alert", R.string.Alert)); + textView.setText(LocaleController.getString("Pebble", R.string.Pebble)); divider.setVisibility(View.INVISIBLE); } else if (i == notificationsServiceRow) { enabled = preferences.getBoolean("pushService", true); textView.setText(LocaleController.getString("NotificationsService", R.string.NotificationsService)); divider.setVisibility(View.INVISIBLE); + } else if (i == badgeNumberRow) { + enabled = preferences.getBoolean("badgeNumber", true); + textView.setText(LocaleController.getString("BadgeNumber", R.string.BadgeNumber)); + divider.setVisibility(View.VISIBLE); } if (enabled) { checkButton.setImageResource(R.drawable.btn_check_on); @@ -664,13 +679,13 @@ public class SettingsNotificationsActivity extends BaseFragment implements Notif @Override public int getItemViewType(int i) { - if (i == messageSectionRow || i == groupSectionRow || i == inappSectionRow || i == eventsSectionRow || i == pebbleSectionRow || i == resetSectionRow) { + if (i == messageSectionRow || i == groupSectionRow || i == inappSectionRow || i == eventsSectionRow || i == otherSectionRow || i == resetSectionRow) { return 0; } else if (i == messageAlertRow || i == messagePreviewRow || i == messageVibrateRow || i == groupAlertRow || i == groupPreviewRow || i == groupVibrateRow || i == inappSoundRow || i == inappVibrateRow || i == inappPreviewRow || i == contactJoinedRow || - i == pebbleAlertRow || i == notificationsServiceRow) { + i == pebbleAlertRow || i == notificationsServiceRow || i == badgeNumberRow) { return 1; } else if (i == messageLedRow || i == groupLedRow) { return 3; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/VideoEditorActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/VideoEditorActivity.java new file mode 100644 index 00000000..2774c356 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/VideoEditorActivity.java @@ -0,0 +1,552 @@ +/* + * This is the source code of Telegram for Android v. 1.7.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2014. + */ + +package org.telegram.ui; + +import android.content.res.Configuration; +import android.media.MediaPlayer; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import com.coremedia.iso.boxes.Container; +import com.googlecode.mp4parser.authoring.Movie; +import com.googlecode.mp4parser.authoring.Track; +import com.googlecode.mp4parser.authoring.builder.DefaultMp4Builder; +import com.googlecode.mp4parser.authoring.container.mp4.MovieCreator; +import com.googlecode.mp4parser.authoring.tracks.CroppedTrack; + +import org.telegram.android.AndroidUtilities; +import org.telegram.android.LocaleController; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; +import org.telegram.ui.Views.ActionBar.ActionBarLayer; +import org.telegram.ui.Views.ActionBar.ActionBarMenu; +import org.telegram.ui.Views.ActionBar.BaseFragment; +import org.telegram.ui.Views.VideoSeekBarView; +import org.telegram.ui.Views.VideoTimelineView; + +import java.io.File; +import java.io.FileOutputStream; +import java.nio.channels.FileChannel; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +public class VideoEditorActivity extends BaseFragment implements SurfaceHolder.Callback { + + private MediaPlayer videoPlayer = null; + private SurfaceHolder surfaceHolder = null; + private VideoTimelineView videoTimelineView = null; + private View videoContainerView = null; + private TextView originalSizeTextView = null; + private TextView editedSizeTextView = null; + private View textContainerView = null; + private ImageView playButton = null; + private VideoSeekBarView videoSeekBarView = null; + + private boolean initied = false; + private String videoPath = null; + private int videoWidth; + private int videoHeight; + private float lastProgress = 0; + private boolean needSeek = false; + private VideoEditorActivityDelegate delegate; + + public interface VideoEditorActivityDelegate { + public abstract void didFinishedVideoConverting(String videoPath); + } + + private Runnable progressRunnable = new Runnable() { + @Override + public void run() { + while (videoPlayer.isPlaying()) { + Utilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + if (videoPlayer.isPlaying()) { + float startTime = videoTimelineView.getLeftProgress() * videoPlayer.getDuration(); + float endTime = videoTimelineView.getRightProgress() * videoPlayer.getDuration(); + if (startTime == endTime) { + startTime = endTime - 0.01f; + } + float progress = (videoPlayer.getCurrentPosition() - startTime) / (endTime - startTime); + if (progress > lastProgress) { + videoSeekBarView.setProgress(progress); + lastProgress = progress; + } + if (videoPlayer.getCurrentPosition() >= endTime) { + try { + videoPlayer.pause(); + onPlayComplete(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + } + }); + try { + Thread.sleep(50); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + }; + + public VideoEditorActivity(Bundle args) { + super(args); + videoPath = args.getString("videoPath"); + } + + @Override + public boolean onFragmentCreate() { + if (videoPath == null) { + return false; + } + videoPlayer = new MediaPlayer(); + videoPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mp) { + Utilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + onPlayComplete(); + } + }); + } + }); + return super.onFragmentCreate(); + } + + @Override + public void onFragmentDestroy() { + if (videoTimelineView != null) { + videoTimelineView.destroy(); + } + super.onFragmentDestroy(); + } + + @Override + public View createView(LayoutInflater inflater, ViewGroup container) { + if (fragmentView == null) { + actionBarLayer.setBackgroundColor(0xff333333); + actionBarLayer.setItemsBackground(R.drawable.bar_selector_white); + actionBarLayer.setDisplayHomeAsUpEnabled(true, R.drawable.photo_back); + actionBarLayer.setTitle(LocaleController.getString("EditVideo", R.string.EditVideo)); + actionBarLayer.setActionBarMenuOnItemClick(new ActionBarLayer.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + } else if (id == 1) { + try { + startConvert(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + }); + + ActionBarMenu menu = actionBarLayer.createMenu(); + View doneItem = menu.addItemResource(1, R.layout.group_create_done_layout); + + TextView doneTextView = (TextView)doneItem.findViewById(R.id.done_button); + doneTextView.setText(LocaleController.getString("Done", R.string.Done).toUpperCase()); + + fragmentView = inflater.inflate(R.layout.video_editor_layout, container, false); + originalSizeTextView = (TextView)fragmentView.findViewById(R.id.original_size); + editedSizeTextView = (TextView)fragmentView.findViewById(R.id.edited_size); + videoContainerView = fragmentView.findViewById(R.id.video_container); + textContainerView = fragmentView.findViewById(R.id.info_container); + + videoTimelineView = (VideoTimelineView)fragmentView.findViewById(R.id.video_timeline_view); + videoTimelineView.setVideoPath(videoPath); + videoTimelineView.setDelegate(new VideoTimelineView.VideoTimelineViewDelegate() { + @Override + public void onLeftProgressChanged(float progress) { + try { + if (videoPlayer.isPlaying()) { + videoPlayer.pause(); + playButton.setImageResource(R.drawable.video_play); + } + videoPlayer.setOnSeekCompleteListener(null); + videoPlayer.seekTo((int)(videoPlayer.getDuration() * progress)); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + needSeek = true; + videoSeekBarView.setProgress(0); + updateVideoEditedInfo(); + } + + @Override + public void onRifhtProgressChanged(float progress) { + try { + if (videoPlayer.isPlaying()) { + videoPlayer.pause(); + playButton.setImageResource(R.drawable.video_play); + } + videoPlayer.setOnSeekCompleteListener(null); + videoPlayer.seekTo((int)(videoPlayer.getDuration() * progress)); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + needSeek = true; + videoSeekBarView.setProgress(0); + updateVideoEditedInfo(); + } + }); + + videoSeekBarView = (VideoSeekBarView)fragmentView.findViewById(R.id.video_seekbar); + videoSeekBarView.delegate = new VideoSeekBarView.SeekBarDelegate() { + @Override + public void onSeekBarDrag(float progress) { + if (videoPlayer.isPlaying()) { + try { + float prog = videoTimelineView.getLeftProgress() + (videoTimelineView.getRightProgress() - videoTimelineView.getLeft()) * progress; + videoPlayer.seekTo((int)(videoPlayer.getDuration() * prog)); + lastProgress = progress; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } else { + lastProgress = progress; + needSeek = true; + } + } + }; + + playButton = (ImageView)fragmentView.findViewById(R.id.play_button); + playButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (surfaceHolder.isCreating()) { + return; + } + play(); + } + }); + + SurfaceView surfaceView = (SurfaceView) fragmentView.findViewById(R.id.video_view); + surfaceHolder = surfaceView.getHolder(); + surfaceHolder.addCallback(this); + surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); + surfaceHolder.setFixedSize(270, 480); + + updateVideoOriginalInfo(); + updateVideoEditedInfo(); + } else { + ViewGroup parent = (ViewGroup)fragmentView.getParent(); + if (parent != null) { + parent.removeView(fragmentView); + } + } + return fragmentView; + } + + @Override + public void onResume() { + super.onResume(); + fixLayout(); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + fixLayout(); + } + + @Override + public void surfaceCreated(SurfaceHolder holder) { + videoPlayer.setDisplay(holder); + try { + videoPlayer.setDataSource(videoPath); + videoPlayer.prepare(); + videoWidth = videoPlayer.getVideoWidth(); + videoHeight = videoPlayer.getVideoHeight(); + fixVideoSize(); + videoPlayer.seekTo((int) (videoTimelineView.getLeftProgress() * videoPlayer.getDuration())); + initied = true; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + updateVideoOriginalInfo(); + updateVideoEditedInfo(); + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + videoPlayer.setDisplay(null); + } + + private void onPlayComplete() { + playButton.setImageResource(R.drawable.video_play); + videoSeekBarView.setProgress(0); + try { + videoPlayer.seekTo((int) (videoTimelineView.getLeftProgress() * videoPlayer.getDuration())); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + private void updateVideoOriginalInfo() { + if (!initied || originalSizeTextView == null) { + return; + } + File file = new File(videoPath); + String videoDimension = String.format("%dx%d", videoPlayer.getVideoWidth(), videoPlayer.getVideoHeight()); + int minutes = videoPlayer.getDuration() / 1000 / 60; + int seconds = (int)Math.ceil(videoPlayer.getDuration() / 1000) - minutes * 60; + String videoTimeSize = String.format("%d:%02d, %s", minutes, seconds, Utilities.formatFileSize(file.length())); + originalSizeTextView.setText(String.format("%s: %s, %s", LocaleController.getString("OriginalVideo", R.string.OriginalVideo), videoDimension, videoTimeSize)); + } + + private void updateVideoEditedInfo() { + if (!initied || editedSizeTextView == null) { + return; + } + File file = new File(videoPath); + long size = file.length(); + float videoWidth = videoPlayer.getVideoWidth(); + float videoHeight = videoPlayer.getVideoHeight(); + if (videoWidth > 640 || videoHeight > 640) { + float scale = videoWidth > videoHeight ? 640.0f / videoWidth : 640.0f / videoHeight; + videoWidth *= scale; + videoHeight *= scale; + size *= (scale * scale); + } + String videoDimension = String.format("%dx%d", (int)videoWidth, (int)videoHeight); + int minutes = videoPlayer.getDuration() / 1000 / 60; + int seconds = (int)Math.ceil(videoPlayer.getDuration() / 1000) - minutes * 60; + String videoTimeSize = String.format("%d:%02d, ~%s", minutes, seconds, Utilities.formatFileSize(size)); + editedSizeTextView.setText(String.format("%s: %s, %s", LocaleController.getString("EditedVideo", R.string.EditedVideo), videoDimension, videoTimeSize)); + } + + private void fixVideoSize() { + if (videoWidth == 0 || videoHeight == 0 || fragmentView == null || getParentActivity() == null) { + return; + } + int viewHeight = 0; + if (!Utilities.isTablet(getParentActivity()) && getParentActivity().getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { + viewHeight = AndroidUtilities.displaySize.y - AndroidUtilities.statusBarHeight - AndroidUtilities.dp(40); + } else { + viewHeight = AndroidUtilities.displaySize.y - AndroidUtilities.statusBarHeight - AndroidUtilities.dp(48); + } + + int width = 0; + int height = 0; + if (getParentActivity().getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { + width = AndroidUtilities.displaySize.x - AndroidUtilities.displaySize.x / 2 - AndroidUtilities.dp(24); + height = viewHeight - AndroidUtilities.dp(32); + } else { + width = AndroidUtilities.displaySize.x; + height = viewHeight - AndroidUtilities.dp(176); + } + + float wr = (float)width / (float)videoWidth; + float hr = (float)height / (float)videoHeight; + float ar = (float)videoWidth / (float)videoHeight; + + if (wr > hr) { + width = (int) (height * ar); + } else { + height = (int) (width / ar); + } + + surfaceHolder.setFixedSize(width, height); + } + + private void fixLayout() { + if (originalSizeTextView == null) { + return; + } + originalSizeTextView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + originalSizeTextView.getViewTreeObserver().removeOnPreDrawListener(this); + if (getParentActivity().getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { + FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams)videoContainerView.getLayoutParams(); + layoutParams.topMargin = AndroidUtilities.dp(16); + layoutParams.bottomMargin = AndroidUtilities.dp(16); + layoutParams.width = AndroidUtilities.displaySize.x / 2 - AndroidUtilities.dp(24); + layoutParams.leftMargin = AndroidUtilities.dp(16); + videoContainerView.setLayoutParams(layoutParams); + + layoutParams = (FrameLayout.LayoutParams)textContainerView.getLayoutParams(); + layoutParams.height = FrameLayout.LayoutParams.MATCH_PARENT; + layoutParams.width = AndroidUtilities.displaySize.x / 2 - AndroidUtilities.dp(24); + layoutParams.leftMargin = AndroidUtilities.displaySize.x / 2 + AndroidUtilities.dp(8); + layoutParams.rightMargin = AndroidUtilities.dp(16); + layoutParams.topMargin = AndroidUtilities.dp(16); + textContainerView.setLayoutParams(layoutParams); + } else { + FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams)videoContainerView.getLayoutParams(); + layoutParams.topMargin = AndroidUtilities.dp(16); + layoutParams.bottomMargin = AndroidUtilities.dp(160); + layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT; + layoutParams.leftMargin = 0; + videoContainerView.setLayoutParams(layoutParams); + + layoutParams = (FrameLayout.LayoutParams)textContainerView.getLayoutParams(); + layoutParams.height = AndroidUtilities.dp(143); + layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT; + layoutParams.leftMargin = 0; + layoutParams.rightMargin = 0; + layoutParams.topMargin = 0; + textContainerView.setLayoutParams(layoutParams); + } + fixVideoSize(); + videoTimelineView.clearFrames(); + return false; + } + }); + } + + private void play() { + if (videoPlayer.isPlaying()) { + videoPlayer.pause(); + playButton.setImageResource(R.drawable.video_play); + } else { + try { + playButton.setImageDrawable(null); + lastProgress = 0; + if (needSeek) { + float prog = videoTimelineView.getLeftProgress() + (videoTimelineView.getRightProgress() - videoTimelineView.getLeft()) * videoSeekBarView.getProgress(); + videoPlayer.seekTo((int)(videoPlayer.getDuration() * prog)); + needSeek = false; + } + videoPlayer.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() { + @Override + public void onSeekComplete(MediaPlayer mp) { + float startTime = videoTimelineView.getLeftProgress() * videoPlayer.getDuration(); + float endTime = videoTimelineView.getRightProgress() * videoPlayer.getDuration(); + if (startTime == endTime) { + startTime = endTime - 0.01f; + } + lastProgress = (videoPlayer.getCurrentPosition() - startTime) / (endTime - startTime); + videoSeekBarView.setProgress(lastProgress); + } + }); + videoPlayer.start(); + new Thread(progressRunnable).start(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + + public void setDelegate(VideoEditorActivityDelegate delegate) { + this.delegate = delegate; + } + + private void startConvert() throws Exception { + Movie movie = MovieCreator.build(videoPath); + + List tracks = movie.getTracks(); + movie.setTracks(new LinkedList()); + + double startTime = videoTimelineView.getLeftProgress() * videoPlayer.getDuration() / 1000.0; + double endTime = videoTimelineView.getRightProgress() * videoPlayer.getDuration() / 1000.0; + + boolean timeCorrected = false; + for (Track track : tracks) { + if (track.getSyncSamples() != null && track.getSyncSamples().length > 0) { + if (timeCorrected) { + throw new RuntimeException("The startTime has already been corrected by another track with SyncSample. Not Supported."); + } + startTime = correctTimeToSyncSample(track, startTime, false); + endTime = correctTimeToSyncSample(track, endTime, true); + timeCorrected = true; + } + } + + for (Track track : tracks) { + long currentSample = 0; + double currentTime = 0; + double lastTime = 0; + long startSample = -1; + long endSample = -1; + + for (int i = 0; i < track.getSampleDurations().length; i++) { + long delta = track.getSampleDurations()[i]; + if (currentTime > lastTime && currentTime <= startTime) { + startSample = currentSample; + } + if (currentTime > lastTime && currentTime <= endTime) { + endSample = currentSample; + } + lastTime = currentTime; + currentTime += (double) delta / (double) track.getTrackMetaData().getTimescale(); + currentSample++; + } + movie.addTrack(new CroppedTrack(track, startSample, endSample)); + } + long start1 = System.currentTimeMillis(); + Container out = new DefaultMp4Builder().build(movie); + long start2 = System.currentTimeMillis(); + + String fileName = Integer.MIN_VALUE + "_" + UserConfig.lastLocalId + ".mp4"; + UserConfig.lastLocalId--; + File cacheFile = new File(AndroidUtilities.getCacheDir(), fileName); + UserConfig.saveConfig(false); + + FileOutputStream fos = new FileOutputStream(cacheFile); + FileChannel fc = fos.getChannel(); + out.writeContainer(fc); + + fc.close(); + fos.close(); + if (delegate != null) { + delegate.didFinishedVideoConverting(cacheFile.getAbsolutePath()); + finishFragment(); + } + } + + private static double correctTimeToSyncSample(Track track, double cutHere, boolean next) { + double[] timeOfSyncSamples = new double[track.getSyncSamples().length]; + long currentSample = 0; + double currentTime = 0; + for (int i = 0; i < track.getSampleDurations().length; i++) { + long delta = track.getSampleDurations()[i]; + if (Arrays.binarySearch(track.getSyncSamples(), currentSample + 1) >= 0) { + timeOfSyncSamples[Arrays.binarySearch(track.getSyncSamples(), currentSample + 1)] = currentTime; + } + currentTime += (double) delta / (double) track.getTrackMetaData().getTimescale(); + currentSample++; + } + double previous = 0; + for (double timeOfSyncSample : timeOfSyncSamples) { + if (timeOfSyncSample > cutHere) { + if (next) { + return timeOfSyncSample; + } else { + return previous; + } + } + previous = timeOfSyncSample; + } + return timeOfSyncSamples[timeOfSyncSamples.length - 1]; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/ClippingImageView.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/ClippingImageView.java index 69b04d21..543272ba 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/ClippingImageView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/ClippingImageView.java @@ -15,6 +15,8 @@ import android.graphics.Paint; import android.graphics.Rect; import android.view.View; +import org.telegram.messenger.FileLog; + public class ClippingImageView extends View { private int clipBottom; private int clipLeft; @@ -64,7 +66,11 @@ public class ClippingImageView extends View { canvas.save(); canvas.clipRect(clipLeft / getScaleY(), clipTop / getScaleY(), getWidth() - clipRight / getScaleY(), getHeight() - clipBottom / getScaleY()); drawRect.set(0, 0, getWidth(), getHeight()); - canvas.drawBitmap(this.bmp, null, drawRect, this.paint); + try { + canvas.drawBitmap(this.bmp, null, drawRect, this.paint); + } catch (Exception e) { + FileLog.e("tmessages", e); + } canvas.restore(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/VideoSeekBarView.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/VideoSeekBarView.java new file mode 100644 index 00000000..4bdab183 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/VideoSeekBarView.java @@ -0,0 +1,133 @@ +/* + * This is the source code of Telegram for Android v. 1.7.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2014. + */ + +package org.telegram.ui.Views; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; + +import org.telegram.android.AndroidUtilities; +import org.telegram.messenger.R; + +public class VideoSeekBarView extends View { + + private static Drawable thumbDrawable1; + private static Drawable thumbDrawablePressed1; + private static Paint innerPaint1 = new Paint(); + private static int thumbWidth; + private static int thumbHeight; + private int thumbDX = 0; + private float progress = 0; + private boolean pressed = false; + public SeekBarDelegate delegate; + + public abstract interface SeekBarDelegate { + public void onSeekBarDrag(float progress); + } + + private void init(Context context) { + if (thumbDrawable1 == null) { + thumbDrawable1 = context.getResources().getDrawable(R.drawable.playback); + thumbDrawablePressed1 = context.getResources().getDrawable(R.drawable.playback_active); + innerPaint1.setColor(0x99999999); + thumbWidth = thumbDrawable1.getIntrinsicWidth(); + thumbHeight = thumbDrawable1.getIntrinsicHeight(); + } + } + + public VideoSeekBarView(Context context) { + super(context); + init(context); + } + + public VideoSeekBarView(Context context, AttributeSet attrs) { + super(context, attrs); + init(context); + } + + public VideoSeekBarView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (event == null) { + return false; + } + float x = event.getX(); + float y = event.getY(); + float thumbX = (int)((getMeasuredWidth() - thumbWidth) * progress); + if (event.getAction() == MotionEvent.ACTION_DOWN) { + int additionWidth = (getMeasuredHeight() - thumbWidth) / 2; + if (thumbX - additionWidth <= x && x <= thumbX + thumbWidth + additionWidth && y >= 0 && y <= getMeasuredHeight()) { + pressed = true; + thumbDX = (int)(x - thumbX); + getParent().requestDisallowInterceptTouchEvent(true); + invalidate(); + return true; + } + } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { + if (pressed) { + if (event.getAction() == MotionEvent.ACTION_UP && delegate != null) { + delegate.onSeekBarDrag(thumbX / (float)(getMeasuredWidth() - thumbWidth)); + } + pressed = false; + invalidate(); + return true; + } + } else if (event.getAction() == MotionEvent.ACTION_MOVE) { + if (pressed) { + thumbX = (int)(x - thumbDX); + if (thumbX < 0) { + thumbX = 0; + } else if (thumbX > getMeasuredWidth() - thumbWidth) { + thumbX = getMeasuredWidth() - thumbWidth; + } + progress = thumbX / (getMeasuredWidth() - thumbWidth); + invalidate(); + return true; + } + } + return false; + } + + public void setProgress(float progress) { + if (progress < 0) { + progress = 0; + } else if (progress > 1) { + progress = 1; + } + this.progress = progress; + invalidate(); + } + + public float getProgress() { + return progress; + } + + @Override + protected void onDraw(Canvas canvas) { + Drawable thumb = null; + if (!pressed) { + thumb = thumbDrawable1; + } else { + thumb = thumbDrawablePressed1; + } + int y = (getMeasuredHeight() - thumbHeight) / 2; + int thumbX = (int)((getMeasuredWidth() - thumbWidth) * progress); + canvas.drawRect(thumbWidth / 2, getMeasuredHeight() / 2 - AndroidUtilities.dp(1), getMeasuredWidth() - thumbWidth / 2, getMeasuredHeight() / 2 + AndroidUtilities.dp(1), innerPaint1); + thumb.setBounds(thumbX, y, thumbX + thumbWidth, y + thumbHeight); + thumb.draw(canvas); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/VideoTimelineView.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/VideoTimelineView.java new file mode 100644 index 00000000..f8fe8e21 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/VideoTimelineView.java @@ -0,0 +1,285 @@ +/* + * This is the source code of Telegram for Android v. 1.7.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2014. + */ + +package org.telegram.ui.Views; + +import android.annotation.TargetApi; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.media.MediaMetadataRetriever; +import android.os.AsyncTask; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; + +import org.telegram.android.AndroidUtilities; +import org.telegram.messenger.FileLog; + +import java.util.ArrayList; + +@TargetApi(10) +public class VideoTimelineView extends View { + private long videoLength = 0; + private float progressLeft = 0; + private float progressRight = 1; + private Paint paint; + private Paint paint2; + private boolean pressedLeft = false; + private boolean pressedRight = false; + private float pressDx = 0; + private MediaMetadataRetriever mediaMetadataRetriever = null; + private VideoTimelineViewDelegate delegate = null; + private ArrayList frames = new ArrayList(); + private AsyncTask currentTask = null; + private static final Integer sync = 1; + private long frameTimeOffset = 0; + private int frameWidth = 0; + private int frameHeight = 0; + private int framesToLoad = 0; + + public abstract interface VideoTimelineViewDelegate { + public void onLeftProgressChanged(float progress); + public void onRifhtProgressChanged(float progress); + } + + private void init() { + paint = new Paint(); + paint.setColor(0xff66d1ee); + paint2 = new Paint(); + paint2.setColor(0x2266d1ee); + } + + public VideoTimelineView(Context context) { + super(context); + init(); + } + + public VideoTimelineView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public VideoTimelineView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + public float getLeftProgress() { + return progressLeft; + } + + public float getRightProgress() { + return progressRight; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (event == null) { + return false; + } + float x = event.getX(); + float y = event.getY(); + + int width = getMeasuredWidth() - AndroidUtilities.dp(12); + int startX = (int)(width * progressLeft) + AndroidUtilities.dp(3); + int endX = (int)(width * progressRight) + AndroidUtilities.dp(9); + + if (event.getAction() == MotionEvent.ACTION_DOWN) { + int additionWidth = AndroidUtilities.dp(12); + if (startX - additionWidth <= x && x <= startX + additionWidth && y >= 0 && y <= getMeasuredHeight()) { + pressedLeft = true; + pressDx = (int)(x - startX); + getParent().requestDisallowInterceptTouchEvent(true); + invalidate(); + return true; + } else if (endX - additionWidth <= x && x <= endX + additionWidth && y >= 0 && y <= getMeasuredHeight()) { + pressedRight = true; + pressDx = (int)(x - endX); + getParent().requestDisallowInterceptTouchEvent(true); + invalidate(); + return true; + } + } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { + if (pressedLeft) { + pressedLeft = false; + return true; + } else if (pressedRight) { + pressedRight = false; + return true; + } + } else if (event.getAction() == MotionEvent.ACTION_MOVE) { + if (pressedLeft) { + startX = (int)(x - pressDx); + if (startX < AndroidUtilities.dp(3)) { + startX = AndroidUtilities.dp(3); + } else if (startX > endX - AndroidUtilities.dp(6)) { + startX = endX - AndroidUtilities.dp(6); + } + progressLeft = (float)(startX - AndroidUtilities.dp(3)) / (float)width; + if (delegate != null) { + delegate.onLeftProgressChanged(progressLeft); + } + invalidate(); + return true; + } else if (pressedRight) { + endX = (int)(x - pressDx); + if (endX < startX + AndroidUtilities.dp(6)) { + endX = startX + AndroidUtilities.dp(6); + } else if (endX > width + AndroidUtilities.dp(9)) { + endX = width + AndroidUtilities.dp(9); + } + progressRight = (float)(endX - AndroidUtilities.dp(9)) / (float)width; + if (delegate != null) { + delegate.onRifhtProgressChanged(progressRight); + } + invalidate(); + return true; + } + } + return false; + } + + public void setVideoPath(String path) { + mediaMetadataRetriever = new MediaMetadataRetriever(); + mediaMetadataRetriever.setDataSource(path); + String duration = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); + videoLength = Long.parseLong(duration); + } + + public void setDelegate(VideoTimelineViewDelegate delegate) { + this.delegate = delegate; + } + + private void reloadFrames(int frameNum) { + if (mediaMetadataRetriever == null) { + return; + } + if (frameNum == 0) { + frameHeight = getMeasuredHeight() - AndroidUtilities.dp(4); + framesToLoad = getMeasuredWidth() / frameHeight; + frameWidth = (int)Math.ceil((float)getMeasuredWidth() / (float)framesToLoad); + frameTimeOffset = videoLength / framesToLoad; + } + currentTask = new AsyncTask() { + private int frameNum = 0; + + @Override + protected Bitmap doInBackground(Integer... objects) { + frameNum = objects[0]; + Bitmap bitmap = null; + if (isCancelled()) { + return null; + } + try { + bitmap = mediaMetadataRetriever.getFrameAtTime(frameTimeOffset * frameNum * 1000); + if (isCancelled()) { + return null; + } + if (bitmap != null) { + Bitmap result = Bitmap.createBitmap(frameWidth, frameHeight, bitmap.getConfig()); + Canvas canvas = new Canvas(result); + float scaleX = (float) frameWidth / (float) bitmap.getWidth(); + float scaleY = (float) frameHeight / (float) bitmap.getHeight(); + float scale = scaleX > scaleY ? scaleX : scaleY; + int w = (int) (bitmap.getWidth() * scale); + int h = (int) (bitmap.getHeight() * scale); + Rect srcRect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); + Rect destRect = new Rect((frameWidth - w) / 2, (frameHeight - h) / 2, w, h); + Paint paint = new Paint(); + canvas.drawBitmap(bitmap, srcRect, destRect, null); + bitmap.recycle(); + bitmap = result; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return bitmap; + } + + @Override + protected void onPostExecute(Bitmap bitmap) { + if (!isCancelled()) { + frames.add(bitmap); + invalidate(); + if (frameNum < framesToLoad) { + reloadFrames(frameNum + 1); + } + } + } + }; + + if (android.os.Build.VERSION.SDK_INT >= 11) { + currentTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, frameNum, null, null); + } else { + currentTask.execute(frameNum, null, null); + } + } + + public void destroy() { + synchronized (sync) { + try { + if (mediaMetadataRetriever != null) { + mediaMetadataRetriever.release(); + mediaMetadataRetriever = null; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + for (Bitmap bitmap : frames) { + if (bitmap != null) { + bitmap.recycle(); + } + } + frames.clear(); + if (currentTask != null) { + currentTask.cancel(true); + currentTask = null; + } + } + + public void clearFrames() { + for (Bitmap bitmap : frames) { + if (bitmap != null) { + bitmap.recycle(); + } + } + frames.clear(); + if (currentTask != null) { + currentTask.cancel(true); + currentTask = null; + } + invalidate(); + } + + @Override + protected void onDraw(Canvas canvas) { + if (frames.isEmpty() && currentTask == null) { + reloadFrames(0); + } else { + int offset = 0; + for (Bitmap bitmap : frames) { + if (bitmap != null) { + canvas.drawBitmap(bitmap, offset * frameWidth, AndroidUtilities.dp(2), null); + } + offset++; + } + } + int width = getMeasuredWidth() - AndroidUtilities.dp(12); + int startX = (int)(width * progressLeft); + int endX = (int)(width * progressRight); + canvas.drawRect(startX, 0, startX + AndroidUtilities.dp(6), getMeasuredHeight(), paint); + canvas.drawRect(endX + AndroidUtilities.dp(6), 0, endX + AndroidUtilities.dp(12), getMeasuredHeight(), paint); + canvas.drawRect(startX + AndroidUtilities.dp(6), AndroidUtilities.dp(4), endX + AndroidUtilities.dp(6), getMeasuredHeight() - AndroidUtilities.dp(4), paint2); + canvas.drawRect(startX + AndroidUtilities.dp(6), AndroidUtilities.dp(2), endX + AndroidUtilities.dp(6), AndroidUtilities.dp(4), paint); + canvas.drawRect(startX + AndroidUtilities.dp(6), getMeasuredHeight() - AndroidUtilities.dp(4), endX + AndroidUtilities.dp(6), getMeasuredHeight() - AndroidUtilities.dp(2), paint); + } +} diff --git a/TMessagesProj/src/main/res/drawable-hdpi/playback.png b/TMessagesProj/src/main/res/drawable-hdpi/playback.png new file mode 100644 index 00000000..1ca26fca Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/playback.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/playback_active.png b/TMessagesProj/src/main/res/drawable-hdpi/playback_active.png new file mode 100644 index 00000000..11760303 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/playback_active.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/video_play.png b/TMessagesProj/src/main/res/drawable-hdpi/video_play.png new file mode 100644 index 00000000..ce78ffab Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/video_play.png differ diff --git a/TMessagesProj/src/main/res/drawable-ldpi/playback.png b/TMessagesProj/src/main/res/drawable-ldpi/playback.png new file mode 100644 index 00000000..d82736e0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-ldpi/playback.png differ diff --git a/TMessagesProj/src/main/res/drawable-ldpi/playback_active.png b/TMessagesProj/src/main/res/drawable-ldpi/playback_active.png new file mode 100644 index 00000000..66d42bc1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-ldpi/playback_active.png differ diff --git a/TMessagesProj/src/main/res/drawable-ldpi/video_play.png b/TMessagesProj/src/main/res/drawable-ldpi/video_play.png new file mode 100644 index 00000000..ef7a3372 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-ldpi/video_play.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/playback.png b/TMessagesProj/src/main/res/drawable-mdpi/playback.png new file mode 100644 index 00000000..729c999e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/playback.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/playback_active.png b/TMessagesProj/src/main/res/drawable-mdpi/playback_active.png new file mode 100644 index 00000000..65c7c475 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/playback_active.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/video_play.png b/TMessagesProj/src/main/res/drawable-mdpi/video_play.png new file mode 100644 index 00000000..9e930642 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/video_play.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/playback.png b/TMessagesProj/src/main/res/drawable-xhdpi/playback.png new file mode 100644 index 00000000..8393b740 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/playback.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/playback_active.png b/TMessagesProj/src/main/res/drawable-xhdpi/playback_active.png new file mode 100644 index 00000000..48c99fb9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/playback_active.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/video_play.png b/TMessagesProj/src/main/res/drawable-xhdpi/video_play.png new file mode 100644 index 00000000..1837fef4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/video_play.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/playback.png b/TMessagesProj/src/main/res/drawable-xxhdpi/playback.png new file mode 100644 index 00000000..517920f7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/playback.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/playback_active.png b/TMessagesProj/src/main/res/drawable-xxhdpi/playback_active.png new file mode 100644 index 00000000..4ed86643 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/playback_active.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/video_play.png b/TMessagesProj/src/main/res/drawable-xxhdpi/video_play.png new file mode 100644 index 00000000..aa05f5c5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/video_play.png differ diff --git a/TMessagesProj/src/main/res/layout/chat_unread_layout.xml b/TMessagesProj/src/main/res/layout/chat_unread_layout.xml index 31c3cf3f..13832bbf 100644 --- a/TMessagesProj/src/main/res/layout/chat_unread_layout.xml +++ b/TMessagesProj/src/main/res/layout/chat_unread_layout.xml @@ -1,13 +1,15 @@ + android:layout_height="40dp" + android:layout_gravity="top"> + android:layout_marginTop="7dp" + android:layout_gravity="top"> diff --git a/TMessagesProj/src/main/res/layout/video_editor_layout.xml b/TMessagesProj/src/main/res/layout/video_editor_layout.xml new file mode 100644 index 00000000..9e314d52 --- /dev/null +++ b/TMessagesProj/src/main/res/layout/video_editor_layout.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TMessagesProj/src/main/res/values-ar/strings.xml b/TMessagesProj/src/main/res/values-ar/strings.xml index eac750ab..f3a3522e 100644 --- a/TMessagesProj/src/main/res/values-ar/strings.xml +++ b/TMessagesProj/src/main/res/values-ar/strings.xml @@ -275,6 +275,7 @@ فقط عندما تكون الشاشة تعمل فقط عندما تكون الشاشة مطفأة دائمًا أظهر الإشعارات المنبثقة + Badge Number لا توجد وسائط بعد @@ -298,6 +299,11 @@ جميع الصور لا توجد صور حتى الآن + + Edit Video + Original Video + Edited Video + التالي رجوع diff --git a/TMessagesProj/src/main/res/values-de/strings.xml b/TMessagesProj/src/main/res/values-de/strings.xml index 84cd6eb9..596ca1e1 100644 --- a/TMessagesProj/src/main/res/values-de/strings.xml +++ b/TMessagesProj/src/main/res/values-de/strings.xml @@ -275,6 +275,7 @@ Nur wenn Bildschirm „an“ Nur wenn Bildschirm „aus“ Popups immer anzeigen + Badge Number Noch keine geteilten Medien vorhanden @@ -298,6 +299,11 @@ Alle Fotos Noch keine Fotos + + Edit Video + Original Video + Edited Video + Weiter Zurück diff --git a/TMessagesProj/src/main/res/values-es/strings.xml b/TMessagesProj/src/main/res/values-es/strings.xml index 7844177d..035676ae 100644 --- a/TMessagesProj/src/main/res/values-es/strings.xml +++ b/TMessagesProj/src/main/res/values-es/strings.xml @@ -275,6 +275,7 @@ Sólo con pantalla encendida Sólo con pantalla apagada Siempre mostrar notificación emergente + Globo de notificación No hay fotos ni vídeos compartidos aún @@ -298,6 +299,11 @@ Todas No hay fotos aún + + Edit Video + Original Video + Edited Video + Siguiente Atrás diff --git a/TMessagesProj/src/main/res/values-it/strings.xml b/TMessagesProj/src/main/res/values-it/strings.xml index b1922974..e4595b3a 100644 --- a/TMessagesProj/src/main/res/values-it/strings.xml +++ b/TMessagesProj/src/main/res/values-it/strings.xml @@ -275,6 +275,7 @@ Solo con schermo acceso Solo con schermo spento Mostra sempre i popup + Badge Number Nessun media condiviso @@ -298,6 +299,11 @@ Tutte le foto Ancora nessuna foto + + Edit Video + Original Video + Edited Video + Avanti Indietro diff --git a/TMessagesProj/src/main/res/values-nl/strings.xml b/TMessagesProj/src/main/res/values-nl/strings.xml index 438f1cb4..e92fc5a4 100644 --- a/TMessagesProj/src/main/res/values-nl/strings.xml +++ b/TMessagesProj/src/main/res/values-nl/strings.xml @@ -275,6 +275,7 @@ Alleen wanneer scherm \"aan\" staat Alleen wanneer scherm \"uit\" staat Altijd popup tonen + Badge Number Nog geen media gedeeld @@ -298,6 +299,11 @@ Alle foto\'s Nog geen foto\'s + + Edit Video + Original Video + Edited Video + Volgende Vorige diff --git a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml index 29b169a3..dbcc8b02 100644 --- a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml +++ b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml @@ -275,6 +275,7 @@ Somente com a tela ligada Somente com a tela desligada Sempre mostrar popup + Badge Number Ainda não há mídia compartilhada @@ -298,6 +299,11 @@ Todas as Fotos Ainda não há fotos + + Edit Video + Original Video + Edited Video + Próximo Voltar diff --git a/TMessagesProj/src/main/res/values-pt-rPT/strings.xml b/TMessagesProj/src/main/res/values-pt-rPT/strings.xml index 8a2936a5..13f7a41d 100644 --- a/TMessagesProj/src/main/res/values-pt-rPT/strings.xml +++ b/TMessagesProj/src/main/res/values-pt-rPT/strings.xml @@ -275,6 +275,7 @@ Only when screen "on" Only when screen "off" Always show popup + Badge Number Ainda não há multimédia partilhado @@ -298,6 +299,11 @@ Todas as fotos Ainda não há fotos + + Edit Video + Original Video + Edited Video + Seguinte Anterior diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index 3ee81583..b5a9c597 100644 --- a/TMessagesProj/src/main/res/values/strings.xml +++ b/TMessagesProj/src/main/res/values/strings.xml @@ -275,6 +275,7 @@ Only when screen "on" Only when screen "off" Always show popup + Badge Number No shared media yet @@ -298,6 +299,11 @@ All Photos No photos yet + + Edit Video + Original Video + Edited Video + Next Back