Managing and Searching for Files in Drive Kit - Huawei Developers

Managing and Searching for Files
Use Case
File management is a core capability of HUAWEI Drive Kit. It enables users to conveniently manage and edit files in Drive , including creating, listing, copying, modifying, deleting, recycling, and searching for files.
Development Procedure
Step 1 Call the Drive.Builder.build API to create the Drive object.
Code:
private Drive buildDrive() {
Drive service = new Drive.Builder(CredentialManager.getInstance().getCredential(), context).build();
return service;
}
Step 2 Call the Files APIs.
NOTE:
Constants used in the sample code:
private static final int DIRECT_UPLOAD_MAX_SIZE = 20 * 1024 * 1024;
private static final int DIRECT_DOWNLOAD_MAX_SIZE = 20 * 1024 * 1024;
Call the Files.create API to create a folder.
Code:
/**
* Create a folder.
*/
private File createDirectory() {
File directory = null;
try {
Drive drive = buildDrive();
Map<String, String> appProperties = new HashMap<>();
appProperties.put("appProperties", "property");
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd_HHmmss_SSS");
String dirName = formatter.format(new Date());
File file = new File();
file.setFileName(dirName)
.setAppSettings(appProperties)
.setMimeType("application/vnd.huawei-apps.folder");
directory = drive.files().create(file).execute();
} catch (Exception e) {
Logger.e(TAG, "createDirectory error: " + e.toString());
}
return directory;
}
Call the Files.create API to create a file. The are two methods for uploading a file: direct upload and resumable upload. The direct upload method allows a file of up to 20 MB to be uploaded while the resumable upload method does not have such a limit. The direct upload method is recommended for files smaller than 5 MB and the resumable upload method for files larger than 5 MB.
Method 1: Directly upload the file.
Code:
/**
* Upload a file. This method supports resumable upload.
* (The upload operation resumes after it is interrupted by a communication failure, for example, network interruption.)
*
* @param filePath File path.
* @param parentId ID of the folder to which the file is to be uploaded.
* @param thumbnailImageBuffer Thumbnail data.
* @param thumbnailMimeType MIME type of the thumbnail.
*/
private void createFile(String filePath, String parentId, byte[] thumbnailImageBuffer, String thumbnailMimeType) {
try {
if (filePath == null) {
Logger.e(TAG, "createFile error, filePath is null.");
return;
}
java.io.File file = new java.io.File(filePath);
FileContent fileContent = new FileContent(null, file);
// Set thumbnail data.
File.ContentExtras contentExtras = new File.ContentExtras();
File.ContentExtras.Thumbnail thumbnail = new File.ContentExtras.Thumbnail();
thumbnail.setContent(Base64.encodeBase64String(thumbnailImageBuffer));
thumbnail.setMimeType(thumbnailMimeType);
contentExtras.setThumbnail(thumbnail);
File content = new File()
.setFileName(file.getName())
.setParentFolder(Collections.singletonList(parentId))
.setContentExtras(contentExtras);
Drive drive = buildDrive();
Drive.Files.Create request = drive.files().create(content, fileContent);
boolean isDirectUpload = false;
// Directly upload the file if it is smaller than 20 MB.
if (file.length() < DIRECT_UPLOAD_MAX_SIZE) {
isDirectUpload = true;
}
// Set the upload mode. By default, resumable upload is used. If the file is smaller than 20 MB, set this parameter to true.
request.getMediaHttpUploader().setDirectUploadEnabled(isDirectUpload);
request.execute();
} catch (Exception e) {
Logger.e(TAG, "createFile exception: " + filePath + e.toString());
}
}
Method 2: Upload the file using InputStream.
Code:
/**
* Upload the file using InputStream.
*
* @param inputStream Input stream, from which file data is read.
* @param parentId ID of the folder to which the file is to be uploaded.
* @param mimeType MIME type, for example, image (jpeg) and video (mp4).
* @param inputStreamLength Stream length.
*/
private void createFile(InputStream inputStream, String parentId, String mimeType, int inputStreamLength) {
try {
InputStreamContent streamContent = new InputStreamContent(mimeType, inputStream);
streamContent.setLength(inputStreamLength);
File content = new File()
.setFileName("video.mp4")
.setParentFolder(Collections.singletonList(parentId));
Drive drive = buildDrive();
drive.files().create(content, streamContent).execute();
} catch (Exception e) {
Logger.e(TAG, "createFile exception: " + e.toString());
}
}
Call the Files.copy API to copy the file.
Code:
/**
* Copy the file to the designated folder.
*
* @param file File to be copied.
* @param dstDir Designated folder.
*/
private void copyFile(File file, ArrayList<String> dstDir) {
try {
File copyFile = new File();
if (file == null || file.getFileName() == null ||dstDir == null) {
Log.e(TAG, "copyFile arguments error");
sendHandleMessage(R.id.drive_files_button_copy, FAIL);
return;
}
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd_HHmmss");
String suffix = formatter.format(new Date());
copyFile.setFileName(file.getFileName() + "_copy" + "_" + suffix);
copyFile.setDescription("copyFile");
copyFile.setParentFolder(dstDir);
copyFile.setFavorite(true);
copyFile.setEditedTime(new DateTime(System.currentTimeMillis()));
Drive drive = buildDrive();
Drive.Files.Copy copyFileReq = drive.files().copy(file.getId(), copyFile);
copyFileReq.setFields("*");
File result = copyFileReq.execute();
} catch (IOException ex) {
Log.e(TAG, "copyFile error: " + ex.toString());
}
}
Call the Files.update API to modify the metadata of the file or folder.
Code:
/**
* Modify the file or folder. The value of MIMEType indicates whether it is a file or a folder.
*
* @param file File or folder to be modified.
*/
private void updateFile(File file) {
try {
if (file == null) {
Logger.e(TAG, "updateFile error, need to create file.");
return;
}
Drive drive = buildDrive();
File updateFile = new File();
updateFile.setFileName(file.getFileName() +"_update")
.setMimeType("application/vnd.huawei-apps.folder")
.setDescription("update folder")
.setFavorite(true);
drive.files().update(file.getId(), updateFile).execute();
} catch (Exception e) {
Logger.e(TAG, "updateFile error: " + e.toString());
}
}
Call the Files.update API to modify the metadata or content of the file.
Code:
/**
* Modify the file.
*
* @param oldFile File to be modified.
* @param newFilePath Path storing the modified file.
*/
private void updateFile(File oldFile, String newFilePath) {
try {
if (oldFile == null || TextUtils.isEmpty(newFilePath)) {
Logger.e(TAG, "updateFile error, need to create file.");
return;
}
java.io.File sourceFile = new java.io.File(newFilePath);
FileContent fileContent = new FileContent(null, sourceFile);
File updateFile = new File();
updateFile.setFileName(oldFile.getFileName() + "_update")
.setDescription("update folder")
.setFavorite(true);
Drive drive = buildDrive();
Drive.Files.Update update = drive.files().update(oldFile.getId(), updateFile, fileContent);
boolean isDirectUpload = false;
// Directly upload the file if it is smaller than 20 MB.
if (sourceFile.length() < DIRECT_UPLOAD_MAX_SIZE) {
isDirectUpload = true;
}
// Set the upload mode. By default, resumable upload is used. If the file is smaller than 20 MB, set this parameter to true.
update.getMediaHttpUploader().setDirectUploadEnabled(isDirectUpload);
update.execute();
} catch (Exception e) {
Logger.e(TAG, "updateFile error: " + e.toString());
}
}
Call the Files.delete API to permanently deletes a file or folder.
Code:
/**
* Permanently deletes a file or folder.
*
* @param file File or folder to be deleted.
*/
private void deleteFile(File file) {
try {
Drive drive = buildDrive();
Drive.Files.Delete deleteFile = drive.files().delete(file.getId());
deleteFile.execute();
} catch (IOException ex) {
Log.e(TAG, "deleteFile error: " + ex.toString());
}
}
Call the Files.get API to obtain the file metadata.
Code:
/**
* Obtain the file metadata.
*
* @param fileId File ID.
*/
private File getFileMetadata(String fileId) {
File file = null;
try {
Drive drive = buildDrive();
Drive.Files.Get request = drive.files().get(fileId);
request.setFields("*");
file = request.execute();
} catch (Exception e) {
Logger.e(TAG, "get metadata error: " + e.toString());
}
return file;
}
Call the Files.get API to download the file metadata and content. A file of any size can be downloaded. To download a file smaller than 20 MB, set directDownloadEnabled to true. Then, simply download the file through a network request.
Code:
/**
* Download the file metadata and content.
*
* @param fileId File ID.
* @param destFile Target file.
*/
private void downLoadFile(String fileId, java.io.File destFile) {
if (fileId == null || destFile == null) {
return;
}
try {
Drive drive = buildDrive();
Drive.Files.Get request = drive.files().get(fileId);
File fileContent = request.execute();
long size = fileContent.getSize();
Drive.Files.Get downloadRequest = drive.files().get(fileId);
MediaHttpDownloader downloader = downloadRequest.getMediaHttpDownloader();
boolean isDirectDownload = false;
// Download the file using the simple download method if it is smaller than 20 MB.
if (size < DIRECT_DOWNLOAD_MAX_SIZE) {
isDirectDownload = true;
}
// Set the range. This parameter is mandatory when the simple download method is not uesd.
downloader.setContentRange(0, size - 1);
// Set the download method. By default, a download method rather than simple download is used. If the file is smaller than 20 MB, set this parameter to true.
downloader.setDirectDownloadEnabled(isDirectDownload);
// Set the progress callback listener.
downloadRequest.getMediaHttpDownloader().setProgressListener(new MediaHttpDownloaderProgressListener() {
@Override
public void progressChanged(MediaHttpDownloader downloader) throws IOException {
// Download progress notification.
}
});
downloadRequest.executeContentAndDownloadTo(new FileOutputStream(destFile));
} catch (Exception e) {
Logger.e(TAG, "download file error:" + fileId + e.getMessage());
if (destFile != null) {
// If the download fails, delete the temporary file.
if (destFile.exists()) {
boolean isDeleteSuccess = destFile.delete();
if (!isDeleteSuccess) {
Logger.e(TAG, "downLoadFile delete file fail");
}
}
}
}
}
Call the Files.list API to search for files.
Code:
/**
* Search for files.
* @param query Query parameter. For details, please refer to Q statements.
* @param orderBy Sorting field.
* @param pageSize Maximum number of files to return per page.
* @param fields Fields to be contained in the response.
*/
private List<File> getFileList(String query, String orderBy, int pageSize, String fields){
List<File> fileList = null;
try{
Drive drive = buildDrive();
Drive.Files.List request = drive.files().list();
String cursor = null;
fileList = new ArrayList<>();
do {
FileList result = null;
result = request.setQueryParam(query)
.setOrderBy(orderBy)
.setPageSize(pageSize)
.setFields(fields)
.execute();
for (File file : result.getFiles()) {
fileList.add(file);
}
cursor = result.getNextCursor();
request.setCursor(cursor);
}while(!StringUtils.isNullOrEmpty(cursor));
}catch (Exception e) {
Logger.e(TAG, "executeFilesList exception: " + e.toString());
}
return fileList;
}
Call the Files.subscribe API to register the channel for tracking changes made to the designated file and enable change notification for the file.
Code:
/**
* register to the channel for tracking changes made to the designated file and enable change notification for the file.
*
* @param fileId File ID
*/
private void filesWatch(String fileId) {
try {
Drive drive = buildDrive();
Channel content = new Channel();
content.setType("web_hook");
content.setUrl("https://xxxx.com"); // Address of the server to which file changes will be sent. You need to build the server.
Drive.Files.Subscribe request = drive.files().subscribe(fileId, content);
Channel channel = request.execute();
SharedPreferences prefs = context.getSharedPreferences("channel_config", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putString("id", channel.getId());
editor.putString("resourceId", channel.getResourceId());
editor.commit();
} catch (Exception e) {
Log.e(TAG, "Exception" + e.getCause());
}
}

Related

[HELP] Adding a Toast message to Decompress activity

Hi everyone,
I am currently working on my first app which grabs a ZIP from the internet and the extracts it to a certain location. Everything works great but I can not figure out how to show a Toast message when the extraction operation is done.
The code I am using for unzipping is:
Code:
package mmarin.test.download;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/**
*
* @author jon
*/
public class Decompress{
private String _zipFile;
private String _location;
byte[] buffer = new byte[1024];
int length;
public Decompress(String zipFile, String location) {
_zipFile = zipFile;
_location = location;
_dirChecker("");
}
public void unzip() {
try {
FileInputStream fin = new FileInputStream(_zipFile);
ZipInputStream zin = new ZipInputStream(fin);
ZipEntry ze = null;
while ((ze = zin.getNextEntry()) != null) {
Log.v("Decompress", "Unzipping " + ze.getName());
if(ze.isDirectory()) {
_dirChecker(ze.getName());
} else {
FileOutputStream fout = new FileOutputStream(_location + ze.getName());
while ((length = zin.read(buffer))>0) {
fout.write(buffer, 0, length);
}
zin.closeEntry();
fout.close();
}
}
zin.close();
} catch(Exception e) {
Log.e("Decompress", "unzip", e);
}
}
private void _dirChecker(String dir) {
File f = new File(_location + dir);
if(!f.isDirectory()) {
f.mkdirs();
}
}
}
I am calling the Decompress activity through a button:
Code:
Button decompress = (Button)findViewById(R.id.button1);
decompress.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
String zipFile = Environment.getExternalStorageDirectory() + "/IPM/Splash.zip";
String unzipLocation = Environment.getExternalStorageDirectory() + "/IPM/Splash/";
Decompress d = new Decompress(zipFile, unzipLocation);
d.unzip();
}
});
I found this here: http://www.jondev.net/articles/Unzipping_Files_with_Android_(Programmatically) and it works great.
As I said above, only issue is displaying a message that everything is done.
Can someone please help me out?
Thank you!
Please use the Q&A Forum for questions &
Read the Forum Rules Ref Posting
Moving to Q&A
Put the toast after zin.close()
www.stackoverflow.com
Here you can find what you want
Xperian using xda app
http://stackoverflow.com/questions/9824772/toast-after-email-intent-message
Check this
Xperian using xda app
RoberGalarga said:
Put the toast after zin.close()
Click to expand...
Click to collapse
Hey,
I tried this but it doesn't work. I used this statement:
Code:
Toast.makeText(this, "Extraction complete", "LENGTH_SHORT").show();
and I got this error message: The method makeText(Context, CharSequence, int) in the type Toast is not applicable for the arguments (Decompress, String, String).
Help?
The method makeText(Context, CharSequence, int) in the type Toast is not applicable for the arguments (Decompress, String, String)
What the above line means is that you need to pass a Context object, a CharSequence object and an int. You are passing the wrong object types (Decompress, String, String).
The example you saw used the Toast in the activity class itself, that is why the first value passed was a this. The "LENGTH_SHORT" is actually a constant Toast.LENGTH_SHORT.
I am guessing you are making the button object in your main activity class. So i'd suggest making an additional method for the activity class that looks like this
Code:
public void displayToast(CharSequence cs)
{
Toast.makeText(this, cs, Toast.LENGTH_SHORT).show();
}
and then make the following change to your code
Code:
Button decompress = (Button)findViewById(R.id.button1);
decompress.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
String zipFile = Environment.getExternalStorageDirectory() + "/IPM/Splash.zip";
String unzipLocation = Environment.getExternalStorageDirectory() + "/IPM/Splash/";
Decompress d = new Decompress(zipFile, unzipLocation);
d.unzip();
// Add the following line
displayToast("Unzip complete");
}
});
Let me know if it worked for you.
The_R said:
The method makeText(Context, CharSequence, int) in the type Toast is not applicable for the arguments (Decompress, String, String)
What the above line means is that you need to pass a Context object, a CharSequence object and an int. You are passing the wrong object types (Decompress, String, String).
The example you saw used the Toast in the activity class itself, that is why the first value passed was a this. The "LENGTH_SHORT" is actually a constant Toast.LENGTH_SHORT.
I am guessing you are making the button object in your main activity class. So i'd suggest making an additional method for the activity class that looks like this
Code:
public void displayToast(CharSequence cs)
{
Toast.makeText(this, cs, Toast.LENGTH_SHORT).show();
}
and then make the following change to your code
Code:
Button decompress = (Button)findViewById(R.id.button1);
decompress.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
String zipFile = Environment.getExternalStorageDirectory() + "/IPM/Splash.zip";
String unzipLocation = Environment.getExternalStorageDirectory() + "/IPM/Splash/";
Decompress d = new Decompress(zipFile, unzipLocation);
d.unzip();
// Add the following line
displayToast("Unzip complete");
}
});
Let me know if it worked for you.
Click to expand...
Click to collapse
PERFECT! You're amazing!

