Draft: Ability to send files / images on clipboard between Android and Linux clients (Android Version)
Summary
Link to the Linux part of this feature.
Reusing the code from composite upload and receive jobs, I implemented a feature to sync clipboard files between connected devices. It works on both Android and Linux, meaning that the file/image on Linux clipboard can be sent and set on Android clipboard and vice versa.
The solution is mostly ready, currently it lacks some notification, error and config handling because it seemed like those are subjects of discussion with project maintainers.
The things that should be discussed are the same as on the Linux merge request. The differences are:
- Where should the synced files be saved? (currently in the Downloads folder)
- Should the feature be blocked until the external storage permissions are granted? (currently not)
I am happy to modify any code based on comment / criticism and provide any additional info to the pull request.
Test Plan
Testing on Android phone and Linux machine was mostly successful on both files and pictures.
However, on LineageOS 21 (Android 14) when using stock Gallery3D app after setting the picture to the clipboard, it crashes the app because of android.os.DeadObjectException exception. Here's a video showing how it looks.
The log messages look like the following:
FATAL EXCEPTION: AsyncTask #2 Process: com.android.gallery3d, PID: 16942 java.lang.RuntimeException: An error occurred while executing doInBackground() at android.os.AsyncTask$4.done(AsyncTask.java:415) at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:381) at java.util.concurrent.FutureTask.setException(FutureTask.java:250) at java.util.concurrent.FutureTask.run(FutureTask.java:269) at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:305) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644) at java.lang.Thread.run(Thread.java:1012) Caused by: java.lang.IllegalArgumentException: column '_data' does not exist. Available columns: [] at android.database.AbstractCursor.getColumnIndexOrThrow(AbstractCursor.java:372) at android.database.CursorWrapper.getColumnIndexOrThrow(CursorWrapper.java:92) at com.android.gallery3d.filtershow.cache.ImageLoader.getDataColumn(ImageLoader.java:148) at com.android.gallery3d.filtershow.cache.ImageLoader.getLocalPathFromUri(ImageLoader.java:134) at com.android.gallery3d.filtershow.cache.ImageLoader.getExif(ImageLoader.java:654) at com.android.gallery3d.filtershow.imageshow.PrimaryImage.loadBitmap(PrimaryImage.java:305) at com.android.gallery3d.filtershow.FilterShowActivity$LoadBitmapTask.doInBackground(FilterShowActivity.java:1848) at com.android.gallery3d.filtershow.FilterShowActivity$LoadBitmapTask.doInBackground(FilterShowActivity.java:1838) at android.os.AsyncTask$3.call(AsyncTask.java:394)
and
Failed to deliver inset control state change to w=Window{631803c u0 com.android.gallery3d/com.android.gallery3d.filtershow.FilterShowActivity EXITING} android.os.DeadObjectException at android.os.BinderProxy.transactNative(Native Method) at android.os.BinderProxy.transact(BinderProxy.java:586) at android.view.IWindow$Stub$Proxy.insetsControlChanged(IWindow.java:485) at com.android.server.wm.WindowState.notifyInsetsControlChanged(WindowState.java:3776) at com.android.server.wm.InsetsStateController.lambda$notifyPendingInsetsControlChanged$3(InsetsStateController.java:376) at com.android.server.wm.InsetsStateController.$r8$lambda$MnP7XA1MDcyrUwoj0hcoT5hTO8E(InsetsStateController.java:0) at com.android.server.wm.InsetsStateController$$ExternalSyntheticLambda0.run(R8$$SyntheticClass:0) at com.android.server.wm.WindowAnimator.executeAfterPrepareSurfacesRunnables(WindowAnimator.java:314) at com.android.server.wm.WindowAnimator.animate(WindowAnimator.java:207) at com.android.server.wm.WindowAnimator.lambda$new$1(WindowAnimator.java:99) at com.android.server.wm.WindowAnimator.$r8$lambda$AS_wbK9i-bc6ocCFop7s9PnXP80(WindowAnimator.java:0) at com.android.server.wm.WindowAnimator$$ExternalSyntheticLambda1.doFrame(R8$$SyntheticClass:0) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1404) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1415) at android.view.Choreographer.doCallbacks(Choreographer.java:1015) at android.view.Choreographer.doFrame(Choreographer.java:941) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1389) at android.os.Handler.handleCallback(Handler.java:959) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loopOnce(Looper.java:232) at android.os.Looper.loop(Looper.java:317) at android.os.HandlerThread.run(HandlerThread.java:85) at com.android.server.ServiceThread.run(ServiceThread.java:46)
However, with other apps accepting clipboard files with different MIME types like Telegram, everything works fine. If you believe that's not relevant here, we can just drop this issue.