====== Differences ====== This shows you the differences between two versions of the page.
Both sides previous revision Previous revision | |||
script_autosetupappfreeze [2016/12/17 18:59] cdfa 1.8.3 |
script_autosetupappfreeze [2017/07/21 08:57] (current) cdfa 1.8.4 |
||
---|---|---|---|
Line 4: | Line 4: | ||
* Initial request: https://plus.google.com/+JaroslavGrochal/posts/BDKDMrTMfxt | * Initial request: https://plus.google.com/+JaroslavGrochal/posts/BDKDMrTMfxt | ||
* GitHub: https://github.com/cdfa/AutoSetupLongTapFreeze | * GitHub: https://github.com/cdfa/AutoSetupLongTapFreeze | ||
- | * Version: 1.8.3 | + | * Version: 1.8.4 |
====== How to use the script ====== | ====== How to use the script ====== | ||
Line 43: | Line 43: | ||
* Added freezeing/unfreezing all item from menu | * Added freezeing/unfreezing all item from menu | ||
* Added long press folder to freeze/unfreeze all items in it | * Added long press folder to freeze/unfreeze all items in it | ||
+ | |||
+ | 1.8.4 | ||
+ | * Ask to unfreeze and run an item if it is frozen instead of saying that the app is not installed | ||
====== Script code ====== | ====== Script code ====== | ||
Line 50: | Line 53: | ||
// for Sources see: http://www.lightninglauncher.com/scripting/reference/api/reference/net/pierrox/lightning_launcher/script/api/Event.html | // for Sources see: http://www.lightninglauncher.com/scripting/reference/api/reference/net/pierrox/lightning_launcher/script/api/Event.html | ||
// for Events see http://www.lightninglauncher.com/scripting/reference/api/reference/net/pierrox/lightning_launcher/script/api/PropertySet.html | // for Events see http://www.lightninglauncher.com/scripting/reference/api/reference/net/pierrox/lightning_launcher/script/api/PropertySet.html | ||
- | // you may only have to set 1 in the future. | ||
, freezeSource = "I_LONG_CLICK" | , freezeSource = "I_LONG_CLICK" | ||
, freezeEvent = "i.longTap"; | , freezeEvent = "i.longTap"; | ||
Line 56: | Line 58: | ||
bindClass("android.widget.Toast"); | bindClass("android.widget.Toast"); | ||
bindClass("android.content.pm.PackageManager"); | bindClass("android.content.pm.PackageManager"); | ||
- | bindClass('java.lang.Runtime'); | + | bindClass("java.lang.Thread"); |
+ | bindClass("android.os.Handler"); | ||
+ | bindClass("android.os.Looper"); | ||
bindClass('java.io.BufferedReader'); | bindClass('java.io.BufferedReader'); | ||
bindClass('java.io.InputStreamReader'); | bindClass('java.io.InputStreamReader'); | ||
bindClass('java.io.DataOutputStream'); | bindClass('java.io.DataOutputStream'); | ||
bindClass('java.lang.StringBuffer'); | bindClass('java.lang.StringBuffer'); | ||
- | bindClass("java.lang.Runnable"); | + | bindClass('java.lang.Runtime'); |
- | bindClass("java.lang.Thread"); | + | |
- | bindClass("android.os.Handler"); | + | |
- | bindClass("android.os.Looper"); | + | |
var script = getCurrentScript() | var script = getCurrentScript() | ||
Line 103: | Line 104: | ||
c.setTag("longTapFreeze", false); | c.setTag("longTapFreeze", false); | ||
restoreEventHandler(c, freezeEvent); | restoreEventHandler(c, freezeEvent); | ||
+ | restoreEventHandler(c, 'i.tap'); | ||
restoreEventHandler(c, "i.menu"); | restoreEventHandler(c, "i.menu"); | ||
restoreEventHandler(c, "menu"); | restoreEventHandler(c, "menu"); | ||
- | if(c.getTag("autosync") == "true") restoreEventHandler(c, "resumed"); | + | if(c.getTag("autosync") === "true") restoreEventHandler(c, "resumed"); |
c.getAllItems().forEach(function(it){ | c.getAllItems().forEach(function(it){ | ||
if(isFrozen(it)) | if(isFrozen(it)) | ||
Line 113: | Line 115: | ||
cs.forEach(function(c){ | cs.forEach(function(c){ | ||
var opener; | var opener; | ||
- | if((opener = c.getOpener()) && opener.getType() == "Folder"){ | + | if((opener = c.getOpener()) && opener.getType() === "Folder"){ |
if(isFrozen(opener)) | if(isFrozen(opener)) | ||
unfreezeEffect(opener); | unfreezeEffect(opener); | ||
Line 121: | Line 123: | ||
} | } | ||
+ | /** | ||
+ | * Checks if an object is an array. | ||
+ | * @param object | ||
+ | * @returns {boolean} | ||
+ | */ | ||
function isArray(object){ | function isArray(object){ | ||
- | return Object.prototype.toString.call(object) == '[object Array]'; | + | return Object.prototype.toString.call(object) === '[object Array]'; |
} | } | ||
- | /* | + | /** |
- | ATTENTION: | + | * If this function is executed in a thread that is the main GUI thread, execute func, or else execute func in the main GUI thread. (Android doesn't like it when you change the GUI outside of the main GUI thread) |
- | if multiple commands are executed as root, the output will be an array of the returned lines | + | * @param func {function} |
- | if multiple commands are not executed as root, the output will be an array of returned outputs (which are themselves arrays of lines) | + | */ |
+ | function handleGUIEdit(func){ | ||
+ | if(Looper.getMainLooper().getThread() === Thread.currentThread()){ | ||
+ | func(); | ||
+ | }else{ | ||
+ | GUIHandler.post(func); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Starts a new background thread with func. | ||
+ | * @param func {function} - The function the thread executes. | ||
+ | */ | ||
+ | function startNewBackgroundThread(func){ | ||
+ | var thread = new Thread(function(){ | ||
+ | func(); | ||
+ | // if a looper was initialized in func, make sure the thread can die by stopping the thread when the Looper idles. | ||
+ | if(threads[Thread.currentThread().getId()].prepared === true){ | ||
+ | Looper.myLooper().getQueue().addIdleHandler(function(){ | ||
+ | Looper.myLooper().quitSafely(); | ||
+ | }); | ||
+ | Looper.loop(); | ||
+ | } | ||
+ | }); | ||
+ | thread.setUncaughtExceptionHandler(function(th, ex){ | ||
+ | handleGUIEdit(function(){ | ||
+ | alert(ex.getMessage()); | ||
+ | }) | ||
+ | }); | ||
+ | threads[thread.getId()] = {}; | ||
+ | thread.start(); | ||
+ | } | ||
+ | |||
+ | //noinspection JSValidateJSDoc | ||
+ | /** | ||
+ | * Gets a handler for the current thread and initializes a looper if necessary. | ||
+ | * @returns {Handler} | ||
+ | */ | ||
+ | function getHandler(){ | ||
+ | if(Looper.getMainLooper().getThread() === Thread.currentThread()){ | ||
+ | return GUIHandler; | ||
+ | }else{ | ||
+ | var threadId = Thread.currentThread().getId(); | ||
+ | if(threads[threadId].prepared !== true){ | ||
+ | Looper.prepare(); | ||
+ | threads[threadId].prepared = true; | ||
+ | } | ||
+ | return new Handler(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * This callback will be called when the executing of the command(s) is finished | ||
+ | * | ||
+ | * @callback finishedCallback | ||
+ | * @param {string[]} An array of the lines the command(s) returned | ||
+ | */ | ||
+ | /** | ||
+ | * This callback will be called when a command is executed. | ||
+ | * | ||
+ | * @callback executedCallback | ||
+ | */ | ||
+ | /** | ||
+ | * Runs a command in the terminal | ||
+ | * @param cmds {string|string[]} - The command or array of commmands to be executed. | ||
+ | * @param [asRoot=false] {boolean} - If the command(s) should be executed as root or not. | ||
+ | * @param [newThread=true] {boolean} - If the executing of commands should happen in a new thread or not. (useful for root commands) | ||
+ | * @param [callback] {finishedCallback} - The callback that handles the output. | ||
+ | * @param [onExecuted] {executedCallback} - A callback that will be called when a command is executed. useful for multiple commands that take some time) | ||
+ | * @returns {string[]||string[][]} - (only if asRoot == false && newThread == false) Returns an array of the lines written in the terminal or an array of arrays if multiple commands were executed. | ||
*/ | */ | ||
function runCmd(cmds, asRoot, newThread, callback, onExecuted){ | function runCmd(cmds, asRoot, newThread, callback, onExecuted){ | ||
Line 134: | Line 210: | ||
, output, process, reader, writer; | , output, process, reader, writer; | ||
+ | // set optional arguments | ||
+ | if(newThread !== false) | ||
+ | newThread = true; | ||
+ | |||
+ | /** | ||
+ | * Helper function for executing the command(s). Gets its parameters from the parent function. | ||
+ | * @returns {string[]||string[][]} - (only if asRoot == false && newThread == false) Returns an array of the lines written in the terminal or an array of arrays if multiple commands were executed. | ||
+ | */ | ||
function execCmd(){ | function execCmd(){ | ||
+ | /** | ||
+ | * Checks if the command is a string and if not alerts the user. | ||
+ | * @param cmd {string} | ||
+ | * @returns {boolean} | ||
+ | */ | ||
function checkCmd(cmd){ | function checkCmd(cmd){ | ||
if(typeof(cmd) === "string"){ | if(typeof(cmd) === "string"){ | ||
Line 145: | Line 234: | ||
} | } | ||
+ | //noinspection JSValidateJSDoc | ||
+ | /** | ||
+ | * Actually executes command. | ||
+ | * @param cmd {string} | ||
+ | * @param writer {DataOutputStream} - The writer to write the command to. | ||
+ | * @returns {boolean} If the command was actually written or not. | ||
+ | */ | ||
function exec(cmd, writer){ | function exec(cmd, writer){ | ||
if(checkCmd(cmd)){ | if(checkCmd(cmd)){ | ||
Line 154: | Line 250: | ||
} | } | ||
+ | //noinspection JSValidateJSDoc | ||
+ | /** | ||
+ | * Read the output from the reader. | ||
+ | * @param reader {BufferedReader} | ||
+ | * @returns {Array} An array of lines that were outputted by the | ||
+ | */ | ||
function readOutput(reader){ | function readOutput(reader){ | ||
var tmp, output = []; | var tmp, output = []; | ||
- | while((tmp = reader.readLine()) != null) | + | while((tmp = reader.readLine()) !== null) |
output.push(tmp); | output.push(tmp); | ||
- | return output.length == 1 ? output[0] : output; | + | return output.length === 1 ? output[0] : output; |
} | } | ||
+ | /** | ||
+ | * Executes the callback and if the callback is not a function alerts the user. | ||
+ | * @param callback | ||
+ | * @param output {Array} - The argument that is passed to the callback | ||
+ | */ | ||
function handleCallback(callback, output){ | function handleCallback(callback, output){ | ||
- | if(typeof callback == "function"){ | + | if(typeof callback === "function"){ |
handler.post(function(){ | handler.post(function(){ | ||
callback(output); | callback(output); | ||
Line 245: | Line 352: | ||
throw new Error("Multiple callbacks are not possible in su mode. Use onExecuteds instead."); | throw new Error("Multiple callbacks are not possible in su mode. Use onExecuteds instead."); | ||
- | if(newThread === false){ | + | if(newThread){ |
- | return execCmd(); | + | |
- | }else{ | + | |
startNewBackgroundThread(function(){ | startNewBackgroundThread(function(){ | ||
execCmd(); | execCmd(); | ||
- | }) | + | }); |
+ | }else{ | ||
+ | return execCmd(); | ||
} | } | ||
} | } | ||
Line 266: | Line 373: | ||
return false; | return false; | ||
- | var onBlackList = false, onWhiteList; | + | var onWhiteList, |
- | for(var i = 0; i < blackList.length; i++){ | + | onBlackList = blackList.some(function(pkg){ |
- | if(pkgName == blackList[i]){ | + | return pkg === pkgName; |
- | onBlackList = true; | + | }); |
- | break; | + | |
- | } | + | |
- | } | + | |
- | if(whiteList.length == 0){ | + | if(whiteList.length === 0){ |
onWhiteList = true; | onWhiteList = true; | ||
}else{ | }else{ | ||
- | onWhiteList = false; | + | onWhiteList = whiteList.some(function(pkg){ |
- | for(var i = 0; i < whiteList.length; i++){ | + | return pkg === pkgName; |
- | if(pkgName == whiteList[i]){ | + | }); |
- | onWhiteList = true; | + | |
- | break; | + | |
- | } | + | |
- | } | + | |
} | } | ||
Line 302: | Line 402: | ||
} | } | ||
- | function freeze(it){ | + | function freeze(it, callback){ |
- | if(it.getType() == "Folder"){ | + | if(it.getType() === "Folder"){ |
freezeContainer(it.getContainer()); | freezeContainer(it.getContainer()); | ||
}else{ | }else{ | ||
Line 309: | Line 409: | ||
runCmd("pm disable " + pkgName, true, true, null, function(){ | runCmd("pm disable " + pkgName, true, true, null, function(){ | ||
freezeEffect(it); | freezeEffect(it); | ||
+ | if(typeof callback === 'function') | ||
+ | callback(); | ||
}); | }); | ||
}); | }); | ||
Line 314: | Line 416: | ||
} | } | ||
- | function unfreeze(it){ | + | function unfreeze(it, callback){ |
- | if(it.getType() == "Folder"){ | + | if(it.getType() === "Folder"){ |
unfreezeContainer(it.getContainer()); | unfreezeContainer(it.getContainer()); | ||
}else{ | }else{ | ||
Line 321: | Line 423: | ||
runCmd("pm enable " + pkgName, true, true, null, function(){ | runCmd("pm enable " + pkgName, true, true, null, function(){ | ||
unfreezeEffect(it); | unfreezeEffect(it); | ||
+ | if(typeof callback === 'function') | ||
+ | callback(); | ||
}); | }); | ||
}); | }); | ||
Line 338: | Line 442: | ||
function batchFreezeAction(items, action, callback){ | function batchFreezeAction(items, action, callback){ | ||
var frozenStateChecker, cmd, effect; | var frozenStateChecker, cmd, effect; | ||
- | if(action == "freeze"){ | + | if(action === "freeze"){ |
frozenStateChecker = function(it){ return !isFrozen(it); }; | frozenStateChecker = function(it){ return !isFrozen(it); }; | ||
cmd = "pm disable "; | cmd = "pm disable "; | ||
effect = function(it){ freezeEffect(it); } | effect = function(it){ freezeEffect(it); } | ||
- | }else if(action == "unfreeze"){ | + | }else if(action === "unfreeze"){ |
frozenStateChecker = function(it){ return isFrozen(it); }; | frozenStateChecker = function(it){ return isFrozen(it); }; | ||
cmd = "pm enable "; | cmd = "pm enable "; | ||
Line 360: | Line 464: | ||
}); | }); | ||
- | if(cmds.length != 0){ | + | if(cmds.length !== 0){ |
var counter = 0; | var counter = 0; | ||
runCmd(cmds, true, true, function(){ | runCmd(cmds, true, true, function(){ | ||
Line 375: | Line 479: | ||
cs.forEach(function(c){ | cs.forEach(function(c){ | ||
var opener; | var opener; | ||
- | if((opener = c.getOpener()) && opener.getType() == "Folder") | + | if((opener = c.getOpener()) && opener.getType() === "Folder") |
effect(opener); | effect(opener); | ||
}); | }); | ||
Line 393: | Line 497: | ||
function isFrozen(it){ | function isFrozen(it){ | ||
- | return it.getTag("frozen") == "true"; | + | return it.getTag("frozen") === 'true'; |
} | } | ||
function getFrozenApps(){ | function getFrozenApps(){ | ||
- | if(frozenApps == null){ | + | if(typeof frozenApps === 'undefined'){ |
frozenApps = []; | frozenApps = []; | ||
var pkgs = runCmd("pm list packages -d", false, false); | var pkgs = runCmd("pm list packages -d", false, false); | ||
Line 418: | Line 522: | ||
function syncItem(it){ | function syncItem(it){ | ||
var frozenApps = getFrozenApps(); | var frozenApps = getFrozenApps(); | ||
- | if(it.getType() == "Shortcut"){ | + | if(it.getType() === "Shortcut"){ |
var pkgName = getPackageName(it); | var pkgName = getPackageName(it); | ||
if(pkgName && isFreezable(pkgName)){ | if(pkgName && isFreezable(pkgName)){ | ||
- | var isFrozen = it.getTag("frozen") == "true"; | + | var isFrozen = it.getTag("frozen") === 'true'; |
var matched = frozenApps.some(function(pkg){ | var matched = frozenApps.some(function(pkg){ | ||
- | return pkg == pkgName; | + | return pkg === pkgName; |
}); | }); | ||
if(!isFrozen && matched){ | if(!isFrozen && matched){ | ||
Line 438: | Line 542: | ||
} | } | ||
- | function handleGUIEdit(func){ | + | if(typeof getEvent !== "undefined"){ |
- | if(Looper.getMainLooper().getThread() == Thread.currentThread()){ | + | |
- | func(); | + | |
- | }else{ | + | |
- | GUIHandler.post(func); | + | |
- | } | + | |
- | } | + | |
- | + | ||
- | function startNewBackgroundThread(func){ | + | |
- | var thread = new Thread(function(){ | + | |
- | func(); | + | |
- | if(threads[Thread.currentThread().getId()].prepared == true){ | + | |
- | Looper.myLooper().getQueue().addIdleHandler(function(){ | + | |
- | Looper.myLooper().quitSafely(); | + | |
- | }); | + | |
- | Looper.loop(); | + | |
- | } | + | |
- | }); | + | |
- | thread.setUncaughtExceptionHandler(function(th, ex){ | + | |
- | handleGUIEdit(function(){ | + | |
- | alert(ex.getMessage()); | + | |
- | }); | + | |
- | }); | + | |
- | threads[thread.getId()] = {}; | + | |
- | thread.start(); | + | |
- | } | + | |
- | + | ||
- | function getHandler(){ | + | |
- | if(Looper.getMainLooper().getThread() == Thread.currentThread()){ | + | |
- | return GUIHandler; | + | |
- | }else{ | + | |
- | var threadId = Thread.currentThread().getId(); | + | |
- | if(threads[threadId].prepared != true){ | + | |
- | Looper.prepare(); | + | |
- | threads[threadId].prepared = true; | + | |
- | } | + | |
- | return new Handler(); | + | |
- | } | + | |
- | } | + | |
- | + | ||
- | if(typeof getEvent != "undefined"){ | + | |
var c | var c | ||
, e = getEvent() | , e = getEvent() | ||
Line 484: | Line 548: | ||
, data = e.getData(); | , data = e.getData(); | ||
if(data){ | if(data){ | ||
- | if(data == "sync"){ | + | if(data === "sync"){ |
if(c = e.getContainer()){ | if(c = e.getContainer()){ | ||
syncContainer(c); | syncContainer(c); | ||
Line 490: | Line 554: | ||
throw new Error("Could not find a way to determine the container to sync. Run the script from an item in the container or from the container itself or add the container id directly afrer 'sync'.") | throw new Error("Could not find a way to determine the container to sync. Run the script from an item in the container or from the container itself or add the container id directly afrer 'sync'.") | ||
} | } | ||
- | }else if(data.substring(0, 4) == "sync"){ | + | }else if(data.substring(0, 4) === "sync"){ |
var cId = data.substring(4, data.length); | var cId = data.substring(4, data.length); | ||
c = screen.getContainerById(cId); | c = screen.getContainerById(cId); | ||
Line 500: | Line 564: | ||
c = e.getContainer(); | c = e.getContainer(); | ||
cId = c.getId(); | cId = c.getId(); | ||
- | if(c.getTag("longTapFreeze") == "true"){ | + | if(c.getTag("longTapFreeze") === "true"){ |
if(confirm("Are you sure you want to uninstall?")){ | if(confirm("Are you sure you want to uninstall?")){ | ||
uninstall(c); | uninstall(c); | ||
Line 509: | Line 573: | ||
c.setTag("longTapFreeze", true); | c.setTag("longTapFreeze", true); | ||
setEventHandlerRestorably(c, freezeEvent, EventHandler.RUN_SCRIPT, script.getId()); | setEventHandlerRestorably(c, freezeEvent, EventHandler.RUN_SCRIPT, script.getId()); | ||
+ | setEventHandlerRestorably(c, 'i.tap', EventHandler.RUN_SCRIPT, script.getId()); | ||
setEventHandlerRestorably(c, "i.menu", EventHandler.RUN_SCRIPT, script.getId()); | setEventHandlerRestorably(c, "i.menu", EventHandler.RUN_SCRIPT, script.getId()); | ||
setEventHandlerRestorably(c, "menu", EventHandler.RUN_SCRIPT, script.getId()); | setEventHandlerRestorably(c, "menu", EventHandler.RUN_SCRIPT, script.getId()); | ||
Line 520: | Line 585: | ||
} | } | ||
}else{ | }else{ | ||
- | //long tap | ||
var src = e.getSource(); | var src = e.getSource(); | ||
- | if(src == freezeSource){ | + | if(src === freezeSource){ |
if(isFrozen(it)){ | if(isFrozen(it)){ | ||
unfreeze(it); | unfreeze(it); | ||
Line 528: | Line 592: | ||
freeze(it); | freeze(it); | ||
} | } | ||
+ | }else if(src === 'I_CLICK'){ | ||
+ | if( isFrozen(it) && confirm("Unfreeze and run?")) | ||
+ | unfreeze(it, function(){ | ||
+ | it.launch(); | ||
+ | }); | ||
+ | else | ||
+ | it.launch(); | ||
} | } | ||
} | } | ||
Line 533: | Line 604: | ||
}else if(menu){ | }else if(menu){ | ||
var mode = menu.getMode(); | var mode = menu.getMode(); | ||
- | if(mode == Menu.MODE_ITEM_SUBMENU_ACTION || mode == Menu.MODE_ITEM_NO_EM){ | + | if(mode === Menu.MODE_ITEM_SUBMENU_ACTION || mode === Menu.MODE_ITEM_NO_EM){ |
menu.addMainItem("Sync frozen-state", function(){ | menu.addMainItem("Sync frozen-state", function(){ | ||
syncItem(item); | syncItem(item); | ||
menu.close(); | menu.close(); | ||
}); | }); | ||
- | }else if(mode == Menu.MODE_CONTAINER_SUBMENU_ITEMS){ | + | }else if(mode === Menu.MODE_CONTAINER_SUBMENU_ITEMS){ |
menu.addMainItem("Sync frozen-state", function(){ | menu.addMainItem("Sync frozen-state", function(){ | ||
syncContainer(container); | syncContainer(container); |