stranges with android mediaservice

I've got nexus 4 and have some issue with media servicem cause my MS could not find music on my internal SD card; So I make an app;
Code:
public class SingleMediaScanner implements MediaScannerConnectionClient {
private MediaScannerConnection mMs;
private File mFile;
public SingleMediaScanner(Context context, File f) {
mFile = f;
mMs = new MediaScannerConnection(context, this);
mMs.connect();
}
[user=439709]@override[/user]
public void onMediaScannerConnected() {
Log.v("MS", "connected");
mMs.scanFile(mFile.getAbsolutePath(), "audio/*");
Log.v("MS-file", mFile.getAbsolutePath());
}
[user=439709]@override[/user]
public void onScanCompleted(String path, Uri uri) {
mMs.disconnect();
}
}
Code:
File root = android.os.Environment.getExternalStorageDirectory();
File dir = new File (root.getAbsolutePath()+"/Music/");
for (int i=0;i<dir.listFiles().length;i++)
{
if (dir.listFiles()[i].isFile()==true&&dir.listFiles()[i].getName().endsWith(".mp3"))
{
new SingleMediaScanner(this, dir.listFiles()[i].getAbsoluteFile());
}
Log says that MS was connected and tried to scan media file, but file doesnt appear in Media library , what's the problem? by the way I have CM ROM

[Q] signapk.java - hardcode key password during CM11 build

anyone know how to update this code snippet so the platform, media, etc. keys get their password? we're running a CM11 build using make -j32 otapackage. the build crashes b/c one of the processes isn't passing the password. for us to build we can only run make otapackage, which takes hours.
/**
* Reads the password from stdin and returns it as a string.
*
* @param keyFile The file containing the private key. Used to prompt the user.
*/
private static String readPassword(File keyFile) {
// TODO: use Console.readPassword() when it's available.
System.out.print("Enter password for " + keyFile + " (password will not be hidden): ");
System.out.flush();
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
try {
return stdin.readLine();
} catch (IOException ex) {
return null;
}
}
Click to expand...
Click to collapse
here is the fix
complexii said:
anyone know how to update this code snippet so the platform, media, etc. keys get their password? we're running a CM11 build using make -j32 otapackage. the build crashes b/c one of the processes isn't passing the password. for us to build we can only run make otapackage, which takes hours.
Click to expand...
Click to collapse
/**
* Reads the password from stdin and returns it as a string.
*
* @param keyFile The file containing the private key. Used to prompt the user.
*/
private static String readPassword(File keyFile) {
try {
InputStream is = null;
InputStreamReader isr = null;
BufferedReader br = null;
// open input stream password.txt for reading purpose.
is = new FileInputStream("build/tools/signapk/password.txt");
// create new input stream reader
isr = new InputStreamReader(is);
// create new buffered reader
br = new BufferedReader(isr);
//BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
return br.readLine();
} catch (IOException ex) {
return null;
}
}

Building an Android QUIC REST Client with HQUIC [kotlin]

In a previous post I've shown you how to use the HQUIC kit to perform a simple GET request to download the latest local news by using a third party API. At this point everything is ok, but, what if I want to send a request with headers? or, how can I perform a POST request?. If you have made the same questions, please keep reading.
Previous requirements
An Android Studio project
Integrating the HQUIC SDK
HQUC will perform HTTP requests over the QUIC protocol to let your users enjoy faster connections with lower bandwidth. If the remote server does not support QUIC, the kit will use HTTP V2 instead, so, you just need to code once.
To add the HQUIC kit to your app, add the next dependency to your app level build.gradle file
Code:
implementation 'com.huawei.hms:hquic-provider:5.0.0.300'
Sync your project and you will be ready to use the HQUIC SDK. We will reuse the HQUICService class provided on the HQUIC sample code, but with little modifications
Code:
class HQUICService(val context: Context) {
private val TAG = "HQUICService"
private val DEFAULT_PORT = 443
private val DEFAULT_ALTERNATEPORT = 443
private val executor: Executor = Executors.newSingleThreadExecutor()
private var cronetEngine: CronetEngine? = null
private var callback: UrlRequest.Callback? = null
/**
* Asynchronous initialization.
*/
init {
HQUICManager.asyncInit(
context,
object : HQUICManager.HQUICInitCallback {
override fun onSuccess() {
Log.i(TAG, "HQUICManager asyncInit success")
}
override fun onFail(e: Exception?) {
Log.w(TAG, "HQUICManager asyncInit fail")
}
})
}
/**
* Create a Cronet engine.
*
* @param url URL.
* @return cronetEngine Cronet engine.
*/
private fun createCronetEngine(url: String): CronetEngine? {
if (cronetEngine != null) {
return cronetEngine
}
val builder = CronetEngine.Builder(context)
builder.enableQuic(true)
builder.addQuicHint(getHost(url), DEFAULT_PORT, DEFAULT_ALTERNATEPORT)
cronetEngine = builder.build()
return cronetEngine
}
/**
* Construct a request
*
* @param url Request URL.
* @param method method Method type.
* @return UrlRequest urlrequest instance.
*/
private fun builRequest(
url: String,
method: String,
headers: HashMap<String, String>?,
body:ByteArray?
): UrlRequest? {
val cronetEngine: CronetEngine? = createCronetEngine(url)
val requestBuilder = cronetEngine?.newUrlRequestBuilder(url, callback, executor)
requestBuilder?.apply {
setHttpMethod(method)
if(method=="POST"){
body?.let {
setUploadDataProvider(UploadDataProviders.create(ByteBuffer.wrap(it)), executor) }
}
headers?.let{
for (key in it.keys) {
addHeader(key, headers[key])
}
}
return build()
}
return null
}
/**
* Send a request to the URL.
*
* @param url Request URL.
* @param method Request method type.
*/
fun sendRequest(url: String, method: String, headers: HashMap<String, String>?=null,body:ByteArray?=null) {
Log.i(TAG, "callURL: url is " + url + "and method is " + method)
val urlRequest: UrlRequest? = builRequest(url, method, headers,body)
urlRequest?.apply { urlRequest.start() }
}
/**
* Parse the domain name to obtain the host name.
*
* @param url Request URL.
* @return host Host name.
*/
private fun getHost(url: String): String? {
var host: String? = null
try {
val url1 = URL(url)
host = url1.host
} catch (e: MalformedURLException) {
Log.e(TAG, "getHost: ", e)
}
return host
}
fun setCallback(mCallback: UrlRequest.Callback?) {
callback = mCallback
}
}
The sendRequest method has been modified to receive a HashMap with the headers, and a ByteArray with the Body payload. Note the sendRequest method if the body or the headers are not null, will be added to the request.
Code:
requestBuilder?.apply {
setHttpMethod(method)
if(method=="POST"){
body?.let {//Adding the request Body
setUploadDataProvider(UploadDataProviders.create(ByteBuffer.wrap(it)), executor) }
}
headers?.let{
for (key in it.keys) {//Adding all the headers
addHeader(key, headers[key])
}
}
With that modifications can perform an HTTP request by this way
Code:
val map=HashMap<String,String>()
map["Content-Type"] = "application/json"
val body=JSONObject().apply {
put("key1","value1")
put("key2","value2")
}
HQUICService(context).sendRequest(HOST,"POST",map,body.toString().toByteArray())
That's enough to send a request, but, what about the response? HQUIC provides an Abstract Class for listening the request events. All we need is inherit from UrlRequest.Callback. Let's do it.
Code:
class HQUICClient(context: Context) : UrlRequest.Callback() {
var hquicService: HQUICService? = null
val CAPACITY = 10240
val TAG="QUICClient"
val response=ByteArrayOutputStream()
var listener:QuicClientListener?=null
init {
hquicService = HQUICService(context)
hquicService?.setCallback(this)
}
fun makeRequest(url: String, method: String, headers: HashMap<String, String>?=null,body:ByteArray?=null){
hquicService?.sendRequest(url,method,headers,body)
}
override fun onRedirectReceived(
request: UrlRequest?,
info: UrlResponseInfo?,
newLocationUrl: String?
) {
request?.followRedirect()
}
override fun onResponseStarted(request: UrlRequest?, info: UrlResponseInfo?) {
val byteBuffer = ByteBuffer.allocateDirect(CAPACITY)
request?.read(byteBuffer)
}
override fun onReadCompleted(
request: UrlRequest?,
info: UrlResponseInfo?,
byteBuffer: ByteBuffer?
) {
byteBuffer?.apply {
response.write(array(),arrayOffset(),position())
response.flush()
}
request?.read(ByteBuffer.allocateDirect(CAPACITY))
}
override fun onSucceeded(request: UrlRequest?, info: UrlResponseInfo?) {
listener?.onSuccess(response.toByteArray())
}
override fun onFailed(request: UrlRequest?, info: UrlResponseInfo?, error: CronetException?) {
listener?.apply { onFailure(error.toString()) }
}
Remember, certain number of bytes can be readed per time, so for long responses, the method onReadCompleated will be called multiple times until the response has been successfully readed, or an error ocurs. When the operation is complete, the onSucceeded callback will be called and you will be able to parse the response. If the request fails, you will get an exception on the onFailed callback.
To report the request result, you can create a public interface
Code:
interface HQUICClientListener{
fun onSuccess(response: ByteArray)
fun onFailure(error: String)
}
And then, if the response is succesful, you can parse your byte array properly.
Code:
override fun onSuccess(response: ByteArray) {
//For text
Log.i(TAG, String(response))
//For images
BitmapFactory.decodeByteArray(response,0,response.size)
}
Conclusion
With HQUIC you can easily create a REST client for your android app, taking advantage of the QUIC features and keeping HTTP 2 compatibility.
Reference
HQUIC developer guide

Someone can tell me why it wouldn't show USB disk mount after I first read USB disk message?

My OS: Android9
Fuction: Showing USB disk's images and copy images to this device when I insert the usb disk
My question:
1.It can read the disk's path and name when I first insert the usb disk, but I can't showing the image from the disk whether using setImageBitmap(bitmap) and setImageURI(uri) of ImageView control
2.It can't show the path on the adb : /mnt/media_rw/, in commont it is will show the usb disk's name , like this: mnt/media_rw/20D3-1E69
my code is below, someone can help me , thanks!
Java:
public class TestActivity2 extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activityLoginBinding = ActivityLoginBinding.inflate(LayoutInflater.from(this));
setContentView(activityLoginBinding.getRoot());
activityLoginBinding.button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
sendBroadcast(new Intent(ACTION_USB_PERMISSION));
}
});
}
/**
* 读取u盘文件
* @param device UsbMassStorageDevice实例对象
*/
private void readAllPicFromUSB(UsbMassStorageDevice device) {
// listImageUSBInfo.clear(); //清空list初始化
try { //遍历文件名
device.init();
// 设备分区
partition = device.getPartitions().get(0);
// 文件系统
currentFs = partition.getFileSystem();
// 获取 U 盘的根目录
mRootFolder = currentFs.getRootDirectory();
readAllPicFromUSB(mRootFolder,currentFs); //递归读取文件
Log.i(TAG, "picSize:" + picSize);
Log.i(TAG,"all pic count:" + picCount + ",all size:" + (long)(picSize / 1024) + "M"); //单位大小为M
picCount = 0; //归零
//所有文件加入list后通知livew刷新
Log.i(TAG,"list size----------------" + listImageUSBInfo.size());
sendBroadcast(new Intent(ACTION_USB_UPDATE_LISTVIEW));
//
} catch (Exception e) {
e.printStackTrace();
Log.i(TAG, "readDevice error:" + e.toString());
}
return;
}
/**
* 获取 U盘读写权限的申请
* @param context 上下文对象
*/
private void permissionRequest(Context context) {
Log.i(TAG,"开始申请设备权限");
try {
// 设备管理器
UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
// 获取 U 盘存储设备
UsbMassStorageDevice[] storageDevices = UsbMassStorageDevice.getMassStorageDevices(context.getApplicationContext());
PendingIntent pendingIntent = PendingIntent.getBroadcast(context.getApplicationContext(),
0, new Intent(ACTION_USB_PERMISSION), 0);
if(storageDevices.length == 0){
Log.i(TAG,"请插入可用的 U 盘");
}else{
//可能有几个 一般只有一个 因为大部分手机只有1个otg插口
for (UsbMassStorageDevice device : storageDevices) {
if (usbManager.hasPermission(device.getUsbDevice())) {
Log.i(TAG,"USB已经获取权限");
} else {//无权限申请权限
usbManager.requestPermission(device.getUsbDevice(), pendingIntent);
}
}
}
} catch (Exception e) {
Log.i(TAG,"申请权限异常:" +e.toString());
}
}//end permissionRequest
/**
* USBDevice 转换成UsbMassStorageDevice 对象
* @param usbDevice UsbDevice对象
*/
private UsbMassStorageDevice getUsbMass(UsbDevice usbDevice) {
UsbMassStorageDevice[] storageDevices = UsbMassStorageDevice.getMassStorageDevices(mContext);
for (UsbMassStorageDevice device : storageDevices) {
if (usbDevice.equals(device.getUsbDevice())) {
return device;
}
}
return null;
}//end
@Override
protected void onResume() {
super.onResume();
initUSBService();
Log.i(TAG,"enter onResume");
}//end onresume
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(usbBroadcast); //注销广播
}
private void initUSBService() { //初始化广播监听器
usbDeviceStateFilter = new IntentFilter();
usbDeviceStateFilter.addAction(ACTION_USB_IN);
usbDeviceStateFilter.addAction(ACTION_USB_OUT);
usbDeviceStateFilter.addAction(ACTION_USB_PERMISSION);
usbDeviceStateFilter.addAction(ACTION_USB_UPDATE_LISTVIEW);
registerReceiver(usbBroadcast,usbDeviceStateFilter);
}
/**
* 广播监听u盘拔插情况
*/
private BroadcastReceiver usbBroadcast = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
mContext=context;
String action=intent.getAction();
switch (action){
case ACTION_USB_PERMISSION: //自定义广播读取u盘文件
try {
UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED,
false)){
Log.i(TAG,"已经有权限111111111111");
if (usbDevice != null) {
readAllPicFromUSB(getUsbMass(usbDevice)); //读取u盘文件
}
else
Log.i(TAG,"没有插入U盘");
}else {
Log.i(TAG,"没有获取读写权限!,开始获取22222222222222");
permissionRequest(mContext); //获取权限
}
}catch (Exception e){
Log.i(TAG, "ACTION_USB_PERMISSION error:" + e.toString());
}
break;
case ACTION_USB_IN:
Log.i(TAG, "插入了u盘");
break;
case ACTION_USB_OUT:
Log.i(TAG,"拔出了u盘");
break;
}
}
};
/**
* 获取本机设备读写权限
*/
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE};
private static int REQUEST_PERMISSION_CODE = 1;
private int ANDROID_VERSION_CURRENT = Build.VERSION.SDK_INT;
private void requestReadAndWriteAccess() {
Log.i(TAG,"now android version is :" + ANDROID_VERSION_CURRENT);
if (ANDROID_VERSION_CURRENT > Build.VERSION_CODES.LOLLIPOP){
if(ActivityCompat.checkSelfPermission(TestActivity2.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!=
PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(TestActivity2.this, PERMISSIONS_STORAGE, REQUEST_PERMISSION_CODE);
Log.i(TAG,"已经获取读写权限");
}
}
}//end requestReadAndWriteAccess
/**
* 递归读取u盘文件图片文件
* @param usbFile 根文件夹
* @param fileSystem 文件系统
*/
private void readAllPicFromUSB(UsbFile usbFile, FileSystem fileSystem) {
try {
long tmp = 0;
String imgPath = "";
String imgName = "";
UsbFile[] usbFileList = usbFile.listFiles();
for (UsbFile usbFileItem:usbFileList){
if (!usbFileItem.isDirectory()){
String FileEnd = usbFileItem.getName().substring(usbFileItem.getName().lastIndexOf(".") + 1,
usbFileItem.getName().length()).toLowerCase(); //后缀名
if(FileEnd.equals("jpg") || FileEnd.equals("png") || FileEnd.equals("gif")
|| FileEnd.equals("jpeg")|| FileEnd.equals("bmp")){ //过滤出照片
tmp = usbFileItem.getLength() / 1024;
imgPath = USB_PATH_PREFIX + usbFileItem.getAbsolutePath(); //需要绝对地址
imgName = usbFileItem.getName();
Log.i(TAG,"img name:" + imgName + ",path:" + imgPath + ",size:" + tmp + "K");
picCount++;
picSize += tmp; //大小为K
// 加入到list
listImageUSBInfo.add(new ImageInfo(imgPath,imgName));
}
}else
readAllPicFromUSB(usbFileItem,fileSystem);
}
} catch (Exception e) {
e.printStackTrace();
Log.i(TAG,"readDevice error:"+e.toString());
}
}//end
}

Categories

Resources