Created
April 8, 2019 18:20
-
-
Save Xiaoy312/ae922076588795a0a70e456f8726ee9b to your computer and use it in GitHub Desktop.
Linqpad script to manage apps on android devices
This file contains hidden or 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
<Query Kind="Program"> | |
<Namespace>LINQPad.Controls</Namespace> | |
<Namespace>System.Threading.Tasks</Namespace> | |
</Query> | |
#define YOLO_NO_CONFIRM | |
void Main() | |
{ | |
Util.AutoScrollResults = false; | |
var searchLabel = new Label("Find:"); | |
searchTextBox = new TextBox(onTextInput: _ => UpdateResults()); | |
useRegexCheckBox = new CheckBox("Regex", true, onClick: _ => UpdateResults()); | |
filterMiscAppsCheckBox = new CheckBox("Filter platform/manufacturer/misc apps", true, onClick: _ => UpdateResults()); | |
promoteKnownAppsCheckBox = new CheckBox("todo: sort nventive(tm) apps on top", false, onClick: _ => UpdateResults()) { Enabled = false, Visible = false }; | |
var refreshButton = new Button("refresh", onClick: _ => UpdateResults()); | |
new WrapPanel(searchLabel, searchTextBox, useRegexCheckBox).Dump(); | |
new WrapPanel(refreshButton, filterMiscAppsCheckBox, promoteKnownAppsCheckBox).Dump(); | |
results = new DumpContainer(GetResults()).Dump("Packages"); | |
} | |
TextBox searchTextBox; | |
CheckBox useRegexCheckBox; | |
CheckBox filterMiscAppsCheckBox, promoteKnownAppsCheckBox; | |
DumpContainer results; | |
// Define other methods and classes here | |
void UpdateResults() | |
{ | |
results.Content = GetResults(); | |
} | |
object GetResults() | |
{ | |
try | |
{ | |
// see: http://adbshell.com/commands/adb-shell-pm-list-packages | |
const string ThirdPartyOnlyOption = "-3"; | |
var packages = Util.Cmd($"adb shell pm list packages {ThirdPartyOnlyOption}", quiet: true) | |
.Where(x => !string.IsNullOrEmpty(x)) | |
.ToArray(); | |
if (packages.Any(x => !x.StartsWith("package:"))) | |
{ | |
packages.Dump(); | |
throw new InvalidOperationException("expected 'package:' to be found on every line"); | |
} | |
return packages | |
.Select(x => x.Substring("package:".Length)) | |
.Where(GetSearchMatcher()) | |
.Where(GetMiscAppsFilter()) | |
.OrderBy(x => x) | |
.Select(x => new | |
{ | |
PackageName = x, | |
Actions = Util.HorizontalRun(true, | |
new Hyperlinq(() => StartApp(x), "Start"), | |
new Hyperlinq(() => KillApp(x), "Kill"), | |
new Hyperlinq(() => CleanApp(x), "Clear Data"), | |
new Hyperlinq(() => UninstallApp(x), "Uninstall") | |
) | |
}); | |
} | |
catch (Exception ex) | |
{ | |
return ex; | |
} | |
} | |
Func<string, bool> GetSearchMatcher() | |
{ | |
if (string.IsNullOrEmpty(searchTextBox.Text)) return x => true; | |
return useRegexCheckBox.Checked | |
? (Func<string, bool>)new Regex(searchTextBox.Text).IsMatch | |
: x => x.Contains(searchTextBox.Text); | |
} | |
Func<string, bool> GetMiscAppsFilter() | |
{ | |
return filterMiscAppsCheckBox.Checked | |
? (Func<string, bool>)FilterMiscApps | |
: x => true; | |
} | |
bool FilterMiscApps(string packageName) | |
{ | |
if (packageName == "android") return false; | |
if (packageName.StartsWith("com.android")) return false; | |
if (packageName.StartsWith("com.sec")) return false; | |
if (packageName.StartsWith("com.google")) return false; | |
if (packageName.StartsWith("com.microsoft")) return false; | |
if (packageName.StartsWith("com.samsung")) return false; | |
if (packageName.StartsWith("com.qualcomm")) return false; | |
// other common apps | |
if (packageName.StartsWith("Mono.Android")) return false; | |
if (packageName.StartsWith("com.monotype")) return false; | |
if (packageName.StartsWith("com.amazon")) return false; | |
if (packageName.StartsWith("com.facebook")) return false; | |
return true; | |
} | |
string[] ExecuteCommand(string command, bool quiet = false) | |
{ | |
Util.Metatext($"> {command}").Dump(); | |
return Util.Cmd(command, quiet); | |
} | |
async Task ConfirmAction(string prompt, Action action, bool useBrain = false) | |
{ | |
#if !YOLO_NO_CONFIRM | |
var challenge = GenerateChallenge(); | |
if (await Util.ReadLineAsync($"{prompt} {challenge.Question}") == challenge.Answer) | |
{ | |
action(); | |
} | |
#else | |
action(); | |
#endif | |
(string Question, string Answer) GenerateChallenge() | |
{ | |
if (useBrain) | |
{ | |
var random = new Random(Guid.NewGuid().GetHashCode()); | |
var leftOperand = random.Next(0, 10); | |
var rightOperand = random.Next(0, 10); | |
return ($"(enter sum of {leftOperand} and {rightOperand})", (leftOperand + rightOperand).ToString()); | |
} | |
else | |
{ | |
return ("(enter y to continue)", "y"); | |
} | |
} | |
} | |
void StartApp(string packageName) => ExecuteCommand($"adb shell monkey -p {packageName} 1"); // see: https://stackoverflow.com/a/25398877 | |
void KillApp(string packageName) => ExecuteCommand($"adb shell am force-stop {packageName}"); | |
void CleanApp(string packageName) => ExecuteCommand($"adb shell pm clear {packageName}"); // kill & clean slate see: https://stackoverflow.com/a/3117310 | |
void UninstallApp(string packageName) => ConfirmAction($"uninstall `{packageName}`?", () => ExecuteCommand($"adb uninstall {packageName}")); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment