This repository has been archived by the owner on Feb 4, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 94
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
🚧 Migrate share plugin to new Flutter plugin API (and a new class)
Also doing some minor refactoring of the share code
- Loading branch information
Showing
2 changed files
with
293 additions
and
244 deletions.
There are no files selected for viewing
263 changes: 19 additions & 244 deletions
263
android/app/src/main/java/com/example/openbook/MainActivity.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,260 +1,35 @@ | ||
package social.openbook.app; | ||
|
||
import android.content.Intent; | ||
import android.net.Uri; | ||
import android.os.Bundle; | ||
import android.util.Log; | ||
import android.webkit.MimeTypeMap; | ||
|
||
import java.io.ByteArrayInputStream; | ||
import java.io.File; | ||
import java.io.FileInputStream; | ||
import java.io.FileNotFoundException; | ||
import java.io.FileOutputStream; | ||
import java.io.InputStream; | ||
import java.io.IOException; | ||
import java.io.OutputStream; | ||
import java.util.ArrayList; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.UUID; | ||
|
||
import com.example.openbook.ImageConverter; | ||
import com.example.openbook.plugins.ImageConverterPlugin; | ||
import com.example.openbook.util.InputStreamSupplier; | ||
|
||
import com.example.openbook.plugins.SharePlugin; | ||
import io.flutter.embedding.android.FlutterActivity; | ||
import io.flutter.embedding.engine.plugins.PluginRegistry; | ||
import io.flutter.plugin.common.EventChannel; | ||
|
||
public class MainActivity extends FlutterActivity { | ||
private SharePlugin sharePlugin; | ||
|
||
public static final String SHARE_STREAM = "openbook.social/receive_share"; | ||
|
||
private EventChannel.EventSink eventSink = null; | ||
private List<Intent> intentBacklog = new ArrayList<>(); | ||
private boolean streamCanceled = false; | ||
|
||
@Override | ||
protected void onCreate(Bundle savedInstanceState) { | ||
super.onCreate(savedInstanceState); | ||
|
||
// Register the ImageConverterPlugin manually. It won't register automatically since it isn't added as a plugin via | ||
// our pubspec.yaml. | ||
// Note: getFlutterEngine() should not be null here since it is created in super.onCreate(). | ||
PluginRegistry pluginRegistry = getFlutterEngine().getPlugins(); | ||
pluginRegistry.add(new ImageConverterPlugin()); | ||
|
||
sendIntent(getIntent()); | ||
} | ||
|
||
@Override | ||
protected void onNewIntent(Intent intent) { | ||
super.onNewIntent(intent); | ||
sendIntent(intent); | ||
} | ||
|
||
private void sendIntent(Intent intent) { | ||
if (intent.getAction().equals(Intent.ACTION_SEND)) { | ||
if (eventSink == null) { | ||
if (!streamCanceled && !intentBacklog.contains(intent)) { | ||
intentBacklog.add(intent); | ||
} | ||
return; | ||
} | ||
|
||
Map<String, String> args = new HashMap<>(); | ||
|
||
try { | ||
if (intent.getType().startsWith("image/")) { | ||
Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM); | ||
if (!getExtensionFromUri(uri).equalsIgnoreCase("gif")) { | ||
args.put("image", copyImageToTempFile(uri).toString()); | ||
} else { | ||
args.put("video", copyVideoToTempFile(uri).toString()); | ||
} | ||
} else if (intent.getType().startsWith("video/")) { | ||
Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM); | ||
args.put("video", copyVideoToTempFile(uri).toString()); | ||
} else if (intent.getType().startsWith("text/")) { | ||
args.put("text", intent.getStringExtra(Intent.EXTRA_TEXT)); | ||
} else { | ||
Log.w(getClass().getSimpleName(), "unknown intent type \"" + intent.getType() + "\" received, ignoring"); | ||
return; | ||
} | ||
} catch (KeyedException e) { | ||
String msg; | ||
if (e.getCause() != null) { | ||
msg = String.format("an exception occurred while receiving share of type %s" + | ||
"%n %s%n caused by %s", intent.getType(), e.toString(), e.getCause().toString()); | ||
} else { | ||
msg = String.format("an exception occurred while receiving share of type %s" + | ||
"%n %s", intent.getType(), e.toString()); | ||
} | ||
String errorTextKey = getLocalizationKey(e); | ||
@Override | ||
protected void onCreate(Bundle savedInstanceState) { | ||
super.onCreate(savedInstanceState); | ||
|
||
args.put("error", errorTextKey); | ||
Log.w(getClass().getSimpleName(), msg); | ||
} | ||
// Register the ImageConverterPlugin manually. It won't register automatically since it isn't added as a plugin via | ||
// our pubspec.yaml. | ||
// Note: getFlutterEngine() should not be null here since it is created in super.onCreate(). | ||
PluginRegistry pluginRegistry = getFlutterEngine().getPlugins(); | ||
pluginRegistry.add(new ImageConverterPlugin()); | ||
sharePlugin = new SharePlugin(); | ||
pluginRegistry.add(sharePlugin); | ||
|
||
Log.i(getClass().getSimpleName(), "sending intent to flutter"); | ||
eventSink.success(args); | ||
// Pass the intent that created this activity to the share plugin, | ||
// just in case it is an ACTION_SEND intent with share data. | ||
sharePlugin.handleIntent(getIntent()); | ||
} | ||
} | ||
|
||
private Uri copyImageToTempFile(Uri imageUri) throws KeyedException { | ||
byte[] data = convertImage(imageUri); | ||
File imageFile = createTemporaryFile(".jpeg"); | ||
copyResourceToFile(() -> new ByteArrayInputStream(data), imageFile); | ||
|
||
return Uri.fromFile(imageFile); | ||
} | ||
|
||
private byte[] convertImage(Uri imageUri) throws KeyedException { | ||
try { | ||
InputStream imageStream; | ||
|
||
if (imageUri.getScheme().equals("content")) { | ||
imageStream = this.getContentResolver().openInputStream(imageUri); | ||
} else if (imageUri.getScheme().equals("file")) { | ||
imageStream = new FileInputStream(imageUri.getPath()); | ||
} else { | ||
throw new KeyedException(KeyedException.Key.UriSchemeNotSupported, imageUri.getScheme(), null); | ||
} | ||
|
||
return ImageConverter.convertImageData(imageStream, ImageConverter.TargetFormat.JPEG); | ||
} catch (FileNotFoundException e) { | ||
throw new KeyedException(KeyedException.Key.ReadFileMissing, e); | ||
} | ||
} | ||
|
||
private Uri copyVideoToTempFile(Uri videoUri) throws KeyedException { | ||
Uri result = null; | ||
|
||
if (videoUri.getScheme().equals("content") || videoUri.getScheme().equals("file")) { | ||
String extension = getExtensionFromUri(videoUri); | ||
File tempFile = createTemporaryFile("." + extension); | ||
copyResourceToFile(() -> getContentResolver().openInputStream(videoUri), tempFile); | ||
result = Uri.fromFile(tempFile); | ||
} else { | ||
throw new KeyedException(KeyedException.Key.UriSchemeNotSupported, videoUri.getScheme(), null); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
private String getExtensionFromUri(Uri uri) throws KeyedException { | ||
if (uri.getScheme().equals("content")) { | ||
String mime = this.getContentResolver().getType(uri); | ||
return MimeTypeMap.getSingleton().getExtensionFromMimeType(mime); | ||
} else if (uri.getScheme().equals("file")) { | ||
return MimeTypeMap.getFileExtensionFromUrl(uri.toString()); | ||
} else { | ||
throw new KeyedException(KeyedException.Key.UriSchemeNotSupported, uri.getScheme(), null); | ||
@Override | ||
protected void onNewIntent(Intent intent) { | ||
super.onNewIntent(intent); | ||
sharePlugin.handleIntent(intent); | ||
} | ||
} | ||
|
||
private File createTemporaryFile(String extension) throws KeyedException { | ||
String name = UUID.randomUUID().toString(); | ||
|
||
try { | ||
File directory = new File(getCacheDir(), "mediaCache"); | ||
if (!directory.exists()) { | ||
directory.mkdirs(); | ||
} | ||
|
||
return File.createTempFile(name, extension, directory); | ||
} catch (IOException e) { | ||
throw new KeyedException(KeyedException.Key.TempCreationFailed, e); | ||
} catch (SecurityException e) { | ||
throw new KeyedException(KeyedException.Key.TempCreationDenied, e); | ||
} | ||
} | ||
|
||
private void copyResourceToFile(InputStreamSupplier inputSupplier, File target) throws KeyedException { | ||
try (InputStream input = inputSupplier.get()) { | ||
try (OutputStream output = new FileOutputStream(target)) { | ||
byte[] data = new byte[1024]; | ||
int length; | ||
while ((length = input.read(data)) > 0) { | ||
output.write(data, 0, length); | ||
} | ||
} | ||
catch (FileNotFoundException e) { | ||
throw new KeyedException(KeyedException.Key.WriteTempMissing, e); | ||
} catch (IOException e) { | ||
throw new KeyedException(KeyedException.Key.WriteTempFailed, e); | ||
} catch (SecurityException e) { | ||
throw new KeyedException(KeyedException.Key.WriteTempDenied, e); | ||
} | ||
} | ||
catch (FileNotFoundException e) { | ||
throw new KeyedException(KeyedException.Key.ReadFileMissing, e); | ||
} catch (IOException e) { | ||
//Exception when closing the streams. Ignore. | ||
} | ||
} | ||
|
||
private String getLocalizationKey(KeyedException e) { | ||
String errorTextKey = ""; | ||
|
||
switch (e.getKey()) { | ||
case TempCreationFailed: | ||
case WriteTempFailed: | ||
case WriteTempMissing: | ||
errorTextKey = "error__receive_share_temp_write_failed"; | ||
break; | ||
case WriteTempDenied: | ||
case TempCreationDenied: | ||
errorTextKey = "error__receive_share_temp_write_denied"; | ||
break; | ||
case UriSchemeNotSupported: | ||
errorTextKey = "error__receive_share_invalid_uri_scheme"; | ||
break; | ||
case ReadFileMissing: | ||
errorTextKey = "error__receive_share_file_not_found"; | ||
break; | ||
} | ||
|
||
return errorTextKey; | ||
} | ||
} | ||
|
||
class KeyedException extends Exception { | ||
public enum Key { | ||
TempCreationFailed("Failed to create temporary file."), | ||
TempCreationDenied(TempCreationFailed.message), | ||
WriteTempDenied("Failed to write to temporary file."), | ||
WriteTempFailed(WriteTempDenied.message), | ||
WriteTempMissing(WriteTempDenied.message), | ||
ReadFileMissing("Failed to read the shared file."), | ||
UriSchemeNotSupported("Unsupported URI scheme: "); | ||
|
||
private String message; | ||
|
||
private Key(String msg) { | ||
message = msg; | ||
} | ||
} | ||
private final Key key; | ||
|
||
public KeyedException(Key key, Throwable cause) { | ||
super("", cause); | ||
this.key = key; | ||
} | ||
|
||
public KeyedException(Key key, String message, Throwable cause) { | ||
super(message, cause); | ||
this.key = key; | ||
} | ||
|
||
public Key getKey() { | ||
return key; | ||
} | ||
|
||
@Override | ||
public String getMessage() { | ||
return key.message + super.getMessage(); | ||
} | ||
} |
Oops, something went wrong.