Video intend can't be used on android (Appcelerator) - android

Video recording works fine on IOS, Android can't catch data.
problem seems to be the
var curActivity = Ti.Android.currentActivity;
curActivity.startActivityForResult(intent, function(e) { ....
there was some advise to use win.getActivity() instead, but i have no variable I can use.
$.cameraWin
this
is not working.
Any advise?
index.xml
<Alloy>
<TabGroup>
<Tab id="websiteTab" title="Web">
<Require backgroundColor="black" color="white" id="webTab" src="website" type="view"/>
</Tab>
<Tab id="cameraTab" title="Camera">
<Require backgroundColor="black" color="white" id="cameraTab" src="camera" type="view"/>
</Tab>
<Tab backgroundColor="black" color="white" id="loginTab" title="Login">
<Require backgroundColor="black" color="white" id="loginTab" src="login" type="view"/>
</Tab>
<Tab backgroundColor="black" color="white" id="registerTab" title="Map">
<Require backgroundColor="black" color="white" id="registerTab" src="register" type="view"/>
</Tab>
</TabGroup>
</Alloy>
camera.xml
<Alloy>
<Window id="cameraWin">
<Label id="Label_1" text="Gib Deinem Video einen Namen"/>
<TextField id="TextField_1"/>
<Button id="Button_1" onClick="doClick" title="Aufnehmen und hochladen"/>
<ProgressBar id="ProgressBar_1"/>
<Picker id="Picker_1" selectionIndicator="true" useSpinner="true">
<PickerColumn id="PickerColumn_1" title="Kategorie">
<Row title="Fußball"/>
<Row title="Handball"/>
<Row title="Schifahren"/>
<Row title="Einkehren"/>
</PickerColumn>
</Picker>
<Label id="Label_2" text="Veranstaltung/Kategorie"/>
</Window>
</Alloy>
camera.js
function doClick(e) {
Ti.API.info(Titanium.Platform.osname);
if (Titanium.Platform.osname == 'iphone') {
//record for iphone
$.ProgressBar_1.value = 0;
$.ProgressBar_1.message = "Hochladen"
Titanium.Media.showCamera({
success: function(event) {
var video = event.media;
movieFile = Titanium.Filesystem.getFile(
Titanium.Filesystem.applicationDataDirectory,
'mymovie.mov');
movieFile.write(video);
videoFile = movieFile.nativePath;
var xhr = Titanium.Network.createHTTPClient();
xhr.onload = function(e) {
Ti.UI.createAlertDialog({
title: 'Success',
message: 'status code ' + this.status
}).show();
Ti.API.info(this.responseText);
};
xhr.open('POST', 'XXXXXXXXXX');
xhr.send({
Filedata: event.media,
/* event.media holds blob from gallery */
title: $.TextField_1.value,
catid: 17
});
// onsendstream called repeatedly, use the progress property to
// update the progress bar
xhr.onsendstream = function(e) {
$.ProgressBar_1.value = e.progress * 100;
$.ProgressBar_1.message = "Hochladen von Video";
Ti.API.info('ONSENDSTREAM - PROGRESS: ' + e.progress * 100);
};
},
cancel: function() {},
error: function(error) {
// create alert
var a =
Titanium.UI.createAlertDialog({
title: 'Video'
});
// set message
if (error.code == Titanium.Media.NO_VIDEO) {
a.setMessage('Device does not have video recording
capabilities ');
} else {
a.setMessage('Unexpected error: ' + error.code);
}
// show alert
a.show();
},
mediaTypes: Titanium.Media.MEDIA_TYPE_VIDEO,
videoMaximumDuration: 120000,
videoQuality: Titanium.Media.QUALITY_MEDIUM
});
} else {
var intent = Titanium.Android.createIntent({
action: 'android.media.action.VIDEO_CAPTURE'
});
Ti.API.info('Intent created. ..');
var curActivity = Ti.Android.currentActivity;
curActivity.startActivityForResult(intent, function(e) {
if (e.error) {
Ti.UI.createNotification({
duration: Ti.UI.NOTIFICATION_DURATION_LONG,
message: 'Error: ' + e.error
}).show();
} else {
Ti.API.info('Drinnen');
Ti.Api.info(e.resultCode);
if (e.resultCode === Titanium.Android.RESULT_OK) {
Ti.API.info('Drinnen');
videoFile = e.intent.data;
var source = Ti.Filesystem.getFile(videoFile);
var movieFile =
Titanium.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory, 'mymovie.3gp');
Ti.API.info('Sichert');
source.copy(movieFile.nativePath);
Titanium.Media.saveToPhotoGallery(movieFile);
var xhr = Titanium.Network.createHTTPClient();
xhr.onload = function(e) {
Ti.UI.createAlertDialog({
title: 'Success',
message: 'status code ' + this.status
}).show();
Ti.API.info(this.responseText);
};
var fileContent = movieFile.read();
Ti.API.info('Video rauf');
xhr.open('POST', 'XXXXXXXXXXX'
Filedata: fileContent,
/* event.media holds blob from gallery */
title: $.TextField_1.value,
catid: 17
});
// onsendstream called repeatedly, use the progress property to
// update the progress bar
xhr.onsendstream = function(e) {
$.ProgressBar_1.value = e.progress * 100;
$.ProgressBar_1.message = "Hochladen von Video";
Ti.API.info('ONSENDSTREAM - PROGRESS: ' + e.progress * 100);
};
} else {
Ti.UI.createNotification({
duration: Ti.UI.NOTIFICATION_DURATION_LONG,
message: 'Canceled/Error? Result code: ' +
e.resultCode
}).show();
}
}
});
}
};

Alternative way:
I'm currently working on getting video recording to android in the normal SDK:
https://github.com/appcelerator/titanium_mobile/pull/7929
It is already working (Samsung Galaxy S6 has a problem a the moment I need to fix: you need to rotate the phone ones to have the proper preview size) but needs some more testing. With this you can use the back/front camera to record video the same way as on iOS.
But it still needs some time to be in the GA version. You can always compile an own sdk for yourself if you need it right away (I can provide a linux build).

I have a similar project, though mine is taking stills, not video, but for all intents and purposes they should behave the same.
In my code I have:
var win = $.camera_view;
This allows me later to start my activity with:
win.activity.startActivityForResult(...
Per your example you would probably set curActivity like this:
var curActivity = $.cameraWin.activity;
[EDIT]
If you still get no result you can try using .putExtraUri to specify the location to store the video:
var tempfile = Ti.Filesystem.getFile(Ti.Filesystem.externalStorageDirectory, "tempvideo.mpg");
intent.putExtraUri("output",tempfile.nativePath);
You would set this before calling startActivityForResult.

Related

How can I put a video in ionic with mediaCapture?

In the app I get this error Object: object,
After recording the video when giving it ready to be displayed on the screen I get that error.
VideoPage.HTML
<ion-header>
<ion-toolbar color="primary">
<ion-title>Subir Video</ion-title>
<ion-buttons slot="start">
<ion-back-button defaultHref="/autoventa"></ion-back-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-progress-bar [value]="uploadProgress" color="tertiary"></ion-progress-bar>
<ion-list>
<ion-item-sliding *ngFor="let f of files">
<ion-item (click)="openFile(f)">
<ion-icon name="videocam" slot="start" *ngIf=" f.name.endsWith('mp4')"></ion-icon>
<ion-label class = "ion-text-wrap">
{{ f.name }}
<p> {{ f.fullPath }}</p>
</ion-label>
</ion-item>
<ion-item-options side="start">
<ion-item-option (click)="deleteFile(f)" color="danger">
<ion-icon name="trash" slot="icon-only"></ion-icon>
</ion-item-option>
</ion-item-options>
<ion-item-options side ="end">
<ion-item-option (click)="uploadFile(f)" color = "primary">
<ion-icon name="cloud-upload" slot = "icon-only"></ion-icon>
</ion-item-option>
</ion-item-options>
</ion-item-sliding>
</ion-list>
</ion-content>
<ion-footer>
<ion-toolbar color = "primary">
<ion-button fill="clear" expand="full" color="light" (click)="selectMedia()">
<ion-icon slot = "start" name="document"></ion-icon>
Seleccionar Media
</ion-button>
</ion-toolbar>
</ion-footer>
Declaration of Variables
media folder... I put it before the #component
and files[] before the constructor
const MEDIA_FOLDER_NAME = 'my_media';
files = [];
my recordVideo in videoPage.ts
I use this method to open the camera and record, this part works but at the moment of giving it ready I get an Object object error
recordVideo(){
this.mediaCapture.captureVideo().then(
(data: MediaFile[]) => {
if(data.length > 0 ){
this.copyFileToLocalDir(data[0].fullPath)
}
},
(err: CaptureError) => {
console.log(err)
alert(err);
}
);
}
CopyFile
after recording command to call this method
but I think the error is in this method
copyFileToLocalDir(fullPath){
let myPath = fullPath;
// Make sure we copy from the right location
if (fullPath.indexOf('file://') < 0) {
myPath = 'file://' + fullPath;
}
const ext = myPath.split('.').pop();
const d = Date.now();
const newName = `${d}.${ext}`;
const name = myPath.substr(myPath.lastIndexOf('/') + 1);
const copyFrom = myPath.substr(0, myPath.lastIndexOf('/') + 1);
const copyTo = this.file.dataDirectory + MEDIA_FOLDER_NAME;
this.file.copyFile(copyFrom, name, copyTo, newName).then(
success => {
this.loadFiles();
},
error => {
console.log('error: ', error);
alert(error);
}
);
}
LoadFiles with this method I show the files
loadFiles(){
this.file.listDir(this.file.dataDirectory, MEDIA_FOLDER_NAME).then(
res => {
this.files = res;
},(err)=> {
console.log('Error al cargar archivos: ', err);
alert(err);
}
);
}
ngOnInit
ngOnInit() {
this.plt.ready().then(() =>{
let path = this.file.dataDirectory +MEDIA_FOLDER_NAME;
this.file.checkDir(path, MEDIA_FOLDER_NAME).then(
() => {
this.loadFiles();
},
err => {
this.file.createDir(path, MEDIA_FOLDER_NAME, false);
}
);
});
}

How can I access my videos from internal storage with react native video?

I am trying to make a simple video player using react native where, when the app is initialized it will fetch the playlist from a server, automatically download them and then play from local storage. I am not sure if i need to store the playlist in a Database.
Currently what I have been able to accomplish is being able to play videos online, as a result when there is no internet I can't play those videos anymore. I was also able to download videos but only one video is being downloaded instead of the whole playlist. As I have repeated videos I don't want to download same videos again and again. Also it seems I am unable to access my downloaded videos from my internal storage as well. I will provide mt code below. Thank you
import React, { useEffect, useState } from 'react';
import { ActivityIndicator, FlatList, Text, View,StyleSheet } from 'react-native';
import Video from 'react-native-video';
import InternetConnectionAlert from "react-native-internet-connection-alert";
import axios from 'axios';
import RNFetchBlob from 'rn-fetch-blob'
// import { getLastUpdateTime } from 'react-native-device-info';
// console.log("YOLO")
export default test = () => {
const [isLoading, setLoading] = useState(true);
const [data, setData] = useState([]);
const [currIndex, setCurrIndex] = useState(0);
const [uri, setUri] = useState("http://admin.ddad-bd.com/storage/campaigns/6/videos/L8j548Msg2d0CrqXw3iTiCPeZFx4J4oEImcpXZpG.mp4");
const [imei, setImei] = useState("14789")
const [campaignId, setCampaignid] = useState("");
// const[started_at, setStartedat] = useState("")
// const[ended_at, setEndedat] = useState("")
var today = new Date();
started_at = today.getFullYear() + '-' + (today.getMonth() + 1) + '-' + today.getDate() + ' ' + today.getHours() + ':' + today.getMinutes() + ':' + today.getSeconds();
ended_at = today.getFullYear() + '-' + (today.getMonth() + 1) + '-' + today.getDate() + ' ' + today.getHours() + ':' + today.getMinutes() + ':' + (today.getSeconds()+35);
let dirs = RNFetchBlob.fs.dirs
var filePath = dirs.DCIMDir
{/* Only Called Once to fetch new Playlist every hour*/}
useEffect(() => {
console.log("First Run")
axios.get('http://dev.ddad-bd.com/api/campaigns/index/', {
params: {
ID: imei
}
})
.then(function (response) {
setData(response.data.play_list)
})
.catch(function (error) {
console.log(error);
})
.finally(() => {
// onDownload(),
setLoading(false)
});
onDownload()
}, []);
const onEnd = () => {
setCurrIndex(currIndex + 1)
setUri(data[currIndex].primary_src)
setCampaignid(data[currIndex].campaign_id)
console.log()
axios.post('http://dev.ddad-bd.com/api/campaigns', {
campaign_type: "campaign",
android_imei: imei,
campaign_id: campaignId,
started_at: started_at,
ended_at: ended_at,
content_type: "primary"
})
.then(function (response) {
console.log("Response Succesfull");
})
.catch(function (error) {
console.log(error);
});
}
const onDownload = () => {
// JSON.parse(data)
let dirs = RNFetchBlob.fs.dirs
console.log(dirs.DCIMDir)
RNFetchBlob
.config({
addAndroidDownloads : {
useDownloadManager : true, // <-- this is the only thing required
// Optional, override notification setting (default to true)
path : dirs.DCIMDir + "/DDAD/",
notification : true,
// Optional, but recommended since android DownloadManager will fail when
// the url does not contains a file extension, by default the mime type will be text/plain
mime : 'video/webm',
description : 'File downloaded by download manager.'
}
})
.fetch('GET', uri)
.then((resp) => {
// the path of downloaded file
resp.path()
})
}
return (
<InternetConnectionAlert
onChange={(connectionState) => {
console.log("Connection State: ", connectionState);
}}
>
{/* {onDownload()} */}
<View style={{ flex: 1, padding: 24 }}>
{isLoading ? <ActivityIndicator/> : (
// uri ? (
// onLoad(),
<Video
source={{uri: uri}} // Can be a URL or a local file.
ref={(ref) => {
this.player = ref
// this.player.presentFullscreenPlayer();
}}
// onLoad={onLoad}
resizeMode={'contain'}
// repeat={true} // Store reference
onBuffer={this.onBuffer} // Callback when remote video is buffering
onError={this.videoError} // Callback when video cannot be loaded
style={styles.backgroundVideo}
onEnd={onEnd}
/>
// ) : (
// <Video
// source={{uri: "http://admin.ddad-bd.com/storage/campaigns/6/videos/L8j548Msg2d0CrqXw3iTiCPeZFx4J4oEImcpXZpG.mp4"}} // Can be a URL or a local file.
// ref={(ref) => {
// this.player = ref
// // this.player.presentFullscreenPlayer();
// }}
// resizeMode={'contain'}
// // repeat={true} // Store reference
// onBuffer={this.onBuffer} // Callback when remote video is buffering
// onError={this.videoError} // Callback when video cannot be loaded
// style={styles.backgroundVideo}
// onEnd={onEnd}
// />
// )
)}
</View>
{/* {... Your whole application should be here ... } */}
</InternetConnectionAlert>
);
};
var styles = StyleSheet.create({
backgroundVideo: {
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
},
});
Update: For videos to play from local storage you need to handle android permission in new android versions. Add android:requestLegacyExternalStorage="true" and also update compileSdkVersion to 29. This solved my problem and the videos are being played offline.

In Nativescript the result from imageSource.fromUrl is coming as {"android":{}}

While following the link https://docs.nativescript.org/cookbook/image-source, in the console, am getting the result as {"android":{}} in my android device.
Below is my js code
var createViewModel = require("./main-view-model").createViewModel;
var imageSource = require("image-source");
function onNavigatingTo(args) {
var page = args.object;
imageSource.fromUrl("https://www.google.com/images/errors/logo_sm_2.png")
.then(function (res) {
console.log("Image successfully loaded");
console.log(JSON.stringify(res));
}, function (error) {
//console.log("Error loading image: " + error);
});
page.bindingContext = createViewModel();
}
exports.onNavigatingTo = onNavigatingTo;
Should we do anything more to get the image. Apologies if the question is too basic, just getting to know Nativescript
There are several approaches to load an image from URL - you can create an instance of image via code behind and attach the imageSource to its src and then dynamically added the image to a page container element (e.g. grid-layout, stack-layout or else)
Or, you can use data binding and once you get the imaageSource to bind it with your view model.
example given:
page.js
var observable_1 = require('data/observable');
var imageSource = require("image-source");
function navigatingTo(args) {
var page = args.object;
var viewModel = new observable_1.Observable();
imageSource.fromUrl("https://www.google.com/images/errors/logo_sm_2.png")
.then(function (res) {
viewModel.set("myUrl", res);
}, function (error) {
//console.log("Error loading image: " + error);
});
page.bindingContext = viewModel;
}
exports.navigatingTo = navigatingTo;
page.xml
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo">
<StackLayout>
<Label text="ImageSource fromUrl example" class="title"/>
<Image src="{{ myUrl }}" stretch="none" />
</StackLayout>
</Page>

Show download progress bar ionic

I am developing an ionic app. I am using cordova's FileTransfer plugin to download pdf file. I am able to download the file to my internal memory,but not able to display single progress bar for downloaidng.
What is the best way of displaying progress for downloading.
Controller
var url = 'http://someurl.com/api/pdf_download/' + id;
// Android
var targetPath = 'file:///storage/sdcard0/' + id + '.pdf';
var trustHosts = true;
var options = {};
$cordovaFileTransfer.download(url, targetPath, options, trustHosts)
.then(function(result) {
console.log(result);
}, function() {
var alertPopup = $ionicPopup.alert({
title: 'No internet access',
buttons: [{
text: 'OK',
type: 'button-assertive'
}]
});
alertPopup.then(function() {});
}, function(progress) {
$timeout(function() {
$scope.downloadProgress = (progress.loaded / progress.total) * 100;
})
console.log('progress--->', $scope.downloadProgress);
});
I have used cordovaToast plugin for this feature.Here is the example for showing pdf download progress
html
<ion-view >
<div class="bar bar-subheader bar-positive" style="padding:0px;height: 8px;" >
<progress id="progressbar" max="100" value="{{ downloadProgress }}" class="progress"> </progress>
</div>
<ion-content>
</ion-content>
</ion-view>
css
.progress {
margin: 0 px;
height: 8 px;
background - color: #F1292B!important;
border - radius: 2 px;
box - shadow: 0 2 px 5 px rgba(0, 0, 0, 0.25) inset;
}
js
if (window.cordova) {
var url = '{{base_url}}/pdf_download/' + id;
// Android
var targetPath = 'file:///storage/sdcard0/' + 'fpl_' + id + '.pdf';
var trustHosts = true;
var options = {};
$cordovaFileTransfer.download(url, targetPath, options, trustHosts)
.then(function(result) {
$cordovaToast
.show('File downloaded successfully..', 'short', 'center')
.then(function() {
// success
}, function() {
// error
});
console.log(result);
}, function() {
var alertPopup = $ionicPopup.alert({
title: 'No internet access',
buttons: [{
text: 'OK',
type: 'button-assertive'
}]
});
alertPopup.then(function() {});
}, function(progress) {
var dnldpgs = progress.loaded.toString().substring(0, 2);
$scope.downloadProgress = parseInt(dnldpgs);
});
}
As benka already answered to my question, you should use the <progress> html element.
The full answer can be found over here -> https://stackoverflow.com/a/25553044/3671726

ngcordova android file select and upload to server

I want to upload file from my ionic application to server. I am using cordovafiletransfer plugin. Using that I am able to upload file by providing static path in controller code. My question is how to get selected file path by user? I only get filename from input tag on the relative path of selected file. How to get that?
View Page Code:
<label class="item item-input">
<div class="input-label">Upload Photo</div>
<input type="file" onchange="angular.element(this).scope().setFile(this)" accept="image/*"/>
</label>
<div class="padding">
<button ng-click="upload()" class="button button-block button-assertive">Upload</button>
</div>
Controller Code:
$scope.upload = function() {
var filename, options, targetPath;
console.log($scope.theFile);
targetPath = cordova.file.externalRootDirectory + '/Download/androidify.png';
filename = targetPath.split('/').pop();
options = {};
options.fileKey = 'image_file';
options.fileName = $scope.theFile.name;
options.chunkedMode = false;
options.mimeType = $scope.theFile.type;
options.headers = {
'Authorization': getDeviceToken()
};
console.log(options);
return $cordovaFileTransfer.upload(domain.uploadphoto(), targetPath, options).then(
(function(result) {
console.log('SUCCESS: ' + JSON.stringify(result.response));
}),
(function(err) {
console.log('ERROR: ' + JSON.stringify(err));
}),
function(progress) {}
);
};
$scope.setFile = function(element) {
return $scope.$apply(function($scope) {
console.log(element);
return $scope.theFile = element.files[0];
});
};
How to get proper target path of selected file?
I came across this post which should solve the problem, (it works for me, with some modification):
In my template:
<input type="file" fileread="file.path" />
<button type="button" class="button button-small button-assertive" ng-click="vm.upload(file)">Upload PDF</button>
and my modified Directive:
.directive("fileread", ['$cordovaFile', function ($cordovaFile) {
return {
scope: {
fileread: "="
},
link: function (scope, element, attributes) {
element.bind("change", function (changeEvent) {
var reader = new FileReader();
reader.onload = function (loadEvent) {
var fileName = changeEvent.target.files[0].name;
$cordovaFile.writeFile(cordova.file.dataDirectory, fileName, loadEvent.target.result, true)
.then(function (result) {
console.log(result)
}, function (err) {
console.warn(err)
});
scope.$apply(function () {
scope.fileread = cordova.file.dataDirectory + fileName;
});
}
reader.readAsArrayBuffer(changeEvent.target.files[0]);
});
}
}
}]);
Remember to clean up after you uploaded the document
use:
$cordovaFile.removeFile(cordova.file.dataDirectory, fileName)
.then(function (success) {
// success
}, function (error) {
// error
});
Also see http://www.javascripture.com/FileReader for more info regarding FileReader

Categories

Resources