[
  {
    "path": "native/src/com/android/commands/monkey/ape/jev/JevRegion.java",
    "sha256": "b5a6fa3a445d94ff17e6b35b2bfb328d311bf791afc8e419ceedd2c969ff1a03",
    "excerpts": [
      {
        "start": 42,
        "end": 104,
        "text": "42:     static final class Link {\n43:         final int source,target,concrete;\n44:         Link(int s,int t,int c){source=s;target=t;concrete=c;}\n45:     }\n46:     static final class Concrete {\n47:         final int id,source;final Set<Integer> targets;final boolean eligible;\n48:         Concrete(int i,int s,Set<Integer> t,boolean e){id=i;source=s;targets=Collections.unmodifiableSet(new HashSet<Integer>(t));eligible=e;}\n49:     }\n50:     static final class Snapshot {\n51:         final long abstraction,topology,concretes,facts;final int current;final String tree;\n52:         final List<Fact> states;final List<Link> links;final Set<Integer> roots;final List<Concrete> entries;\n53:         Snapshot(long a,long t,long c,long f,int cur,String tr,List<Fact> s,List<Link> l,Set<Integer> r,List<Concrete> e){\n54:             abstraction=a;topology=t;concretes=c;facts=f;current=cur;tree=tr;\n55:             states=Collections.unmodifiableList(new ArrayList<Fact>(s));links=Collections.unmodifiableList(new ArrayList<Link>(l));\n56:             roots=Collections.unmodifiableSet(new HashSet<Integer>(r));entries=Collections.unmodifiableList(new ArrayList<Concrete>(e));\n57:         }\n58:     }\n59:     static final class Result {\n60:         final Snapshot input;final Set<Integer> blocked,isolated,members;final List<Set<Integer>> regions;final String reason;final long nanos,dominatorNanos,summaryNanos,reachabilityNanos;\n61:         Result(Snapshot s,Set<Integer>b,Set<Integer>i,Set<Integer>m,List<Set<Integer>> regions,String r,long n,long d,long a,long reach){\n62:             input=s;blocked=Collections.unmodifiableSet(b);isolated=Collections.unmodifiableSet(i);members=Collections.unmodifiableSet(m);\n63:             List<Set<Integer>> copy=new ArrayList<Set<Integer>>();for(Set<Integer> region:regions)copy.add(Collections.unmodifiableSet(new HashSet<Integer>(region)));\n64:             this.regions=Collections.unmodifiableList(copy);reason=r;nanos=n;dominatorNanos=d;summaryNanos=a;reachabilityNanos=reach;\n65:         }\n66:     }\n67:     /** Tree reuse depends only on confirmed State connections and real roots, never strength. */\n68:     static final class Calculator {\n69:         long abstraction=-1,topology=-1;BitSet[] dominators;BitSet reachable;\n70:         int[] parents;List<List<Integer>> children;List<Integer> order;\n71:         void prepare(Snapshot s) {\n72:             int n=s.states.size();\n73:             if(abstraction!=s.abstraction || topology!=s.topology) {\n74:                 reachable=reach(s,s.roots,Collections.<Integer>emptySet());dominators=new BitSet[n];\n75:                 for(int i=0;i<n;i++){dominators[i]=new BitSet(n);if(reachable.get(i)){dominators[i].or(reachable);if(s.roots.contains(i)){dominators[i].clear();dominators[i].set(i);}}}\n76:                 List<List<Integer>> predecessors=new ArrayList<List<Integer>>();for(int i=0;i<n;i++)predecessors.add(new ArrayList<Integer>());\n77:                 for(Link l:s.links)if(reachable.get(l.source))predecessors.get(l.target).add(l.source);\n78:                 boolean changed;\n79:                 do {changed=false;for(int v=0;v<n;v++)if(reachable.get(v) && !s.roots.contains(v)) {\n80:                     checkInterrupted();BitSet d=(BitSet)reachable.clone();\n81:                     for(int p:predecessors.get(v))d.and(dominators[p]);\n82:                     d.set(v);if(!d.equals(dominators[v])){dominators[v]=d;changed=true;}\n83:                 }}while(changed);\n84:                 parents=new int[n];Arrays.fill(parents,-1);children=new ArrayList<List<Integer>>();order=new ArrayList<Integer>();\n85:                 for(int i=0;i<n;i++)children.add(new ArrayList<Integer>());\n86:                 for(int v=0;v<n;v++)if(reachable.get(v)) {\n87:                     checkInterrupted();int depth=-1;\n88:                     for(int d=dominators[v].nextSetBit(0);d>=0;d=dominators[v].nextSetBit(d+1))if(d!=v && dominators[d].cardinality()>depth){parents[v]=d;depth=dominators[d].cardinality();}\n89:                     if(parents[v]>=0)children.get(parents[v]).add(v);\n90:                 }\n91:                 for(int v=0;v<n;v++)if(reachable.get(v) && parents[v]<0)order.add(v);\n92:                 for(int i=0;i<order.size();i++)order.addAll(children.get(order.get(i)));\n93:                 abstraction=s.abstraction;topology=s.topology;\n94:             }\n95:         }\n96:         /** All non-entry dominator subtrees, independent of exploration facts. */\n97:         List<JevRegionLocator.Region> structure(Snapshot s) {\n98:             prepare(s);List<JevRegionLocator.Region> regions=new ArrayList<JevRegionLocator.Region>();\n99:             for(int d:order)if(!s.roots.contains(d)) {\n100:                 Set<Integer> members=new TreeSet<Integer>();ArrayDeque<Integer> queue=new ArrayDeque<Integer>();queue.add(d);\n101:                 while(!queue.isEmpty()){checkInterrupted();int v=queue.remove();members.add(v);queue.addAll(children.get(v));}\n102:                 regions.add(new JevRegionLocator.Region(d,members));\n103:             }\n104:             return regions;"
      },
      {
        "start": 493,
        "end": 517,
        "text": "493:     private void transitionNow(GUITreeTransition transition,String transitionId,boolean confirmed,String executionContextId,org.json.JSONObject sourceContext) {\n494:         if(!transitionIds.add(transitionId))return;\n495:         State source=transition.getSource().getCurrentState(),target=transition.getTarget().getCurrentState();int from=id(source),to=id(target);\n496:         GUITreeAction historical=transition.getAction();GUITreeNode node=historical.getGUITreeNode();\n497:         ModelAction action=locator==null?historical.getModelAction():shadowAction(transition);\n498:         GUITreeAction concrete=locator==null?historical:new GUITreeAction(transition.getSource(),node,action);\n499:         String name=node==null?\"<lifecycle>\":observedFullName(node);\n500:         Map<String,Bucket> group=byAction.get(action);if(group==null){group=new HashMap<String,Bucket>();byAction.put(action,group);}\n501:         Bucket bucket=group.get(name);if(bucket==null){bucket=new Bucket(nextConcreteId++,action,concrete);bucket.abstraction=abstraction;bucket.historicalAnchor=historical;buckets.put(bucket.id,bucket);group.put(name,bucket);concretes++;dirty=true;\n502:             if(locator!=null && action!=historical.getModelAction())locator.rebound(step,abstraction,shadowDiagnostic(bucket,transition));}\n503:         if(node!=null && observedNode(bucket.anchor,transition.getSource(),action)!=node)bucket.ambiguous=true;\n504:         if(implementations.add(from+\":\"+to+\":\"+bucket.id)){links.add(new Link(from,to,bucket.id));topology++;dirty=true;}\n505:         if(bucket.targets.add(to)){concretes++;dirty=true;}\n506:         if(confirmed) {\n507:             bucket.executions++;\n508:             bucket.confirmedTargets.add(transition.getTarget());\n509:             org.json.JSONArray labels=JevEvidence.resultLabels(transition.getTarget().getRootNode());\n510:             boolean sameGui=JevEvidence.guiIdentity(transition.getSource()).equals(JevEvidence.guiIdentity(transition.getTarget()));\n511:             String key=new org.json.JSONArray().put(target.getActivity()).put(labels).put(source==target).put(sameGui).toString();\n512:             bucket.confirmedPatterns.put(transitionId,key);\n513:             org.json.JSONObject outcome=bucket.outcomes.get(key);\n514:             if(outcome==null){outcome=JevRegistry.fields(\"target_activity\",JevEvidence.boundedText(target.getActivity()),\"result_labels\",labels,\"count\",0,\n515:                 \"self_loop\",source==target,\"activity_unchanged\",Objects.equals(source.getActivity(),target.getActivity()),\"gui_unchanged\",sameGui);bucket.outcomes.put(key,outcome);}\n516:             try{outcome.put(\"count\",outcome.getInt(\"count\")+1);}catch(org.json.JSONException impossible){throw new IllegalStateException(impossible);}\n517:         }"
      },
      {
        "start": 599,
        "end": 613,
        "text": "599:         try{if(locator!=null)shadowModel=model;safePointNow(model,state,tree,timestamp);}\n600:         catch(RuntimeException error){\n601:             if(locator==null)throw error;\n602:             shadowInvalid=error instanceof SnapshotInvalid?(SnapshotInvalid)error:new SnapshotInvalid(\"shadow_snapshot_exception\",JevRegistry.merge(shadowDiagnostic(null,null),JevRegistry.fields(\"exception\",error.getClass().getName(),\"message\",String.valueOf(error.getMessage()))));\n603:             if(locator.needsSnapshot())locator.snapshotInvalid(timestamp,abstraction,shadowInvalid.detail);\n604:         }\n605:         finally{timing.record(\"region_safe_point\",System.nanoTime()-started);}\n606:     }\n607:     private void safePointNow(Model model,State state,GUITree tree,long timestamp) {\n608:         step=timestamp;current=state;currentTree=tree;utgStateCount=model.getGraph().getStates().size();id(state);for(State root:model.getGraph().getEntryStates())root(root);touch(state);\n609:         recordMembershipVersion(model);\n610:         if(locator==null && !warmupStarted){warmupStarted=true;next=System.nanoTime()+warmup;events.emit(\"REGION_WARMUP_STARTED\",step,abstraction,state.getGraphId(),null,JevRegistry.fields(\"warmup_ms\",TimeUnit.NANOSECONDS.toMillis(warmup)));}\n611:         for(State touchedState:touched){Integer id=ids.get(touchedState);if(id==null)continue;Fact fact=runtime.explorationFact(touchedState);\n612:             if(!fact.equals(stateFacts.get(id))){stateFacts.set(id,fact);facts++;dirty=true;}}\n613:         touched.clear();"
      }
    ]
  },
  {
    "path": "native/src/com/android/commands/monkey/ape/jev/JevRegionLocator.java",
    "sha256": "9231e3d2c5f8c04d3dd0b07b92a224094fb7767ef7e2425636bb43cf77e7a8d8",
    "excerpts": [
      {
        "start": 169,
        "end": 209,
        "text": "169:         Analysis compute(JevRegion.Snapshot s,Stats stats){\n170:             if(version!=s.abstraction){stamps.clear();version=s.abstraction;}\n171:             List<Candidate> candidates=new ArrayList<Candidate>();\n172:             List<Region> regions=calculator.structure(s);\n173:             for(Region region:regions){\n174:                 if(Thread.currentThread().isInterrupted())throw new CancellationException();\n175:                 Candidate c=new Candidate(region);c.lastProgress=Long.MIN_VALUE;\n176:                 for(int v:region.members){c.visits+=stats.visits[v];c.recent+=stats.recent[v];c.actions+=stats.actionCount[v];c.unvisited+=stats.unvisited[v];\n177:                 }\n178:                 for(int v:region.members)if(stats.unknown.containsKey(v))c.noveltyStatus=\"UNKNOWN\";\n179:                 for(int[] edge:stats.recentTransitions)if(!region.members.contains(edge[0]) && region.members.contains(edge[1]))c.reentries++;\n180:                 c.average=(double)c.visits/region.members.size();\n181:                 for(Discovery event:stats.discoveries)if(region.members.contains(event.source)){\n182:                     if(event.known){c.lastProgress=Math.max(c.lastProgress,event.time);if(recent(event.time,stats))c.newStates++;}\n183:                     else if(recent(event.time,stats))c.noveltyStatus=\"UNKNOWN\";\n184:                 }\n185:                 Stamp old=stamps.get(region.header);c.membershipChanged=old!=null && !old.members.equals(region.members);\n186:                 stamps.put(region.header,new Stamp(region.members));\n187:                 for(JevRegion.Concrete concrete:s.entries)if(!region.members.contains(concrete.source)){\n188:                     Entry entry=new Entry(concrete,region);if(entry.inside.contains(region.header))c.entries.add(entry);\n189:                 }\n190:                 Collections.sort(c.entries,new Comparator<Entry>(){public int compare(Entry a,Entry b){return Integer.compare(a.concrete.id,b.concrete.id);}});\n191:                 boolean reviewable=false;for(Entry e:c.entries)reviewable |= e.concrete.eligible;\n192:                 c.reason=c.entries.isEmpty()?\"no_entry\":!reviewable?\"no_reviewable_entry\":c.average<=2?\"avg_visits_not_above_2\":c.recent<minRecent?\"insufficient_recent_visits\":\n193:                     !c.noveltyStatus.equals(\"KNOWN\")?\"novelty_unknown\":c.lastProgress>stats.now-stats.window?\"recent_region_progress\":\"mature\";\n194:                 c.mature=c.reason.equals(\"mature\");candidates.add(c);\n195:             }\n196:             List<Candidate> ranked=new ArrayList<Candidate>(candidates);\n197:             Collections.sort(ranked,new Comparator<Candidate>(){public int compare(Candidate a,Candidate b){int size=Integer.compare(a.region.members.size(),b.region.members.size());return size!=0?size:Integer.compare(a.region.header,b.region.header);}});\n198:             Set<Integer> selectedMembers=new HashSet<Integer>(),requested=new HashSet<Integer>();\n199:             for(Candidate c:ranked)if(c.mature){\n200:                 if(!Collections.disjoint(selectedMembers,c.region.members)){c.reason=\"nested_deferred\";continue;}\n201:                 c.selected=true;selectedMembers.addAll(c.region.members);\n202:                 for(Entry e:c.entries){\n203:                     e.status=e.concrete.eligible?\"ready_for_review\":\"unconfirmed_or_unmatchable\";\n204:                     if(e.concrete.eligible)requested.add(e.concrete.id);\n205:                 }\n206:             }\n207:             // Legacy saturation/guard computation is comparison telemetry only. It\n208:             // cannot filter new nominations, including mixed-target concretes.\n209:             return new Analysis(s,stats,candidates,compareLegacy?calculator.compute(s):null,Collections.unmodifiableSet(new TreeSet<Integer>(requested)));"
      }
    ]
  },
  {
    "path": "native/src/com/android/commands/monkey/ape/model/StateKey.java",
    "sha256": "0571fa722b7a09ba445124d6e729d85200be19b7e4860ca03741826a616ca36c",
    "excerpts": [
      {
        "start": 42,
        "end": 86,
        "text": "42:     private Name[] widgets;\n43:     private int hashCode;\n44: \n45:     public StateKey(ComponentName activity, Naming naming, Name[] widgets) {\n46:         this.activity = activity.getClassName();\n47:         this.naming = naming;\n48:         this.widgets = widgets;\n49:     }\n50: \n51:     @Override\n52:     public int hashCode() {\n53:         if (hashCode == 0) {\n54:             final int prime = 31;\n55:             int result = 1;\n56:             result = prime * result + ((activity == null) ? 0 : activity.hashCode());\n57:             result = prime * result + ((naming == null) ? 0 : naming.hashCode());\n58:             result = prime * result + Arrays.hashCode(widgets);\n59:             hashCode = result;\n60:         }\n61:         return hashCode;\n62:     }\n63: \n64:     @Override\n65:     public boolean equals(Object obj) {\n66:         if (this == obj)\n67:             return true;\n68:         if (obj == null)\n69:             return false;\n70:         if (getClass() != obj.getClass())\n71:             return false;\n72:         StateKey other = (StateKey) obj;\n73:         if (activity == null) {\n74:             if (other.activity != null)\n75:                 return false;\n76:         } else if (!activity.equals(other.activity))\n77:             return false;\n78:         if (naming == null) {\n79:             if (other.naming != null)\n80:                 return false;\n81:         } else if (!naming.equals(other.naming))\n82:             return false;\n83:         if (!Arrays.equals(widgets, other.widgets))\n84:             return false;\n85:         return true;\n86:     }"
      }
    ]
  },
  {
    "path": "native/src/com/android/commands/monkey/ape/jev/ConcreteActionIdentity.java",
    "sha256": "17b1ccffaa18a863b342f75c67b508c0b7854756480c69dde6825b94580c95e6",
    "excerpts": [
      {
        "start": 5,
        "end": 73,
        "text": "5: /**\n6:  * Stable identity of one concrete action. Scope such as Activity or State is\n7:  * deliberately supplied by the caller and is never folded into this value.\n8:  */\n9: public final class ConcreteActionIdentity {\n10:     private final String actionType;\n11:     private final String canonicalFullName;\n12: \n13:     public ConcreteActionIdentity(String actionType, String canonicalFullName) {\n14:         if (actionType == null || actionType.length() == 0)\n15:             throw new IllegalArgumentException(\"actionType must not be empty\");\n16:         if (canonicalFullName == null || canonicalFullName.length() == 0)\n17:             throw new IllegalArgumentException(\"canonicalFullName must not be empty\");\n18:         this.actionType = actionType;\n19:         this.canonicalFullName = canonicalFullName;\n20:     }\n21: \n22:     public static ConcreteActionIdentity of(String actionType, GUITreeNode node) {\n23:         if (node == null) throw new IllegalArgumentException(\"node must not be null\");\n24:         return new ConcreteActionIdentity(actionType, canonical(node));\n25:     }\n26: \n27:     /**\n28:      * Production nodes use the exact native fullName.  Small JVM fixtures may\n29:      * omit optional accessibility strings that the legacy Name renderer\n30:      * assumes are non-null; use a deterministic attribute chain there rather\n31:      * than making identity lookup crash or guessing from bounds.\n32:      */\n33:     public static String canonical(final GUITreeNode node) {\n34:         // Observing an identity returns a string, never a native Name. Do not\n35:         // assign global Name order to controls merely inspected by review.\n36:         long start=JevReviewProfile.start();\n37:         try {return com.android.commands.monkey.ape.naming.NameManager.withoutInterning(\n38:             new java.util.function.Supplier<String>() {public String get(){return canonicalReadOnly(node);}});\n39:         } finally {JevReviewProfile.end(\"canonical_render\",start);}\n40:     }\n41: \n42:     private static String canonicalReadOnly(GUITreeNode node) {\n43:         try { return JevIdentity.fullName(node).toXPath(); }\n44:         catch (RuntimeException unavailable) {\n45:             StringBuilder out=new StringBuilder(\"fallback:\");\n46:             for(GUITreeNode current=node;current!=null;current=current.getParent()) {\n47:                 out.append('[').append(String.valueOf(current.getClassName())).append('|')\n48:                     .append(String.valueOf(current.getResourceID())).append('|').append(current.getIndex()).append('|')\n49:                     .append(String.valueOf(JevIdentity.text(current))).append('|').append(String.valueOf(current.getContentDesc()))\n50:                     .append('|').append(current.isClickable()).append('|').append(current.isLongClickable()).append('|')\n51:                     .append(current.isCheckable()).append('|').append(current.isScrollable()).append(']');\n52:             }\n53:             return out.toString();\n54:         }\n55:     }\n56: \n57:     public String actionType() { return actionType; }\n58:     public String canonicalFullName() { return canonicalFullName; }\n59: \n60:     @Override public int hashCode() {\n61:         return 31 * actionType.hashCode() + canonicalFullName.hashCode();\n62:     }\n63: \n64:     @Override public boolean equals(Object other) {\n65:         if (!(other instanceof ConcreteActionIdentity)) return false;\n66:         ConcreteActionIdentity value = (ConcreteActionIdentity) other;\n67:         return actionType.equals(value.actionType)\n68:             && canonicalFullName.equals(value.canonicalFullName);\n69:     }\n70: \n71:     @Override public String toString() {\n72:         return actionType + \"|\" + canonicalFullName;\n73:     }"
      }
    ]
  },
  {
    "path": "native/src/com/android/commands/monkey/ape/jev/JevIdentity.java",
    "sha256": "ad8b4e330097ec3b2aa134000143afa18f790c8d3626a32536fddf750a5a0850",
    "excerpts": [
      {
        "start": 25,
        "end": 71,
        "text": "25: /**\n26:  * Provenance-aware identity for Jev concrete controls.\n27:  *\n28:  * <p>Jev cross-GUI concrete fullName must ignore ONLY the synthetic image-hash\n29:  * text that APE generates at the bitmap hashing write in\n30:  * {@link GUITreeNode#computeAndSetImageText(android.graphics.Bitmap)}\n31:  * (recorded through {@link GUITreeNode#setGeneratedImageText(String)}). Real\n32:  * text -- including text that literally looks like \"#1234\" -- content-desc,\n33:  * index, ancestor naming, class/resource id, and action flags are never\n34:  * altered, and the marker is never inferred from string content.\n35:  *\n36:  * <p>This helper does not mutate live nodes, cached Names, or global naming\n37:  * configuration. For nodes whose own text and every ancestor carry no\n38:  * synthetic image-hash provenance, {@link #fullName(GUITreeNode)} returns the\n39:  * exact same cached Name instance the native full namer produces for the live\n40:  * node.\n41:  */\n42: public final class JevIdentity {\n43: \n44:     private JevIdentity() {\n45:     }\n46: \n47:     /**\n48:      * Returns the node text, or the empty string when the current text is the\n49:      * synthetic image-hash write. Ordinary text is returned exactly.\n50:      */\n51:     public static String text(GUITreeNode node) {\n52:         if (node == null) {\n53:             throw new IllegalArgumentException(\"node must not be null\");\n54:         }\n55:         return node.isGeneratedImageText() ? \"\" : node.getText();\n56:     }\n57: \n58:     /**\n59:      * Returns the node's full native name (type, text, index, ancestor path,\n60:      * and action patch) with every synthetic image-hash text in the chain\n61:      * normalized to the empty string. Ordinary nodes keep their names exactly.\n62:      */\n63:     public static Name fullName(GUITreeNode node) {\n64:         if (node == null) {\n65:             throw new IllegalArgumentException(\"node must not be null\");\n66:         }\n67:         for (GUITreeNode n = node; n != null; n = n.getParent()) {\n68:             if (n.isGeneratedImageText()) return NamerFactory.fullNamer().naming(shadowChain(node));\n69:         }\n70:         return NamerFactory.fullNamer().naming(node);\n71:     }"
      }
    ]
  },
  {
    "path": "native/src/com/android/commands/monkey/ape/jev/JevRuntime.java",
    "sha256": "e5b22f7d4a5613f50c24938d3cf06d49da186078f8dc873c8084f79583cc535e",
    "excerpts": [
      {
        "start": 900,
        "end": 945,
        "text": "900:                         \"action_fingerprint\",action.getActionFingerprint()));\n901:                 if(++batch%32==0)output.drain();\n902:             }\n903:         }\n904:         output.drain();\n905:     }\n906: \n907:     private void writeGraphSnapshot() {\n908:         if(lastModel==null)return;\n909:         try {\n910:             Graph graph=lastModel.getGraph();JSONObject snapshot=new JSONObject();\n911:             snapshot.put(\"event\",\"graph_snapshot\").put(\"abstraction_version\",registry.version()).put(\"graph_step\",step);\n912:             JSONArray roots=new JSONArray();for(State state:graph.getEntryStates())roots.put(state.getGraphId());snapshot.put(\"roots\",roots);\n913:             JSONArray states=new JSONArray(),edges=new JSONArray();\n914:             Set<StateTransition> allEdges=new HashSet<StateTransition>();\n915:             for(State state:graph.getStates()) {\n916:                 JSONObject item=stateTelemetry(state,\"close\");item.put(\"id\",state.getGraphId());\n917:                 item.put(\"activity\",String.valueOf(state.getActivity()));item.put(\"visits\",state.getVisitedCount());\n918:                 item.put(\"first_seen\",state.getFirstVisitedTimestamp());item.put(\"last_seen\",state.getLastVisitedTimestamp());\n919:                 JSONArray shots=new JSONArray();\n920:                 String captured=stateScreenshotPaths.get(state.getGraphId());\n921:                 if(captured!=null)shots.put(captured);\n922:                 else for(GUITree tree:state.getGUITrees()) {String path=relativeImagePath(tree.getJevImage());if(path!=null){shots.put(path);break;}}\n923:                 item.put(\"screenshot_paths\",shots).put(\"screenshot_status\",shots.length()>0?\"saved\":screenshotFailureReasons.containsKey(state.getGraphId())?\n924:                     screenshotFailureReasons.get(state.getGraphId()):\"not_observed_at_safe_point\")\n925:                     .put(\"screenshot_failure_count\",screenshotFailures.containsKey(state.getGraphId())?screenshotFailures.get(state.getGraphId()):0);\n926:                 item.put(\"model_actions\",graphActionDetails(state));states.put(item);\n927:                 allEdges.addAll(graph.getOutStateTransitions(state));\n928:             }\n929:             for(StateTransition edge:allEdges) {\n930:                 JSONObject item=new JSONObject();item.put(\"id\",edge.getGraphId()).put(\"source\",edge.getSource().getGraphId())\n931:                     .put(\"target\",edge.getTarget().getGraphId()).put(\"action\",edge.getAction().getGraphId())\n932:                     .put(\"action_fingerprint\",edge.getAction().getActionFingerprint()).put(\"target_activity\",String.valueOf(edge.getTarget().getActivity()))\n933:                     .put(\"type\",String.valueOf(edge.getType())).put(\"visits\",edge.getVisitedCount()).put(\"is_circle\",edge.isCircle())\n934:                     .put(\"first_seen\",edge.getFirstVisitedTimestamp()).put(\"last_seen\",edge.getLastVisitedTimestamp());edges.put(item);\n935:             }\n936:             snapshot.put(\"states\",states).put(\"edges\",edges);\n937:             output.save(graphSnapshotFile,snapshot,false);\n938:         } catch(Exception e) {output.fail(e);}\n939:     }\n940: \n941:     private JSONArray graphActionDetails(State state) throws JSONException {\n942:         JSONArray actions=new JSONArray();\n943:         for(ModelAction action:state.getActions()) {\n944:             JSONObject item=new JSONObject().put(\"id\",action.getGraphId()).put(\"type\",action.getType().name())\n945:                 .put(\"visits\",action.getVisitedCount()).put(\"unvisited\",action.isUnvisited())"
      }
    ]
  },
  {
    "path": "native/src/com/android/commands/monkey/ape/model/Graph.java",
    "sha256": "5676b123e0aaf93065e72c76ac33aab20d738b0a7262415977c8f1aa35a80022",
    "excerpts": [
      {
        "start": 374,
        "end": 395,
        "text": "374:     public StateTransition addTransition(State source, ModelAction action, State target, GUITree sourceTree,\n375:             GUITreeAction treeAction, GUITree targetTree) {\n376:         StateTransition edge = addStateTransition(source, action, target);\n377:         if (edge == null) {\n378:             return null;\n379:         }\n380:         GUITreeTransition treeTransition = new GUITreeTransition(sourceTree, treeAction, targetTree);\n381:         treeTransition.setThrottle(action.getThrottle());\n382:         edge.updateThrottle(treeTransition.getThrottle());\n383:         stateTransitionHistory.add(edge);\n384:         treeTransitionHistory.add(treeTransition);\n385:         edge.append(treeTransition);\n386: \n387:         edge.strengthen();\n388:         markVisited(edge, timestamp);\n389:         fireStateTransitionEvents(edge);\n390:         if (this.entryGUITrees.contains(sourceTree)) {\n391:             this.entryStates.add(source);\n392:         }\n393:         if (this.cleanEntryGUITrees.contains(sourceTree)) {\n394:             this.cleanEntryStates.add(source);\n395:         }"
      }
    ]
  },
  {
    "path": "native/src/com/android/commands/monkey/MonkeySourceApe.java",
    "sha256": "200f76ef08f336dd0e70daeee6829d5f55e86d77a03775c9c7bfe6e31e9165ae",
    "excerpts": [
      {
        "start": 490,
        "end": 515,
        "text": "490:             break;\n491:         case EVENT_CLEAN_RESTART:\n492:             restartPackage(((StartAction) action).getActivity(), true, \"start action\");\n493:             break;\n494:         case EVENT_NOP:\n495:             generateThrottleEvent(action.getThrottle());\n496:             break;\n497:         case EVENT_ACTIVATE:\n498:             generateActivateEvent();\n499:             break;\n500:         case MODEL_BACK:\n501:             generateKeyBackEvent();\n502:             break;\n503:         case MODEL_CLICK:\n504:             GUITreeNode node = action.getResolvedNode();\n505:             generateClickEventAt(action.getResolvedNode().getBoundsInScreen(), CLICK_WAIT_TIME);\n506:             if (node != null && node.getInputText() != null) {\n507:                 generateThrottleEvent(200); // Let the click event to be scheduled\n508:                 doInput(action, node);\n509:             }\n510:             break;\n511:         case MODEL_LONG_CLICK:\n512:             generateClickEventAt(action.getResolvedNode().getBoundsInScreen(), LONG_CLICK_WAIT_TIME);\n513:             break;\n514:         case MODEL_SCROLL_BOTTOM_UP:\n515:         case MODEL_SCROLL_TOP_DOWN:"
      }
    ]
  },
  {
    "path": "native/src/com/android/commands/monkey/MonkeySourceApeInput.java",
    "sha256": "f4f9f8cf2bf91d8c872ead794e0775f91531d79a67b5a5f8f51c37c7b44e58e4",
    "excerpts": [
      {
        "start": 75,
        "end": 100,
        "text": "75: \n76:     private static float lerp(float a, float b, float alpha) {\n77:         return (b - a) * alpha + a;\n78:     }\n79: \n80:     void doInput(MonkeySourceApe source, Action action, GUITreeNode node) {\n81:         if (lastInputTimestamp == source.getAgent().getTimestamp()) {\n82:             Logger.wprintln(\"checkVirtualKeyboard: Input only once.\");\n83:         } else {\n84:             lastInputTimestamp = source.getAgent().getTimestamp();\n85:         }\n86:         String inputText = node.getInputText();\n87:         if (inputText != null) {\n88:             Logger.iprintln(\"Input text is \" + inputText);\n89:             generateClearEvent(source, node);\n90:             boolean sent = AndroidDevice.sendText(inputText);\n91:             if (source.getAgent() instanceof com.android.commands.monkey.ape.agent.StatefulAgent)\n92:                 ((com.android.commands.monkey.ape.agent.StatefulAgent) source.getAgent()).jevDirectTextInput(action, inputText, sent);\n93:             if (!sent) {\n94:                 attemptToSendTextByKeyEvents(source, inputText);\n95:             }\n96:         } else if (node.isEditText() || AndroidDevice.isVirtualKeyboardOpened()) {\n97:             source.generateKeyEvent(KeyEvent.KEYCODE_ESCAPE);\n98:         }\n99:     }\n100: "
      },
      {
        "start": 125,
        "end": 150,
        "text": "125:         String fullText = info.getText().toString();\n126:         if (fullText.isEmpty()) {\n127:             return 0;\n128:         }\n129:         return fullText.split(System.lineSeparator()).length;\n130:     }\n131: \n132:     private void attemptToSendTextByKeyEvents(MonkeySourceApe source, String inputText) {\n133:         char[] chars = inputText.toCharArray();\n134:         char[] one = new char[1];\n135:         for (int i = 0; i < chars.length; i++) {\n136:             one[0] = chars[i];\n137:             if (MonkeySourceApe.CharMap.getEvents(one) == null) {\n138:                 chars[i] = ' ';\n139:             }\n140:         }\n141:         KeyEvent[] events = MonkeySourceApe.CharMap.getEvents(chars);\n142:         for (int i = 0; i < events.length; i++) {\n143:             source.addEvent(new MonkeyKeyEvent(events[i]));\n144:         }\n145:         source.generateKeyEvent(KeyEvent.KEYCODE_ENTER);\n146:         source.generateThrottleEvent(200);\n147:     }\n148: }"
      }
    ]
  }
]
